updated category page abd functionality, created new schema for menu item page
This commit is contained in:
parent
ee1869b0b8
commit
79548f963c
7 changed files with 135 additions and 49 deletions
|
@ -1,6 +1,8 @@
|
||||||
|
import mongoose from "mongoose";
|
||||||
import { Category } from "../models/Category";
|
import { Category } from "../models/Category";
|
||||||
|
|
||||||
export async function POST(req){
|
export async function POST(req){
|
||||||
|
mongoose.connect(process.env.MONGO_URL)
|
||||||
const {name} = await req.json();
|
const {name} = await req.json();
|
||||||
const categoryDoc = await Category.create({name})
|
const categoryDoc = await Category.create({name})
|
||||||
|
|
||||||
|
@ -8,13 +10,15 @@ export async function POST(req){
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function PUT(req){
|
export async function PUT(req){
|
||||||
|
mongoose.connect(process.env.MONGO_URL)
|
||||||
const {_id, name} = await req.json();
|
const {_id, name} = await req.json();
|
||||||
await Category.updateOne({_id}, {name});
|
await Category.updateOne({_id}, {name});
|
||||||
|
|
||||||
return Response.json(true);
|
return Response.json(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function GET(req){
|
export async function GET(){
|
||||||
|
mongoose.connect(process.env.MONGO_URL)
|
||||||
return Response.json(
|
return Response.json(
|
||||||
await Category.find()
|
await Category.find()
|
||||||
)
|
)
|
||||||
|
|
10
donutshop_ecommerce/src/app/api/menu-items/route.js
Normal file
10
donutshop_ecommerce/src/app/api/menu-items/route.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
import { MenuItem } from "../models/MenuItem";
|
||||||
|
|
||||||
|
export async function POST(req){
|
||||||
|
mongoose.connect(process.env.MONGO_URL)
|
||||||
|
const data = await req.json();
|
||||||
|
const menuItemDoc = await MenuItem.create(data);
|
||||||
|
|
||||||
|
return Response.json(menuItemDoc)
|
||||||
|
}
|
19
donutshop_ecommerce/src/app/api/models/MenuItem.js
Normal file
19
donutshop_ecommerce/src/app/api/models/MenuItem.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { Schema, model, models } from "mongoose";
|
||||||
|
|
||||||
|
const MenuItemSchema = new Schema({
|
||||||
|
itemName:{
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
menuImg:{
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
description:{
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
basePrice:{
|
||||||
|
type: Number
|
||||||
|
},
|
||||||
|
|
||||||
|
}, {timestamps: true})
|
||||||
|
|
||||||
|
export const MenuItem = models?.MenuItem || model('MenuItem', MenuItemSchema)
|
|
@ -1,13 +1,40 @@
|
||||||
"use client"
|
"use client"
|
||||||
import React from 'react'
|
import React, { useState } from 'react'
|
||||||
import UserTab from '../../components/layout/UserTab'
|
import UserTab from '../../components/layout/UserTab'
|
||||||
import useProfile from '../../components/UseProfile'
|
import useProfile from '../../components/UseProfile'
|
||||||
|
import EditImage from '../../components/layout/EditImage'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
|
||||||
const MenuItemsPage = () => {
|
const MenuItemsPage = () => {
|
||||||
const {loading, data} = useProfile();
|
const {loading, data} = useProfile();
|
||||||
|
const [menuImg, setMenuImg] = useState('');
|
||||||
|
const [itemName, setItemName] = useState('');
|
||||||
|
const [description, setDescription] = useState('');
|
||||||
|
const [basePrice, setBasePrice] = useState('');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function handleMenuFormSubmit(ev){
|
||||||
|
ev.preventDefault();
|
||||||
|
const data = {menuImg, itemName, description, basePrice,};
|
||||||
|
const menuSavingPromise = new Promise(async (resolve, reject) => {
|
||||||
|
const response = await fetch('/api/menu-items', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
headers: {'Content-Type': 'application/json'}
|
||||||
|
});
|
||||||
|
if(response.ok)
|
||||||
|
resolve();
|
||||||
|
else
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
await toast.promise(menuSavingPromise, {
|
||||||
|
loading: 'Saving...',
|
||||||
|
success: 'Menu is saved',
|
||||||
|
error: 'Fail to save menu!',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(loading){
|
if(loading){
|
||||||
return <p className='flex justify-center items-center'>Loading...</p>
|
return <p className='flex justify-center items-center'>Loading...</p>
|
||||||
|
@ -16,23 +43,31 @@ const MenuItemsPage = () => {
|
||||||
return <p className='flex justify-center items-center'>Please login as an admin</p>
|
return <p className='flex justify-center items-center'>Please login as an admin</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='px-5 mb-10 max-w-md mx-auto'>
|
<div className='px-5 mb-10'>
|
||||||
<UserTab isAdmin={true}/>
|
<UserTab isAdmin={true}/>
|
||||||
<form className='mt-10'>
|
<div className='max-w-md mx-auto mt-10'>
|
||||||
<div className='flex flex-col'>
|
<form className='mt-10' onSubmit={handleMenuFormSubmit}>
|
||||||
<label className='-mb-1 text-gray-700 font-semibold text-sm flex'>Items name</label>
|
<div className='flex flex-col gap-2 justify-center items-center max-w-[100px] mx-auto mb-5'>
|
||||||
<div className='flex gap-2 items-center'>
|
<EditImage link={menuImg} setLink={setMenuImg}/>
|
||||||
<div className='grow'>
|
|
||||||
<input type='text' placeholder='Enter items name'/>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button type='submit' className='bg-pink-500 text-white p-2 rounded-md hover:opacity-80 duration-300'>Create</button>
|
<label className='-mb-1 text-gray-700 font-semibold text-sm flex'>Item name</label>
|
||||||
|
<input type='text' placeholder='Enter items name' value={itemName} onChange={ev => setItemName(ev.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className='-mb-1 text-gray-700 font-semibold text-sm flex'>Description</label>
|
||||||
|
<input type='text' placeholder='Enter discription' value={description} onChange={ev => setDescription(ev.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className='-mb-1 text-gray-700 font-semibold text-sm flex'>Price</label>
|
||||||
|
<input type='text' placeholder='Enter base price' value={basePrice} onChange={ev => setBasePrice(ev.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
|
<button type='submit' className='w-full bg-pink-500 text-white p-2 rounded-md hover:opacity-80 duration-300'>Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { redirect } from 'next/navigation';
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import UserTabs from "../../components/layout/UserTab"
|
import UserTabs from "../../components/layout/UserTab"
|
||||||
|
import EditImage from "../../components/layout/EditImage"
|
||||||
|
|
||||||
const ProfilePage = () => {
|
const ProfilePage = () => {
|
||||||
//use session
|
//use session
|
||||||
|
@ -65,31 +65,6 @@ const ProfilePage = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleImgchange(ev){
|
|
||||||
const files = ev.target.files;
|
|
||||||
if(files?.length === 1){
|
|
||||||
const data = new FormData;
|
|
||||||
data.set('file', files[0]);
|
|
||||||
|
|
||||||
|
|
||||||
const uploadPromise = fetch('/api/upload', {
|
|
||||||
method: 'POST',
|
|
||||||
body: data,
|
|
||||||
}).then(response => {
|
|
||||||
if(response.ok){
|
|
||||||
return response.json().then(link => {
|
|
||||||
setImage(link)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw new Error('Something went wrong!')
|
|
||||||
});
|
|
||||||
await toast.promise(uploadPromise, {
|
|
||||||
loading: 'Uploading',
|
|
||||||
success: 'An image is uploaded',
|
|
||||||
error: 'Fail to upload image!',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(status === 'loading' || !profileFetchd){
|
if(status === 'loading' || !profileFetchd){
|
||||||
return <p className='flex justify-center items-center'>Loading...</p>
|
return <p className='flex justify-center items-center'>Loading...</p>
|
||||||
|
@ -105,13 +80,7 @@ const ProfilePage = () => {
|
||||||
<UserTabs isAdmin={isAdmin}/>
|
<UserTabs isAdmin={isAdmin}/>
|
||||||
<div className='max-w-md mx-auto mt-10'>
|
<div className='max-w-md mx-auto mt-10'>
|
||||||
<div className='flex flex-col gap-2 justify-center items-center max-w-[100px] mx-auto'>
|
<div className='flex flex-col gap-2 justify-center items-center max-w-[100px] mx-auto'>
|
||||||
{image && (
|
<EditImage link={image} setLink={setImage}/>
|
||||||
<Image src={image} width={100} height={100} alt={'user-image'} className='rounded-full'/>
|
|
||||||
)}
|
|
||||||
<label>
|
|
||||||
<input type='file' onChange={handleImgchange} className='hidden'/>
|
|
||||||
<span className='px-2 py-1 border border-[#DCA0AE] rounded-md text-sm cursor-pointer'>Edit</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<form className='mt-5 text-sm sm:text-base flex flex-col gap-0 sm:gap-1' onSubmit={handleInfoUpdate}>
|
<form className='mt-5 text-sm sm:text-base flex flex-col gap-0 sm:gap-1' onSubmit={handleInfoUpdate}>
|
||||||
<div>
|
<div>
|
||||||
|
@ -148,7 +117,7 @@ const ProfilePage = () => {
|
||||||
<label className='text-gray-700 text-sm font-semibold'>Country</label>
|
<label className='text-gray-700 text-sm font-semibold'>Country</label>
|
||||||
<input type='text' placeholder='Country' value={country} onChange={ev => setCountry(ev.target.value)}/>
|
<input type='text' placeholder='Country' value={country} onChange={ev => setCountry(ev.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<button className='rounded-md bg-[#DCA0AE] text-white hover:opacity-80 duration-300 p-2 font-semibold block w-full disabled:cursor-not-allowed'>Save</button>
|
<button className='w-full bg-pink-500 text-white p-2 rounded-md hover:opacity-80 duration-300 disabled:cursor-not-allowed'>Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
48
donutshop_ecommerce/src/components/layout/EditImage.js
Normal file
48
donutshop_ecommerce/src/components/layout/EditImage.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import Image from 'next/image';
|
||||||
|
import React from 'react'
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
|
const EditImage = ({link, setLink}) => {
|
||||||
|
async function handleImgchange(ev){
|
||||||
|
const files = ev.target.files;
|
||||||
|
if(files?.length === 1){
|
||||||
|
const data = new FormData;
|
||||||
|
data.set('file', files[0]);
|
||||||
|
|
||||||
|
const uploadPromise = fetch('/api/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: data,
|
||||||
|
}).then(response => {
|
||||||
|
if(response.ok){
|
||||||
|
return response.json().then(link => {
|
||||||
|
setLink(link)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw new Error('Something went wrong!')
|
||||||
|
});
|
||||||
|
await toast.promise(uploadPromise, {
|
||||||
|
loading: 'Uploading',
|
||||||
|
success: 'An image is uploaded',
|
||||||
|
error: 'Fail to upload image!',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{link && (
|
||||||
|
<Image src={link} width={500} height={500} alt='user-image' className='mb-2'/>
|
||||||
|
)}
|
||||||
|
{!link && (
|
||||||
|
<div className='bg-gray-200 mb-2 px-3 py-8 text-gray-500 text-center'>No image</div>
|
||||||
|
)}
|
||||||
|
<label className='flex justify-center items-center'>
|
||||||
|
<input type='file' onChange={handleImgchange} className='hidden'/>
|
||||||
|
<span className='px-2 py-1 border border-[#DCA0AE] rounded-md text-sm cursor-pointer'>Edit</span>
|
||||||
|
</label>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditImage
|
|
@ -8,6 +8,7 @@ const MenuItem = () => {
|
||||||
<div className='py-1 sm:py-5 flex flex-col gap-2 sm:gap-4 justify-center items-center text-center rounded-xl bg-white h-[350px] sm:h-[450px]'>
|
<div className='py-1 sm:py-5 flex flex-col gap-2 sm:gap-4 justify-center items-center text-center rounded-xl bg-white h-[350px] sm:h-[450px]'>
|
||||||
<Image src='/donut1.png' width={300} height={300} alt='menu-donut' className='w-[200px] sm:w-[300px]'/>
|
<Image src='/donut1.png' width={300} height={300} alt='menu-donut' className='w-[200px] sm:w-[300px]'/>
|
||||||
<p className='text-sm sm:text-base font-semibold capitalize text-[#95743D] px-2'>Chocolate Beurre noisette Walnut Cream</p>
|
<p className='text-sm sm:text-base font-semibold capitalize text-[#95743D] px-2'>Chocolate Beurre noisette Walnut Cream</p>
|
||||||
|
<p className='text-xs sm:text-sm px-2'>Desciption</p>
|
||||||
<p className='text-[#95743D] text-sm'>$5.99</p>
|
<p className='text-[#95743D] text-sm'>$5.99</p>
|
||||||
<button className='px-2 py-1 sm:px-4 sm:py-2 rounded-full text-xs sm:text-sm border border-[#E78895] text-[#95743D] font-semibold hover:bg-[#E78895] hover:text-[#FDE2DE] duration-300'>Add to cart</button>
|
<button className='px-2 py-1 sm:px-4 sm:py-2 rounded-full text-xs sm:text-sm border border-[#E78895] text-[#95743D] font-semibold hover:bg-[#E78895] hover:text-[#FDE2DE] duration-300'>Add to cart</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue