Compare commits

...

10 commits

19 changed files with 163 additions and 77 deletions

View file

@ -1 +1,11 @@
# E-commerce web application with Next.js
This project is a full stack donut delivery web application. We will be using MongoDB to store data and Amazon S3 to store all images. For user authentication, we will be using NextAuth.js and have two options (google provider and credentials provider) for users to register/login into their dashboard.
## Web application architecture diagram
<p><img src="./public/web_app_architechture.png" width="800" height="380" /></p>
## To start the project
* `npm run dev`

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -1,9 +1,9 @@
import Image from 'next/image'
import React from 'react'
import Footer from '../../components/layout/Footer'
const AboutPage = () => {
return (
<>
<div className='w-full h-full lg:h-screen flex flex-col relative'>
@ -41,7 +41,11 @@ const AboutPage = () => {
<Image src='/about-founder1.jpg' width={1600} height={1600} alt='about-story' className='h-full rounded-3xl object-cover'/>
</div>
<div className="flip-card-back rounded-3xl">
<h3>Hello</h3>
<div className='flex flex-col gap-2 px-4'>
<h3 className='text-pink-500'>Jane Doe</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p><br/>
<p>Et harum quidem rerum facilis est et expedita distinctio.</p>
</div>
</div>
</div>
</div>
@ -51,13 +55,23 @@ const AboutPage = () => {
<Image src='/about-founder2.jpg' width={1600} height={1600} alt='about-story' className='h-full rounded-3xl object-cover'/>
</div>
<div className="flip-card-back rounded-3xl">
<h3>Hello</h3>
<div className='flex flex-col gap-2 px-4'>
<h3 className='text-pink-500'>Jennie Doe</h3>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className='bg-[#FFC55A] -mt-10'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320">
<path fill="#E1AFD1" fill-opacity="1" d="M0,96L16,106.7C32,117,64,139,96,133.3C128,128,160,96,192,69.3C224,43,256,21,288,26.7C320,32,352,64,384,80C416,96,448,96,480,117.3C512,139,544,181,576,176C608,171,640,117,672,85.3C704,53,736,43,768,80C800,117,832,203,864,245.3C896,288,928,288,960,288C992,288,1024,288,1056,250.7C1088,213,1120,139,1152,96C1184,53,1216,43,1248,80C1280,117,1312,203,1344,250.7C1376,299,1408,309,1424,314.7L1440,320L1440,0L1424,0C1408,0,1376,0,1344,0C1312,0,1280,0,1248,0C1216,0,1184,0,1152,0C1120,0,1088,0,1056,0C1024,0,992,0,960,0C928,0,896,0,864,0C832,0,800,0,768,0C736,0,704,0,672,0C640,0,608,0,576,0C544,0,512,0,480,0C448,0,416,0,384,0C352,0,320,0,288,0C256,0,224,0,192,0C160,0,128,0,96,0C64,0,32,0,16,0L0,0Z"></path>
</svg>
</div>
<Footer/>
</>
)
}

View file

@ -21,7 +21,7 @@ export const authOptions = {
id: 'credentials',
credentials: {
username: { label: "Email", type: "email", placeholder: "test@example.com" },
password: { label: "Password", type: "password" }
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
const email = credentials?.email;
@ -32,12 +32,15 @@ export const authOptions = {
const user = await User.findOne({email});
const passwordOk = user && bcrypt.compareSync(password, user.password);
if(passwordOk){
return user
}
return null
}
return user;
} else {
return null;
}}
}),
],
session:{
strategy: "jwt",
},
};
export async function isAdmin(){

View file

@ -93,7 +93,7 @@ const CartPage = () => {
)}
{product.extra?.length > 0 && (
<div className='text-gray-800 font-semibold text-xs sm:text-sm flex flex-col'>Add: {product.extra.map(extras => (
<span className='w-full lg:w-[200px] text-[10px] sm:text-xs text-gray-600'>{extras.itemName} (+${extras.price})</span>
<span key={extras._id} className='w-full lg:w-[200px] text-[10px] sm:text-xs text-gray-600'>{extras.itemName} (+${extras.price})</span>
))}
</div>
)}

View file

