diff --git a/next.config.mjs b/next.config.mjs index 4678774..4601cfb 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,8 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + images: { + domains: ['whyphi-zap.s3.amazonaws.com'], + }, +}; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 60c8079..d6e9922 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,13 @@ "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "flowbite-react": "^0.10.1", "lucide-react": "^0.368.0", "next": "14.2.1", "next-auth": "^4.24.7", "react": "^18", "react-dom": "^18", + "react-timestamp": "^6.0.0", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7" }, @@ -24,8 +26,9 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", - "postcss": "^8", - "tailwindcss": "^3.4.1", + "autoprefixer": "^10.4.19", + "postcss": "^8.4.40", + "tailwindcss": "^3.4.7", "typescript": "^5" } }, @@ -51,6 +54,54 @@ "node": ">=6.9.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz", + "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", + "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.17", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.17.tgz", + "integrity": "sha512-ESD+jYWwqwVzaIgIhExrArdsCL1rOAzryG/Sjlu8yaD3Mtqi3uVyhbE2V7jD58Mo52qbzKz2eUY/Xgh5I86FCQ==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.0", + "@floating-ui/utils": "^0.2.0", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -299,6 +350,15 @@ "node": ">=14" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@radix-ui/primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", @@ -615,6 +675,43 @@ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -650,6 +747,38 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -670,9 +799,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001609", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz", - "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==", + "version": "1.0.30001643", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", + "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", "funding": [ { "type": "opencollective", @@ -741,6 +870,11 @@ "node": ">=6" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -816,6 +950,17 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "devOptional": true }, + "node_modules/debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.1.0.tgz", + "integrity": "sha512-OkL3+0pPWCqoBc/nhO9u6TIQNTK44fnBnzuVtJAbp13Naxw9R6u21x+8tVTka87AhDZ3htqZ2pSSsZl9fqL2Wg==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -831,11 +976,26 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/electron-to-chromium": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.1.tgz", + "integrity": "sha512-FKbOCOQ5QRB3VlIbl1LZQefWIYwszlBloaXcY2rbfpu9ioJnNh3TK03YtIDKDo3WKBi8u+YV4+Fn2CkEozgf4w==", + "dev": true + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -881,6 +1041,34 @@ "node": ">=8" } }, + "node_modules/flowbite": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-2.3.0.tgz", + "integrity": "sha512-pm3JRo8OIJHGfFYWgaGpPv8E+UdWy0Z3gEAGufw+G/1dusaU/P1zoBLiQpf2/+bYAi+GBQtPVG86KYlV0W+AFQ==", + "dependencies": { + "@popperjs/core": "^2.9.3", + "mini-svg-data-uri": "^1.4.3" + } + }, + "node_modules/flowbite-react": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/flowbite-react/-/flowbite-react-0.10.1.tgz", + "integrity": "sha512-T6rdfrEvIqrf7aIB+OLkuvDaa/h0Ufnl7/5vJR9JJ4IpKIvJm/JzhAiYmkD+jDj3HuILsN21+ZVV6gd4tlndYQ==", + "dependencies": { + "@floating-ui/core": "1.6.2", + "@floating-ui/react": "0.26.17", + "classnames": "2.5.1", + "debounce": "2.1.0", + "flowbite": "2.3.0", + "react-icons": "5.2.1", + "tailwind-merge": "2.3.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18", + "tailwindcss": "^3" + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -896,6 +1084,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1125,6 +1326,14 @@ "node": ">=8.6" } }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, "node_modules/minimatch": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", @@ -1277,6 +1486,12 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1285,6 +1500,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/oauth": { "version": "0.9.15", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", @@ -1376,9 +1600,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -1408,9 +1632,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.40", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", + "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", "funding": [ { "type": "opencollective", @@ -1427,7 +1651,7 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "source-map-js": "^1.2.0" }, "engines": { @@ -1615,6 +1839,22 @@ "react": "^18.2.0" } }, + "node_modules/react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-timestamp": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/react-timestamp/-/react-timestamp-6.0.0.tgz", + "integrity": "sha512-ZVyVuVp1MBWQGmcip3Nzb9n1uzAqkyGJgngiAa7WbQbWuw+IS3qlnYBoXThlHAt1Yby9eOuzMZse/jRQfq/LeQ==", + "peerDependencies": { + "react": "^18.2.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -1882,12 +2122,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/tailwind-merge": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.2.tgz", - "integrity": "sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.3.0.tgz", + "integrity": "sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==", "dependencies": { - "@babel/runtime": "^7.24.0" + "@babel/runtime": "^7.24.1" }, "funding": { "type": "github", @@ -1895,9 +2140,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz", + "integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -1997,6 +2242,36 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 5ddd149..3ac352f 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev", + "dev": "next dev -p 3001", "build": "next build", - "start": "next start", + "start": "next start -p 3001", "lint": "next lint" }, "dependencies": { @@ -13,11 +13,13 @@ "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "flowbite-react": "^0.10.1", "lucide-react": "^0.368.0", "next": "14.2.1", "next-auth": "^4.24.7", "react": "^18", "react-dom": "^18", + "react-timestamp": "^6.0.0", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7" }, @@ -25,8 +27,9 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", - "postcss": "^8", - "tailwindcss": "^3.4.1", + "autoprefixer": "^10.4.19", + "postcss": "^8.4.40", + "tailwindcss": "^3.4.7", "typescript": "^5" } } diff --git a/public/pct-logo-dark.png b/public/pct-logo-dark.png new file mode 100644 index 0000000..42f3ea3 Binary files /dev/null and b/public/pct-logo-dark.png differ diff --git a/public/pct-logo.png b/public/pct-logo.png new file mode 100644 index 0000000..6c9dc8d Binary files /dev/null and b/public/pct-logo.png differ diff --git a/src/app/attendance/layout.tsx b/src/app/attendance/layout.tsx new file mode 100644 index 0000000..6a6741d --- /dev/null +++ b/src/app/attendance/layout.tsx @@ -0,0 +1,29 @@ +import '../globals.css' +import UserSessionProvider from '@/app/providers/userSessionProvider' +import NavSidebar from '@/components/NavSidebar' +import type { Metadata } from 'next' + + +export const metadata: Metadata = { + title: 'WhyPhi - Rush Home', + description: "PCT Zeta Chapter - Rush Attendance", +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + +
+
+ {children} +
+
+
+ + + ) +} diff --git a/src/app/attendance/page.tsx b/src/app/attendance/page.tsx new file mode 100644 index 0000000..0f2a8cd --- /dev/null +++ b/src/app/attendance/page.tsx @@ -0,0 +1,10 @@ +"use client" + +export default function Attendance() { + + return ( +
+

In progress...

+
+ ); +}; \ No newline at end of file diff --git a/src/app/checkin/[id]/layout.tsx b/src/app/checkin/[id]/layout.tsx index 4ee9fc0..f763912 100644 --- a/src/app/checkin/[id]/layout.tsx +++ b/src/app/checkin/[id]/layout.tsx @@ -1,11 +1,12 @@ // import '../../globals.css' -import UserSessionProvider from '@/app/providers' +import UserSessionProvider from '@/app/providers/userSessionProvider' +import NavSidebar from '@/components/NavSidebar' import type { Metadata } from 'next' export const metadata: Metadata = { - title: 'Whyphi - Rush', - description: "PCT Zeta Chapter - Rush", + title: 'WhyPhi - Rush Checkin', + description: "PCT Zeta Chapter - Rush Checkin Page", } export default function RootLayout({ @@ -15,11 +16,14 @@ export default function RootLayout({ }) { return ( -
- {children} + +
+
+ {children} +
) -} +} \ No newline at end of file diff --git a/src/app/checkin/[id]/page.tsx b/src/app/checkin/[id]/page.tsx index ad5a672..6cefb5f 100644 --- a/src/app/checkin/[id]/page.tsx +++ b/src/app/checkin/[id]/page.tsx @@ -1,9 +1,6 @@ "use client" import { useState, useEffect } from "react" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Checkbox } from "@/components/ui/checkbox" import { useSession, signOut } from "next-auth/react"; import { Event } from "@/types/Events" import { useRouter } from 'next/navigation' @@ -14,6 +11,7 @@ import { AlertDescription, AlertTitle, } from "@/components/ui/alert" +import { Badge, TextInput, Button } from "flowbite-react" export default function Checkin({ params }: { params: { id: string } }) { @@ -28,6 +26,9 @@ export default function Checkin({ params }: { params: { id: string } }) { useEffect(() => { fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/events/rush/${params.id}`, { + method: "POST", + body: JSON.stringify({}), + headers: { "Content-Type": "application/json" }, }) .then((res) => { if (!res.ok) { @@ -122,19 +123,24 @@ export default function Checkin({ params }: { params: { id: string } }) { return } return ( -
+
-
- -

Hi, {session?.user?.name}!

Welcome to Phi Chi Theta, Zeta Chapter's Rush! We're excited to have you here.

-

Please enter your code to check-in to {event?.name}:

-
- setCode(e.target.value)} /> +

Please enter your code to check-in to {event?.name}:

+
+ setCode(e.target.value)} />
- +
); diff --git a/src/app/checkin/error/layout.tsx b/src/app/checkin/error/layout.tsx new file mode 100644 index 0000000..469da4c --- /dev/null +++ b/src/app/checkin/error/layout.tsx @@ -0,0 +1,29 @@ +// import '../../globals.css' +import UserSessionProvider from '@/app/providers/userSessionProvider' +import NavSidebar from '@/components/NavSidebar' +import type { Metadata } from 'next' + + +export const metadata: Metadata = { + title: 'WhyPhi - Error', + description: "PCT Zeta Chapter - Rush Checkin Error", +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + +
+
+ {children} +
+
+
+ + + ) +} \ No newline at end of file diff --git a/src/app/checkin/success/layout.tsx b/src/app/checkin/success/layout.tsx new file mode 100644 index 0000000..092b351 --- /dev/null +++ b/src/app/checkin/success/layout.tsx @@ -0,0 +1,29 @@ +// import '../../globals.css' +import UserSessionProvider from '@/app/providers/userSessionProvider' +import NavSidebar from '@/components/NavSidebar' +import type { Metadata } from 'next' + + +export const metadata: Metadata = { + title: 'WhyPhi - Success', + description: "PCT Zeta Chapter - Rush Checkin Page", +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + +
+
+ {children} +
+
+
+ + + ) +} \ No newline at end of file diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx new file mode 100644 index 0000000..ee06c44 --- /dev/null +++ b/src/app/dashboard/layout.tsx @@ -0,0 +1,29 @@ +import '../globals.css' +import UserSessionProvider from '@/app/providers/userSessionProvider' +import NavSidebar from '@/components/NavSidebar' +import type { Metadata } from 'next' + + +export const metadata: Metadata = { + title: 'WhyPhi - Rush Home', + description: "PCT Zeta Chapter - Rush Home Page", +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + +
+
+ {children} +
+
+
+ + + ) +} diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx new file mode 100644 index 0000000..2c2ea12 --- /dev/null +++ b/src/app/dashboard/page.tsx @@ -0,0 +1,58 @@ +"use client" + +import { useState, useEffect } from "react" +import { useSession } from "next-auth/react"; +import { RushCategory } from "@/types/Events" +import { useRouter } from 'next/navigation' +import Loader from "@/components/Loader" +import EventCard from "@/components/dashboard/EventCard"; + +export default function Dashboard() { + const { data: session } = useSession(); + const [rushCategory, setRushCategory] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + // ensure user is defined + if (!session?.user) return; + + const email = session.user.email + + const fetchRushEvents = async () => { + try { + const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/events/rush/default`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ email: email }) + }); + if (!response.ok) { + // router.push("/checkin/error"); + setError(new Error("Failed to fetch event")); + } + const data: RushCategory = await response.json(); + setRushCategory(data); + setIsLoading(false); + } catch (error) { + setError(error); + } + } + + fetchRushEvents(); + }, [session]); + + if (isLoading) { + return + } + return ( +
+
+ {rushCategory?.events.map((event, index) => ( +
+ +
+ ))} +
+
+ ); +}; \ No newline at end of file diff --git a/src/app/favicon.ico b/src/app/favicon.ico index 718d6fe..820a413 100644 Binary files a/src/app/favicon.ico and b/src/app/favicon.ico differ diff --git a/src/app/globals.css b/src/app/globals.css index bd6213e..ce727f8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,3 +1,66 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +/* Custom styles */ +body { + /* Default background color */ + background-color: #ffffff; /* Light mode background */ +} + +.dark body { + /* Dark mode background color */ + /* Gray-700 */ + /* background-color: #374151; */ + /* Gray-800 */ + /* background-color: #1f2937; */ + + /* Somwhere in between 700 and 800 */ + background-color: #29313e; +} + +/************************** glowing border effect ***************************/ +/* source: https://www.youtube.com/watch?v=ezP4kbOvs_E&list=PLZ6KBrFKcaDtqcqHv9NUCpul8a2B3F33F&index=6 */ +.card { + position: relative; +} + +@property --angle { + syntax: ""; + initial-value: 0deg; + inherits: false; +} + +.card:hover::after, +.card:hover::before, +.card:active::after, +.card:active::before { + content: ''; + position: absolute; + height: 101%; + width: 101%; + /* background-image: conic-gradient(from var(--angle), #bb4ec4, #f148c8,#2c12ed, #ffe900, #7fff00, #ffa500, #bb4ec4); */ + background-image: conic-gradient(from var(--angle), #bb4ec4, #f148c8,#2c12ed, #ffa500, #bb4ec4); + top: 50%; + left: 50%; + translate: -50% -50%; + border-radius: 10px; + z-index: -1; + animation: 3s spin linear infinite; +} + +.card:hover::before, +.card:active::before { + filter: blur(1rem); + opacity: 0.7; +} + +@keyframes spin{ + from{ + --angle: 0deg; + } + to{ + --angle: 360deg; + } +} +/*****************************************************************************/ \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0c38844..190e545 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,5 +1,6 @@ "use client" +import { Flowbite, ThemeModeScript } from "flowbite-react"; // import { Inter } from "next/font/google"; import "./globals.css"; import { SessionProvider } from "next-auth/react" @@ -13,11 +14,17 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - + + + + - - {children} - + + + + {children} + + ); diff --git a/src/app/page.tsx b/src/app/page.tsx index 83edb64..5c71849 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,75 @@ -import { redirect } from 'next/navigation'; +"use client" + +import Loader from "@/components/Loader"; +import { useThemeMode } from "flowbite-react"; +import React, { useEffect, useState } from "react"; export default function Home() { - redirect("https://bupct.com/"); -} \ No newline at end of file + const { mode } = useThemeMode(); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + if (mode) setIsLoading(false); + },[mode]) + + if (isLoading) return + + return ( +
+
+ + +
+
+ + Phi Chi Theta Zeta Chapter Logo + + +

+ Welcome to WhyPhi! +

+ +

+ {`WhyPhi is Phi Chi Theta Zeta Chapter's rush checkin and application website.`} +

+ + + + +
+

+ Not working? Contact PCT Tech Team! +

+
+
+
+
+
+ ); +} + diff --git a/src/app/providers/index.tsx b/src/app/providers/userSessionProvider.tsx similarity index 100% rename from src/app/providers/index.tsx rename to src/app/providers/userSessionProvider.tsx diff --git a/src/components/NavSidebar.tsx b/src/components/NavSidebar.tsx new file mode 100644 index 0000000..ec41e2a --- /dev/null +++ b/src/components/NavSidebar.tsx @@ -0,0 +1,90 @@ +"use client"; +import React, { useState } from "react"; +import { useSession, signOut } from "next-auth/react"; +import { Dropdown, Avatar, Sidebar, DarkThemeToggle, useThemeMode } from "flowbite-react"; +import { HiChartPie, HiTable } from "react-icons/hi"; + + + +export default function NavSidebar() { + const { data: session } = useSession(); + const [isSidebarOpen, setIsSidebarOpen] = useState(false); + const { mode } = useThemeMode(); + + + const toggleSidebar = () => { + setIsSidebarOpen(!isSidebarOpen); + }; + + return ( + <> + + + + + + + Dashboard + + + Attendance + + + + + + ); +} diff --git a/src/components/dashboard/EventCard.tsx b/src/components/dashboard/EventCard.tsx new file mode 100644 index 0000000..a03a6f4 --- /dev/null +++ b/src/components/dashboard/EventCard.tsx @@ -0,0 +1,71 @@ +import { DashboardEvent } from "@/types/Events"; +import { Badge, Card } from "flowbite-react"; +import { useRouter } from 'next/navigation' +import { useState } from "react"; +import Timestamp from "react-timestamp"; + +interface EventCardProps { + event: DashboardEvent +} + +export default function EventCard({ + event +}: EventCardProps) { + const router = useRouter(); + + const eventDeadline = new Date(event.deadline); + const isEventPassed = eventDeadline < new Date(); + const disabled = isEventPassed || event.checkedIn + + const handleEventClick = () => { + if (!disabled) { + router.push(`/checkin/${event._id}`) + } + } + + const renderStatus = () => ( + event.checkedIn ? ( + Checked-in + ) : ( + <> + {isEventPassed ? ( + Did not attend + ) : ( + Not checked-in + )} + + ) + ) + + return ( + ( +
+ {event.eventCoverImageName} + {disabled &&
} +
+ )} + onClick={handleEventClick} + > +
+ + {event.name} +
+

+ +

+

+ Location: {event.location} +

+

+ Status: + {renderStatus()} +

+
+ ) +}; \ No newline at end of file diff --git a/src/types/Events.tsx b/src/types/Events.tsx index 4d39827..b14a9ca 100644 --- a/src/types/Events.tsx +++ b/src/types/Events.tsx @@ -1,7 +1,26 @@ +export interface RushCategory { + _id: string, + name: string, + defaultRushCategory: boolean, + dateCreated: string, + events: [DashboardEvent], +} + export interface Event { - _id: string - categoryId: string - name: string - dateCreated: string - numAttendees: number | null + _id: string, + categoryId: string, + name: string, + dateCreated: string, + numAttendees: number | null, + location: string, + date: string, + deadline: string, + eventCoverImage: string, + eventCoverImageName: string, + lastModified: string, + attendeesId: string, +} + +export interface DashboardEvent extends Event { + checkedIn: boolean, } \ No newline at end of file diff --git a/tailwind.config.ts b/tailwind.config.ts index ca64324..3dfc77a 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,4 +1,5 @@ import type { Config } from "tailwindcss" +const flowbite = require("flowbite-react/tailwind"); const config = { darkMode: ["class"], @@ -7,6 +8,7 @@ const config = { './components/**/*.{ts,tsx}', './app/**/*.{ts,tsx}', './src/**/*.{ts,tsx}', + flowbite.content(), ], prefix: "", theme: { @@ -34,7 +36,10 @@ const config = { }, }, }, - plugins: [require("tailwindcss-animate")], + plugins: [ + require("tailwindcss-animate"), + flowbite.plugin(), + ], } satisfies Config export default config \ No newline at end of file