diff --git a/next.config.mjs b/next.config.mjs index d5456a1..4498dd1 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,14 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "**", + }, + ], + }, }; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 19850b1..42a5548 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "clsx": "^2.1.1", "framer-motion": "^11.2.10", "lucide-react": "^0.396.0", - "next": "14.2.3", + "next": "^14.2.13", "react": "^18", "react-dom": "^18", "react-google-charts": "^4.0.1", @@ -10358,9 +10358,9 @@ "license": "MIT" }, "node_modules/@next/env": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz", - "integrity": "sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==" + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.13.tgz", + "integrity": "sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==" }, "node_modules/@next/eslint-plugin-next": { "version": "14.2.3", @@ -10372,9 +10372,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz", - "integrity": "sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.13.tgz", + "integrity": "sha512-IkAmQEa2Htq+wHACBxOsslt+jMoV3msvxCn0WFSfJSkv/scy+i/EukBKNad36grRxywaXUYJc9mxEGkeIs8Bzg==", "cpu": [ "arm64" ], @@ -10387,9 +10387,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz", - "integrity": "sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.13.tgz", + "integrity": "sha512-Dv1RBGs2TTjkwEnFMVL5XIfJEavnLqqwYSD6LXgTPdEy/u6FlSrLBSSfe1pcfqhFEXRAgVL3Wpjibe5wXJzWog==", "cpu": [ "x64" ], @@ -10402,9 +10402,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz", - "integrity": "sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.13.tgz", + "integrity": "sha512-yB1tYEFFqo4ZNWkwrJultbsw7NPAAxlPXURXioRl9SdW6aIefOLS+0TEsKrWBtbJ9moTDgU3HRILL6QBQnMevg==", "cpu": [ "arm64" ], @@ -10417,9 +10417,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz", - "integrity": "sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.13.tgz", + "integrity": "sha512-v5jZ/FV/eHGoWhMKYrsAweQ7CWb8xsWGM/8m1mwwZQ/sutJjoFaXchwK4pX8NqwImILEvQmZWyb8pPTcP7htWg==", "cpu": [ "arm64" ], @@ -10432,9 +10432,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz", - "integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.13.tgz", + "integrity": "sha512-aVc7m4YL7ViiRv7SOXK3RplXzOEe/qQzRA5R2vpXboHABs3w8vtFslGTz+5tKiQzWUmTmBNVW0UQdhkKRORmGA==", "cpu": [ "x64" ], @@ -10447,9 +10447,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz", - "integrity": "sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.13.tgz", + "integrity": "sha512-4wWY7/OsSaJOOKvMsu1Teylku7vKyTuocvDLTZQq0TYv9OjiYYWt63PiE1nTuZnqQ4RPvME7Xai+9enoiN0Wrg==", "cpu": [ "x64" ], @@ -10462,9 +10462,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz", - "integrity": "sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.13.tgz", + "integrity": "sha512-uP1XkqCqV2NVH9+g2sC7qIw+w2tRbcMiXFEbMihkQ8B1+V6m28sshBwAB0SDmOe0u44ne1vFU66+gx/28RsBVQ==", "cpu": [ "arm64" ], @@ -10477,9 +10477,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz", - "integrity": "sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.13.tgz", + "integrity": "sha512-V26ezyjPqQpDBV4lcWIh8B/QICQ4v+M5Bo9ykLN+sqeKKBxJVDpEc6biDVyluTXTC40f5IqCU0ttth7Es2ZuMw==", "cpu": [ "ia32" ], @@ -10492,9 +10492,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz", - "integrity": "sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.13.tgz", + "integrity": "sha512-WwzOEAFBGhlDHE5Z73mNU8CO8mqMNLqaG+AO9ETmzdCQlJhVtWZnOl2+rqgVQS+YHunjOWptdFmNfbpwcUuEsw==", "cpu": [ "x64" ], @@ -10572,6 +10572,26 @@ "@parcel/watcher-win32-x64": "2.4.1" } }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz", + "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-darwin-arm64": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", @@ -10593,6 +10613,206 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz", + "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz", + "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz", + "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz", + "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", + "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz", + "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz", + "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz", + "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -15027,11 +15247,10 @@ } }, "node_modules/dset": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", - "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -17822,9 +18041,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -18014,11 +18233,11 @@ "license": "MIT" }, "node_modules/next": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.3.tgz", - "integrity": "sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.13.tgz", + "integrity": "sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==", "dependencies": { - "@next/env": "14.2.3", + "@next/env": "14.2.13", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -18033,15 +18252,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.3", - "@next/swc-darwin-x64": "14.2.3", - "@next/swc-linux-arm64-gnu": "14.2.3", - "@next/swc-linux-arm64-musl": "14.2.3", - "@next/swc-linux-x64-gnu": "14.2.3", - "@next/swc-linux-x64-musl": "14.2.3", - "@next/swc-win32-arm64-msvc": "14.2.3", - "@next/swc-win32-ia32-msvc": "14.2.3", - "@next/swc-win32-x64-msvc": "14.2.3" + "@next/swc-darwin-arm64": "14.2.13", + "@next/swc-darwin-x64": "14.2.13", + "@next/swc-linux-arm64-gnu": "14.2.13", + "@next/swc-linux-arm64-musl": "14.2.13", + "@next/swc-linux-x64-gnu": "14.2.13", + "@next/swc-linux-x64-musl": "14.2.13", + "@next/swc-win32-arm64-msvc": "14.2.13", + "@next/swc-win32-ia32-msvc": "14.2.13", + "@next/swc-win32-x64-msvc": "14.2.13" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", diff --git a/package.json b/package.json index f068eb5..6bc5ddf 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,14 @@ "lint": "next lint" }, "dependencies": { + "@aws-amplify/adapter-nextjs": "^1.2.10", + "@aws-amplify/auth": "^6.3.7", + "@aws-amplify/ui-react": "^6.1.12", "@radix-ui/react-avatar": "^1.1.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@mui/icons-material": "^5.15.21", "@mui/material": "^5.15.21", - "@aws-amplify/adapter-nextjs": "^1.2.10", - "@aws-amplify/auth": "^6.3.7", - "@aws-amplify/ui-react": "^6.1.12", - "aws-amplify": "^6.3.8", "@radix-ui/react-checkbox": "^1.1.0", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", @@ -32,7 +31,7 @@ "clsx": "^2.1.1", "framer-motion": "^11.2.10", "lucide-react": "^0.396.0", - "next": "14.2.3", + "next": "^14.2.13", "react": "^18", "react-dom": "^18", "react-google-charts": "^4.0.1", diff --git a/src/components/EventsDashboard/EventCard.tsx b/src/components/EventsDashboard/EventCard.tsx new file mode 100644 index 0000000..0d5bf3d --- /dev/null +++ b/src/components/EventsDashboard/EventCard.tsx @@ -0,0 +1,150 @@ +import { BiztechEvent } from "@/types/types"; +import { AnimatePresence, motion } from "framer-motion"; +import Image from "next/image"; +import { Bookmark } from "lucide-react"; +import { getCurrentUser } from "@aws-amplify/auth"; +import { Dispatch, SetStateAction, useState } from "react"; +import { fetchBackend } from "@/lib/db"; +import Link from "next/link"; + +interface EventCardProps { + event: BiztechEvent; + user: string; + registered: string[]; + saved: string[]; + setSaved: Dispatch>; +} + +const months = ["Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."]; + +export const EventCard: React.FC = ({ event, user, registered, saved, setSaved }) => { + const [fill, setFill] = useState(false); + let dateString = new Date(event.startDate); + + // const handleSaveClick = async (e: React.MouseEvent, id: string, year: number) => { + // e.preventDefault(); + // let isFavourite; + // const eventId = `${id};${year}`; + // let newSaved: string[] = saved; + // if (saved.includes(eventId)) { + // newSaved = saved.filter((s) => { + // return s !== eventId; + // }); + // isFavourite = false; + // setFill(false); + // } else { + // newSaved.push(eventId); + // isFavourite = true; + // setFill(true); + // } + // setSaved(newSaved); + + // if (!user) { + // return; + // } + + // const body = { + // eventID: id, + // year, + // isFavourite, + // }; + + // try { + // await fetchBackend({ endpoint: `/users/favEvent/${user}`, method: "PATCH", data: body }); + // } catch (err) { + // console.error(err); + // } + // }; + + const timeStateIndicator = (ev: BiztechEvent) => { + const startDate = new Date(ev.startDate); + const deadline = new Date(ev.deadline); + if (new Date() >= deadline && startDate >= new Date()) { + return ( +
+ COMING UP +
+ ); + } else if (startDate > new Date() && !registered.includes(`${ev.id};${ev.year}`)) { + return ( +
+ REGISTER BY {`${deadline.getMonth() + 1}/${deadline.getDate()}`} +
+ ); + } else { + return <>; + } + }; + + const registeredIndicator = (ev: BiztechEvent) => { + if (registered.includes(`${ev.id};${ev.year}`)) { + return ( +
+ REGISTERED +
+ ); + } else { + return <>; + } + }; + + const dateText = + `${months[dateString.getMonth()]} ${dateString.getDate()}, ${event.year}` + " " + `${dateString.toTimeString().slice(0, 5)}`; + + const eventPricingText = + `${event.pricing && event.pricing > 0 ? "$" + event.pricing.members.toFixed(2) : "Free!"} ` + + `${event.pricing.nonMembers ? `(Non-members ${event.pricing?.nonMembers.toFixed(2)})` : "(Members only)"}`; + + return ( + <> + + + e.stopPropagation()} + > +
+
+
+ {event.ename} +
+
+
+
{event.ename}
+
+
{registeredIndicator(event)}
+
{timeStateIndicator(event)}
+
+ {/* TODO: awaiting backend favEvent fix */} + {/* handleSaveClick(e, event.id, event.year)} + className={`cursor-pointer ${saved.includes(`${event.id};${event.year}`) || fill ? "fill-white" : ""}`} + /> */} +
+
+

