Skip to content

Commit

Permalink
Merge pull request #7 from WebmasterCamp/feature/add-cart-and-modal-p…
Browse files Browse the repository at this point in the history
…ayment

Feature/add cart and modal payment
  • Loading branch information
ninew089 authored Jul 16, 2023
2 parents bfaa9b4 + 5981f5c commit d663dab
Show file tree
Hide file tree
Showing 8 changed files with 403 additions and 81 deletions.
Binary file added public/assets/price.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions src/components/CartItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useState } from "react";
import { LazyImage } from "./LazyImage";
import { twMerge } from "tailwind-merge";

export default function CartItem({
name,
price,
img,
total,
onDelete,
}: {
name: string;
price: string;
img: string;
total: number;
onDelete?: () => void;
}) {
const [totalItem, setTotalItem] = useState<number>(total);
return (
<div
className={twMerge(
"flex gap-x-4 rounded-md p-3 shadow-md",
(total === 0 || totalItem === 0) && "hidden"
)}
>
<div className="h-fit overflow-hidden rounded-lg">
<LazyImage src={img} ratio="1/1" width={120} height={120} />
</div>

<div>
<p className="text-h5 font-bold">{name}</p>
<p className="text-h6 font-bold">{price}</p>
<div className="mt-6 flex w-fit items-center gap-x-3 rounded-lg bg-[#F5F5F5] p-1">
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="cursor-pointer"
onClick={() => {
setTotalItem(0);
onDelete?.();
}}
>
<path
d="M15.75 4.5H12V3.2475C11.9824 2.76736 11.7752 2.31379 11.4237 1.98622C11.0722 1.65864 10.6052 1.48379 10.125 1.5H7.875C7.39482 1.48379 6.9278 1.65864 6.57632 1.98622C6.22485 2.31379 6.01759 2.76736 6 3.2475V4.5H2.25C2.05109 4.5 1.86032 4.57901 1.71967 4.71967C1.57902 4.86032 1.5 5.05108 1.5 5.25C1.5 5.44891 1.57902 5.63967 1.71967 5.78033C1.86032 5.92098 2.05109 6 2.25 6H3V14.25C3 14.8467 3.23705 15.419 3.65901 15.841C4.08097 16.2629 4.65326 16.5 5.25 16.5H12.75C13.3467 16.5 13.919 16.2629 14.341 15.841C14.7629 15.419 15 14.8467 15 14.25V6H15.75C15.9489 6 16.1397 5.92098 16.2803 5.78033C16.421 5.63967 16.5 5.44891 16.5 5.25C16.5 5.05108 16.421 4.86032 16.2803 4.71967C16.1397 4.57901 15.9489 4.5 15.75 4.5ZM7.5 3.2475C7.5 3.1275 7.6575 3 7.875 3H10.125C10.3425 3 10.5 3.1275 10.5 3.2475V4.5H7.5V3.2475ZM13.5 14.25C13.5 14.4489 13.421 14.6397 13.2803 14.7803C13.1397 14.921 12.9489 15 12.75 15H5.25C5.05109 15 4.86032 14.921 4.71967 14.7803C4.57902 14.6397 4.5 14.4489 4.5 14.25V6H13.5V14.25Z"
fill="#5F5F5F"
/>
<path
d="M6.75 12.75C6.94891 12.75 7.13968 12.671 7.28033 12.5303C7.42098 12.3897 7.5 12.1989 7.5 12V9C7.5 8.80108 7.42098 8.61032 7.28033 8.46967C7.13968 8.32901 6.94891 8.25 6.75 8.25C6.55109 8.25 6.36032 8.32901 6.21967 8.46967C6.07902 8.61032 6 8.80108 6 9V12C6 12.1989 6.07902 12.3897 6.21967 12.5303C6.36032 12.671 6.55109 12.75 6.75 12.75Z"
fill="#5F5F5F"
/>
<path
d="M11.25 12.75C11.4489 12.75 11.6397 12.671 11.7803 12.5303C11.921 12.3897 12 12.1989 12 12V9C12 8.80108 11.921 8.61032 11.7803 8.46967C11.6397 8.32901 11.4489 8.25 11.25 8.25C11.0511 8.25 10.8603 8.32901 10.7197 8.46967C10.579 8.61032 10.5 8.80108 10.5 9V12C10.5 12.1989 10.579 12.3897 10.7197 12.5303C10.8603 12.671 11.0511 12.75 11.25 12.75Z"
fill="#5F5F5F"
/>
</svg>
<p>{totalItem}</p>
<svg
className="cursor-pointer"
onClick={() => setTotalItem(totalItem + 1)}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 6V18M18 12L6 12"
stroke="#5F5F5F"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
</div>
</div>
);
}
79 changes: 79 additions & 0 deletions src/components/ModalConfirm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useEffect, useState } from "react";
import { LazyImage } from "./LazyImage";
import { useSearchParams, useRouter } from "next/navigation";

