diff --git a/app/Header.tsx b/app/Header.tsx deleted file mode 100644 index bf089bb..0000000 --- a/app/Header.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export default function Head() { - return ( - <> - Checks! - - - - - ) - } - \ No newline at end of file diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx new file mode 100644 index 0000000..237190a --- /dev/null +++ b/app/components/Footer.tsx @@ -0,0 +1,64 @@ +import Link from "next/link"; + +const Footer = () => { + return ( +
+
+
+

Checks!

+

+ Built by{" "} + + @TaiDev + {" "} + (2023). See source code{" "} + + here. + +

+

+ Powered by{" "} + + Vercel + + ,{" "} + + Railway + {" "} + &{" "} + + AWS S3 + + . +

+
+ +
+

This is not a real e-commerce site.

+
+
+
+ ); +}; + +export default Footer; diff --git a/app/components/Header.tsx b/app/components/Header.tsx new file mode 100644 index 0000000..90bea93 --- /dev/null +++ b/app/components/Header.tsx @@ -0,0 +1,60 @@ +"use client"; + +import { usePathname, useRouter } from "next/navigation"; +import cn from "../helpers/cn"; +import { useUserContext } from "../providers/UserProvider"; +import SearchSection from "./SearchSection/SearchSection"; +import TitleClick from "./TitleClick"; +import AuthButton from "./buttons/AuthButton"; +import CheckoutBtn from "./menus/CartMenu"; + +const Header = () => { + const { isAdmin } = useUserContext(); + const path = usePathname(); + const router = useRouter(); + + const isInPath = (route: string) => path === route; + + const adminSection = isAdmin && !!path?.startsWith("/admin"); + + return ( +
+
+ + Checks! + + {!adminSection ? ( + + ) : ( +
+

router.push("/admin")} + > + Orders +

+

router.push("/admin/products")} + > + Products +

+
+ )} +
+
+ +
+ {!adminSection && } +
+
+ ); +}; + +export default Header; diff --git a/app/components/SearchSection/SearchSection.tsx b/app/components/SearchSection/SearchSection.tsx new file mode 100644 index 0000000..fc9c073 --- /dev/null +++ b/app/components/SearchSection/SearchSection.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const SearchSection = () => { + return
SearchSection
; +}; + +export default SearchSection; diff --git a/app/components/TitleClick.tsx b/app/components/TitleClick.tsx new file mode 100644 index 0000000..418386e --- /dev/null +++ b/app/components/TitleClick.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import React from "react"; +import cn from "../helpers/cn"; + +interface TitleClickProps extends React.HTMLAttributes { + route: string; +} + +const TitleClick = ({ + route, + children, + className = "", + ...props +}: TitleClickProps) => { + const router = useRouter(); + + return ( +
router.push(route)} + > + {children} +
+ ); +}; + +export default TitleClick; diff --git a/app/components/buttons/AuthButton.tsx b/app/components/buttons/AuthButton.tsx new file mode 100644 index 0000000..f927edb --- /dev/null +++ b/app/components/buttons/AuthButton.tsx @@ -0,0 +1,20 @@ +"use client"; + +import { useUserContext } from "../../providers/UserProvider"; +import UserMenu from "../menus/UserMenu"; +import { SignInButton } from "./SignInButton"; +const AuthButton = () => { + const { user, isAdmin } = useUserContext(); + + if (!user) { + return ; + } + + return ( +
+ +
+ ); +}; + +export default AuthButton; diff --git a/app/components/buttons/Button.tsx b/app/components/buttons/Button.tsx new file mode 100644 index 0000000..56f462e --- /dev/null +++ b/app/components/buttons/Button.tsx @@ -0,0 +1,76 @@ +"use client"; + +import React, { useState } from "react"; +import { FiLoader } from "react-icons/fi"; +import cn from "../../helpers/cn"; + +interface ButtonProps extends React.ButtonHTMLAttributes { + onClick?: (e: React.MouseEvent) => void; + isLoading?: boolean; + localLoaderOnClick?: boolean; // default to true + disabled?: boolean; + children: React.ReactNode; + color?: "primary" | "secondary" | "red"; +} + +const Button = ({ + onClick, + className = "", + isLoading = false, + localLoaderOnClick = true, + disabled = false, + children, + color, + ...props +}: ButtonProps) => { + const [localLoading, setLocalLoading] = useState(false); + + const loadStatus = isLoading || (localLoaderOnClick && localLoading); + + const baseClassName = + "rounded-md ease-in duration-100 flex flex-row items-center justify-center text-[14px]"; + const primaryClassName = cn( + baseClassName, + "bg-zinc-700 hover:bg-zinc-900 text-gray-100", + loadStatus || (disabled && "bg-zinc-900 cursor-not-allowed") + ); + const secondaryClassName = cn( + baseClassName, + "border border-zinc-300 hover:bg-zinc-200 text-zinc-600", + loadStatus || (disabled && "bg-zinc-200 cursor-not-allowed") + ); + const redClassName = cn( + baseClassName, + "bg-red-800 hover:bg-red-900 text-gray-100", + loadStatus || (disabled && "bg-red-900 cursor-not-allowed") + ); + + const handleClick = (e: React.MouseEvent) => { + if (disabled || loadStatus) return; + setLocalLoading(true); + if (onClick) { + return onClick(e); + } + }; + + return ( + + ); +}; + +export default Button; diff --git a/app/components/buttons/SignInButton.tsx b/app/components/buttons/SignInButton.tsx new file mode 100644 index 0000000..ffe6eac --- /dev/null +++ b/app/components/buttons/SignInButton.tsx @@ -0,0 +1,36 @@ +"use client"; + +import { Menu, MenuHandler, MenuList } from "@material-tailwind/react"; +import Button from "./Button"; + +export const SignInButton = () => { + const handleSignIn = async (provider: "github" | "twitch") => { + alert(provider); + }; + + return ( + + +
+ Login +
+
+ +

Select provider:

+ + + +
+
+ ); +}; diff --git a/app/components/menus/CartMenu.tsx b/app/components/menus/CartMenu.tsx new file mode 100644 index 0000000..da67a53 --- /dev/null +++ b/app/components/menus/CartMenu.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const CheckoutBtn = () => { + return
CheckoutBtn
; +}; + +export default CheckoutBtn; diff --git a/app/components/menus/UserMenu.tsx b/app/components/menus/UserMenu.tsx new file mode 100644 index 0000000..6ce71ce --- /dev/null +++ b/app/components/menus/UserMenu.tsx @@ -0,0 +1,9 @@ +"use client"; + +import React from "react"; + +const UserMenu = () => { + return
UserMenu
; +}; + +export default UserMenu; diff --git a/app/head.tsx b/app/head.tsx new file mode 100644 index 0000000..15804fa --- /dev/null +++ b/app/head.tsx @@ -0,0 +1,10 @@ +export default function Head() { + return ( + <> + Checks! + + + + + ); +} diff --git a/app/helpers/cn.ts b/app/helpers/cn.ts new file mode 100644 index 0000000..cc89787 --- /dev/null +++ b/app/helpers/cn.ts @@ -0,0 +1,6 @@ +import clsx, { ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)); + +export default cn; diff --git a/app/layout.tsx b/app/layout.tsx index 844b1b8..aad9ec6 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,23 +1,29 @@ -import './globals.css' -import type { Metadata } from 'next' -import { Inter } from 'next/font/google' +import "./globals.css"; +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import Footer from "./components/Footer"; +import Header from "./components/Header"; -const inter = Inter({ subsets: ['latin'] }) +const inter = Inter({ subsets: ["latin"], variable: "--font-inter" }); export const metadata: Metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -} + title: "Create Next App", + description: "Generated by create next app", +}; export default function RootLayout({ children, }: { - children: React.ReactNode + children: React.ReactNode; }) { return ( - + - {children} + +
+ {children} +