{dateText}

+
+

{eventPricingText}

+
{registeredIndicator(event)}
+
{timeStateIndicator(event)}
+
+
+
+
+
+ +
+ + ); +}; diff --git a/src/components/EventsDashboard/EventDashboard.tsx b/src/components/EventsDashboard/EventDashboard.tsx new file mode 100644 index 0000000..87270a5 --- /dev/null +++ b/src/components/EventsDashboard/EventDashboard.tsx @@ -0,0 +1,89 @@ +import { BiztechEvent } from "@/types/types"; +import { AnimatePresence, motion } from "framer-motion"; +import React, { Dispatch, SetStateAction, useEffect } from "react"; +import { EventCard } from "./EventCard"; + +interface EventDashboardProps { + events: BiztechEvent[]; + user: string; + registered: string[]; + saved: string[]; + setSaved: Dispatch>; +} + +export const EventDashboard: React.FC = ({ events, user, registered, saved, setSaved }) => { + const currentEvents = events.filter((event) => { + const time = new Date(event.startDate); + return new Date() < time; + }); + + const pastEvents = events.filter((event) => { + const time = new Date(event.startDate); + return new Date() > time; + }); + + return ( + <> + {currentEvents.length > 0 && ( + + e.stopPropagation()} + > +

Current Events

+
+
+ )} +
+ + {currentEvents.length > 0 && + currentEvents.map((event, i) => { + return ( +
+ +
+ ); + })} +
+
+ {pastEvents.length > 0 && ( + + e.stopPropagation()} + > +

Past Events

+
+
+ )} +
+ {pastEvents.length > 0 && + pastEvents.map((event) => { + return ( +
+ +
+ ); + })} +
+ + ); +}; diff --git a/src/components/EventsDashboard/FilterTab.tsx b/src/components/EventsDashboard/FilterTab.tsx new file mode 100644 index 0000000..455f71b --- /dev/null +++ b/src/components/EventsDashboard/FilterTab.tsx @@ -0,0 +1,25 @@ +import { ListIcon, LucideProps } from "lucide-react"; +import { ForwardRefExoticComponent, RefAttributes } from "react"; + +const filterStates = { + all: "all", + saved: "saved", +}; + +export const FilterTab: React.FC<{ + title: string; + filter: string; + filterState: string; + handleUiClick: (s: string) => void; + Icon: ForwardRefExoticComponent & RefAttributes>; +}> = ({ title, filter, filterState, handleUiClick, Icon }) => ( +
handleUiClick(filter)} + > + {" "} +