export default function ModalConfirm() {
const [open, setOpen] = useState<boolean>(false);
const searchParams = useSearchParams();
const route = useRouter();
const search = searchParams.get("status");
useEffect(() => {
if (search?.includes("success")) {
setOpen(true);
}
}, [search]);
useEffect(() => {
if (open) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "visible";
}

return () => {
document.body.style.overflow = "visible";
};
}, [open]);
return (
open && (
<div
id="popup-modal"
className="fixed left-0 right-0 top-0 z-[99] flex h-screen max-h-full items-center justify-center overflow-y-auto overflow-x-hidden bg-[#000]/80 p-4 md:inset-0"
>
<div className="relative max-h-full w-full max-w-md ">
<div className="relative w-[380px] rounded-lg bg-white shadow">
<button
type="button"
className="absolute right-2.5 top-3 ml-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-600 dark:hover:text-white"
data-modal-hide="popup-modal"
onClick={() => {
setOpen(false);
route.push("/");
}}
>
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17.8709 15.9922L23.5968 10.2792C24.1189 9.75703 24.1189 8.9104 23.5968 8.38822C23.0746 7.86604 22.228 7.86604 21.7059 8.38822L15.9934 14.1145L10.2808 8.38822C9.75869 7.86604 8.91212 7.86604 8.38998 8.38822C7.86783 8.9104 7.86783 9.75703 8.38998 10.2792L14.1158 15.9922L8.38998 21.7051C8.13789 21.9551 7.99609 22.2955 7.99609 22.6506C7.99609 23.0057 8.13789 23.346 8.38998 23.5961C8.64 23.8482 8.98035 23.99 9.33541 23.99C9.69046 23.99 10.0308 23.8482 10.2808 23.5961L15.9934 17.8698L21.7059 23.5961C21.9559 23.8482 22.2963 23.99 22.6513 23.99C23.0064 23.99 23.3467 23.8482 23.5968 23.5961C23.8488 23.346 23.9906 23.0057 23.9906 22.6506C23.9906 22.2955 23.8488 21.9551 23.5968 21.7051L17.8709 15.9922Z"
fill="#637381"
/>
</svg>
<span className="sr-only">Close modal</span>
</button>
<div className="flex flex-col items-center justify-center p-6 text-center ">
<LazyImage src="/assets/price.gif" width={174} height={174} />
<h3 className="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">
Sustainability is served. Keep going champ.
</h3>
<button
data-modal-hide="popup-modal"
type="button"
className="flex items-center rounded-lg bg-primary-main px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-primary-dark focus:outline-none focus:ring-4 focus:ring-primary-light"
onClick={() => {
setOpen(false);
route.push("/");
}}
>
Back to home
</button>
</div>
</div>
</div>
</div>
)
);
}
148 changes: 95 additions & 53 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,105 @@
import { signIn, signOut, useSession } from "next-auth/react"
import { useRouter } from "next/router"
import { useCallback, type FC, useEffect, useState } from "react"
import { twMerge } from 'tailwind-merge'

import { signIn, signOut, useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useCallback, type FC, useEffect, useState } from "react";
import { twMerge } from "tailwind-merge";

export interface INavbarProps {
data: { name: string, href: string }[],
data: { name: string; href: string }[];
}

