Skip to content

Commit

Permalink
added order and payment functionality to user dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
WTanardi committed Jun 11, 2023
1 parent 9e68ab0 commit 5b1ac44
Show file tree
Hide file tree
Showing 13 changed files with 1,568 additions and 36 deletions.
31 changes: 31 additions & 0 deletions app/api/order/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NextResponse } from "next/server";
import { PrismaClient, Order } from "@prisma/client";
const prisma = new PrismaClient();

export const PATCH = async (
req: Request,
{ params }: { params: { id: string } }
) => {
const body: Order = await req.json();
const order = await prisma.order.update({
where: {
id: Number(params.id),
},
data: {
isPaid: body.isPaid,
},
});
return NextResponse.json(order, { status: 200 });
};

export const DELETE = async (
req: Request,
{ params }: { params: { id: string } }
) => {
const recipe = await prisma.order.delete({
where: {
id: Number(params.id),
},
});
return NextResponse.json(recipe, { status: 200 });
};
43 changes: 43 additions & 0 deletions app/api/order/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import prisma from "@/lib/prisma";
import { NextResponse } from "next/server";

export async function GET(req: Request) {
const recipes = await prisma.order.findFirst({
select: {
id: true,
totalPrice: true,
foodId: true,
userId: true,
isPaid: true,
},
take: -1,
});

return NextResponse.json(recipes);
}

export async function POST(req: Request) {
const { totalPrice, foodId, userId, isPaid } = await req.json();

console.log(
"totalPrice: ",
totalPrice,
"foorID: ",
foodId,
"userId: ",
userId,
"isPaid: ",
isPaid
);

const order = await prisma.order.create({
data: {
totalPrice,
foodId,
userId,
isPaid,
},
});

return NextResponse.json(order);
}
4 changes: 2 additions & 2 deletions app/dashboard/admin/UpdateIngredient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type Ingredient = {
categoryId: number;
};