@ -0,0 +1,64 @@
import Image from 'next/image'
import React from 'react'
import Footer from '../../components/layout/Footer'
const ContactPage = () => {
return (
<>
<div className='w-full h-full flex flex-col relative'>
<p className='text-center mt-20 uppercase text-[50px] sm:text-[72px] md:text-[90px] lg:text-[125px] xl:text-[140px] leading-none text-black font-extrabold tracking-tighter drop-shadow-[0_3px_3px_rgba(45,45,45,0.5)] px-5'>Contact</p>
<div className='bg-[#FAF3E8] w-full h-full rounded-t-3xl -mt-5 sm:-mt-10 px-5 pb-20'>
<p className='mt-14 text-center text-sm sm:text-base text-gray-700'>Feel free to use this contact form to reach out to us</p>
<p className='text-center text-sm sm:text-base text-gray-700'>Our team is ready for you!</p>
<div className='max-w-7xl mx-auto mt-10'>
<div className='grid grid-col-2 md:grid-cols-3 gap-10'>
<div className='col-span-1 md:col-span-2 pr-0 lg:pr-5 xl:pr-20 flex flex-col gap-2'>
<div>
<label className='text-gray-700 font-medium'>Name</label>
<input type='text' className=''/>
</div>
<div>
<label className='text-gray-700 font-medium'>Email</label>
<input type='email' className=''/>
</div>
<div>
<label className='text-gray-700 font-medium'>Phone Number</label>
<input type='text' className=''/>
</div>
<div className='flex flex-col'>
<label className='text-gray-700 font-medium'>Message</label>
<textarea className='outline-none resize-none' rows="5"/>
</div>
<button type='button' className='bg-[#DCA0AE] p-2 rounded-md text-white font-medium'>Send</button>
</div>
<div className=''>
<div className='flex flex-col border-b border-[#DCA0AE] pb-5 mb-5'>
<p className='font-semibold mb-3 text-gray-700'>Snail Mail</p>
<p>148 Terry Lane</p>
<p>Maitland, FL 32751</p>
</div>
<div className='flex flex-col border-b border-[#DCA0AE] pb-5 mb-5'>
<p className='font-semibold mb-3 text-gray-700'>Electronic Mail</p>
<p>puffydough@example.com</p>
</div>
<div className='flex flex-col border-b border-[#DCA0AE] pb-5'>
<p className='font-semibold mb-3 text-gray-700'>Phone Support</p>
<p>Hours: 9am - 5pm (CST), Monday - Friday</p>
<p>321-329-8783</p>
</div>
</div>
</div>
</div>
</div>
<div className='bg-[#FFC55A]'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320">
<path fill="#FAF3E8" fill-opacity="1" d="M0,64L12,106.7C24,149,48,235,72,229.3C96,224,120,128,144,96C168,64,192,96,216,128C240,160,264,192,288,208C312,224,336,224,360,208C384,192,408,160,432,160C456,160,480,192,504,224C528,256,552,288,576,298.7C600,309,624,299,648,272C672,245,696,203,720,165.3C744,128,768,96,792,106.7C816,117,840,171,864,160C888,149,912,75,936,42.7C960,11,984,21,1008,26.7C1032,32,1056,32,1080,69.3C1104,107,1128,181,1152,202.7C1176,224,1200,192,1224,154.7C1248,117,1272,75,1296,85.3C1320,96,1344,160,1368,186.7C1392,213,1416,203,1428,197.3L1440,192L1440,0L1428,0C1416,0,1392,0,1368,0C1344,0,1320,0,1296,0C1272,0,1248,0,1224,0C1200,0,1176,0,1152,0C1128,0,1104,0,1080,0C1056,0,1032,0,1008,0C984,0,960,0,936,0C912,0,888,0,864,0C840,0,816,0,792,0C768,0,744,0,720,0C696,0,672,0,648,0C624,0,600,0,576,0C552,0,528,0,504,0C480,0,456,0,432,0C408,0,384,0,360,0C336,0,312,0,288,0C264,0,240,0,216,0C192,0,168,0,144,0C120,0,96,0,72,0C48,0,24,0,12,0L0,0Z"></path>
</svg>
</div>
</div>
<Footer/>
</>
)
}
export default ContactPage

View file