{title}

+
+); diff --git a/src/components/EventsDashboard/GuestBanner.tsx b/src/components/EventsDashboard/GuestBanner.tsx new file mode 100644 index 0000000..748cc50 --- /dev/null +++ b/src/components/EventsDashboard/GuestBanner.tsx @@ -0,0 +1,57 @@ +import React, { useState } from "react"; +import Link from "next/link"; +import { X } from "lucide-react"; +import { AnimatePresence, motion } from "framer-motion"; + +interface GuestBannerProps { + message?: string; +} + +const GuestBanner: React.FC = ({ message }) => { + const [visible, setVisible] = useState(true); + return ( + <> + + {visible && ( + e.stopPropagation()} + className="relative p-5 pb-10 rounded-b-[5px] bg-login-form-card border-baby-blue border-l-2 border-b-2 border-r-2 w-full flex flex-col justify-center items-center top-0" + > +
{message}
+
+ {" "} + Click here to{" "} + + sign in + {" "} + or{" "} + + register here + {" "} + {`if you don't have an account.`} +
+ { + setVisible(false); + }} + /> +
+ )} +
+ + ); +}; + +export default GuestBanner; diff --git a/src/components/EventsDashboard/SearchBar.tsx b/src/components/EventsDashboard/SearchBar.tsx new file mode 100644 index 0000000..c2ac032 --- /dev/null +++ b/src/components/EventsDashboard/SearchBar.tsx @@ -0,0 +1,20 @@ +import { SearchIcon } from "lucide-react"; +import { ChangeEvent } from "react"; + +export const SearchBar: React.FC<{ + handleChange: (e: ChangeEvent) => void; + searchField: string; +}> = ({ handleChange, searchField }) => ( +
+
+ +
+ +
+); diff --git a/src/lib/db.ts b/src/lib/db.ts index 3a44842..77d2612 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -1,9 +1,9 @@ -import { API_URL } from './dbconfig'; -import { AuthTokens, fetchAuthSession } from 'aws-amplify/auth'; +import { API_URL } from "./dbconfig"; +import { AuthTokens, fetchAuthSession } from "aws-amplify/auth"; interface FetchBackendOptions { endpoint: string; - method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; data?: Record; authenticatedCall?: boolean; } @@ -18,25 +18,20 @@ async function currentSession(): Promise { } } -export async function fetchBackend({ - endpoint, - method, - data, - authenticatedCall = true -}: FetchBackendOptions): Promise { +export async function fetchBackend({ endpoint, method, data, authenticatedCall = true }: FetchBackendOptions): Promise { const headers: Record = {}; - if (method === 'POST' || method === 'PUT') { - headers['Accept'] = 'application/json'; - headers['Content-Type'] = 'application/json'; + if (method === "POST" || method === "PUT") { + headers["Accept"] = "application/json"; + headers["Content-Type"] = "application/json"; } if (authenticatedCall) { const session = await currentSession(); if (session) { - headers['Authorization'] = `Bearer ${session.idToken}`; + headers["Authorization"] = `Bearer ${session.idToken}`; } else { - throw new Error('Failed to retrieve authentication session.'); + throw new Error("Failed to retrieve authentication session."); } } @@ -46,7 +41,7 @@ export async function fetchBackend({ const response = await fetch(API_URL + endpoint, { method, headers, - body + body, }); const responseData = await response.json(); @@ -62,4 +57,4 @@ export async function fetchBackend({ } catch (error) { throw error; } -} \ No newline at end of file +} diff --git a/src/middleware.ts b/src/middleware.ts index 88f462e..d54a4c3 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -12,11 +12,7 @@ export async function middleware(request: NextRequest) { try { const { signInDetails } = await getCurrentUser(contextSpec); const email = signInDetails?.loginId; - return ( - email && - email.substring(email.indexOf("@") + 1, email.length) === - "ubcbiztech.com" - ); + return email && email.substring(email.indexOf("@") + 1, email.length) === "ubcbiztech.com"; } catch (error) { console.log(error); return false; diff --git a/src/pages/events.tsx b/src/pages/events.tsx new file mode 100644 index 0000000..10d4ff0 --- /dev/null +++ b/src/pages/events.tsx @@ -0,0 +1,159 @@ +import { EventDashboard } from "@/components/EventsDashboard/EventDashboard"; +import { FilterTab } from "@/components/EventsDashboard/FilterTab"; +import GuestBanner from "@/components/EventsDashboard/GuestBanner"; +import { SearchBar } from "@/components/EventsDashboard/SearchBar"; +import { fetchBackend } from "@/lib/db"; +import { BiztechEvent } from "@/types/types"; +import { AuthError, getCurrentUser } from "@aws-amplify/auth"; +import { ListIcon, Bookmark } from "lucide-react"; +import React, { ChangeEvent, useEffect, useMemo, useRef, useState } from "react"; + +interface registeredEvent { + "eventID;year": string; + [key: string | symbol]: unknown; +} + +interface EventProps { + events: BiztechEvent[]; +} + +const filterStates = { + all: "all", + saved: "saved" +}; + +export default function Page({ events }: EventProps) { + const [signedIn, setSignedIn] = useState(true); + const [searchField, setSearchField] = useState(""); + const [filterState, setFilterState] = useState(filterStates.all); + const isCooldownRef = useRef(false); + // these useStates will be empty arrays by default, but currently have mocks before i verify backend integration works + const [saved, setSaved] = useState([]); + const [registered, setRegistered] = useState([]); + const [email, setEmail] = useState(""); + + useEffect(() => { + fetchData(); + }, []); + + const uiStateFilter = () => { + let filteredEvents: BiztechEvent[] = events; + if (filterState === filterStates.saved) { + filteredEvents = filteredEvents.filter((ev) => { + return saved.includes(`${ev.id};${ev.year}`); + }); + } + + filteredEvents = filteredEvents.filter((ev) => { + return ev.ename.startsWith(searchField); + }); + + return filteredEvents; + }; + + const displayedEvents = useMemo(() => uiStateFilter(), [uiStateFilter, filterState, searchField, saved]); + + const fetchData = async () => { + try { + const { signInDetails } = await getCurrentUser(); + const email = signInDetails?.loginId; + const user = await fetchBackend({ endpoint: `/users/${email}`, method: "GET" }); + const registeredEvents = await fetchBackend({ endpoint: `/registrations?email=${email}`, method: "GET" }); + setEmail(email ? email : ""); + setSaved(user["favedEventsID;year"] ? user["favedEventsID;year"] : []); + setRegistered( + registeredEvents + ? registeredEvents.data.map((event: registeredEvent) => { + return event["eventID;year"]; + }) + : [] + ); + } catch (e) { + if (e instanceof AuthError && e.name === "UserUnAuthenticatedException") { + setSignedIn(false); + } else { + console.error(e); + } + } + }; + + const handleUiClick = (s: string) => { + if (isCooldownRef.current) { + //return + } else { + if (filterState != s) { + setFilterState(s); + } else { + setFilterState(filterStates.all); + } + isCooldownRef.current = true; + setTimeout(() => { + isCooldownRef.current = false; + }, 400); + } + }; + + const handleChange = (e: ChangeEvent) => { + setSearchField(e.target.value); + }; + + return ( +
+
+ {!signedIn && } +
+ +

Event Dashboard

+
+

View and register for our events!

+
+
+
+
+ +
+ + {/* TODO: awaiting backend API fix */} + {/* {signedIn && } */} +
+
+ + {displayedEvents.length === 0 ?
No events found...
: <>} + +
+
+
+ ); +} + +export async function getStaticProps() { + try { + let events = await fetchBackend({ endpoint: "/events", method: "GET", authenticatedCall: false }); + + events.sort((a: BiztechEvent, b: BiztechEvent) => { + return new Date(b.startDate).getTime() - new Date(a.startDate).getTime(); + }); + + events = events.filter((e: BiztechEvent) => { + return e.isPublished; + }); + + return { + props: { + events + } + }; + } catch (error) { + return { + props: { + events: [] + } + }; + } +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 63dc6b1..4f2948c 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -2,42 +2,41 @@ import type { Config } from 'tailwindcss'; const config: Config = { darkMode: ['class'], - content: [ - './src/pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './src/app/**/*.{js,ts,jsx,tsx,mdx}' - ], + content: ['./src/pages/**/*.{js,ts,jsx,tsx,mdx}', './src/components/**/*.{js,ts,jsx,tsx,mdx}', './src/app/**/*.{js,ts,jsx,tsx,mdx}'], prefix: '', theme: { container: { center: true, padding: '2rem', screens: { - '2xl': '1400px' - } + '2xl': '1400px', + }, }, colors: { primary: { color: '#162039', // biztech navy DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))' + foreground: 'hsl(var(--primary-foreground))', }, secondary: { color: '#7AD040', // biztech green DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))' + foreground: 'hsl(var(--secondary-foreground))', }, // Login Page Colors login: { 'page-bg': '#11192E', - 'form-card': '#1C253D' + 'form-card': '#1C253D', }, // Navbar Page Colors navbar: { - 'tab-hover-bg': '#324269' + 'tab-hover-bg': '#324269', }, // Events Page Colors events: { + 'coming-up': '#EC722D', + 'baby-blue': '#B2C9FC', + 'user-card-bg': '#304068', 'navigation-bg': '#11192E', 'active-tab-bg': '#1C253D', 'card-bg': '#263354', @@ -52,8 +51,8 @@ const config: Config = { 'biztech-green': '#7AD040', 'dark-navy': '#0C1221', 'desat-navy': '#A2A7B3', - 'dark-slate': "#324269", - 'pale-blue': "#C4D5FF", + 'dark-slate': '#324269', + 'pale-blue': '#C4D5FF', 'baby-blue': '#B2C9FC', 'light-blue': '#E0E9FE', 'white-blue': '#F7FAFF', @@ -72,34 +71,34 @@ const config: Config = { foreground: 'hsl(var(--foreground))', destructive: { DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))' + foreground: 'hsl(var(--destructive-foreground))', }, muted: { DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))' + foreground: 'hsl(var(--muted-foreground))', }, accent: { DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))' + foreground: 'hsl(var(--accent-foreground))', }, popover: { DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))' + foreground: 'hsl(var(--popover-foreground))', }, card: { DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))' - } + foreground: 'hsl(var(--card-foreground))', + }, }, fontFamily: { sans: ['Open Sans', 'sans-serif'], poppins: ['Poppins', 'sans-serif'], - montserrat: ['Montserrat', 'sans-serif'] + montserrat: ['Montserrat', 'sans-serif'], }, fontWeight: { '400': '400', '500': '500', - '600': '600' + '600': '600', }, fontSize: { xs: '14px', @@ -108,36 +107,35 @@ const config: Config = { lg: '24px', xl: '32px', '2xl': '40px', - '3xl': '48px' + '3xl': '48px', }, extend: { backgroundImage: { 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', - 'gradient-conic': - 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))' + 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', }, borderRadius: { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)' + sm: 'calc(var(--radius) - 4px)', }, keyframes: { 'accordion-down': { from: { height: '0' }, - to: { height: 'var(--radix-accordion-content-height)' } + to: { height: 'var(--radix-accordion-content-height)' }, }, 'accordion-up': { from: { height: 'var(--radix-accordion-content-height)' }, - to: { height: '0' } - } + to: { height: '0' }, + }, }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', - 'accordion-up': 'accordion-up 0.2s ease-out' - } - } + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + }, }, - plugins: [require('tailwindcss-animate')] + plugins: [require('tailwindcss-animate')], }; export default config;