const Updateingredient = ({
const UpdateIngredient = ({
categories,
ingredient,
}: {
Expand Down Expand Up @@ -97,4 +97,4 @@ const Updateingredient = ({
);
};

export default Updateingredient;
export default UpdateIngredient;
6 changes: 3 additions & 3 deletions app/dashboard/admin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -344,10 +344,10 @@ export default function AdminDashboard() {
</div>
{/* Ingredient list table */}
<>
<div className="flex justify-between py-8">
<p className="text-5xl lg:text-6xl font-bold">Ingredients</p>
<div className="flex justify-between py-4">
<p className="text-4xl lg:text-6xl font-bold">Ingredients</p>
<button
className="px-3 lg:p-4 border-rose-600 rounded-xl bg-rose-600"
className="px-2 lg:p-4 border-rose-600 rounded-xl bg-rose-600"
onClick={handleIngredientAddModal}
>
<Plus className="text-white" />
Expand Down
113 changes: 113 additions & 0 deletions app/dashboard/user/AddOrder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"use client";
import { SyntheticEvent, useEffect, useState } from "react";
import { CheckCircle2 } from "lucide-react";
import axios from "axios";
import { Prisma } from "@prisma/client";
import toast from "react-hot-toast";
import { useSession } from "next-auth/react";
import { fetchData } from "next-auth/client/_utils";

type Order = Prisma.OrderGetPayload<{}>;
type Recipe = Prisma.RecipeGetPayload<{}>;

const AddOrder = ({
price,
name,
foodId,
}: {
price: number;
name: string;
foodId: number;
}) => {
const [isOpen, setIsOpen] = useState(false);
const [orders, setOrders] = useState<Order | null>(null);

const fetcher = (url: string) => axios.get(url).then((res) => res.data);

const { data: session } = useSession();

const [newOrder, setNewOrder] = useState({
userId: session?.user.id,
foodId: foodId,
totalPrice: Number(price),
isPaid: false,
});

const [paid, setPaid] = useState(false);

const createOrder = async () => {
await axios
.post("/api/order", {
userId: newOrder.userId,
foodId: newOrder.foodId,
totalPrice: newOrder.totalPrice,
isPaid: newOrder.isPaid,
})
.then(() => toast.success("Creating order..."))
.catch(() => toast.error("Something went wrong!"));

setIsOpen(!isOpen);

const fetchData = async () => {
try {
const [orderResponse] = await Promise.all([fetcher("/api/order")]);
setOrders(orderResponse);
} catch (error) {
console.error("Error:", error);
}
};

fetchData();
};

const updatePayment = async (e: SyntheticEvent) => {
e.preventDefault();

!paid
? toast.error("Payment incomplete")
: await axios
.patch(`/api/order/${orders?.id}`, { isPaid: true })
.then(() => toast.success("Order success"))
.then(() => setIsOpen(!isOpen));
};

const deleteOrder = async () => {
await axios
.delete(`/api/order/${orders?.id}`)
.then(() => toast.error("Order cancelled"));
setIsOpen(!isOpen);
};

return (
<div>
<button onClick={createOrder} className="btn btn-primary">
Order Now
</button>
<div className={isOpen ? "modal modal-open" : "modal"}>
<div className="modal-box ">
<div className="text-black">
<p className="text-2xl pb-4">Buy {name}</p>
<div className="flex flex-row justify-between">
<p className="text-lg">
Make payment of ${price.toFixed(2)} to 082111442634
</p>
<button onClick={() => setPaid(!paid)}>
<CheckCircle2 color={!paid ? "red" : "green"} />
</button>
</div>
</div>
<div className="modal-action">
<div className="btn" onClick={deleteOrder}>
Cancel
</div>
<div className="btn btn-primary" onClick={updatePayment}>
Confirm
</div>
</div>
</div>
</div>
</div>
);
};

export default AddOrder;
31 changes: 21 additions & 10 deletions app/dashboard/user/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import RecipeCard from "@/components/RecipeCard";
import { Book, LogOut, Refrigerator, Search } from "lucide-react";
import SignOut from "@/components/sign-out";
import { Prisma } from "@prisma/client";
import { useState, useEffect, FC } from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import Image from "next/image";
import { signOut } from "next-auth/react";
import { signOut, useSession } from "next-auth/react";

type Ingredient = Prisma.IngredientGetPayload<{
select: {
Expand All @@ -31,6 +30,7 @@ type Recipe = Prisma.RecipeGetPayload<{
name: true;
img: true;
step: true;
price: true;
ingredients: {
select: {
amount: true;
Expand All @@ -41,12 +41,15 @@ type Recipe = Prisma.RecipeGetPayload<{
};
}>;

type Order = Prisma.OrderGetPayload<{}>;

const fetcher = (url: string) => axios.get(url).then((res) => res.data);

export default function UserDashboard() {
const [ingredients, setIngredients] = useState<Ingredient[] | null>(null);
const [categories, setCategories] = useState<Category[] | null>(null);
const [recipes, setRecipes] = useState<Recipe[] | null>(null);
const [orders, setOrders] = useState<Order[] | null>(null);
const [showPantry, setShowPantry] = useState(true);

const handlePantryClick = () => {
Expand All @@ -60,15 +63,21 @@ export default function UserDashboard() {
useEffect(() => {
const fetchData = async () => {
try {
const [ingredientResponse, categoryResponse, recipeResponse] =
await Promise.all([
fetcher("/api/ingredient"),
fetcher("/api/category"),
fetcher("/api/recipe"),
]);
const [
ingredientResponse,
categoryResponse,
recipeResponse,
orderResponse,
] = await Promise.all([
fetcher("/api/ingredient"),
fetcher("/api/category"),
fetcher("/api/recipe"),
fetcher("/api/order"),
]);
setIngredients(ingredientResponse);
setCategories(categoryResponse);
setRecipes(recipeResponse);
setOrders(orderResponse);
} catch (error) {
console.error("Error:", error);
}
Expand Down Expand Up @@ -134,7 +143,7 @@ export default function UserDashboard() {
<button className="absolute inset-y-0 right-0 px-4 py-1 text-gray-300 font-medium rounded-md focus:outline-none">
<Search />
</button>
</div>
</div>
</div>
{/* <!-- Pantry Content --> */}
<div className="flex flex-col md:flex-row md:flex-wrap gap-8 md:justify-center items-center p-8 overflow-y-auto">
Expand Down Expand Up @@ -190,6 +199,8 @@ export default function UserDashboard() {
ingredients={e.ingredients}
img={e.img}
step={e.step}
price={e.price}
id={e.id}
></RecipeCard>
))}
</div>
Expand Down
19 changes: 17 additions & 2 deletions components/RecipeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React, { FC, useState } from "react";
import Image from "next/image";
import { Prisma } from "@prisma/client";
import { X } from "lucide-react";
import { ShoppingCart, X } from "lucide-react";
import AddOrder from "@/app/dashboard/user/AddOrder";

type Recipe = Prisma.RecipeGetPayload<{
select: {
id: true;
name: true;
img: true;
step: true;
price: true;
ingredients: {
select: {
amount: true;
Expand All @@ -22,7 +25,14 @@ type Recipe = Prisma.RecipeGetPayload<{
};
}>;

const RecipeCard: FC<Recipe> = ({ name, img, ingredients, step }) => {
const RecipeCard: FC<Recipe> = ({
name,
img,
ingredients,
step,
price,
id,
}) => {
const [isOpen, setIsOpen] = useState(false);

const handleModal = () => {
Expand Down Expand Up @@ -82,6 +92,11 @@ const RecipeCard: FC<Recipe> = ({ name, img, ingredients, step }) => {
))}
</ol>
</div>
<div className="modal-action">
<div className="m-4">
<AddOrder price={price} name={name} foodId={id} />
</div>
</div>
<div
className="absolute top-0 right-0 m-4 cursor-pointer"
onClick={handleModal}
Expand Down
Loading

1 comment on commit 5b1ac44

@vercel
Copy link

@vercel vercel bot commented on 5b1ac44 Jun 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

pantry-pilot-2 – ./

pantry-pilot-2-git-main-wtanardi.vercel.app
pantry-pilot-2-wtanardi.vercel.app
pantry-pilot-2.vercel.app

Please sign in to comment.