export const Navbar: FC<INavbarProps> = (props) => {
const { data } = props
const router = useRouter()
const [path, setPath] = useState<string>('/')
const user = useSession()
const { data } = props;
const router = useRouter();
const [path, setPath] = useState<string>("/");
const user = useSession();

const isActive = useCallback((href: string): boolean => {
const res = path.includes(href)
return res
}, [path])
const isActive = useCallback(
(href: string): boolean => {
const res = path.includes(href);
return res;
},
[path]
);

useEffect(() => {
setPath(router.asPath)
}, [router.asPath])
useEffect(() => {
setPath(router.asPath);
}, [router.asPath]);

return <nav className="bg-white fixed w-full z-20 top-0 left-0 border-b border-gray-200 dark:border-gray-600">
<div className="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
<a href="https://flowbite.com/" className="flex items-center">
<img src="https://flowbite.com/docs/images/logo.svg" className="h-8 mr-3" alt="Flowbite Logo" />
<span className="self-center text-2xl font-semibold whitespace-nowrap">Flowbite</span>
</a>
<div className="flex md:order-2">
<button type="button" onClick={() => {
if (user.status == 'unauthenticated') {
void signIn('google')
return
} else {
void signOut()
}
}} className="text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 text-center mr-3 md:mr-0">{user.status === 'unauthenticated' ? 'Log in' : 'Log out'}</button>
<button data-collapse-toggle="navbar-sticky" type="button" className="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200" aria-controls="navbar-sticky" aria-expanded="false">
<span className="sr-only">Open main menu</span>
<svg className="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15" />
</svg>
</button>
</div>
<div className="items-center justify-between hidden w-full md:flex md:w-auto md:order-1" id="navbar-sticky">
<ul className="flex flex-col p-4 md:p-0 mt-4 font-medium border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 md:mt-0 md:border-0 md:bg-white">
{
data.map(({ name, href }, i) =>
<li key={i}>
<a href={href} className={twMerge("block py-2 pl-3 pr-4 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0", isActive(href) && "text-white md:text-blue-700 bg-blue-700 rounded md:bg-transparent")}>
{name}
</a>
</li>)
}
</ul>
</div>
return (
<nav className="fixed left-0 top-0 z-20 w-full border-b border-gray-200 bg-white dark:border-gray-600">
<div className="mx-auto flex max-w-screen-xl flex-wrap items-center justify-between p-4">
<a href="https://flowbite.com/" className="flex items-center">
<img
src="https://flowbite.com/docs/images/logo.svg"
className="mr-3 h-8"
alt="Flowbite Logo"
/>
<span className="self-center whitespace-nowrap text-2xl font-semibold">
Flowbite
</span>
</a>
<div className="flex md:order-2">
<button
type="button"
onClick={() => {
if (user.status == "unauthenticated") {
void signIn("google");
return;
} else {
void signOut();
}
}}
className="mr-3 rounded-lg bg-green-700 px-4 py-2 text-center text-sm font-medium text-white hover:bg-green-800 focus:outline-none focus:ring-4 focus:ring-blue-300 md:mr-0"
>
{user.status === "unauthenticated" ? "Log in" : "Log out"}
</button>
<button
data-collapse-toggle="navbar-sticky"
type="button"
className="inline-flex h-10 w-10 items-center justify-center rounded-lg p-2 text-sm text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 md:hidden"
aria-controls="navbar-sticky"
aria-expanded="false"
>
<span className="sr-only">Open main menu</span>
<svg
className="h-5 w-5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 17 14"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M1 1h15M1 7h15M1 13h15"
/>
</svg>
</button>
</div>
<div
className="hidden w-full items-center justify-between md:order-1 md:flex md:w-auto"
id="navbar-sticky"
>
<ul className="mt-4 flex flex-col rounded-lg border border-gray-100 bg-gray-50 p-4 font-medium md:mt-0 md:flex-row md:space-x-8 md:border-0 md:bg-white md:p-0">
{data.map(({ name, href }, i) => (
<li key={i}>
<a
href={href}
className={twMerge(
"block rounded py-2 pl-3 pr-4 text-gray-900 hover:bg-gray-100 md:p-0 md:hover:bg-transparent md:hover:text-blue-700",
isActive(href) &&
"rounded bg-blue-700 text-white md:bg-transparent md:text-blue-700"
)}
>
{name}
</a>
</li>
))}
</ul>
</div>
</div>
</nav>
}

);
};
70 changes: 70 additions & 0 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useRouter } from "next/navigation";
import React from "react";
import { twMerge } from "tailwind-merge";
import CartItem from "./CartItem";

export const Sidebar = ({
open,
handleClose,
}: {
open: boolean;
handleClose: () => void;
}) => {
const route = useRouter();
return (
<>
{open && (
<div className="fixed left-0 right-0 top-0 z-[50] flex h-screen max-h-full items-center justify-center overflow-y-auto overflow-x-hidden bg-[#000]/80 p-4 md:inset-0" />
)}
<div
id="drawer-navigation"
className={twMerge(
"fixed right-0 top-0 z-[60] h-screen w-[465px] overflow-y-auto bg-white transition-all duration-300",
!open && "-right-[1000px]"
)}
aria-labelledby="drawer-navigation-label"
>
<div className="flex h-full flex-col overflow-y-auto py-4">
<p className="px-6 text-h6 font-bold">Your Basket</p>
<div className="my-6 h-[0.5px] w-full bg-[#919EAB]/30 " />
<div className="px-6">
<CartItem
name="Chicken Salad"
price="50"
total={1}
img="https://images.unsplash.com/photo-1484659619207-9165d119dafe?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80"
/>
</div>
<div className="mt-auto border-t-[0.5px] border-[#DEDEDE]" />
<div className="px-6">
<div className="mb-3 flex items-center justify-between pt-3">
<p className="text-subtitle1 font-bold">Total</p>
<p className="font-semibold">฿50</p>
</div>
<div className="flex items-center gap-x-2">
<button
data-modal-hide="popup-modal"
type="button"
onClick={handleClose}
className="flex w-full items-center justify-center rounded-lg border border-primary-main px-5 py-2.5 text-center text-sm font-medium text-primary-main"
>
Continue Shopping
</button>

<button
data-modal-hide="popup-modal"
type="button"
className="flex w-full items-center justify-center rounded-lg bg-primary-main px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-primary-dark focus:outline-none focus:ring-4 focus:ring-primary-light"
onClick={() =>
route.push("https://buy.stripe.com/test_fZe3f2gSYcSL9moaEE")
}
>
Purchase
</button>
</div>
</div>
</div>
</div>
</>
);
};
Loading

0 comments on commit d663dab

Please sign in to comment.