@ -10,7 +10,7 @@ body{
overflow-x: hidden;
}
/*===== general setup =====*/
input[type="email"], input[type="password"], input[type="text"], input[type="tel"]{
input[type="email"], input[type="password"], input[type="text"], input[type="tel"], textarea{
@apply border p-2 block my-2 w-full rounded-md outline-none border-[#DCA0AE]
}
/*===== strokel =====*/

View file

@ -8,15 +8,15 @@ import { signIn } from "next-auth/react";
const LoginPage = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loginInProgress, setLoginInProgreass] = useState(false);
const [loginInProgress, setLoginInProgress] = useState(false);
async function handleFormSubmit(ev) {
ev.preventDefault();
setLoginInProgreass(true)
setLoginInProgress(true)
await signIn('credentials', {email, password, callbackUrl:'/'})
await signIn('credentials', {email, password, callbackUrl:'/', redirect: true});
setLoginInProgreass(false)
setLoginInProgress(false)
}

View file

@ -73,7 +73,7 @@ const Header = () => {
</ul>
<div onClick={() => setNav(!nav)} className="cursor-pointer pr-4 z-20 text-[#95743D] md:hidden "> {nav ? <IoCloseOutline size={30} /> : <HiBars2 size={30} />}</div>
{nav && (
<ul className="w-full h-[80%] flex justify-start items-center text-center absolute top-0 left-0 bg-gradient-to-b from-[#f8cdc6] to-[#FDE2DE] text-[#95743D] z-10">
<ul className="w-full h-[100%] flex justify-start items-center text-center absolute top-0 left-0 bg-gradient-to-b from-[#f8cdc6] to-[#FDE2DE] text-[#95743D] z-10">
<li onClick={() => setNav(!nav)} className="w-full flex flex-col gap-5 cursor-pointer capitalize text-xl px-5">
<div className="flex flex-col gap-20 justify-between">
<div className="flex flex-col gap-3">
@ -92,6 +92,7 @@ const Header = () => {
)}
{status === 'unauthenticated' && (
<>
<Link href='/cart' className="flex gap-1 items-center text-sm">Your cart({cartProducts.length})</Link>
<Link href='/login' className="border border-[#95743D] p-1 w-[100px] rounded-full">login</Link>
<Link href='/register' className="bg-[#95743D] p-1 w-[100px] text-white rounded-full">Register</Link>
</>

View file

@ -1,36 +1,6 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
# Kanban boards with Next.js
## Getting Started
This project offers a dynamic way to manage your projects and tasks. Designed to enhance productivity and streamline workflow. You can easily access through the application with google provider. Your change on boards is active for all users that have access to your board.
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
## To start the project
* `npm run dev`

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>

Before

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View file

@ -6,7 +6,7 @@ import Header from "@/components/Header";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Task Management App",
title: "Agenda board",
description: "Generated by create next app",
};
@ -17,6 +17,7 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<link rel="shortcut icon" href="/logo.png" />
<body className={inter.className}>
<Header/>
<main className="p-10">

View file

@ -1,5 +1,6 @@
import Boards from "@/components/Boards";
import LoginView from "@/components/views/LoginView";
import Hero from "@/components/Hero";
import { authOptions } from "@/lib/authOptions";
import { getServerSession } from "next-auth";
import Link from "next/link";
@ -10,7 +11,10 @@ export default async function Home() {
const session = await getServerSession(authOptions);
if(!session){
return(
<>
<Hero/>
<LoginView/>
</>
);
}
return (

View file

@ -3,13 +3,17 @@ import { getServerSession } from 'next-auth'
import LogoutButton from './LogoutButton';
import LoginButton from './LoginButton';
import Link from 'next/link';
import Image from 'next/image';
import Logo from '../../public/logo.png'
const Header = async () => {
const session = await getServerSession(authOptions);
return (
<header className="p-4 border border-b-[#9BBEC8] px-4 md:px-10">
<div className='flex justify-between items-center'>
<Link href="/" className="logo text-[#427D9D] font-semibold">Task Management</Link>
<Link href="/" className="logo text-[#427D9D] font-semibold">
<Image src={Logo} alt='logo' className='w-[90px]'/>
</Link>
<div>
{session && (
<div className='flex justify-center items-center'>
@ -21,7 +25,6 @@ const Header = async () => {
)}
{!session && (
<div className='text-sm md:text-base'>
Not logged in
<LoginButton/>
</div>
)}

View file

@ -0,0 +1,18 @@
import Image from 'next/image'
import React from 'react'
import Img_hero from '../../public/img.png'
function Hero() {
return (
<div>
<div className='items-center text-center my-10 pb-5'>
<p className='uppercase text-4xl md:text-5xl font-semibold drop-shadow-xl font-outline-2 text-[#37B7C3] mb-5'>Manage your workflow with us!</p>
</div>
<div className='flex justify-center'>
<Image src={Img_hero} alt='img-hero'/>
</div>
</div>
)
}
export default Hero