diff --git a/README.md b/README.md index 003d640..8ca2e18 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Cooper is a tool for Northeastern students to both submit reviews of their co-op - [Next.js](https://nextjs.org) - Web development framework - [Tailwind CSS](https://tailwindcss.com) - CSS framework +- [shadcn/ui](https://ui.shadcn.com/) - Pre-built components - [NextAuth.js](https://next-auth.js.org/) - Authentication - [Prisma](https://www.prisma.io/) - ORM - [PostgreSQL](https://www.postgresql.org/) - Relational database @@ -49,7 +50,7 @@ docker compose up -d 5. Sync the `prisma` schema with the database schema. Do **not** run this in a production environment. ```bash -pnpm dlx prisma db push +pnpm prisma db push ``` 6. Run the application diff --git a/components.json b/components.json new file mode 100644 index 0000000..027a454 --- /dev/null +++ b/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/styles/globals.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "~/components", + "utils": "~/lib/utils" + } +} diff --git a/package.json b/package.json index e8c1d54..d90afd7 100644 --- a/package.json +++ b/package.json @@ -16,20 +16,29 @@ "prepare": "husky" }, "dependencies": { + "@hookform/resolvers": "^3.3.4", "@next-auth/prisma-adapter": "^1.0.7", "@prisma/client": "^5.6.0", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-slot": "^1.0.2", "@t3-oss/env-nextjs": "^0.7.1", "@tanstack/react-query": "^4.36.1", "@trpc/client": "^10.43.6", "@trpc/next": "^10.43.6", "@trpc/react-query": "^10.43.6", "@trpc/server": "^10.43.6", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "lucide-react": "^0.323.0", "next": "^14.0.4", "next-auth": "^4.24.5", "react": "18.2.0", "react-dom": "18.2.0", + "react-hook-form": "^7.50.1", "server-only": "^0.0.1", "superjson": "^2.2.1", + "tailwind-merge": "^2.2.1", + "tailwindcss-animate": "^1.0.7", "zod": "^3.22.4" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b8d218..e4d8bca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,12 +5,21 @@ settings: excludeLinksFromLockfile: false dependencies: + "@hookform/resolvers": + specifier: ^3.3.4 + version: 3.3.4(react-hook-form@7.50.1) "@next-auth/prisma-adapter": specifier: ^1.0.7 version: 1.0.7(@prisma/client@5.8.1)(next-auth@4.24.5) "@prisma/client": specifier: ^5.6.0 version: 5.8.1(prisma@5.8.1) + "@radix-ui/react-label": + specifier: ^2.0.2 + version: 2.0.2(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + "@radix-ui/react-slot": + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.2.48)(react@18.2.0) "@t3-oss/env-nextjs": specifier: ^0.7.1 version: 0.7.3(typescript@5.3.3)(zod@3.22.4) @@ -29,6 +38,15 @@ dependencies: "@trpc/server": specifier: ^10.43.6 version: 10.45.0 + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.0 + version: 2.1.0 + lucide-react: + specifier: ^0.323.0 + version: 0.323.0(react@18.2.0) next: specifier: ^14.0.4 version: 14.1.0(react-dom@18.2.0)(react@18.2.0) @@ -41,12 +59,21 @@ dependencies: react-dom: specifier: 18.2.0 version: 18.2.0(react@18.2.0) + react-hook-form: + specifier: ^7.50.1 + version: 7.50.1(react@18.2.0) server-only: specifier: ^0.0.1 version: 0.0.1 superjson: specifier: ^2.2.1 version: 2.2.1 + tailwind-merge: + specifier: ^2.2.1 + version: 2.2.1 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.1) zod: specifier: ^3.22.4 version: 3.22.4 @@ -131,7 +158,6 @@ packages: integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==, } engines: { node: ">=10" } - dev: true /@babel/code-frame@7.23.5: resolution: @@ -437,6 +463,17 @@ packages: engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } dev: true + /@hookform/resolvers@3.3.4(react-hook-form@7.50.1): + resolution: + { + integrity: sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==, + } + peerDependencies: + react-hook-form: ^7.0.0 + dependencies: + react-hook-form: 7.50.1(react@18.2.0) + dev: false + /@humanwhocodes/config-array@0.11.14: resolution: { @@ -479,7 +516,6 @@ packages: strip-ansi-cjs: /strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: true /@jridgewell/gen-mapping@0.3.3: resolution: @@ -491,7 +527,6 @@ packages: "@jridgewell/set-array": 1.1.2 "@jridgewell/sourcemap-codec": 1.4.15 "@jridgewell/trace-mapping": 0.3.22 - dev: true /@jridgewell/resolve-uri@3.1.1: resolution: @@ -499,7 +534,6 @@ packages: integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==, } engines: { node: ">=6.0.0" } - dev: true /@jridgewell/set-array@1.1.2: resolution: @@ -507,14 +541,12 @@ packages: integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==, } engines: { node: ">=6.0.0" } - dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: { integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==, } - dev: true /@jridgewell/trace-mapping@0.3.22: resolution: @@ -524,7 +556,6 @@ packages: dependencies: "@jridgewell/resolve-uri": 3.1.1 "@jridgewell/sourcemap-codec": 1.4.15 - dev: true /@next-auth/prisma-adapter@1.0.7(@prisma/client@5.8.1)(next-auth@4.24.5): resolution: @@ -672,7 +703,6 @@ packages: dependencies: "@nodelib/fs.stat": 2.0.5 run-parallel: 1.2.0 - dev: true /@nodelib/fs.stat@2.0.5: resolution: @@ -680,7 +710,6 @@ packages: integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, } engines: { node: ">= 8" } - dev: true /@nodelib/fs.walk@1.2.8: resolution: @@ -691,7 +720,6 @@ packages: dependencies: "@nodelib/fs.scandir": 2.1.5 fastq: 1.16.0 - dev: true /@panva/hkdf@1.1.1: resolution: @@ -707,7 +735,6 @@ packages: } engines: { node: ">=14" } requiresBuild: true - dev: true optional: true /@prisma/client@5.8.1(prisma@5.8.1): @@ -768,6 +795,89 @@ packages: dependencies: "@prisma/debug": 5.8.1 + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: + { + integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + dependencies: + "@babel/runtime": 7.23.8 + "@types/react": 18.2.48 + react: 18.2.0 + dev: false + + /@radix-ui/react-label@2.0.2(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: + { + integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + dependencies: + "@babel/runtime": 7.23.8 + "@radix-ui/react-primitive": 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + "@types/react": 18.2.48 + "@types/react-dom": 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: + { + integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==, + } + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + dependencies: + "@babel/runtime": 7.23.8 + "@radix-ui/react-slot": 1.0.2(@types/react@18.2.48)(react@18.2.0) + "@types/react": 18.2.48 + "@types/react-dom": 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-slot@1.0.2(@types/react@18.2.48)(react@18.2.0): + resolution: + { + integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==, + } + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + dependencies: + "@babel/runtime": 7.23.8 + "@radix-ui/react-compose-refs": 1.0.1(@types/react@18.2.48)(react@18.2.0) + "@types/react": 18.2.48 + react: 18.2.0 + dev: false + /@rushstack/eslint-patch@1.7.0: resolution: { @@ -964,7 +1074,6 @@ packages: { integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==, } - dev: true /@types/react-dom@18.2.18: resolution: @@ -973,7 +1082,6 @@ packages: } dependencies: "@types/react": 18.2.48 - dev: true /@types/react@18.2.48: resolution: @@ -984,14 +1092,12 @@ packages: "@types/prop-types": 15.7.11 "@types/scheduler": 0.16.8 csstype: 3.1.3 - dev: true /@types/scheduler@0.16.8: resolution: { integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==, } - dev: true /@types/semver@7.5.6: resolution: @@ -1244,7 +1350,6 @@ packages: integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, } engines: { node: ">=8" } - dev: true /ansi-regex@6.0.1: resolution: @@ -1252,7 +1357,6 @@ packages: integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==, } engines: { node: ">=12" } - dev: true /ansi-styles@3.2.1: resolution: @@ -1272,7 +1376,6 @@ packages: engines: { node: ">=8" } dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@6.2.1: resolution: @@ -1280,14 +1383,12 @@ packages: integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==, } engines: { node: ">=12" } - dev: true /any-promise@1.3.0: resolution: { integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, } - dev: true /anymatch@3.1.3: resolution: @@ -1298,14 +1399,12 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true /arg@5.0.2: resolution: { integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, } - dev: true /argparse@2.0.1: resolution: @@ -1512,7 +1611,6 @@ packages: { integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, } - dev: true /base64-js@1.5.1: resolution: @@ -1527,7 +1625,6 @@ packages: integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==, } engines: { node: ">=8" } - dev: true /bl@4.1.0: resolution: @@ -1557,7 +1654,6 @@ packages: } dependencies: balanced-match: 1.0.2 - dev: true /braces@3.0.2: resolution: @@ -1567,7 +1663,6 @@ packages: engines: { node: ">=8" } dependencies: fill-range: 7.0.1 - dev: true /browserslist@4.22.2: resolution: @@ -1636,7 +1731,6 @@ packages: integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==, } engines: { node: ">= 6" } - dev: true /camelcase-keys@6.2.2: resolution: @@ -1718,7 +1812,15 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true + + /class-variance-authority@0.7.0: + resolution: + { + integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==, + } + dependencies: + clsx: 2.0.0 + dev: false /cli-cursor@3.1.0: resolution: @@ -1794,6 +1896,22 @@ packages: engines: { node: ">=0.8" } dev: true + /clsx@2.0.0: + resolution: + { + integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==, + } + engines: { node: ">=6" } + dev: false + + /clsx@2.1.0: + resolution: + { + integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==, + } + engines: { node: ">=6" } + dev: false + /color-convert@1.9.3: resolution: { @@ -1811,7 +1929,6 @@ packages: engines: { node: ">=7.0.0" } dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: @@ -1825,7 +1942,6 @@ packages: { integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, } - dev: true /colorette@2.0.20: resolution: @@ -1848,7 +1964,6 @@ packages: integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, } engines: { node: ">= 6" } - dev: true /commitizen@4.3.0(@types/node@18.19.8)(typescript@5.3.3): resolution: @@ -1999,7 +2114,6 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true /cssesc@3.0.0: resolution: @@ -2008,14 +2122,12 @@ packages: } engines: { node: ">=4" } hasBin: true - dev: true /csstype@3.1.3: resolution: { integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, } - dev: true /cz-conventional-changelog@3.3.0(@types/node@18.19.8)(typescript@5.3.3): resolution: @@ -2176,7 +2288,6 @@ packages: { integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==, } - dev: true /dir-glob@3.0.1: resolution: @@ -2193,7 +2304,6 @@ packages: { integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, } - dev: true /doctrine@2.1.0: resolution: @@ -2230,7 +2340,6 @@ packages: { integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, } - dev: true /electron-to-chromium@1.4.640: resolution: @@ -2251,14 +2360,12 @@ packages: { integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, } - dev: true /emoji-regex@9.2.2: resolution: { integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, } - dev: true /enhanced-resolve@5.15.0: resolution: @@ -2814,7 +2921,6 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true /fast-json-stable-stringify@2.1.0: resolution: @@ -2837,7 +2943,6 @@ packages: } dependencies: reusify: 1.0.4 - dev: true /figures@3.2.0: resolution: @@ -2867,7 +2972,6 @@ packages: engines: { node: ">=8" } dependencies: to-regex-range: 5.0.1 - dev: true /find-node-modules@2.1.3: resolution: @@ -2958,7 +3062,6 @@ packages: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 - dev: true /fraction.js@4.3.7: resolution: @@ -2995,7 +3098,6 @@ packages: engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] requiresBuild: true - dev: true optional: true /function-bind@1.1.2: @@ -3003,7 +3105,6 @@ packages: { integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, } - dev: true /function.prototype.name@1.1.6: resolution: @@ -3112,7 +3213,6 @@ packages: engines: { node: ">= 6" } dependencies: is-glob: 4.0.3 - dev: true /glob-parent@6.0.2: resolution: @@ -3122,7 +3222,6 @@ packages: engines: { node: ">=10.13.0" } dependencies: is-glob: 4.0.3 - dev: true /glob@10.3.10: resolution: @@ -3137,7 +3236,6 @@ packages: minimatch: 9.0.3 minipass: 7.0.4 path-scurry: 1.10.1 - dev: true /glob@7.2.3: resolution: @@ -3320,7 +3418,6 @@ packages: engines: { node: ">= 0.4" } dependencies: function-bind: 1.1.2 - dev: true /homedir-polyfill@1.0.3: resolution: @@ -3531,7 +3628,6 @@ packages: engines: { node: ">=8" } dependencies: binary-extensions: 2.2.0 - dev: true /is-boolean-object@1.1.2: resolution: @@ -3559,7 +3655,6 @@ packages: } dependencies: hasown: 2.0.0 - dev: true /is-date-object@1.0.5: resolution: @@ -3577,7 +3672,6 @@ packages: integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, } engines: { node: ">=0.10.0" } - dev: true /is-finalizationregistry@1.0.2: resolution: @@ -3594,7 +3688,6 @@ packages: integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, } engines: { node: ">=8" } - dev: true /is-fullwidth-code-point@4.0.0: resolution: @@ -3632,7 +3725,6 @@ packages: engines: { node: ">=0.10.0" } dependencies: is-extglob: 2.1.1 - dev: true /is-interactive@1.0.0: resolution: @@ -3673,7 +3765,6 @@ packages: integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, } engines: { node: ">=0.12.0" } - dev: true /is-obj@2.0.0: resolution: @@ -3851,7 +3942,6 @@ packages: { integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, } - dev: true /iterator.prototype@1.1.2: resolution: @@ -3876,7 +3966,6 @@ packages: "@isaacs/cliui": 8.0.2 optionalDependencies: "@pkgjs/parseargs": 0.11.0 - dev: true /jiti@1.21.0: resolution: @@ -3884,7 +3973,6 @@ packages: integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==, } hasBin: true - dev: true /jose@4.15.4: resolution: @@ -4037,7 +4125,6 @@ packages: integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==, } engines: { node: ">=10" } - dev: true /lilconfig@3.0.0: resolution: @@ -4045,14 +4132,12 @@ packages: integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==, } engines: { node: ">=14" } - dev: true /lines-and-columns@1.2.4: resolution: { integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, } - dev: true /lint-staged@15.2.1: resolution: @@ -4243,7 +4328,6 @@ packages: integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==, } engines: { node: 14 || >=16.14 } - dev: true /lru-cache@6.0.0: resolution: @@ -4254,6 +4338,17 @@ packages: dependencies: yallist: 4.0.0 + /lucide-react@0.323.0(react@18.2.0): + resolution: + { + integrity: sha512-rTXZFILl2Y4d1SG9p1Mdcf17AcPvPvpc/egFIzUrp7IUy60MUQo3Oi1mu8LGYXUVwuRZYsSMt3csHRW5mAovJg==, + } + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /map-obj@1.0.1: resolution: { @@ -4311,7 +4406,6 @@ packages: integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, } engines: { node: ">= 8" } - dev: true /merge@2.1.1: resolution: @@ -4329,7 +4423,6 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true /mimic-fn@2.1.0: resolution: @@ -4372,7 +4465,6 @@ packages: engines: { node: ">=16 || 14 >=14.17" } dependencies: brace-expansion: 2.0.1 - dev: true /minimist-options@4.1.0: resolution: @@ -4406,7 +4498,6 @@ packages: integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==, } engines: { node: ">=16 || 14 >=14.17" } - dev: true /ms@2.1.2: resolution: @@ -4438,7 +4529,6 @@ packages: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: true /nanoid@3.3.7: resolution: @@ -4563,7 +4653,6 @@ packages: integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, } engines: { node: ">=0.10.0" } - dev: true /normalize-range@0.1.2: resolution: @@ -4606,7 +4695,6 @@ packages: integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, } engines: { node: ">=0.10.0" } - dev: true /object-hash@2.2.0: resolution: @@ -4622,7 +4710,6 @@ packages: integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==, } engines: { node: ">= 6" } - dev: true /object-inspect@1.13.1: resolution: @@ -4901,7 +4988,6 @@ packages: integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, } engines: { node: ">=8" } - dev: true /path-key@4.0.0: resolution: @@ -4916,7 +5002,6 @@ packages: { integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, } - dev: true /path-scurry@1.10.1: resolution: @@ -4927,7 +5012,6 @@ packages: dependencies: lru-cache: 10.1.0 minipass: 7.0.4 - dev: true /path-type@4.0.0: resolution: @@ -4949,7 +5033,6 @@ packages: integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, } engines: { node: ">=8.6" } - dev: true /pidtree@0.6.0: resolution: @@ -4966,7 +5049,6 @@ packages: integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, } engines: { node: ">=0.10.0" } - dev: true /pirates@4.0.6: resolution: @@ -4974,7 +5056,6 @@ packages: integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==, } engines: { node: ">= 6" } - dev: true /postcss-import@15.1.0(postcss@8.4.33): resolution: @@ -4989,7 +5070,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - dev: true /postcss-js@4.0.1(postcss@8.4.33): resolution: @@ -5002,7 +5082,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.33 - dev: true /postcss-load-config@4.0.2(postcss@8.4.33): resolution: @@ -5022,7 +5101,6 @@ packages: lilconfig: 3.0.0 postcss: 8.4.33 yaml: 2.3.4 - dev: true /postcss-nested@6.0.1(postcss@8.4.33): resolution: @@ -5035,7 +5113,6 @@ packages: dependencies: postcss: 8.4.33 postcss-selector-parser: 6.0.15 - dev: true /postcss-selector-parser@6.0.15: resolution: @@ -5046,14 +5123,12 @@ packages: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - dev: true /postcss-value-parser@4.2.0: resolution: { integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, } - dev: true /postcss@8.4.31: resolution: @@ -5077,7 +5152,6 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true /preact-render-to-string@5.2.6(preact@10.19.3): resolution: @@ -5212,7 +5286,6 @@ packages: { integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, } - dev: true /quick-lru@4.0.1: resolution: @@ -5235,6 +5308,18 @@ packages: scheduler: 0.23.0 dev: false + /react-hook-form@7.50.1(react@18.2.0): + resolution: + { + integrity: sha512-3PCY82oE0WgeOgUtIr3nYNNtNvqtJ7BZjsbxh6TnYNbXButaD5WpjOmTjdxZfheuHKR68qfeFnEDVYoSSFPMTQ==, + } + engines: { node: ">=12.22.0" } + peerDependencies: + react: ^16.8.0 || ^17 || ^18 + dependencies: + react: 18.2.0 + dev: false + /react-is@16.13.1: resolution: { @@ -5259,7 +5344,6 @@ packages: } dependencies: pify: 2.3.0 - dev: true /read-pkg-up@7.0.1: resolution: @@ -5306,7 +5390,6 @@ packages: engines: { node: ">=8.10.0" } dependencies: picomatch: 2.3.1 - dev: true /redent@3.0.0: resolution: @@ -5422,7 +5505,6 @@ packages: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true /resolve@2.0.0-next.5: resolution: @@ -5464,7 +5546,6 @@ packages: integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==, } engines: { iojs: ">=1.0.0", node: ">=0.10.0" } - dev: true /rfdc@1.3.1: resolution: @@ -5498,7 +5579,6 @@ packages: } dependencies: queue-microtask: 1.2.3 - dev: true /rxjs@7.8.1: resolution: @@ -5625,7 +5705,6 @@ packages: engines: { node: ">=8" } dependencies: shebang-regex: 3.0.0 - dev: true /shebang-regex@3.0.0: resolution: @@ -5633,7 +5712,6 @@ packages: integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, } engines: { node: ">=8" } - dev: true /side-channel@1.0.4: resolution: @@ -5659,7 +5737,6 @@ packages: integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, } engines: { node: ">=14" } - dev: true /slash@3.0.0: resolution: @@ -5775,7 +5852,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true /string-width@5.1.2: resolution: @@ -5787,7 +5863,6 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - dev: true /string-width@7.1.0: resolution: @@ -5869,7 +5944,6 @@ packages: engines: { node: ">=8" } dependencies: ansi-regex: 5.0.1 - dev: true /strip-ansi@7.1.0: resolution: @@ -5879,7 +5953,6 @@ packages: engines: { node: ">=12" } dependencies: ansi-regex: 6.0.1 - dev: true /strip-bom@3.0.0: resolution: @@ -5966,7 +6039,6 @@ packages: mz: 2.7.0 pirates: 4.0.6 ts-interface-checker: 0.1.13 - dev: true /superjson@2.2.1: resolution: @@ -6004,7 +6076,26 @@ packages: integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, } engines: { node: ">= 0.4" } - dev: true + + /tailwind-merge@2.2.1: + resolution: + { + integrity: sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==, + } + dependencies: + "@babel/runtime": 7.23.8 + dev: false + + /tailwindcss-animate@1.0.7(tailwindcss@3.4.1): + resolution: + { + integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==, + } + peerDependencies: + tailwindcss: ">=3.0.0 || insiders" + dependencies: + tailwindcss: 3.4.1 + dev: false /tailwindcss@3.4.1: resolution: @@ -6038,7 +6129,6 @@ packages: sucrase: 3.35.0 transitivePeerDependencies: - ts-node - dev: true /tapable@2.2.1: resolution: @@ -6071,7 +6161,6 @@ packages: engines: { node: ">=0.8" } dependencies: thenify: 3.3.1 - dev: true /thenify@3.3.1: resolution: @@ -6080,7 +6169,6 @@ packages: } dependencies: any-promise: 1.3.0 - dev: true /through2@4.0.2: resolution: @@ -6116,7 +6204,6 @@ packages: engines: { node: ">=8.0" } dependencies: is-number: 7.0.0 - dev: true /trim-newlines@3.0.1: resolution: @@ -6143,7 +6230,6 @@ packages: { integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, } - dev: true /tsconfig-paths@3.15.0: resolution: @@ -6345,7 +6431,6 @@ packages: { integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, } - dev: true /uuid@8.3.2: resolution: @@ -6453,7 +6538,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: true /word-wrap@1.2.5: resolution: @@ -6473,7 +6557,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-ansi@8.1.0: resolution: @@ -6485,7 +6568,6 @@ packages: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - dev: true /wrap-ansi@9.0.0: resolution: @@ -6526,7 +6608,6 @@ packages: integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==, } engines: { node: ">= 14" } - dev: true /yargs-parser@20.2.9: resolution: diff --git a/src/app/(protected)/review/page.tsx b/src/app/(protected)/review/page.tsx new file mode 100644 index 0000000..f0ff694 --- /dev/null +++ b/src/app/(protected)/review/page.tsx @@ -0,0 +1,18 @@ +import { ReviewForm } from "~/components/review-form"; +import { getServerSession } from "next-auth"; +import { authOptions } from "~/server/auth"; +import { redirect } from "next/navigation"; + +export default async function Page() { + const session = await getServerSession(authOptions); + + if (!session) { + redirect("/"); + } + + return ( +
+ +
+ ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 101f8bc..13d0be2 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,10 +1,11 @@ import "~/styles/globals.css"; -import { Inter } from "next/font/google"; +import { Inter as FontSans } from "next/font/google"; import { TRPCReactProvider } from "~/trpc/react"; +import { cn } from "~/lib/utils"; -const inter = Inter({ +const fontSans = FontSans({ subsets: ["latin"], variable: "--font-sans", }); @@ -21,8 +22,13 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - - + + {children} diff --git a/src/components/review-form.tsx b/src/components/review-form.tsx new file mode 100644 index 0000000..2019682 --- /dev/null +++ b/src/components/review-form.tsx @@ -0,0 +1,137 @@ +"use client"; + +import { zodResolver } from "@hookform/resolvers/zod"; +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { Button } from "~/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "~/components/ui/form"; +import { Input } from "~/components/ui/input"; +import { Textarea } from "~/components/ui/textarea"; + +const formSchema = z.object({ + reviewHeadline: z.string().min(8, { + message: "The review headline must be at least 8 characters.", + }), + pros: z.string().min(8, { + message: "Pros must be at least 8 characters.", + }), + cons: z.string().min(8, { + message: "Cons must be at least 8 characters.", + }), + location: z.string().min(2, { + message: "Location must be at least 2 characters.", + }), + hourlyPay: z.coerce.number(), +}); + +export function ReviewForm() { + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + reviewHeadline: "", + pros: "", + cons: "", + location: "", + hourlyPay: 0, + }, + }); + + function onSubmit(values: z.infer) { + console.log(values); + } + + return ( +
+

Review

+
+ + ( + + Review Headline* + + + + + + )} + /> + ( + + Pros* + +