diff --git a/.env.example b/.env.example deleted file mode 100644 index f542c9b4..00000000 --- a/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -API_URL=http://localhost:8080 -REACT_APP_AUTH0_DOMAIN=dev-auth0domain-goes-here.us.auth0.com -REACT_APP_AUTH0_CLIENT_ID=some-client-id-goes-here -REACT_APP_AUTH0_AUDIENCE=https://dev-find-this-under-APIs-in-the-dashboard.us.auth0.com/api/v2/ diff --git a/.gitignore b/.gitignore index 4f5ff540..08105c27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ node_modules .env -dist/main.* \ No newline at end of file +dist/main.* +.txt +cookies.txt +*.cookies diff --git a/ISSUE-guest-logout-on-refresh.md b/ISSUE-guest-logout-on-refresh.md new file mode 100644 index 00000000..e69de29b diff --git a/ISSUE-poll-viewing-backend-integration.md b/ISSUE-poll-viewing-backend-integration.md new file mode 100644 index 00000000..e69de29b diff --git a/README.md b/README.md index 4604947a..0ae231f9 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,22 @@ With that done, run the following commands: 3. Preview your React app: `npm run start-dev` You should be able to deploy this application to Vercel by simply connecting the GitHub repo to a new Vercel project. You will also need to configure the `API_URL` environment variable on Vercel to match the deployed API url for your backend. Likewise, you may need to configure the `FRONTEND_URL` environment varialbe on your Backend to match the deployed URL for this app. + +# Team's Norm +[Google Docs- Team 1 Norms](https://docs.google.com/document/d/1RHJ7jtspaNzsc--etkQTvNSEmy2uNYQkhy2pSislH18/edit?tab=t.wb6r1sewz6o8) +| **Name** | **Day** | **Availability** | **Notes** | +| ----------- | ----------------- | ------------------------------------ | --------------------------- | +| **Olivia** | Monday | On campus until 2:30 PM | Available after midnight | +| | Wednesday | On campus until 2:30 PM | Available after midnight | +| | Thursday | On campus until 2:30 PM | Available after midnight | +| **Hailia** | Monday | 9:00 AM – 4:30 PM (Internship hours) | Attention may be split | +| | Wednesday | 9:00 AM – 4:00 PM (Internship hours) | Attention may be split | +| | Thursday | 9:00 AM – 2:30 PM (Internship hours) | Attention may be split | +| | Tuesday (July 16) | **Unavailable** | Off campus | +| **Tran Vo** | Monday | 9:00 AM – 5:00 PM | Fully available | +| | Tuesday | 9:00 AM – 2:30 PM | Not available after 3:00 PM | +| | Wednesday | 9:00 AM – 2:30 PM | Not available after 3:00 PM | +| | Thursday | 9:00 AM – 5:00 PM | Fully available | +| | Friday | 9:00 AM – 5:00 PM | Not available after 3:00 PM | +| **Flo** | | | Available 24/7 | + | diff --git a/dist/favicon.ico b/dist/favicon.ico deleted file mode 100644 index f63c4b5f..00000000 Binary files a/dist/favicon.ico and /dev/null differ diff --git a/dist/index.html b/dist/index.html index e864e00a..5ab4de6f 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1,13 +1,14 @@ - + - + + - - - Capstone 1 - - - + Rankzilla + + + +
- - + + + \ No newline at end of file diff --git a/dist/react-logo.svg b/dist/react-logo.svg deleted file mode 100644 index ea77a618..00000000 --- a/dist/react-logo.svg +++ /dev/null @@ -1,9 +0,0 @@ - - React Logo - - - - - - - diff --git a/dist/spongebob-404.webp b/dist/spongebob-404.webp deleted file mode 100644 index a1807a96..00000000 Binary files a/dist/spongebob-404.webp and /dev/null differ diff --git a/package-lock.json b/package-lock.json index 1da56e59..946d833a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "oauth-demo-frontend", + "name": "capstone-1-frontend", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "oauth-demo-frontend", + "name": "capstone-1-frontend", "version": "1.0.0", "license": "ISC", "dependencies": { @@ -15,6 +15,7 @@ "axios": "^1.10.0", "babel-loader": "^10.0.0", "dotenv": "^17.1.0", + "jwt-decode": "^4.0.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-router-dom": "^7.6.3", @@ -27,6 +28,7 @@ "eslint": "^9.29.0", "eslint-plugin-react": "^7.37.5", "globals": "^16.2.0", + "html-webpack-plugin": "^5.6.3", "style-loader": "^4.0.0", "webpack-dev-server": "^5.2.2" } @@ -582,13 +584,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz", - "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { @@ -596,9 +598,9 @@ } }, "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz", - "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -890,6 +892,13 @@ "@types/send": "*" } }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/http-errors": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", @@ -1319,6 +1328,16 @@ "ansi-html": "bin/ansi-html" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1534,13 +1553,13 @@ } }, "node_modules/axios": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", - "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -1640,6 +1659,13 @@ "multicast-dns": "^7.2.5" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1787,6 +1813,17 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001721", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz", @@ -1871,6 +1908,19 @@ "node": ">=6.0" } }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -1943,9 +1993,9 @@ } }, "node_modules/compression": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", - "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, "license": "MIT", "dependencies": { @@ -1953,7 +2003,7 @@ "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" }, @@ -2111,6 +2161,36 @@ "node": ">=10" } }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -2344,6 +2424,86 @@ "node": ">=0.10.0" } }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/dotenv": { "version": "17.1.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.1.0.tgz", @@ -2406,6 +2566,16 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", @@ -3212,9 +3382,9 @@ } }, "node_modules/form-data": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", - "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -3530,6 +3700,16 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -3576,6 +3756,91 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -4421,6 +4686,15 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4489,6 +4763,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4509,6 +4790,16 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4713,6 +5004,17 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -4739,6 +5041,19 @@ "node": ">=0.10.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4868,9 +5183,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true, "license": "MIT", "engines": { @@ -4989,6 +5304,17 @@ "node": ">=6" } }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5012,6 +5338,17 @@ "node": ">= 0.8" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5259,6 +5596,17 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5528,6 +5876,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -6311,6 +6683,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -6683,6 +7068,13 @@ "dev": true, "license": "MIT" }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true, + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index da1486c6..fe651f12 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "capstone-1-frontend", "version": "1.0.0", "main": "index.js", + "homepage": ".", "scripts": { "start": "webpack --mode production", "build": "webpack --mode production", @@ -20,6 +21,7 @@ "axios": "^1.10.0", "babel-loader": "^10.0.0", "dotenv": "^17.1.0", + "jwt-decode": "^4.0.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-router-dom": "^7.6.3", @@ -32,6 +34,7 @@ "eslint": "^9.29.0", "eslint-plugin-react": "^7.37.5", "globals": "^16.2.0", + "html-webpack-plugin": "^5.6.3", "style-loader": "^4.0.0", "webpack-dev-server": "^5.2.2" } diff --git a/pollcard-menu-permissions-ticket.md b/pollcard-menu-permissions-ticket.md new file mode 100644 index 00000000..e69de29b diff --git a/public/index.html b/public/index.html new file mode 100644 index 00000000..dbc86f75 --- /dev/null +++ b/public/index.html @@ -0,0 +1,13 @@ + + + + + + Rankzilla + + + +
+ + + \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index d793b9af..f12a7384 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,36 +3,106 @@ import { createRoot } from "react-dom/client"; import axios from "axios"; import "./AppStyles.css"; import NavBar from "./components/NavBar"; -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; -import Login from "./components/Login"; -import Signup from "./components/Signup"; -import Home from "./components/Home"; +import { BrowserRouter, HashRouter, Routes, Route } from "react-router-dom"; import NotFound from "./components/NotFound"; + +import Home from "./pages/Home"; +import Login from "./pages/Login"; +import Dashboard from "./pages/Dashboard"; +import SmartDashboardRedirect from "./components/SmartDashboardRedirect"; +import AdminDashboard from "./pages/AdminDashboard"; +import EditPoll from "./pages/EditPoll"; +import CreatePoll from "./pages/CreatePoll"; +import VotePollPage from "./pages/VotePollPage"; +import HostPollView from "./pages/HostPollView"; +//import Demo from "./pages/Demo"; + import { API_URL } from "./shared"; +import ViewResultsPage from "./pages/ViewResultsPage"; + + +//import SmartPollView from "./pages/SmartPollView"; +import PollFormModal from "./components/PollFormModal"; +import UserProfile from "./pages/UserProfile"; + +// const RouterComponent = process.env.NODE_ENV === 'development' ? BrowserRouter : HashRouter; + const App = () => { const [user, setUser] = useState(null); + const [isCreatePollOpen, setIsCreatePollOpen] = useState(false); + + const cleanupExpiredGuestSession = () => { + const savedGuestSession = localStorage.getItem('guestSession'); + if (savedGuestSession) { + try { + const guestUser = JSON.parse(savedGuestSession); + const now = Date.now(); + const sessionAge = now - (guestUser.loginTime || 0); + const maxAge = 24 * 60 * 60 * 1000; // 24 hours + + // Kick out expired guest sessions + if (sessionAge > maxAge) { + localStorage.removeItem('guestSession'); + return true; + } + } catch (e) { + // If the data is corrupted or weird, just delete it + localStorage.removeItem('guestSession'); + return true; // Cleaned up the mess + } + } + return false; //nothing to clean up + }; + console.log("Current user:", user); const checkAuth = async () => { + // Clean up any old guest sessions first + cleanupExpiredGuestSession(); + + // Check if someone's logged in as a guest (stored in browser) + const savedGuestSession = localStorage.getItem('guestSession'); + if (savedGuestSession) { + try { + const guestUser = JSON.parse(savedGuestSession); + if (guestUser.isGuest) { + setUser(guestUser); + return; // Found guest user, no need to check server + } + } catch (e) { + // Something went wrong with the saved data, just delete it + localStorage.removeItem('guestSession'); + } + } + + + // Now check if someone's actually logged in with the server try { const response = await axios.get(`${API_URL}/auth/me`, { withCredentials: true, }); - setUser(response.data.user); + setUser(response.data); + // If they're properly logged in, we don't need the guest session anymore + localStorage.removeItem('guestSession'); } catch { console.log("Not authenticated"); setUser(null); } }; - // Check authentication status on app load + // Check who's logged in when the app first loads useEffect(() => { checkAuth(); }, []); const handleLogout = async () => { try { - // Logout from our backend + // If they're just a guest, just clear their browser data + if (user?.isGuest) { + localStorage.removeItem('guestSession'); + setUser(null); + return; + } await axios.post( `${API_URL}/auth/logout`, {}, @@ -46,28 +116,61 @@ const App = () => { } }; + const handleOpenCreatePoll = () => { + setIsCreatePollOpen(true); + }; + const handleCloseCreatePoll = () => { + setIsCreatePollOpen(false); + }; + return (
- +
- } /> - } /> } /> + } /> + + {/* Demo route (optional) */} + {/* } /> */} + + {/* Smart redirect based on admin status */} + } /> + } /> + } /> + + {/* Poll CRUD */} + } /> + } /> + + {/* Voting and hosting */} + } /> + } /> + + {/* Results (fixes path param) */} + } /> + + {/* User profile */} + } /> + + {/* Optional fallback */} } />
+ {isCreatePollOpen && ( + + )}
); }; const Root = () => { return ( - + - + ); }; const root = createRoot(document.getElementById("root")); -root.render(); +root.render(); \ No newline at end of file diff --git a/src/components/Home.jsx b/src/components/Home.jsx deleted file mode 100644 index 130ea9eb..00000000 --- a/src/components/Home.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react"; - -const Home = () => { - return ( - <> -

Hello React!

- React Logo - - ); -}; - -export default Home; diff --git a/src/components/Login.jsx b/src/components/Login.jsx deleted file mode 100644 index 849e495a..00000000 --- a/src/components/Login.jsx +++ /dev/null @@ -1,130 +0,0 @@ -import React, { useState } from "react"; -import { useNavigate, Link } from "react-router-dom"; -import axios from "axios"; -import { API_URL } from "../shared"; -import "./AuthStyles.css"; - -const Login = ({ setUser }) => { - const [formData, setFormData] = useState({ - username: "", - password: "", - }); - const [errors, setErrors] = useState({}); - const [isLoading, setIsLoading] = useState(false); - const navigate = useNavigate(); - - const validateForm = () => { - const newErrors = {}; - - if (!formData.username) { - newErrors.username = "Username is required"; - } else if (formData.username.length < 3 || formData.username.length > 20) { - newErrors.username = "Username must be between 3 and 20 characters"; - } - - if (!formData.password) { - newErrors.password = "Password is required"; - } else if (formData.password.length < 6) { - newErrors.password = "Password must be at least 6 characters"; - } - - setErrors(newErrors); - return Object.keys(newErrors).length === 0; - }; - - const handleSubmit = async (e) => { - e.preventDefault(); - - if (!validateForm()) { - return; - } - - setIsLoading(true); - try { - const response = await axios.post(`${API_URL}/auth/login`, formData, { - withCredentials: true, - }); - - setUser(response.data.user); - navigate("/"); - } catch (error) { - if (error.response?.data?.error) { - setErrors({ general: error.response.data.error }); - } else { - setErrors({ general: "An error occurred during login" }); - } - } finally { - setIsLoading(false); - } - }; - - const handleChange = (e) => { - const { name, value } = e.target; - setFormData((prev) => ({ - ...prev, - [name]: value, - })); - - // Clear error when user starts typing - if (errors[name]) { - setErrors((prev) => ({ - ...prev, - [name]: "", - })); - } - }; - - return ( -
-
-

Login

- - {errors.general && ( -
{errors.general}
- )} - -
-
- - - {errors.username && ( - {errors.username} - )} -
- -
- - - {errors.password && ( - {errors.password} - )} -
- - -
- -

- Don't have an account? Sign up -

-
-
- ); -}; - -export default Login; diff --git a/src/components/NavBar.jsx b/src/components/NavBar.jsx index 648f3808..d32a1a13 100644 --- a/src/components/NavBar.jsx +++ b/src/components/NavBar.jsx @@ -1,18 +1,47 @@ -import React from "react"; +import React, { useState } from "react"; import { Link } from "react-router-dom"; +import PollFormModal from "./PollFormModal"; import "./NavBarStyles.css"; const NavBar = ({ user, onLogout }) => { + const [isPollModalOpen, setIsPollModalOpen] = useState(false); + return (