├── .eslintrc.json ├── .gitignore ├── README.md ├── components ├── bs.tsx ├── button.tsx ├── floating-button.tsx ├── input.tsx ├── item.tsx ├── layout.tsx ├── message.tsx ├── product-list.tsx └── textarea.tsx ├── libs ├── client │ ├── useCoords.ts │ ├── useMutation.ts │ ├── useUser.ts │ └── utils.ts └── server │ ├── client.ts │ ├── withHandler.ts │ └── withSession.ts ├── next-env.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── _app.tsx ├── _document.tsx ├── _middleware.ts ├── api │ ├── files.ts │ ├── posts │ │ ├── [id] │ │ │ ├── answers.ts │ │ │ ├── index.ts │ │ │ └── wonder.ts │ │ └── index.ts │ ├── products │ │ ├── [id] │ │ │ ├── fav.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── reviews.ts │ ├── streams │ │ ├── [id] │ │ │ ├── index.ts │ │ │ └── messages.ts │ │ └── index.ts │ └── users │ │ ├── confirm.ts │ │ ├── enter.ts │ │ └── me │ │ ├── favs.ts │ │ ├── index.ts │ │ ├── purchases.ts │ │ └── sales.ts ├── blog │ ├── [slug].tsx │ └── index.tsx ├── chats │ ├── [id].tsx │ └── index.tsx ├── community │ ├── [id].tsx │ ├── index.tsx │ └── write.tsx ├── enter.tsx ├── index.tsx ├── products │ ├── [id].tsx │ └── upload.tsx ├── profile │ ├── bought.tsx │ ├── edit.tsx │ ├── index.tsx │ ├── loved.tsx │ └── sold.tsx └── streams │ ├── [id].tsx │ ├── create.tsx │ └── index.tsx ├── postcss.config.js ├── posts ├── 01-first-post.md ├── 02-my-trip-to-egypt.md ├── 03-back-home.md └── 04-wow.md ├── prisma ├── schema.prisma └── seed.ts ├── public ├── favicon.ico ├── local.jpeg └── vercel.svg ├── styles └── globals.css ├── tailwind.config.js └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | .env 33 | 34 | # vercel 35 | .vercel 36 | 37 | # typescript 38 | *.tsbuildinfo 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Carrot Market 2 | 3 | Serverless Carrot Market Clone using NextJS, Tailwind, Prisma, PlanetScale and Cloudflare. 4 | -------------------------------------------------------------------------------- /components/bs.tsx: -------------------------------------------------------------------------------- 1 | console.log("hello im bs"); 2 | export default function Bs() { 3 | return

hello

; 4 | } 5 | -------------------------------------------------------------------------------- /components/button.tsx: -------------------------------------------------------------------------------- 1 | import { cls } from "@libs/client/utils"; 2 | 3 | interface ButtonProps { 4 | large?: boolean; 5 | text: string; 6 | [key: string]: any; 7 | } 8 | 9 | export default function Button({ 10 | large = false, 11 | onClick, 12 | text, 13 | ...rest 14 | }: ButtonProps) { 15 | return ( 16 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /components/floating-button.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import React from "react"; 3 | 4 | interface FloatingButton { 5 | children: React.ReactNode; 6 | href: string; 7 | } 8 | 9 | export default function FloatingButton({ children, href }: FloatingButton) { 10 | return ( 11 | 12 | 13 | {children} 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /components/input.tsx: -------------------------------------------------------------------------------- 1 | import type { UseFormRegisterReturn } from "react-hook-form"; 2 | 3 | interface InputProps { 4 | label: string; 5 | name: string; 6 | kind?: "text" | "phone" | "price"; 7 | type: string; 8 | register: UseFormRegisterReturn; 9 | required: boolean; 10 | } 11 | 12 | export default function Input({ 13 | label, 14 | name, 15 | kind = "text", 16 | register, 17 | type, 18 | required, 19 | }: InputProps) { 20 | return ( 21 |
22 | 28 | {kind === "text" ? ( 29 |
30 | 37 |
38 | ) : null} 39 | {kind === "price" ? ( 40 |
41 |
42 | $ 43 |
44 | 51 |
52 | KRW 53 |
54 |
55 | ) : null} 56 | {kind === "phone" ? ( 57 |
58 | 59 | +82 60 | 61 | 68 |
69 | ) : null} 70 |
71 | ); 72 | } 73 | -------------------------------------------------------------------------------- /components/item.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import Link from "next/link"; 3 | 4 | interface ItemProps { 5 | title: string; 6 | id: number; 7 | price: number; 8 | image: string; 9 | hearts: number; 10 | } 11 | 12 | export default function Item({ title, price, hearts, id, image }: ItemProps) { 13 | return ( 14 | 15 | 16 |
17 |
18 | 23 |
24 |
25 |

{title}

26 | ${price} 27 |
28 |
29 |
30 |
31 | 38 | 44 | 45 | {hearts} 46 |
47 |
48 |
49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /components/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "next/link"; 3 | import { cls } from "@libs/client/utils"; 4 | import { useRouter } from "next/router"; 5 | import Head from "next/head"; 6 | 7 | interface LayoutProps { 8 | title?: string; 9 | canGoBack?: boolean; 10 | hasTabBar?: boolean; 11 | children: React.ReactNode; 12 | seoTitle?:string; 13 | } 14 | 15 | export default function Layout({ 16 | title, 17 | canGoBack, 18 | hasTabBar, 19 | children, 20 | seoTitle 21 | }: LayoutProps) { 22 | const router = useRouter(); 23 | const onClick = () => { 24 | router.back(); 25 | }; 26 | return ( 27 |
28 | 29 | {seoTitle} | Carrot Market 30 | 31 |
32 | {canGoBack ? ( 33 | 49 | ) : null} 50 | {title ? ( 51 | {title} 52 | ) : null} 53 |
54 |
{children}
55 | {hasTabBar ? ( 56 | 188 | ) : null} 189 |
190 | ); 191 | } 192 | -------------------------------------------------------------------------------- /components/message.tsx: -------------------------------------------------------------------------------- 1 | import { cls } from "@libs/client/utils"; 2 | 3 | interface MessageProps { 4 | message: string; 5 | reversed?: boolean; 6 | avatarUrl?: string; 7 | } 8 | 9 | export default function Message({ 10 | message, 11 | avatarUrl, 12 | reversed, 13 | }: MessageProps) { 14 | return ( 15 |
21 |
22 |
23 |

{message}

24 |
25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /components/product-list.tsx: -------------------------------------------------------------------------------- 1 | import { ProductWithCount } from "pages"; 2 | import useSWR from "swr"; 3 | import Item from "./item"; 4 | 5 | interface ProductListProps { 6 | kind: "favs" | "sales" | "purchases"; 7 | } 8 | 9 | interface Record { 10 | id: number; 11 | product: ProductWithCount; 12 | } 13 | 14 | interface ProductListResponse { 15 | [key: string]: Record[]; 16 | } 17 | 18 | export default function ProductList({ kind }: ProductListProps) { 19 | const { data } = useSWR(`/api/users/me/${kind}`); 20 | return data ? ( 21 | <> 22 | {data[kind]?.map((record) => ( 23 | 31 | ))} 32 | 33 | ) : null; 34 | } 35 | -------------------------------------------------------------------------------- /components/textarea.tsx: -------------------------------------------------------------------------------- 1 | import { UseFormRegisterReturn } from "react-hook-form"; 2 | 3 | interface TextAreaProps { 4 | label?: string; 5 | name?: string; 6 | register: UseFormRegisterReturn; 7 | [key: string]: any; 8 | } 9 | 10 | export default function TextArea({ 11 | label, 12 | name, 13 | register, 14 | ...rest 15 | }: TextAreaProps) { 16 | return ( 17 |
18 | {label ? ( 19 | 25 | ) : null} 26 |