From 5aaea9eae1312afdd6ab65883bfeed1cb889e4c1 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Tue, 19 Nov 2024 20:53:05 +0000 Subject: [PATCH 01/20] feat: added authentication and user data --- package-lock.json | 1315 ++++++++++++++--- package.json | 10 +- public/assets/icons/glass/ic-donate.svg | 1 + public/assets/icons/glass/ic-glass-bag.svg | 30 - public/assets/icons/glass/ic-wallet.svg | 1 + public/assets/icons/navbar/ic-donate.svg | 1 + public/assets/icons/navbar/ic-exit.svg | 1 + public/assets/icons/status/ic-failed.svg | 1 + public/assets/icons/status/ic-pending.svg | 1 + public/assets/icons/status/ic-success.svg | 1 + public/assets/images/logo.png | Bin 0 -> 5126 bytes public/favicon.ico | Bin 15406 -> 25974 bytes src/_mock/_countries.ts | 1247 ++++++++++++++++ src/_mock/_data.ts | 281 ++++ src/_mock/_mock.ts | 10 + src/app.tsx | 29 +- src/components/country-select/index.tsx | 34 + src/components/logo/logo.tsx | 6 +- src/components/provider/index.tsx | 43 + src/components/shared/alert/index.tsx | 75 + .../shared/modals/contributeForm.tsx | 116 ++ src/config-global.ts | 2 +- src/configs/firebase.ts | 77 + src/configs/index.tsx | 1 + src/constants/factory.ts | 7 + src/constants/fxns.ts | 6 + src/constants/index.ts | 2 + src/constants/urls.ts | 1 + src/hooks/useAuth.ts | 30 + src/hooks/useUser.ts | 9 + src/layouts/components/account-popover.tsx | 8 - src/layouts/config-nav-dashboard.tsx | 58 +- src/layouts/dashboard/layout.tsx | 40 +- src/layouts/dashboard/nav.tsx | 43 +- src/pages/contributions.tsx | 18 + src/pages/home.tsx | 11 +- src/pages/logout.tsx | 20 + src/routes/sections.tsx | 64 +- src/sections/auth/sign-in-view.tsx | 238 ++- .../contributions-table-head.tsx | 73 + .../contributions/contributions-table-row.tsx | 114 ++ .../contributions-table-toolbar.tsx | 70 + .../contributions/table-empty-rows.tsx | 31 + src/sections/contributions/table-no-data.tsx | 32 + src/sections/contributions/utils.ts | 80 + .../contributions/view/contributions-view.tsx | 216 +++ src/sections/contributions/view/index.ts | 1 + .../overview/analytics-widget-summary.tsx | 23 +- .../overview/view/overview-analytics-view.tsx | 75 +- src/services/auth/auth.dto.ts | 13 + src/services/auth/index.ts | 61 + src/services/pay/index.ts | 18 + src/services/pay/pay.dto.ts | 3 + src/services/trxn/trx.dto.ts | 30 + src/services/user/index.ts | 29 + src/services/user/user.dto.ts | 16 + src/utils/alert.ts | 13 + src/utils/cache.ts | 30 + src/utils/encrypt.ts | 15 + src/utils/errors.ts | 5 + src/utils/fstore.ts | 7 + src/utils/index.ts | 5 + yarn.lock | 924 ++++++++++-- 63 files changed, 5154 insertions(+), 568 deletions(-) create mode 100644 public/assets/icons/glass/ic-donate.svg delete mode 100644 public/assets/icons/glass/ic-glass-bag.svg create mode 100644 public/assets/icons/glass/ic-wallet.svg create mode 100644 public/assets/icons/navbar/ic-donate.svg create mode 100644 public/assets/icons/navbar/ic-exit.svg create mode 100644 public/assets/icons/status/ic-failed.svg create mode 100644 public/assets/icons/status/ic-pending.svg create mode 100644 public/assets/icons/status/ic-success.svg create mode 100644 public/assets/images/logo.png create mode 100644 src/_mock/_countries.ts create mode 100644 src/components/country-select/index.tsx create mode 100644 src/components/provider/index.tsx create mode 100644 src/components/shared/alert/index.tsx create mode 100644 src/components/shared/modals/contributeForm.tsx create mode 100644 src/configs/firebase.ts create mode 100644 src/configs/index.tsx create mode 100644 src/constants/factory.ts create mode 100644 src/constants/fxns.ts create mode 100644 src/constants/index.ts create mode 100644 src/constants/urls.ts create mode 100644 src/hooks/useAuth.ts create mode 100644 src/hooks/useUser.ts create mode 100644 src/pages/contributions.tsx create mode 100644 src/pages/logout.tsx create mode 100644 src/sections/contributions/contributions-table-head.tsx create mode 100644 src/sections/contributions/contributions-table-row.tsx create mode 100644 src/sections/contributions/contributions-table-toolbar.tsx create mode 100644 src/sections/contributions/table-empty-rows.tsx create mode 100644 src/sections/contributions/table-no-data.tsx create mode 100644 src/sections/contributions/utils.ts create mode 100644 src/sections/contributions/view/contributions-view.tsx create mode 100644 src/sections/contributions/view/index.ts create mode 100644 src/services/auth/auth.dto.ts create mode 100644 src/services/auth/index.ts create mode 100644 src/services/pay/index.ts create mode 100644 src/services/pay/pay.dto.ts create mode 100644 src/services/trxn/trx.dto.ts create mode 100644 src/services/user/index.ts create mode 100644 src/services/user/user.dto.ts create mode 100644 src/utils/alert.ts create mode 100644 src/utils/cache.ts create mode 100644 src/utils/encrypt.ts create mode 100644 src/utils/errors.ts create mode 100644 src/utils/fstore.ts create mode 100644 src/utils/index.ts diff --git a/package-lock.json b/package-lock.json index bcd1a82ae..0066b5add 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@minimal/material-kit-react", - "version": "2.0.0", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@minimal/material-kit-react", - "version": "2.0.0", + "version": "1.0.0", "dependencies": { "@emotion/cache": "^11.13.1", "@emotion/react": "^11.13.3", @@ -16,9 +16,14 @@ "@iconify/react": "^5.0.2", "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.16.7", + "@paystack/inline-js": "^2.22.1", "apexcharts": "^3.52.0", + "bcryptjs": "^2.4.3", + "crypto-js": "^4.2.0", "dayjs": "^1.11.13", + "firebase": "^11.0.1", "history": "^5.3.0", + "jwt-decode": "^4.0.0", "react": "^18.3.1", "react-apexcharts": "^1.4.1", "react-dom": "^18.3.1", @@ -27,7 +32,10 @@ "simplebar-react": "^3.2.6" }, "devDependencies": { + "@types/bcryptjs": "^2.4.6", + "@types/crypto-js": "^4.2.2", "@types/node": "^22.5.0", + "@types/paystack__inline-js": "^1.0.0", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.18.0", @@ -65,12 +73,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -78,73 +87,59 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.4.tgz", - "integrity": "sha512-NFtZmZsyzDPJnk9Zg3BbTfKKc9UlHYzD0E//p2Z3B9nCwwtJW9T0gVbCz8+fBngnn4zf1Dr3IK8PHQQHq0lDQw==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.4", + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", - "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.4" + "@babel/types": "^7.26.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -154,9 +149,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz", - "integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -166,30 +161,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", - "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.4", - "@babel/parser": "^7.25.4", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.4", + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -198,14 +193,13 @@ } }, "node_modules/@babel/types": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", - "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -289,15 +283,15 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", - "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, @@ -346,9 +340,9 @@ } }, "node_modules/@emotion/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==", "license": "MIT" }, "node_modules/@emotion/weak-memoize": { @@ -861,6 +855,612 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@firebase/analytics": { + "version": "0.10.9", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.9.tgz", + "integrity": "sha512-FrvW6u6xDBKXUGYUy1WIUh0J9tvbppMsk90mig0JhHST8iLveKu/dIBVeVE/ZYZhmXy4fkI7SPSWvD1V0O4tXw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/installations": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.15.tgz", + "integrity": "sha512-C5to422Sr8FkL0MPwXcIecbMnF4o2Ll7MtoWvIm4Q/LPJvvM+tWa1DiU+LzsCdsd1/CYE9EIW9Ma3ko9XnAAYw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.9", + "@firebase/analytics-types": "0.8.2", + "@firebase/component": "0.6.10", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2.tgz", + "integrity": "sha512-EnzNNLh+9/sJsimsA/FGqzakmrAUKLeJvjRHlg8df1f97NLUlFidk9600y0ZgWOp3CAxn6Hjtk+08tixlUOWyw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.10.15", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.15.tgz", + "integrity": "sha512-he6qlG3pmwL+LHdG/BrSMBQeJzzutciq4fpXN3lGa1uSwYSijJ24VtakS/bP2X9SiDf8jGywJ4u+OgXAenJsNg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.9.tgz", + "integrity": "sha512-YzVn1mMLzD2JboMPVVO0Pe20YOgWzrF+aXoAmmd0v3xec051n83YpxSUZbacL69uYvk0dHrEsbea44QtQ5WPDA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.16.tgz", + "integrity": "sha512-AxIGzLRXrTFNL+H6V+4BO0w/gERloROfRbWI/FoJUnQd0qPZIzyfdHZBbThFzFGLfDt/mVs2kdjYFx/l9I8NhQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.8.9", + "@firebase/app-check-types": "0.5.2", + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz", + "integrity": "sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2.tgz", + "integrity": "sha512-FSOEzTzL5bLUbD2co3Zut46iyPWML6xc4x+78TeaXMSuJap5QObfb+rVvZJtla3asN4RwU7elaQaduP+HFizDA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.2.45", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.45.tgz", + "integrity": "sha512-5rYbXq1ndtMTg+07oH4WrkYuP+NZq61uzVwW1hlmybp/gr4cXq2SfaP9fc6/9IzTKmu3dh3H0fjj++HG7Z7o/w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.10.15", + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz", + "integrity": "sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.8.0.tgz", + "integrity": "sha512-/O7UDWE5S5ux456fzNHSLx/0YN/Kykw/WyAzgDQ6wvkddZhSEmPX19EzxgsFldzhuFjsl5uOZTz8kzlosCiJjg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.15.tgz", + "integrity": "sha512-jz6k1ridPiecKI8CBRiqCM6IMOhwYp2MD+YvoxnMiK8nQLSTm57GvHETlPNX3WlbyQnCjMCOvrAhe27whyxAEg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.8.0", + "@firebase/auth-types": "0.12.2", + "@firebase/component": "0.6.10", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz", + "integrity": "sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2.tgz", + "integrity": "sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.10.tgz", + "integrity": "sha512-OsNbEKyz9iLZSmMUhsl6+kCADzte00iisJIRUspnUqvDCX+RSGZOBIqekukv/jN177ovjApBQNFaxSYIDc/SyQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/data-connect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.1.1.tgz", + "integrity": "sha512-RBJ7XE/a3oXFv31Jlw8cbMRdsxQoI8F3L7xm4n93ab+bIr1NQUiYGgW9L7TTw7obdNev91ZnW0xfqJtXcPA5yA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/database": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.9.tgz", + "integrity": "sha512-EkiPSKSu2TJJGtOjyISASf3UFpFJDil1lMbfqnxilfbmIsilvC8DzgjuLoYD+eOitcug4wtU9Fh1tt2vgBhskA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.0.tgz", + "integrity": "sha512-2xlODKWwf/vNAxCmou0GFhymx2pqZKkhXMN9B5aiTjZ6+81sOxGim53ELY2lj+qKG2IvgiCYFc4X+ZJA2Ad5vg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/database": "1.0.9", + "@firebase/database-types": "1.0.6", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.6.tgz", + "integrity": "sha512-sMI7IynSZBsyGbUugc8PKE1jwKbnvaieAz/RxuM57PZQNCi6Rteiviwcw/jqZOX6igqYJwXWZ3UzKOZo2nUDRA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.2", + "@firebase/util": "1.10.1" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.4.tgz", + "integrity": "sha512-K2nq4w+NF8J1waGawY5OHLawP/Aw5CYxyDstVv1NZemGPcM3U+LZ9EPaXr1PatYIrPA7fS4DxZoWcbB0aGJ8Zg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "@firebase/webchannel-wrapper": "1.0.2", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.39", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.39.tgz", + "integrity": "sha512-CsK8g34jNeHx95LISDRTcArJLonW+zJCqHI1Ez9WNiLAK2X8FeQ4UiD+RwOwxAIR+t2a6xED/5Fe6ZIqx7MuoQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/firestore": "4.7.4", + "@firebase/firestore-types": "3.0.2", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2.tgz", + "integrity": "sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.11.9", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.9.tgz", + "integrity": "sha512-dhO5IUfQRCsrc20YD20nSOX+QCT+cH6N86HlZOLz2XgyEFgzOdBQnUot4EabBJQRkMBI7fZWUrbYfRcnov53ug==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/auth-interop-types": "0.2.3", + "@firebase/component": "0.6.10", + "@firebase/messaging-interop-types": "0.2.2", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.15.tgz", + "integrity": "sha512-eiHpc6Sd9Y/SNhBsGi944SapiFbfTPKsiSUQ74QxNSs0yoxvABeIRolVMFk4TokP57NGmstGYpYte02XGNPcYw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/functions": "0.11.9", + "@firebase/functions-types": "0.6.2", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2.tgz", + "integrity": "sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.10.tgz", + "integrity": "sha512-TuGSOMqkFrllxa0X/8VZIqBCRH4POndU/iWKWkRmkh12+/xKSpdp+y/kWaVbsySrelltan6LeYlcYPmLibWbwg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/util": "1.10.1", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.10.tgz", + "integrity": "sha512-YTonkcVz3AK7RF8xFhvs5CwDuJ0xbzzCJIwXoV14gnzdYbMgy6vWlUUbzkvbtEDXzPRHB0n7aGZl56oy9dLOFw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/installations": "0.6.10", + "@firebase/installations-types": "0.5.2", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2.tgz", + "integrity": "sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.3.tgz", + "integrity": "sha512-Th42bWJg18EF5bJwhRosn2M/eYxmbWCwXZr4hHX7ltO0SE3QLrpgiMKeRBR/NW7vJke7i0n3i8esbCW2s93qBw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.13", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.13.tgz", + "integrity": "sha512-YLa8PWl+BgiOVR5WOyzl21fVJFJeBRfniNuN25d9DBrQzppSAahuN6yS+vt1OIjvZNPN4pZ/lcRLYupbGu4W0w==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/installations": "0.6.10", + "@firebase/messaging-interop-types": "0.2.2", + "@firebase/util": "1.10.1", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.13.tgz", + "integrity": "sha512-9ootPClS6m2c2KIzo7AqSHaWzAw28zWcjQPjVv7WeQDu6wjufpbOg+7tuVzb+gqpF9Issa3lDoYOwlO0ZudO3g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/messaging": "0.12.13", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz", + "integrity": "sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.10.tgz", + "integrity": "sha512-x/mNYKGxq7A+QV0EiEZeD2S+E+kw+UcZ8FXuE7qDJyGGt/0Wd+bIIL7RakG/VrFt7/UYc//nKygDc7/Ig7sOmQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/installations": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.10.tgz", + "integrity": "sha512-0h1qYkF6I79DSSpHfTQFvb91fo8shmmwiPzWFYAPdPK02bSWpKwVssNYlZX2iUnumxerDMbl7dWN+Im/W3bnXA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/performance": "0.6.10", + "@firebase/performance-types": "0.2.2", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2.tgz", + "integrity": "sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.10.tgz", + "integrity": "sha512-jTRjy3TdqzVna19m5a1HEHE5BG4Z3BQTxBgvQRTmMKlHacx4QS0CToAas7R9M9UkxpgFcVuAE7FpWIOWQGCEWw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/installations": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.10.tgz", + "integrity": "sha512-fIi5OB2zk0zpChMV/tTd0oEZcZI8TlwQDlLlcrDpMOV5l5dqd0JNlWKh6Fwmh4izmytk+rZIAIpnak/NjGVesQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/remote-config": "0.4.10", + "@firebase/remote-config-types": "0.3.2", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz", + "integrity": "sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.3.tgz", + "integrity": "sha512-B5HiJ7isYKaT4dOEV43f2ySdhQxzq+SQEm7lqXebJ8AYCsebdHrgGzrPR0LR962xGjPzJHFKx63gA8Be/P2MCw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.13.tgz", + "integrity": "sha512-15kje7JALswRCBKsCSvKg5FbqUYykaIMqMbZRD7I6uVRWwdyTvez5MBQfMhBia2JcEmPiDpXhJTXH4PAWFiA8g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.10", + "@firebase/storage": "0.13.3", + "@firebase/storage-types": "0.8.2", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2.tgz", + "integrity": "sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.1.tgz", + "integrity": "sha512-AIhFnCCjM8FmCqSNlNPTuOk3+gpHC1RkeNUBLtPbcqGYpN5MxI5q7Yby+rxycweOZOCboDzfIj8WyaY4tpQG/g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/vertexai": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.0.0.tgz", + "integrity": "sha512-48N3Lp/9GgiCCRfrSdHS+Y1IiMdYXvnHFO/f+HL1PgUtBq7WQ/fWmYOX3mzAN36zvytq13nb68ImF+GALopp+Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.2", + "@firebase/component": "0.6.10", + "@firebase/logger": "0.4.3", + "@firebase/util": "1.10.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.2.tgz", + "integrity": "sha512-3F4iA2E+NtdMbOU0XC1cHE8q6MqpGIKRj62oGOF38S6AAx5VHR9cXmoDUSj7ejvTAT7m6jxuEeQkHeq0F+mU2w==", + "license": "Apache-2.0" + }, "node_modules/@floating-ui/core": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", @@ -911,6 +1511,37 @@ "integrity": "sha512-4F+rbfklgWHatFheB3ZQgTFjkqzMiWfHomy69TWSGc0qU+w+QhX9dGz7IVQRksvKciJoXAhxijCxwAJw418g4Q==", "license": "OFL-1.1" }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", + "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -1270,12 +1901,12 @@ } }, "node_modules/@mui/types": { - "version": "7.2.15", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", - "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "version": "7.2.19", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", + "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", "license": "MIT", "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -1351,6 +1982,16 @@ "node": ">= 8" } }, + "node_modules/@paystack/inline-js": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/@paystack/inline-js/-/inline-js-2.22.1.tgz", + "integrity": "sha512-h9cf+3UbFY/+/GRA5XeWj769KaSHuedqIcuYDdV6voKGnwF9qcmJ3BorpIST45Y3qVXljOXsexL2tS6GZXJbmg==", + "license": "ISC", + "engines": { + "node": ">= 18.0.0", + "npm": ">= 10.0.0" + } + }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", @@ -1364,15 +2005,79 @@ "url": "https://opencollective.com/unts" } }, - "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==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } + "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==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" }, "node_modules/@remix-run/router": { "version": "1.19.1", @@ -1833,6 +2538,20 @@ "@swc/counter": "^0.1.3" } }, + "node_modules/@types/bcryptjs": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", + "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -1866,7 +2585,6 @@ "version": "22.5.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -1878,10 +2596,17 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "license": "MIT" }, + "node_modules/@types/paystack__inline-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/paystack__inline-js/-/paystack__inline-js-1.0.0.tgz", + "integrity": "sha512-LCU5rSBs3FAG8tkn1hgV9FHTTRk+Kj2s/DupNlJRem5NaVabj6AASjWJ9tBtJX6dt7bcKhkf8c5MzgJUkpOG2g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", "license": "MIT" }, "node_modules/@types/react": { @@ -2192,24 +2917,11 @@ "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": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -2488,6 +3200,12 @@ "dev": true, "license": "MIT" }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "license": "MIT" + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2550,29 +3268,6 @@ "node": ">=6" } }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -2614,6 +3309,20 @@ "node": ">= 6" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -2623,21 +3332,6 @@ "node": ">=6" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -2699,6 +3393,12 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -3153,6 +3853,15 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4019,6 +4728,18 @@ "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4068,6 +4789,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/firebase": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.0.1.tgz", + "integrity": "sha512-qsFb8dMcQINEDhJteG7RP+GqwgSRvfyiexQqHd5JToDdm87i9I2rGC4XQsGawKGxzKwZ/ISdgwNWxXAFYdCC6A==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.9", + "@firebase/analytics-compat": "0.2.15", + "@firebase/app": "0.10.15", + "@firebase/app-check": "0.8.9", + "@firebase/app-check-compat": "0.3.16", + "@firebase/app-compat": "0.2.45", + "@firebase/app-types": "0.9.2", + "@firebase/auth": "1.8.0", + "@firebase/auth-compat": "0.5.15", + "@firebase/data-connect": "0.1.1", + "@firebase/database": "1.0.9", + "@firebase/database-compat": "2.0.0", + "@firebase/firestore": "4.7.4", + "@firebase/firestore-compat": "0.3.39", + "@firebase/functions": "0.11.9", + "@firebase/functions-compat": "0.3.15", + "@firebase/installations": "0.6.10", + "@firebase/installations-compat": "0.2.10", + "@firebase/messaging": "0.12.13", + "@firebase/messaging-compat": "0.2.13", + "@firebase/performance": "0.6.10", + "@firebase/performance-compat": "0.2.10", + "@firebase/remote-config": "0.4.10", + "@firebase/remote-config-compat": "0.2.10", + "@firebase/storage": "0.13.3", + "@firebase/storage-compat": "0.3.13", + "@firebase/util": "1.10.1", + "@firebase/vertexai": "1.0.0" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -4174,6 +4931,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -4367,15 +5133,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -4467,6 +5224,18 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "license": "MIT" + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4728,6 +5497,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -5004,15 +5782,15 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-parse-even-better-errors": { @@ -5077,6 +5855,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/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -5145,6 +5932,12 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "license": "MIT" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5152,6 +5945,12 @@ "dev": true, "license": "MIT" }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "license": "Apache-2.0" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5545,9 +6344,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { @@ -5658,6 +6457,30 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5861,6 +6684,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -6004,6 +6836,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -6191,6 +7043,26 @@ "node": ">= 0.4" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, "node_modules/string.prototype.includes": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", @@ -6296,7 +7168,6 @@ "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" @@ -6334,18 +7205,6 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "license": "MIT" }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -6490,15 +7349,6 @@ "dev": true, "license": "MIT" }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6542,7 +7392,6 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true, "license": "0BSD" }, "node_modules/type-check": { @@ -6682,7 +7531,6 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, "license": "MIT" }, "node_modules/universalify": { @@ -7002,6 +7850,29 @@ "dev": true, "license": "MIT" }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7101,6 +7972,56 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7108,6 +8029,15 @@ "dev": true, "license": "ISC" }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -7117,6 +8047,33 @@ "node": ">= 6" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 8842c7bea..1e0d5b2b6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@minimal/material-kit-react", "author": "minimals.cc", "licence": "MIT", - "version": "2.0.0", + "version": "1.0.0", "private": false, "type": "module", "scripts": { @@ -32,9 +32,14 @@ "@iconify/react": "^5.0.2", "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.16.7", + "@paystack/inline-js": "^2.22.1", "apexcharts": "^3.52.0", + "bcryptjs": "^2.4.3", + "crypto-js": "^4.2.0", "dayjs": "^1.11.13", + "firebase": "^11.0.1", "history": "^5.3.0", + "jwt-decode": "^4.0.0", "react": "^18.3.1", "react-apexcharts": "^1.4.1", "react-dom": "^18.3.1", @@ -43,7 +48,10 @@ "simplebar-react": "^3.2.6" }, "devDependencies": { + "@types/bcryptjs": "^2.4.6", + "@types/crypto-js": "^4.2.2", "@types/node": "^22.5.0", + "@types/paystack__inline-js": "^1.0.0", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.18.0", diff --git a/public/assets/icons/glass/ic-donate.svg b/public/assets/icons/glass/ic-donate.svg new file mode 100644 index 000000000..b4d273e5c --- /dev/null +++ b/public/assets/icons/glass/ic-donate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/icons/glass/ic-glass-bag.svg b/public/assets/icons/glass/ic-glass-bag.svg deleted file mode 100644 index 5875b6f39..000000000 --- a/public/assets/icons/glass/ic-glass-bag.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/assets/icons/glass/ic-wallet.svg b/public/assets/icons/glass/ic-wallet.svg new file mode 100644 index 000000000..3b30bbf91 --- /dev/null +++ b/public/assets/icons/glass/ic-wallet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/icons/navbar/ic-donate.svg b/public/assets/icons/navbar/ic-donate.svg new file mode 100644 index 000000000..80a633dc6 --- /dev/null +++ b/public/assets/icons/navbar/ic-donate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/icons/navbar/ic-exit.svg b/public/assets/icons/navbar/ic-exit.svg new file mode 100644 index 000000000..4e637896c --- /dev/null +++ b/public/assets/icons/navbar/ic-exit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/icons/status/ic-failed.svg b/public/assets/icons/status/ic-failed.svg new file mode 100644 index 000000000..0bda5ac56 --- /dev/null +++ b/public/assets/icons/status/ic-failed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/icons/status/ic-pending.svg b/public/assets/icons/status/ic-pending.svg new file mode 100644 index 000000000..b3df1c3da --- /dev/null +++ b/public/assets/icons/status/ic-pending.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/icons/status/ic-success.svg b/public/assets/icons/status/ic-success.svg new file mode 100644 index 000000000..cdfff398c --- /dev/null +++ b/public/assets/icons/status/ic-success.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/images/logo.png b/public/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8a5addbd3204127535dd5e79fb95c3c321235478 GIT binary patch literal 5126 zcmV+h6#46kP)zjxm6KxXq2)4UAQ3NiY=={uNM&YbmFF84fM=vO;_sM zo4#C!0|bHZ5RR(qYKv~0B7}Y+m|+PF$_dO&fpxkrUQk8wMPFlmJ-#FCcjmcV)vl1k zdJ~=2g^&FUofs+fc`DR3`8ERznIwL%;TwP zg>^B$3n|MI`-_P^#ymMa?bbV}#-HK)3LW!8A~e6Jm}o%{fTyTx6|V^)&c^o{0%OQx zUzq1Ca|gXG>#>j6C+4xVSxYK@OGG_JL>&;l)?F~2l7WR~t^!-}hd!U%ha8dfw3TiL zEUSo+Y8<3s-;s3Tgj}bwf*iop)T&$89?XnmF#Rk5(pk>|-DX~4Rqd7ZXVrmnKYAL> zKw;6>hWphmbW7)P1Ju|O9D-myXmggjV~U96p%fZQQy# zQ=yDHkF6?YK33pxf{qok-x-jWdF;m>?CwZTAY;h==KiNEmX>)OZXI@v3xoSD!_Bm1 zQh*G^Y^q=}jv%G}OUk@MA$sU3a1>(msVBPK_3p%bNvADE4>uiQoPl)Hw~OS3^KoAz z``SV42{b|`babs&AhtyANLF`zD@+WfPz#&QsBg&e10&aur+T<8Mybn% z@-kPrFXa#^OlUa48;7`}EOjKN2{E34LQD$q zD9cP|M)7qnF2Vxg^ZC%$+L}lUJ*T3?>6GU@NO4rq!$G3KWJcnBZX*;5!b;bP8cBz* z(?`z)QB+tUJIZzNp=%l>xm3<#Rb&|$KS^*?N^Kn{MB-bF0a@53U6~hKG}F{eKdrud z!#MUm6PS?3gifH=vLN-uI>fD}I>~*`LY4L>HXp{#WSBr**9cb_L zBU#6eIl2!@sJ%>mW=U`F=#Xu>Tie2t9}9zV)Fg@>3Y>NwPWo%h5L12Cq@pd5s!_PD z{!oo+d9CJkntXMsDja|6DOkL49_b4!GJ!j>YgZFiu6Y-aJiY`QKi?d=ciPx7cxut_ z@yMf3;_e3@NlM+r_uqvx>P|y866~kxwszeHy!`4L_~Y{DB_k1jQc*OVTep_o%Agn03iT zSh0LD#*RKo)?v@H;kvn3qR3f<8?La zYV*O1%kcP>rI>MY0ftoBkZ;kYE)>wx9v0cxv>0!mNao2PSRiROl`9fCs=uJ?J;9Mm zedyV!$T~A=Am^b)w_ccv-8>Geu1QO$Yw2qi3P~QhEQ%soF0Tz6Is}(pJOz`_m;h&? z>1GJbnsE`9KeqzwHhvL(UN@i0G+MEA7-hN5sb`ME@U~~rr=V5NmS|b-gP>_1ZX`MN zMqjnek|Oy9%#$U_1g}EMMQT#IL`X!OGt^z`D#60X=3_$L>5*%1tz3i6Tejea>*mH) zu;$&rW6I3gP*r2xnfyYV6*ijsk*+fnbUi6uqfQ)-r%5#w6cj*LLuh{QUIe$j8J1}J zS7>M=HTdKjH{Mw1g}cL)u~Z;;h}|+_%_M-UDc+r+gy|TOu0oYM6QYp~Dn{k04+YIF zt$6SK4-iXaS*Z*2A9@s9x5gXu(LWf8iQ`X=lx6mHkc7AS17z|1^6&-&@RI-5^-%HN zho9ihw^qsV@NWMY!5x2#85$jH>w}o}=uRyApaZ*o7WfrDtZ9!d7#HD}RjwQfJ#F5K zb=1%yLu3@8Lr?2Hm6Mxs?m1_|lrWZ@#$CIJsU9p|x(v6Ia<|*<@}7hK-ukou#K)g( zK#RvCuSvC?m5voM8mX!2FWn>Wwv|Aj-Ds1ZZy=ZBzn|HIog{fh1q%9C+L8-!Y>o8X zPPc|#t!k#GUCcMDBD88fL%cX)+^KkS;e7JbSVfvrlDfQUU{qC=9{uZYyhYLrJp1Pt z@uR61VC2ZCppQCn7^Y72gEZYDPqx3Qf z2Q!Ytw7k4Ll$MrKJqnsy+_>+7hp_yqMUttK1{#pLS6+&jUwadcjk|HxkbXgYh+1Ux}{ZO>je)^7Y9e|h00 zOq=?{2!mZE#rXBDKkq_G!}jgiP2pZDu$y8dakDB8ST!T861s{}HFoS=?~Aa388~af zHx!~7k&wxtyDurn*nxJLO)>PLAJ8jJ+W315>@pwDYN`ZNNZ-q=ETz1(EI2?|+ zXO=zv99s6YP^0Yn2rPK)NsOgfmqR%dQ!Y3MZnqn;l|J|97jW-=4@qAyS?FI_kdHZ6 z%)sLKK?d8Z6;VHB6i_KU{k{CNhY~&zUl$Xan%VmS~Z$SE( zh&%XNYiB3keES`EokO81(M0NSN(S6~b`fP$BHcA22uZ6j4$ge)#=UNX zlqtUMCv(W9iFTr+qZ9Z1_5rxtym8voN0#^xi~lGsYywent?(?8x(Sd5C+?uawtNSs zUpx(#UZdc#924nKd94N9!qZk>1$eEj?*oBcf$CM=mInW%havDAg z9V_2ngV)|zDLWer?)Y9$8y^1sW4P-#x5DLE0QmTm) z114B%e)r%*=m-R*u8Rf#V%_)jvnw!d+7yf$nLI-5*SD`cGQm<=j*9-nv9+xQwXM&h zATOFyci05_QV;vOZ0JcSWHsE_N3aup`>$@6si#;hf95%SO36?)iGO8IB6q77k1TjX zhFCf2o-pz#x7WK*AN*y_W?VXdC;mZkZ9qj#%#j)0nZUfBYo*a~?*q*eLkADS`Daaz zyXI|c$G!JI)MdIRf*JezUsqCw<$atud>C>8M;U9^t;fQJPvWIl-$Z~c>P<_VFnMSJ z&K#akQ`3fuA{#9ZAtqIo1R{F|@~d3J+55N^bar97f`cje9&^$NnEoKAyI&z)76`E# z*D;wgBV%~l#l$sR$Wea&rPnA#Qjm!x3n}iChM$1bDcx@&DK--argWx4fHE!tQVE}b zz6l#X{S3|SRvD5p*bQNAmPhIMqf4#mT`W*uY@_;~g3uvssV7gf-F`V?b0yWy4}7yCkcm;~^|Es5Kd) z7_}HKj&5W$v@p#^d0_;>5r!HbprkQo_M`(9TV=`1ui#bkYtt9ham6W4%)g>HM)bGg zha(Db%Xt;(puG0RZwy6WRifaj>-yrA_3iM7jMm50I`H_9d*RYCC6wOQ@Yy%P2m_Z~ z-3y=76xri7WMz0?D;8hX8yAl$hNm-xExU|`^Esy%1jug;Gjcee|^-*%%mIQ|?vd`>OIC*3_V!A7-3VjB6Hs13^q^Y1eT3 z^NpA=q(Hg>ri3{xS{%b~J;#OLy|Nd#{Ao8XKeb2_DpithlvPBu?3{7MSo(e|=Dprb zj4GwXt1hR{Gat6$m(Mm)XG8e$qHnQbhcN(r-%rfCcIhrkUTQQzg>m%eS+t0+H@u%6 zr_|aold{SUO##dqYitK$_MJ7oMIzVOS1Y$VYQ zdo=9!0^d@$^;-`yO*1_C$Vlmte-i@cC6*d=@D;;S}WqJN9bW+^9*3 zistDr;S~34E4-H0!6g;B*lFU;@=!J|=ggcNkk}@`mMU?tp`d%Auy`T*L zMbkawTCr{n+=9z{;Sy3QudZ)LI$hPT%!=jL9EI7WKJYGfCB51X>&|@2Nd9$08$Q_{ zOk015(m?mU(t?Gn+Yq}F#P;`-h9GWS)=bNuz<^#Bq%{~i)|vbCV%fX~$V9Dqq^vmo zJrQ49^jyPJ*Y-gbIkI~?Xn{Q>V7I2P(5Oz}|3C0z;t(e}!^!DlHNj=S^@NDQ0h~TK zANNczi`4R~^UHAhz#;Zc3XO1g23?Ss*gc5;9BxlCfW) z-4{aLUB}0uu+>DZ8RZ z>S^l;;*8@R7X2*tSPpY0406O0ag(a4rknAKrZqYAG-y4d}|>n)fx)Jgiwg*#U4r4C2k z9uDv~{40Q{A{4S+_Sd{V9m_v#N8buN4Ala(kbC!KV{{s`f4Q6_^zMr)X+d4bf>qIt zmCHZsL}9*#{MK?TdAE(|3?h}}@&3Hnt+jD14)1(imF&ShQUy#fZ^+cbs*l4~-rHeB z42JI&3anX(7*z@(LM&hneMi;wG+?|80D@=B-C%xY@(9`_dzu>Q9Bwp*nJSmoxF~AW-LHtPe zDt+>oSp4dpoGHZ-$c%AFsPmHDOUgX9ykrKlp1y}T?o9Oohm>!62fTah^9oB#$@-1K z;R>3r?Yp+!o9cGjK<;p!zH)(w`k$^$TITWeuk=_2L5~o4pB(PHEvsyZTW6} zl;%)oV0RhE$h=IH1mO>*t~ey#1~>NVOwHyyDv8L6d5j}pG0X8QW(;nSKU{Fo#=%54 z)4wlYam-orV!@vgp+5)3H(0{oTb`54G)+X0eD;zJiN#s+qN2<9(7(Uo97~&Do!Q#_ z)h6@+dPMSK5!QuwrheW2fM7M}DZjU0t4+iKXChfqT9bK!+F#leQ#2X&8}m$rnOG;^ zBp1l(^OD`fYC6{NYG9_=bYHRGnHP&A--ho&u(K`Sx|A;uivG;Z@Eb|haRrSj=$2c6 ofqJ^o!21d*fM0hY|E~o91|*SS3`1yN?*IS*07*qoM6N<$f(1d@1poj5 literal 0 HcmV?d00001 diff --git a/public/favicon.ico b/public/favicon.ico index 5c435e6bb910369a79aa4a76f7b91675408a8a44..26fe61f5b0dacb440b45aa63fb349cfb745a7850 100644 GIT binary patch literal 25974 zcmeHQ33yc1y&qq{uYKP~!XlE8kdWDDl1%o=KH1no0eN);YFQKn1wlnESRk?pVG$m- zQWqA>hp)E!RiQ4m&ur<3Fxm zU2+`>@z**M<5oKp<9_e#9T#-;?$UsqbSW|Jn5a*T+sFO5Kkmo#^KHyRt4(k1{qI&+ zVwV|=5imHW!^enMtoPD5K^~XKZ#8CGVIt;-WdvC5yDV5WjcE|`)LOfD@7@aRwa64Q zW*b`xFTIX4zLK7A!2H!M!e9#w+UA&<%VqHUtj_{7w)y6?hs#A9^kX0MebZ&OXTlG* z0Upg=E1AwV*JEBo5nr?e%#0Yfr3}h;t-(lBd%9;CY;8LzVp_8pwjIi!9A~zQ4zq1* zPqGy&t;|;ogdOUT9ThhP-F-_CuF#-`-Aq33Tj|{jZ4M zI*LDS=DG>|F5x_(y~e$l%dRm0s-tX1p|jbzNO(j3#x(;rOJ~+qBZkejeVtub!|;ny zcZFYVrd>78)e-Mw+4q9)VC=ldYtH4QvP*}%w%zdlM%OR4HvQQA%;g_qkG{wNH0)CU+%g5>lUT|;Ry_YO=8>>qe!V^)mE65f%L_pQZ1U#$srbI9$z@FxG`c))s#yL8xoydUF6Ogh#V&HEXNbCz1%D(@PJx6S+KOvm zr1ZQ(wQuRq{)@6kOrnedH&B4barBk>19liY@X$80Cn|CT>~iuz(_7@UCQ~t<&8Qfv z_Rkz}J^80Sf_tfddSMxr*X<-%c0Lu(c!KgLE|&YoQ|{O~N36kTQy^p(n}Y zNaVTL)?r@Y$vWb)_odSLe;{u`SyZ`$Ztm0ijHcoeRqpyUt+N-4ofAI72VE<#3sS-4 zI_S2~+cpeSZpk)TuO)d9z5+Tc?AgHU;fEg)y2sBjb_KGp;20{ihV9*E z5l{L0T}yeRex~vYk9`r#enV?0^?z$7iGw`(SKtV_VAcQPrBgRCLceD!OkI zRj=76c;$Ac!R>KU)za;1jKcMq95%S9X! zfbH@PhW=nqPWd;?pvtAMQ`IByQRR{yi2eGD{^?mcsCyUk7^K3x){z^!sEn1>|Ho7` zbtTqGwpoaK3&zc-%7=GT$?V^dCp$;(3*UtGEUSG9@zk4$z2?NGv!GXgS2$joGinYx zY`qc7!$;X+$L%PqSjc>ecDc-L>^tp9HrY1w_{u(n>y_uFdE-St9>b|7?$b@KSH@vX zv4=sj%55ymVt*j71CK4}L%qTi>o$+gZHjM|<`0b}VsFhe%Clyi|s-v^mhmIrnj(zv9o#<_^_K<2Vw*7oN2y_M)_e1hOV1k}aVZ z>UzrKDdY3lQWCWAe7(^I8p7w3*AHWd=u@6$I%R&CCy}skl;f8WeX{Jz>!Q>P+@$X< z)%8)@w0ZwhKixBZ8qJzMU8KoBy_q~ISE_b@+>N7XRb3seT86|q(zHpp2>cY^pdHUx zwu85kgZk6b2Op#*3l`DCb<5?nOdU@dSDV)@T1boL&844Q_hZWQxCB1Rn(|sO#FR~pXv0bCQ<#Lx6@Z&ennq?`K4~0 zSZ*3GT%dh>_t5molgOO{d1ZO(YbD>XNmMxdcT@(SQuTNPRjvDoDxW+WIjuWNIoIC< znq$DOcU%yAjD~2u#eyB%kF75}8^-1{Pj7}Uu0tvBeZYN?uh9he|wKk zpFTyOeEcbG+EP!~Z1{jGpnF2j}4z@zW$WU?)=WBdv; zZFKO!KNRRhe(KwA>5f|`LU;AD$G$tqZ6~&!%4Nikv0t+Sdt2BamVaa7IWw#Yw06yE zdTZAny7j5|fSXp9j#Am;ZN&R7M_Q85MP5UZIA#G&{(CoTu!~)1FHP>Gb2{x9umLpZ zo;&I6xw8r!BLC;14=CH2CTLdrdr}f;<&q`BPAQ!Qc3@We5wk~qf7^`z0R z*LNy#h@9o;fmwH{c8}>EF|Z$G?h{?V&p-Q&-al|aSNESQvByumitGuT5bNpERg`H> zqlNQoY3k;`0XJD!;TKBgZXq|$0~OpPnU!K@rjuh-8)BG3$X!77Bh8RI={x!cWqh;T z%vUgvg;_qxl07VC+WOLrsZ(HsPOBI&cJKUU5BW2sGdZ?%&p-Dpu`khHPd)iK?Fa^S zviRYLhiT95-4WB@_wT2_ymx>`Y&@jO9An`dJVxlc!V}|VOHCoW)kzMk3%QgE@Bc0Q zih_CU*vaupP#NDWH^a`zvzGtH3yt)_!Gm=C_;Izm5ooMhwn)eT@9D1TUqjqad!0Cb zjB;J6!0yjF?6iH%%ID9Yr@i|dXwdo(RqU#Oh0Co!53ynI5x{vgw<$3m$9ol=6uE<~ z%)Q}WoozA0MAXT@&x+U%Tg+`!C;mhi8=LW9tUGn;lqy$8kA4Kd!1fV)@8kr;Bztw; z8yhdsvWKKI$sNJ%&BBiT`o054Xz&Kv)&ZNEbw_Z{uRnufa0=QQ-Gke{ezx%2X#M%o|PlX~L(=hq?mQsgWwKMJ{<6%%%h8~=_lBDO;A;_3DY zW9b}XPcSX`W;|F{%oA&Tg+_Y?DH->shOO`SNJRxGZi^M%z#D0wT`ix%&pM|a7hkXWYVw6<*t3%jV%mjAfajvlr_D=kc z(pYc2&v7Nw=#hhH?5LqMX4DWQCFim}-8O!#x=&yP8RtK~^rGNn!O!P}?R)p`ewzwB zsbTaQV>#nJ)9A&y+`E5$2Qkq(TJY+}vK@o|LGH?yzJaq&pP1JP|CL@;LFt8o=m~v1 zZbuj`Mm+dl`8G7td)d%4@oF5R#3N?8@cjursBX~$RrVOacVOT0aK?BDK16$+Idd91 z{2w}6IcDSYE3@&nb<$i{($?pHkGUG@jYB7B=&#uiglt#w+^uAHXJRazJ0T{~K5tg$ zF=MoK;@p_ej)74ygp*!gdA&KNupzFpA;z*H){2&LaTdhBQhU{J`x8C>=r445a{HUF z)svgwzsNem`sGROP3e78ky1qRruM;kS9o%x?)u>)=$mi85wd;u+yz<~{7lFm`%T7> zV~@b9edN1#I$5o5aW2>wXM>TFI5&iz$AF*aeMRK=WX#uX6UNYK_|3E5osF9KoQmz6 zV(%Cq;VTyW9P#oFzE!W2Cr;4t0Rg?tA$~F9u0EhC@c2qns`Q`RtiS0VeDNbTSN^zE%LH`4dfV z^FY_&ih`I@|I%D4#J<%fzH`&l;7;j5L#vC(XG=82j%lnc$N=W0bT!WLqorZhB~)FM z1JO$-Zle2H=U4j8K@jH6{UQ7dLv4C^ni zfl5o1HDS4l^n6>?$3nA_u4p^}pA9NlhJu;w@%(x26zX4^Bi7fG(w&A>`KcgX`aZ5S z$3cT2ll*O`7j6AYawyBr-{i&7fbx8*D)I>#t3iE{&o1iOuCZ(y=^ju9nZ@}j*Lx7V zXxmw~2A1dHEJm8w*v@@RvK`b9bn^J@E35pOVvKA@5)G><5%hagd(eD$SoEE^33&u-Wk#&uvI zUu|RC&HV7(HNdb)#wF9*i~5&jh0!+{Jf)}cx4GuDv%crJ%yo)!sL1zVtt7md7Pd3# zz>3EkR#PN$t{+xi2!8zH-tSGtdZdXm#{*8hJBToUn2*o_hZ{55i!hcnhxl$GG@qHw zUySaU&1p8az8`#qiS5((F<+Oa`WWL9BW}t);+0iRjn%2zfro-kQ#oS{-EHVp_(ZT1 zj6)>f8VN@{6EWWFWSCY*!YEpOr`O$P=&BLN&itFai_z6E{5qrU!~4Tn{i+c!<9#gO zhITL;SZ&1MQtlzc<2o2VrZF({c_}zWdbXqE*HXACcy?6$S{gS6Kj?0C)9;5aZtv6D zb^(|*DDS)!{#rWk2zw94?Q;3k=He~?ZnS;weG&IIcdyl4d}8U(I?QX>+WK}e^D&)B zE#gaK!OE;pyO2SaHN^U6^nV}fm^R2m@M2`5rJjMDZTLQ8W?VPmzfcAwF_wv{=-?hb@+FN)5VRA(zkdWAmk+$GMy)mFv0uBdJ`=vv1rSOl`*?oEZTCtQvXAXB~rOo>GN+EODtujdq>D);aA(IUST>4o`;n_ zhPBYHm$n>ft+nz1QIRebv}LVa>Ex|m>MrE)uv8ZEDNiiqRx8h1IhQ9O4hZR bvc8CcWIYlO%lgF>DSF46q3WX;jmP{yQ?K%n literal 15406 zcmeHN3s@A_72dp>q={8TVDT+6K8PkN!B3lNeBd)G7(o$ypa?30f}&tV1w~PeR`DGX z6h#z4MHDfu+N4RoCe@l6(^wyg(S#Zx0y{f9v$J?l&za>e!wMRV>DMpc?)Uwi$36Gl zGiQgHyXPLA?g`yfx@OIENZadXJ+0IA*6DQZ+gs%>PC8u%>U#938SkXied40ibwL}P zf-|goB){4Z;3X0sgoJh`r0ckE(|YeV zLbB(-g_T`P#FW>1-idX4p(@_}mJp|B=mRPi=|6=4-BZToZn4H>Peu?{dV(prdjR>6 zcMO{)?HI~T+lPW_$FMb|tBP+qk>*z{)UzA2UD(Cx`i0`U-sQ%1-XOl)n~CpwGt;}h zuRw0VQ;;*Qjhr|As+>QgM9G`dljhU4-(9Hx@ailV_;_M-xDxBh#LWYNVA?W}afsUn zhm(DMpKs$|^18C1^S#Tl-I%!REs%DPVk*){nN8`VKqfhTlu^#`n{CeW4T7EF&)EBs z_K)9f&JJYK{y>oSPe25g$=N|K%liWr1kji|zHj_e`?(|=4urQb=ZBUcKsgf1%tu0# zNN>)czE_p=LcyFj{Sp*KJxlufK1yL!Z_CNKx0RDoXCOD`d9p!!7t~!;PR{*OE{b}o zzIhJaqh)}eGwl%r5cGUk2YWZ?fh1CXeDlJLKb@_e}0Gs0qhk|EyxD|}B@Tj74i z5U)=)#kFkPP%OgYjxL6GTJJNw)5>62(&`5xq0I{NRi8awld!Dga$#wQQekO(QCRMg zU76AycSzQc5a(V@?`V5e#p}hYIJZD<$LZZQ9!-U19$y-kd4LriR7!s9+iw`x_FQ0G z^BNOUUIPO0#+?NB4Xws~#Bgp))VQ)shH*t_Mi7!Z1E*HLONiE% zc+=)LKNr*bgK2Yr#wqgm3|j^}bK9yo_l>kZUz^8LiMk(R^tVeRTwWwwF{OvMaaA{F zT-6X_Kvl!Um4%l3BU7FTA!n8 zk)Hi0#tmri^F^rhYVv1Hef^Yitru9)tA<)-F|`*HQ@xmRo!4T%Hc|Od@B;bZWH29^ z%!t;&mVa)G_rXkl{gsRKa3|W0U7zg&m!>(hPlB3Dx0ZC9VA{}!5ybUGy6o582y z9YEUd!%W)-gK4Wz4etY{ZMERz()Ph<=OfDL!#Xx*ZEpMZyf(S&+JR1RdTdkp%j8zf zuyrU%yGAh6dm~iJc`g%G`I>R7e&iRBIa1I4;y(HL%587mmv=tSshs_mN5$qL^39~) z>}K-s@qQi6qzqr+kTZQ%nW&uMTY->iOsnUzDZ}@!lTL>`c1TpzQ zFc4oC!6(R?_T6$$P+8qEKCg!61m*wKwYi=7;51+5a0pZKtS}!A0RriW%DEx7=b||` zBt<)hG7xAk>MKq8!L7O9#!%&GSi1RWIB+P(!Wi+&vGB86Kad;R9Cc*~K3+=;!h*H7 zjp6CHic&b|ua*;Y7*epDh(sD$As0m4_rFzrGIE@yF!CObb2~5>&Pi>|diB}Dxri5) zQ_;JWQ!ysQCFRsS@A~XWSAA;!BujDh_lP@6QFJuGqy7GF$iGAH$bcgQjtu--GC*|_ zEYa#h5RN(tCc*J>WWbRDM+O`jaAd%dfnPKOkm&gv!Y{hWV{%S)Rm0*|&cb5%x3N~7 zhqb~I1J=o~PI(VeQW@ud6l-Ub?qbat>%Bjz#zJ-Bs)W`r8y2@-SGBn1O@xRzFD`8} zy)vb(Q+>5u`^%xcPE$>cFbJwpY2h&U-YEpQsS; zJ`3ZeJlpF1yynYwH8R~-d+)}1G}X>09`NiyNb2;FF{u+15<7uCB^?LmF*+CPy7oRu zmN)euY1;Hgxw!EUKtP^pd6G?OZ=_Ps0iO?v?VrPIIL%|_RC^7a$L~rikJU%=xkRZ~ zz?AG6X4lC}>K)V_rsSfAa=`xmH(0cGrG z5O)ksFWEWTb`Q}!tZ(hW%-TgBJ z7+1eq2V%;rjG)zvt6#OCybjVj-q#y|_1clr9=~#|&jLZ-U~7lpaot7D_fw4@8-I~*LZgERhV<$xsdkHsqwGr6=q!16X>2*?_1>6`yn=ltyOg52<(8tk684jPAfJdF!~0Bl%=Q%Uo-o9@e@WLs=S`*a-Qc?@ zS4QVPmqS~?g(=PP?8gbt1~|co!LCY0YM*LxV?TUO^uy;wKYV7?1=ka`@o9DV{g3;7 zZ&>U$3VWL>DfU~G_gOBCVn2_uQ{K<|J3;YSC-`c9S3G+hp!OcA{YTV?v<3T+ti4Ee z`jI5;O_H{%{Ylnw*}?an2P{qGq2$AM1l%s7nQw<)|I;L6I@zX_(D!$Ep)I3vn= zt*q5^o>NIPm*&Xtjad6*+KAuT$4I?jbjD_{f0%qNs^hbzt6xw5I{p>75Y`$#2y}t7 z6W!pmh)z(t0rQT1W`vqvv-^1MIJY6n`FiG7>J) zkJJYy?i=PVrjIVG+CBm*whm)=w+;tk7sgCyg*ERNE!DnjYIu{J>33D$<7**1(rIn( zo15WxPs;EsLz`!9 z+-GB{lpj7&IX1J*d~7Cgpo~18T^EEi;+2A#-$23a`}UR8uc8!$g`uqxZ5YAkgJkk^ zRP|d7CnIeA6^)JYLH2My{294$_Ch@KHY&&Q+`BM>DaRwg%Hvu1@i`{tWJE|qKHzlh z3wUOJ%u+b#9)j$(bHRK(;wtLd1g21C9(hGT_L7BLj{MI5ObKfFlF- GXW+kkX}mE2 diff --git a/src/_mock/_countries.ts b/src/_mock/_countries.ts new file mode 100644 index 000000000..1875f2c86 --- /dev/null +++ b/src/_mock/_countries.ts @@ -0,0 +1,1247 @@ +export default [ + { + code: 'af', + label: 'Afghanistan', + icon: 'twemoji:flag-afghanistan', + }, + { + code: 'ax', + label: 'Aland Islands', + icon: 'twemoji:flag-aland-islands', + }, + { + code: 'al', + label: 'Albania', + icon: 'twemoji:flag-albania', + }, + { + code: 'dz', + label: 'Algeria', + icon: 'twemoji:flag-algeria', + }, + { + code: 'as', + label: 'American Samoa', + icon: 'twemoji:flag-american-samoa', + }, + { + code: 'ad', + label: 'Andorra', + icon: 'twemoji:flag-andorra', + }, + { + code: 'ao', + label: 'Angola', + icon: 'twemoji:flag-angola', + }, + { + code: 'ai', + label: 'Anguilla', + icon: 'twemoji:flag-anguilla', + }, + { + code: 'aq', + label: 'Antarctica', + icon: 'twemoji:flag-antarctica', + }, + { + code: 'ag', + label: 'Antigua and Barbuda', + icon: 'twemoji:flag-antigua-and-barbuda', + }, + { + code: 'ar', + label: 'Argentina', + icon: 'twemoji:flag-argentina', + }, + { + code: 'am', + label: 'Armenia', + icon: 'twemoji:flag-armenia', + }, + { + code: 'aw', + label: 'Aruba', + icon: 'twemoji:flag-aruba', + }, + { + code: 'au', + label: 'Australia', + icon: 'twemoji:flag-australia', + }, + { + code: 'at', + label: 'Austria', + icon: 'twemoji:flag-austria', + }, + { + code: 'az', + label: 'Azerbaijan', + icon: 'twemoji:flag-azerbaijan', + }, + { + code: 'bs', + label: 'Bahamas', + icon: 'twemoji:flag-bahamas', + }, + { + code: 'bh', + label: 'Bahrain', + icon: 'twemoji:flag-bahrain', + }, + { + code: 'bd', + label: 'Bangladesh', + icon: 'twemoji:flag-bangladesh', + }, + { + code: 'bb', + label: 'Barbados', + icon: 'twemoji:flag-barbados', + }, + { + code: 'by', + label: 'Belarus', + icon: 'twemoji:flag-belarus', + }, + { + code: 'be', + label: 'Belgium', + icon: 'twemoji:flag-belgium', + }, + { + code: 'bz', + label: 'Belize', + icon: 'twemoji:flag-belize', + }, + { + code: 'bj', + label: 'Benin', + icon: 'twemoji:flag-benin', + }, + { + code: 'bm', + label: 'Bermuda', + icon: 'twemoji:flag-bermuda', + }, + { + code: 'bt', + label: 'Bhutan', + icon: 'twemoji:flag-bhutan', + }, + { + code: 'bo', + label: 'Bolivia', + icon: 'twemoji:flag-bolivia', + }, + { + code: 'ba', + label: 'Bosnia and Herzegovina', + icon: 'twemoji:flag-bosnia-and-herzegovina', + }, + { + code: 'bw', + label: 'Botswana', + icon: 'twemoji:flag-botswana', + }, + { + code: 'bv', + label: 'Bouvet Island', + icon: 'twemoji:flag-bouvet-island', + }, + { + code: 'br', + label: 'Brazil', + icon: 'twemoji:flag-brazil', + }, + { + code: 'io', + label: 'British Indian Ocean Territory', + icon: 'twemoji:flag-british-indian-ocean-territory', + }, + { + code: 'vg', + label: 'British Virgin Islands', + icon: 'twemoji:flag-british-virgin-islands', + }, + { + code: 'bn', + label: 'Brunei', + icon: 'twemoji:flag-brunei', + }, + { + code: 'bg', + label: 'Bulgaria', + icon: 'twemoji:flag-bulgaria', + }, + { + code: 'bf', + label: 'Burkina Faso', + icon: 'twemoji:flag-burkina-faso', + }, + { + code: 'bi', + label: 'Burundi', + icon: 'twemoji:flag-burundi', + }, + { + code: 'kh', + label: 'Cambodia', + icon: 'twemoji:flag-cambodia', + }, + { + code: 'cm', + label: 'Cameroon', + icon: 'twemoji:flag-cameroon', + }, + { + code: 'ca', + label: 'Canada', + icon: 'twemoji:flag-canada', + }, + { + code: 'cv', + label: 'Cape Verde', + icon: 'twemoji:flag-cape-verde', + }, + { + code: 'ky', + label: 'Cayman Islands', + icon: 'twemoji:flag-cayman-islands', + }, + { + code: 'cf', + label: 'Central African Republic', + icon: 'twemoji:flag-central-african-republic', + }, + { + code: 'td', + label: 'Chad', + icon: 'twemoji:flag-chad', + }, + { + code: 'cl', + label: 'Chile', + icon: 'twemoji:flag-chile', + }, + { + code: 'cn', + label: 'China', + icon: 'twemoji:flag-china', + }, + { + code: 'cx', + label: 'Christmas Island', + icon: 'twemoji:flag-christmas-island', + }, + { + code: 'cc', + label: 'Cocos Islands', + icon: 'twemoji:flag-cocos-keeling-islands', + }, + { + code: 'co', + label: 'Colombia', + icon: 'twemoji:flag-colombia', + }, + { + code: 'km', + label: 'Comoros', + icon: 'twemoji:flag-comoros', + }, + { + code: 'ck', + label: 'Cook Islands', + icon: 'twemoji:flag-cook-islands', + }, + { + code: 'cr', + label: 'Costa Rica', + icon: 'twemoji:flag-costa-rica', + }, + { + code: 'hr', + label: 'Croatia', + icon: 'twemoji:flag-croatia', + }, + { + code: 'cu', + label: 'Cuba', + icon: 'twemoji:flag-cuba', + }, + { + code: 'cw', + label: 'Curacao', + icon: 'twemoji:flag-curacao', + }, + { + code: 'cy', + label: 'Cyprus', + icon: 'twemoji:flag-cyprus', + }, + { + code: 'cz', + label: 'Czech Republic', + icon: 'twemoji:flag-czechia', + }, + { + code: 'cd', + label: 'Democratic Republic of the Congo', + icon: 'twemoji:flag-congo-kinshasa', + }, + { + code: 'dk', + label: 'Denmark', + icon: 'twemoji:flag-denmark', + }, + { + code: 'dj', + label: 'Djibouti', + icon: 'twemoji:flag-djibouti', + }, + { + code: 'dm', + label: 'Dominica', + icon: 'twemoji:flag-dominica', + }, + { + code: 'do', + label: 'Dominican Republic', + icon: 'twemoji:flag-dominican-republic', + }, + { + code: 'tl', + label: 'East Timor', + icon: 'twemoji:flag-timor-leste', + }, + { + code: 'ec', + label: 'Ecuador', + icon: 'twemoji:flag-ecuador', + }, + { + code: 'eg', + label: 'Egypt', + icon: 'twemoji:flag-egypt', + }, + { + code: 'sv', + label: 'El Salvador', + icon: 'twemoji:flag-el-salvador', + }, + { + code: 'gq', + label: 'Equatorial Guinea', + icon: 'twemoji:flag-equatorial-guinea', + }, + { + code: 'er', + label: 'Eritrea', + icon: 'twemoji:flag-eritrea', + }, + { + code: 'ee', + label: 'Estonia', + icon: 'twemoji:flag-estonia', + }, + { + code: 'et', + label: 'Ethiopia', + icon: 'twemoji:flag-ethiopia', + }, + { + code: 'fk', + label: 'Falkland Islands', + icon: 'twemoji:flag-falkland-islands', + }, + { + code: 'fo', + label: 'Faroe Islands', + icon: 'twemoji:flag-faroe-islands', + }, + { + code: 'fj', + label: 'Fiji', + icon: 'twemoji:flag-fiji', + }, + { + code: 'fi', + label: 'Finland', + icon: 'twemoji:flag-finland', + }, + { + code: 'fr', + label: 'France', + icon: 'twemoji:flag-france', + }, + { + code: 'gf', + label: 'French Guiana', + icon: 'twemoji:flag-french-guiana', + }, + { + code: 'pf', + label: 'French Polynesia', + icon: 'twemoji:flag-french-polynesia', + }, + { + code: 'tf', + label: 'French Southern Territories', + icon: 'twemoji:flag-french-southern-territories', + }, + { + code: 'ga', + label: 'Gabon', + icon: 'twemoji:flag-gabon', + }, + { + code: 'gm', + label: 'Gambia', + icon: 'twemoji:flag-gambia', + }, + { + code: 'ge', + label: 'Georgia', + icon: 'twemoji:flag-georgia', + }, + { + code: 'de', + label: 'Germany', + icon: 'twemoji:flag-germany', + }, + { + code: 'gh', + label: 'Ghana', + icon: 'twemoji:flag-ghana', + }, + { + code: 'gi', + label: 'Gibraltar', + icon: 'twemoji:flag-gibraltar', + }, + { + code: 'gr', + label: 'Greece', + icon: 'twemoji:flag-greece', + }, + { + code: 'gl', + label: 'Greenland', + icon: 'twemoji:flag-greenland', + }, + { + code: 'gd', + label: 'Grenada', + icon: 'twemoji:flag-grenada', + }, + { + code: 'gp', + label: 'Guadeloupe', + icon: 'twemoji:flag-guadeloupe', + }, + { + code: 'gu', + label: 'Guam', + icon: 'twemoji:flag-guam', + }, + { + code: 'gt', + label: 'Guatemala', + icon: 'twemoji:flag-guatemala', + }, + { + code: 'gg', + label: 'Guernsey', + icon: 'twemoji:flag-guernsey', + }, + { + code: 'gn', + label: 'Guinea', + icon: 'twemoji:flag-guinea', + }, + { + code: 'gw', + label: 'Guinea-Bissau', + icon: 'twemoji:flag-guinea-bissau', + }, + { + code: 'gy', + label: 'Guyana', + icon: 'twemoji:flag-guyana', + }, + { + code: 'ht', + label: 'Haiti', + icon: 'twemoji:flag-haiti', + }, + { + code: 'hm', + label: 'Heard Island and McDonald Islands', + icon: 'twemoji:flag-heard-and-mcdonald-islands', + }, + { + code: 'hn', + label: 'Honduras', + icon: 'twemoji:flag-honduras', + }, + { + code: 'hk', + label: 'Hong Kong', + icon: 'twemoji:flag-hong-kong-sar-china', + }, + { + code: 'hu', + label: 'Hungary', + icon: 'twemoji:flag-hungary', + }, + { + code: 'is', + label: 'Iceland', + icon: 'twemoji:flag-iceland', + }, + { + code: 'in', + label: 'India', + icon: 'twemoji:flag-india', + }, + { + code: 'id', + label: 'Indonesia', + icon: 'twemoji:flag-indonesia', + }, + { + code: 'ir', + label: 'Iran', + icon: 'twemoji:flag-iran', + }, + { + code: 'iq', + label: 'Iraq', + icon: 'twemoji:flag-iraq', + }, + { + code: 'ie', + label: 'Ireland', + icon: 'twemoji:flag-ireland', + }, + { + code: 'im', + label: 'Isle of Man', + icon: 'twemoji:flag-isle-of-man', + }, + { + code: 'il', + label: 'Israel', + icon: 'twemoji:flag-israel', + }, + { + code: 'it', + label: 'Italy', + icon: 'twemoji:flag-italy', + }, + { + code: 'ci', + label: 'Ivory Coast', + icon: 'twemoji:flag-cote-divoire', + }, + { + code: 'jm', + label: 'Jamaica', + icon: 'twemoji:flag-jamaica', + }, + { + code: 'jp', + label: 'Japan', + icon: 'twemoji:flag-japan', + }, + { + code: 'je', + label: 'Jersey', + icon: 'twemoji:flag-jersey', + }, + { + code: 'jo', + label: 'Jordan', + icon: 'twemoji:flag-jordan', + }, + { + code: 'kz', + label: 'Kazakhstan', + icon: 'twemoji:flag-kazakhstan', + }, + { + code: 'ke', + label: 'Kenya', + icon: 'twemoji:flag-kenya', + }, + { + code: 'ki', + label: 'Kiribati', + icon: 'twemoji:flag-kiribati', + }, + { + code: 'xk', + label: 'Kosovo', + icon: 'twemoji:flag-kosovo', + }, + { + code: 'kw', + label: 'Kuwait', + icon: 'twemoji:flag-kuwait', + }, + { + code: 'kg', + label: 'Kyrgyzstan', + icon: 'twemoji:flag-kyrgyzstan', + }, + { + code: 'la', + label: 'Laos', + icon: 'twemoji:flag-laos', + }, + { + code: 'lv', + label: 'Latvia', + icon: 'twemoji:flag-latvia', + }, + { + code: 'lb', + label: 'Lebanon', + icon: 'twemoji:flag-lebanon', + }, + { + code: 'ls', + label: 'Lesotho', + icon: 'twemoji:flag-lesotho', + }, + { + code: 'lr', + label: 'Liberia', + icon: 'twemoji:flag-liberia', + }, + { + code: 'ly', + label: 'Libya', + icon: 'twemoji:flag-libya', + }, + { + code: 'li', + label: 'Liechtenstein', + icon: 'twemoji:flag-liechtenstein', + }, + { + code: 'lt', + label: 'Lithuania', + icon: 'twemoji:flag-lithuania', + }, + { + code: 'lu', + label: 'Luxembourg', + icon: 'twemoji:flag-luxembourg', + }, + { + code: 'mo', + label: 'Macao', + icon: 'twemoji:flag-macao-sar-china', + }, + { + code: 'mk', + label: 'Macedonia', + icon: 'twemoji:flag-north-macedonia', + }, + { + code: 'mg', + label: 'Madagascar', + icon: 'twemoji:flag-madagascar', + }, + { + code: 'mw', + label: 'Malawi', + icon: 'twemoji:flag-malawi', + }, + { + code: 'my', + label: 'Malaysia', + icon: 'twemoji:flag-malaysia', + }, + { + code: 'mv', + label: 'Maldives', + icon: 'twemoji:flag-maldives', + }, + { + code: 'ml', + label: 'Mali', + icon: 'twemoji:flag-mali', + }, + { + code: 'mt', + label: 'Malta', + icon: 'twemoji:flag-malta', + }, + { + code: 'mh', + label: 'Marshall Islands', + icon: 'twemoji:flag-marshall-islands', + }, + { + code: 'mq', + label: 'Martinique', + icon: 'twemoji:flag-martinique', + }, + { + code: 'mr', + label: 'Mauritania', + icon: 'twemoji:flag-mauritania', + }, + { + code: 'mu', + label: 'Mauritius', + icon: 'twemoji:flag-mauritius', + }, + { + code: 'yt', + label: 'Mayotte', + icon: 'twemoji:flag-mayotte', + }, + { + code: 'mx', + label: 'Mexico', + icon: 'twemoji:flag-mexico', + }, + { + code: 'fm', + label: 'Micronesia', + icon: 'twemoji:flag-micronesia', + }, + { + code: 'md', + label: 'Moldova', + icon: 'twemoji:flag-moldova', + }, + { + code: 'mc', + label: 'Monaco', + icon: 'twemoji:flag-monaco', + }, + { + code: 'mn', + label: 'Mongolia', + icon: 'twemoji:flag-mongolia', + }, + { + code: 'me', + label: 'Montenegro', + icon: 'twemoji:flag-montenegro', + }, + { + code: 'ms', + label: 'Montserrat', + icon: 'twemoji:flag-montserrat', + }, + { + code: 'ma', + label: 'Morocco', + icon: 'twemoji:flag-morocco', + }, + { + code: 'mz', + label: 'Mozambique', + icon: 'twemoji:flag-mozambique', + }, + { + code: 'mm', + label: 'Myanmar', + icon: 'twemoji:flag-myanmar-burma', + }, + { + code: 'na', + label: 'Namibia', + icon: 'twemoji:flag-namibia', + }, + { + code: 'nr', + label: 'Nauru', + icon: 'twemoji:flag-nauru', + }, + { + code: 'np', + label: 'Nepal', + icon: 'twemoji:flag-nepal', + }, + { + code: 'nl', + label: 'Netherlands', + icon: 'twemoji:flag-netherlands', + }, + { + code: 'nc', + label: 'New Caledonia', + icon: 'twemoji:flag-new-caledonia', + }, + { + code: 'nz', + label: 'New Zealand', + icon: 'twemoji:flag-new-zealand', + }, + { + code: 'ni', + label: 'Nicaragua', + icon: 'twemoji:flag-nicaragua', + }, + { + code: 'ne', + label: 'Niger', + icon: 'twemoji:flag-niger', + }, + { + code: 'ng', + label: 'Nigeria', + icon: 'twemoji:flag-nigeria', + }, + { + code: 'nu', + label: 'Niue', + icon: 'twemoji:flag-niue', + }, + { + code: 'nf', + label: 'Norfolk Island', + icon: 'twemoji:flag-norfolk-island', + }, + { + code: 'kp', + label: 'North Korea', + icon: 'twemoji:flag-north-korea', + }, + { + code: 'mp', + label: 'Northern Mariana Islands', + icon: 'twemoji:flag-northern-mariana-islands', + }, + { + code: 'no', + label: 'Norway', + icon: 'twemoji:flag-norway', + }, + { + code: 'om', + label: 'Oman', + icon: 'twemoji:flag-oman', + }, + { + code: 'pk', + label: 'Pakistan', + icon: 'twemoji:flag-pakistan', + }, + { + code: 'pw', + label: 'Palau', + icon: 'twemoji:flag-palau', + }, + { + code: 'ps', + label: 'Palestinian Territory', + icon: 'twemoji:flag-palestinian-territories', + }, + { + code: 'pa', + label: 'Panama', + icon: 'twemoji:flag-panama', + }, + { + code: 'pg', + label: 'Papua New Guinea', + icon: 'twemoji:flag-papua-new-guinea', + }, + { + code: 'py', + label: 'Paraguay', + icon: 'twemoji:flag-paraguay', + }, + { + code: 'pe', + label: 'Peru', + icon: 'twemoji:flag-peru', + }, + { + code: 'ph', + label: 'Philippines', + icon: 'twemoji:flag-philippines', + }, + { + code: 'pn', + label: 'Pitcairn', + icon: 'twemoji:flag-pitcairn-islands', + }, + { + code: 'pl', + label: 'Poland', + icon: 'twemoji:flag-poland', + }, + { + code: 'pt', + label: 'Portugal', + icon: 'twemoji:flag-portugal', + }, + { + code: 'pr', + label: 'Puerto Rico', + icon: 'twemoji:flag-puerto-rico', + }, + { + code: 'qa', + label: 'Qatar', + icon: 'twemoji:flag-qatar', + }, + { + code: 'cg', + label: 'Republic of the Congo', + icon: 'twemoji:flag-congo-brazzaville', + }, + { + code: 're', + label: 'Reunion', + icon: 'twemoji:flag-reunion', + }, + { + code: 'ro', + label: 'Romania', + icon: 'twemoji:flag-romania', + }, + { + code: 'ru', + label: 'Russia', + icon: 'twemoji:flag-russia', + }, + { + code: 'rw', + label: 'Rwanda', + icon: 'twemoji:flag-rwanda', + }, + { + code: 'bl', + label: 'Saint Barthelemy', + icon: 'twemoji:flag-st-barthelemy', + }, + { + code: 'sh', + label: 'Saint Helena', + icon: 'twemoji:flag-st-helena', + }, + { + code: 'kn', + label: 'Saint Kitts and Nevis', + icon: 'twemoji:flag-st-kitts-and-nevis', + }, + { + code: 'lc', + label: 'Saint Lucia', + icon: 'twemoji:flag-st-lucia', + }, + { + code: 'mf', + label: 'Saint Martin', + icon: 'twemoji:flag-st-martin', + }, + { + code: 'pm', + label: 'Saint Pierre and Miquelon', + icon: 'twemoji:flag-st-pierre-and-miquelon', + }, + { + code: 'vc', + label: 'Saint Vincent and the Grenadines', + icon: 'twemoji:flag-st-vincent-and-grenadines', + }, + { + code: 'ws', + label: 'Samoa', + icon: 'twemoji:flag-samoa', + }, + { + code: 'sm', + label: 'San Marino', + icon: 'twemoji:flag-san-marino', + }, + { + code: 'st', + label: 'Sao Tome and Principe', + icon: 'twemoji:flag-sao-tome-and-principe', + }, + { + code: 'sa', + label: 'Saudi Arabia', + icon: 'twemoji:flag-saudi-arabia', + }, + { + code: 'sn', + label: 'Senegal', + icon: 'twemoji:flag-senegal', + }, + { + code: 'rs', + label: 'Serbia', + icon: 'twemoji:flag-serbia', + }, + { + code: 'sc', + label: 'Seychelles', + icon: 'twemoji:flag-seychelles', + }, + { + code: 'sl', + label: 'Sierra Leone', + icon: 'twemoji:flag-sierra-leone', + }, + { + code: 'sg', + label: 'Singapore', + icon: 'twemoji:flag-singapore', + }, + { + code: 'sx', + label: 'Sint Maarten', + icon: 'twemoji:flag-sint-maarten', + }, + { + code: 'sk', + label: 'Slovakia', + icon: 'twemoji:flag-slovakia', + }, + { + code: 'si', + label: 'Slovenia', + icon: 'twemoji:flag-slovenia', + }, + { + code: 'sb', + label: 'Solomon Islands', + icon: 'twemoji:flag-solomon-islands', + }, + { + code: 'so', + label: 'Somalia', + icon: 'twemoji:flag-somalia', + }, + { + code: 'za', + label: 'South Africa', + icon: 'twemoji:flag-south-africa', + }, + { + code: 'gs', + label: 'South Georgia and the South Sandwich Islands', + icon: 'twemoji:flag-south-georgia-and-south-sandwich-islands', + }, + { + code: 'kr', + label: 'South Korea', + icon: 'twemoji:flag-south-korea', + }, + { + code: 'ss', + label: 'South Sudan', + icon: 'twemoji:flag-south-sudan', + }, + { + code: 'es', + label: 'Spain', + icon: 'twemoji:flag-spain', + }, + { + code: 'lk', + label: 'Sri Lanka', + icon: 'twemoji:flag-sri-lanka', + }, + { + code: 'sd', + label: 'Sudan', + icon: 'twemoji:flag-sudan', + }, + { + code: 'sr', + label: 'Suriname', + icon: 'twemoji:flag-suriname', + }, + { + code: 'sj', + label: 'Svalbard and Jan Mayen', + icon: 'twemoji:flag-svalbard-and-jan-mayen', + }, + { + code: 'sz', + label: 'Swaziland', + icon: 'emojione-v1:flag-for-swaziland', + }, + { + code: 'se', + label: 'Sweden', + icon: 'twemoji:flag-sweden', + }, + { + code: 'ch', + label: 'Switzerland', + icon: 'twemoji:flag-switzerland', + }, + { + code: 'sy', + label: 'Syria', + icon: 'twemoji:flag-syria', + }, + { + code: 'tw', + label: 'Taiwan', + icon: 'twemoji:flag-taiwan', + }, + { + code: 'tj', + label: 'Tajikistan', + icon: 'twemoji:flag-tajikistan', + }, + { + code: 'tz', + label: 'Tanzania', + icon: 'twemoji:flag-tanzania', + }, + { + code: 'th', + label: 'Thailand', + icon: 'twemoji:flag-thailand', + }, + { + code: 'tg', + label: 'Togo', + icon: 'twemoji:flag-togo', + }, + { + code: 'tk', + label: 'Tokelau', + icon: 'twemoji:flag-tokelau', + }, + { + code: 'to', + label: 'Tonga', + icon: 'twemoji:flag-tonga', + }, + { + code: 'tt', + label: 'Trinidad and Tobago', + icon: 'twemoji:flag-trinidad-and-tobago', + }, + { + code: 'tn', + label: 'Tunisia', + icon: 'twemoji:flag-tunisia', + }, + { + code: 'tr', + label: 'Turkey', + icon: 'twemoji:flag-for-flag-turkey', + }, + { + code: 'tm', + label: 'Turkmenistan', + icon: 'twemoji:flag-turkmenistan', + }, + { + code: 'tc', + label: 'Turks and Caicos Islands', + icon: 'twemoji:flag-turks-and-caicos-islands', + }, + { + code: 'tv', + label: 'Tuvalu', + icon: 'twemoji:flag-tuvalu', + }, + { + code: 'vi', + label: 'U.S. Virgin Islands', + icon: 'twemoji:flag-us-virgin-islands', + }, + { + code: 'ug', + label: 'Uganda', + icon: 'twemoji:flag-uganda', + }, + { + code: 'ua', + label: 'Ukraine', + icon: 'twemoji:flag-ukraine', + }, + { + code: 'ae', + label: 'United Arab Emirates', + icon: 'twemoji:flag-united-arab-emirates', + }, + { + code: 'gb', + label: 'United Kingdom', + icon: 'twemoji:flag-united-kingdom', + }, + { + code: 'us', + label: 'United States', + icon: 'twemoji:flag-united-states', + }, + { + code: 'um', + label: 'United States Minor Outlying Islands', + icon: 'twemoji:flag-us-outlying-islands', + }, + { + code: 'uy', + label: 'Uruguay', + icon: 'twemoji:flag-uruguay', + }, + { + code: 'uz', + label: 'Uzbekistan', + icon: 'twemoji:flag-uzbekistan', + }, + { + code: 'vu', + label: 'Vanuatu', + icon: 'twemoji:flag-vanuatu', + }, + { + code: 'va', + label: 'Vatican', + icon: 'twemoji:flag-vatican-city', + }, + { + code: 've', + label: 'Venezuela', + icon: 'twemoji:flag-venezuela', + }, + { + code: 'vn', + label: 'Vietnam', + icon: 'twemoji:flag-vietnam', + }, + { + code: 'wf', + label: 'Wallis and Futuna', + icon: 'twemoji:flag-wallis-and-futuna', + }, + { + code: 'eh', + label: 'Western Sahara', + icon: 'twemoji:flag-western-sahara', + }, + { + code: 'ye', + label: 'Yemen', + icon: 'twemoji:flag-yemen', + }, + { + code: 'zm', + label: 'Zambia', + icon: 'twemoji:flag-zambia', + }, + { + code: 'zw', + label: 'Zimbabwe', + icon: 'twemoji:flag-zimbabwe', + }, +]; diff --git a/src/_mock/_data.ts b/src/_mock/_data.ts index d6dadc0eb..0b59c6e84 100644 --- a/src/_mock/_data.ts +++ b/src/_mock/_data.ts @@ -1,3 +1,5 @@ +import { ContributionProps } from 'src/sections/contributions/contributions-table-row'; +import { fShortenNumber } from 'src/utils/format-number'; import { _id, _price, @@ -9,6 +11,8 @@ import { _postTitles, _description, _productNames, + _months, + _amount, } from './_mock'; // ---------------------------------------------------------------------- @@ -63,6 +67,17 @@ export const _posts = [...Array(23)].map((_, index) => ({ // ---------------------------------------------------------------------- +export const _contributions: ContributionProps[] = [...Array(24)].map((_, index) => ({ + id: _id(index), + sender: { id: `${_id(index)}'2'`, name: _fullName(index) }, + months: _months(Math.ceil(Math.random() * 3)), + status: index % 4 ? 'success' : 'failed', + timestamp: new Date().toISOString(), + amount: _amount(), +})); + +// ---------------------------------------------------------------------- + const COLORS = [ '#00AB55', '#000000', @@ -116,6 +131,272 @@ export const _langs = [ }, ]; +export const _countries = [ + { + value: 'GH', + icon: 'twemoji:flag-ghana', + label: 'Ghana', + }, + { + value: 'ng', + icon: 'twemoji:flag-nigeria', + label: 'Nigeria', + }, +]; + +export const COUNTRIES = { + BD: 'Bangladesh', + BE: 'Belgium', + BF: 'Burkina Faso', + BG: 'Bulgaria', + BA: 'Bosnia and Herzegovina', + BB: 'Barbados', + WF: 'Wallis and Futuna', + BL: 'Saint Barthelemy', + BM: 'Bermuda', + BN: 'Brunei', + BO: 'Bolivia', + BH: 'Bahrain', + BI: 'Burundi', + BJ: 'Benin', + BT: 'Bhutan', + JM: 'Jamaica', + BV: 'Bouvet Island', + BW: 'Botswana', + WS: 'Samoa', + BQ: 'Bonaire, Saint Eustatius and Saba ', + BR: 'Brazil', + BS: 'Bahamas', + JE: 'Jersey', + BY: 'Belarus', + BZ: 'Belize', + RU: 'Russia', + RW: 'Rwanda', + RS: 'Serbia', + TL: 'East Timor', + RE: 'Reunion', + TM: 'Turkmenistan', + TJ: 'Tajikistan', + RO: 'Romania', + TK: 'Tokelau', + GW: 'Guinea-Bissau', + GU: 'Guam', + GT: 'Guatemala', + GS: 'South Georgia and the South Sandwich Islands', + GR: 'Greece', + GQ: 'Equatorial Guinea', + GP: 'Guadeloupe', + JP: 'Japan', + GY: 'Guyana', + GG: 'Guernsey', + GF: 'French Guiana', + GE: 'Georgia', + GD: 'Grenada', + GB: 'United Kingdom', + GA: 'Gabon', + SV: 'El Salvador', + GN: 'Guinea', + GM: 'Gambia', + GL: 'Greenland', + GI: 'Gibraltar', + GH: 'Ghana', + OM: 'Oman', + TN: 'Tunisia', + JO: 'Jordan', + HR: 'Croatia', + HT: 'Haiti', + HU: 'Hungary', + HK: 'Hong Kong', + HN: 'Honduras', + HM: 'Heard Island and McDonald Islands', + VE: 'Venezuela', + PR: 'Puerto Rico', + PS: 'Palestinian Territory', + PW: 'Palau', + PT: 'Portugal', + SJ: 'Svalbard and Jan Mayen', + PY: 'Paraguay', + IQ: 'Iraq', + PA: 'Panama', + PF: 'French Polynesia', + PG: 'Papua New Guinea', + PE: 'Peru', + PK: 'Pakistan', + PH: 'Philippines', + PN: 'Pitcairn', + PL: 'Poland', + PM: 'Saint Pierre and Miquelon', + ZM: 'Zambia', + EH: 'Western Sahara', + EE: 'Estonia', + EG: 'Egypt', + ZA: 'South Africa', + EC: 'Ecuador', + IT: 'Italy', + VN: 'Vietnam', + SB: 'Solomon Islands', + ET: 'Ethiopia', + SO: 'Somalia', + ZW: 'Zimbabwe', + SA: 'Saudi Arabia', + ES: 'Spain', + ER: 'Eritrea', + ME: 'Montenegro', + MD: 'Moldova', + MG: 'Madagascar', + MF: 'Saint Martin', + MA: 'Morocco', + MC: 'Monaco', + UZ: 'Uzbekistan', + MM: 'Myanmar', + ML: 'Mali', + MO: 'Macao', + MN: 'Mongolia', + MH: 'Marshall Islands', + MK: 'Macedonia', + MU: 'Mauritius', + MT: 'Malta', + MW: 'Malawi', + MV: 'Maldives', + MQ: 'Martinique', + MP: 'Northern Mariana Islands', + MS: 'Montserrat', + MR: 'Mauritania', + IM: 'Isle of Man', + UG: 'Uganda', + TZ: 'Tanzania', + MY: 'Malaysia', + MX: 'Mexico', + IL: 'Israel', + FR: 'France', + IO: 'British Indian Ocean Territory', + SH: 'Saint Helena', + FI: 'Finland', + FJ: 'Fiji', + FK: 'Falkland Islands', + FM: 'Micronesia', + FO: 'Faroe Islands', + NI: 'Nicaragua', + NL: 'Netherlands', + NO: 'Norway', + NA: 'Namibia', + VU: 'Vanuatu', + NC: 'New Caledonia', + NE: 'Niger', + NF: 'Norfolk Island', + NG: 'Nigeria', + NZ: 'New Zealand', + NP: 'Nepal', + NR: 'Nauru', + NU: 'Niue', + CK: 'Cook Islands', + XK: 'Kosovo', + CI: 'Ivory Coast', + CH: 'Switzerland', + CO: 'Colombia', + CN: 'China', + CM: 'Cameroon', + CL: 'Chile', + CC: 'Cocos Islands', + CA: 'Canada', + CG: 'Republic of the Congo', + CF: 'Central African Republic', + CD: 'Democratic Republic of the Congo', + CZ: 'Czech Republic', + CY: 'Cyprus', + CX: 'Christmas Island', + CR: 'Costa Rica', + CW: 'Curacao', + CV: 'Cape Verde', + CU: 'Cuba', + SZ: 'Swaziland', + SY: 'Syria', + SX: 'Sint Maarten', + KG: 'Kyrgyzstan', + KE: 'Kenya', + SS: 'South Sudan', + SR: 'Suriname', + KI: 'Kiribati', + KH: 'Cambodia', + KN: 'Saint Kitts and Nevis', + KM: 'Comoros', + ST: 'Sao Tome and Principe', + SK: 'Slovakia', + KR: 'South Korea', + SI: 'Slovenia', + KP: 'North Korea', + KW: 'Kuwait', + SN: 'Senegal', + SM: 'San Marino', + SL: 'Sierra Leone', + SC: 'Seychelles', + KZ: 'Kazakhstan', + KY: 'Cayman Islands', + SG: 'Singapore', + SE: 'Sweden', + SD: 'Sudan', + DO: 'Dominican Republic', + DM: 'Dominica', + DJ: 'Djibouti', + DK: 'Denmark', + VG: 'British Virgin Islands', + DE: 'Germany', + YE: 'Yemen', + DZ: 'Algeria', + US: 'United States', + UY: 'Uruguay', + YT: 'Mayotte', + UM: 'United States Minor Outlying Islands', + LB: 'Lebanon', + LC: 'Saint Lucia', + LA: 'Laos', + TV: 'Tuvalu', + TW: 'Taiwan', + TT: 'Trinidad and Tobago', + TR: 'Turkey', + LK: 'Sri Lanka', + LI: 'Liechtenstein', + LV: 'Latvia', + TO: 'Tonga', + LT: 'Lithuania', + LU: 'Luxembourg', + LR: 'Liberia', + LS: 'Lesotho', + TH: 'Thailand', + TF: 'French Southern Territories', + TG: 'Togo', + TD: 'Chad', + TC: 'Turks and Caicos Islands', + LY: 'Libya', + VA: 'Vatican', + VC: 'Saint Vincent and the Grenadines', + AE: 'United Arab Emirates', + AD: 'Andorra', + AG: 'Antigua and Barbuda', + AF: 'Afghanistan', + AI: 'Anguilla', + VI: 'U.S. Virgin Islands', + IS: 'Iceland', + IR: 'Iran', + AM: 'Armenia', + AL: 'Albania', + AO: 'Angola', + AQ: 'Antarctica', + AS: 'American Samoa', + AR: 'Argentina', + AU: 'Australia', + AT: 'Austria', + AW: 'Aruba', + IN: 'India', + AX: 'Aland Islands', + AZ: 'Azerbaijan', + IE: 'Ireland', + ID: 'Indonesia', + UA: 'Ukraine', + QA: 'Qatar', + MZ: 'Mozambique', +}; + // ---------------------------------------------------------------------- export const _timeline = [...Array(5)].map((_, index) => ({ diff --git a/src/_mock/_mock.ts b/src/_mock/_mock.ts index 46f120bb1..70bce3624 100644 --- a/src/_mock/_mock.ts +++ b/src/_mock/_mock.ts @@ -1,5 +1,12 @@ +import { fShortenNumber } from 'src/utils/format-number'; + +const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + export const _id = (index: number) => `e99f09a7-dd88-49d5-b1c8-1daf80c2d7b${index}`; +export const _amount = () => + fShortenNumber(Math.ceil(Math.max(Math.random() * 500, Math.random() * 5000))).toString(); + export const _times = (index: number) => // 'MM/DD/YYYY' [ @@ -91,6 +98,9 @@ export const _company = (index: number) => 'Streich Group', ][index]; +export const _months = (length: number) => + new Array(length).fill(0).map(() => MONTHS[Math.ceil(Math.random() * 11)]); + export const _boolean = (index: number) => [ true, diff --git a/src/app.tsx b/src/app.tsx index 68bbf1784..d1be1bc5f 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,44 +1,27 @@ import 'src/global.css'; -import Fab from '@mui/material/Fab'; - import { Router } from 'src/routes/sections'; import { useScrollToTop } from 'src/hooks/use-scroll-to-top'; import { ThemeProvider } from 'src/theme/theme-provider'; -import { Iconify } from 'src/components/iconify'; +import AppAlert from './components/shared/alert'; +import { AlertUtil } from './utils'; // ---------------------------------------------------------------------- export default function App() { useScrollToTop(); - const githubButton = ( - - - - ); + const setAlert = (ref: any) => { + AlertUtil.setRef(ref); + }; return ( - {githubButton} + setAlert(ref)} /> ); } diff --git a/src/components/country-select/index.tsx b/src/components/country-select/index.tsx new file mode 100644 index 000000000..120f52c15 --- /dev/null +++ b/src/components/country-select/index.tsx @@ -0,0 +1,34 @@ +import { FormControl, InputLabel, MenuItem, Select, SelectProps } from '@mui/material'; +import _countries from 'src/_mock/_countries'; +import { Iconify } from '../iconify'; + +function CountrySelect({ label = 'Country', ...props }: SelectProps) { + return ( + + {label} + + + ); +} + +export default CountrySelect; diff --git a/src/components/logo/logo.tsx b/src/components/logo/logo.tsx index fae19d7ce..8385dbb83 100644 --- a/src/components/logo/logo.tsx +++ b/src/components/logo/logo.tsx @@ -1,12 +1,13 @@ import type { BoxProps } from '@mui/material/Box'; -import { useId, forwardRef } from 'react'; +import { forwardRef, useId } from 'react'; import Box from '@mui/material/Box'; import { useTheme } from '@mui/material/styles'; import { RouterLink } from 'src/routes/components'; +import logo from 'public/assets/images/logo.png'; import { logoClasses } from './classes'; // ---------------------------------------------------------------------- @@ -212,7 +213,8 @@ export const Logo = forwardRef( }} {...other} > - {isSingle ? singleLogo : fullLogo} + {/* {isSingle ? singleLogo : fullLogo} */} + logo ); } diff --git a/src/components/provider/index.tsx b/src/components/provider/index.tsx new file mode 100644 index 000000000..03bf37f90 --- /dev/null +++ b/src/components/provider/index.tsx @@ -0,0 +1,43 @@ +import React, { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; +import UserService from 'src/services/user'; +import { User } from 'src/services/user/user.dto'; + +export const UserContext = React.createContext<{ + user?: User; + refetchUser?: () => void; +}>({ + user: undefined, + refetchUser: undefined, +}); + +const AppProvider = ({ children }: { children: ReactNode }) => { + const [user, setUser] = useState(); + + const fetchUser = useCallback(async () => { + try { + const res = await UserService.me(); + console.log('USER>>>', res); + if (res) { + setUser(res); + } + } catch (error) { + console.error(error); + } + }, []); + + useEffect(() => { + fetchUser(); + }, [fetchUser]); + + const contextValues = useMemo( + () => ({ + user, + reFetchUser: fetchUser, + }), + [user, fetchUser] + ); + + return {children}; +}; + +export default AppProvider; diff --git a/src/components/shared/alert/index.tsx b/src/components/shared/alert/index.tsx new file mode 100644 index 000000000..f4e150e72 --- /dev/null +++ b/src/components/shared/alert/index.tsx @@ -0,0 +1,75 @@ +import { Alert, AlertProps, Box, IconButton, Portal, Slide } from '@mui/material'; +import { forwardRef, useImperativeHandle, useRef, useState } from 'react'; +import { Iconify, IconifyProps } from 'src/components/iconify'; + +export interface AppAlertProps { + id?: string; + label: string; + icon?: IconifyProps['icon']; + type: AlertProps['severity']; +} + +export interface AppAlertMethods { + show: (data: AppAlertProps, cb?: () => void) => void; + close: (data: AppAlertProps, cb?: () => void) => void; +} + +const AppAlert = forwardRef((_, ref) => { + const [visible, setVisible] = useState(false); + const dataRef = useRef(null); + const container = useRef(); + + const handleOpenClose = (open: boolean, data?: AppAlertProps | null) => { + if (open) { + dataRef.current = data ?? null; + setVisible(true); + } else { + setVisible(false); + dataRef.current = null; + } + }; + + const clearData = () => { + dataRef.current = null; + }; + + const onClose = () => { + setVisible(false); + }; + + useImperativeHandle( + ref, + () => ({ + show(data) { + handleOpenClose(true, data); + }, + close() { + handleOpenClose(false); + }, + }), + [] + ); + + return ( + + + + } + action={ + + + + } + > + {dataRef.current?.label} + + + + + ); +}); + +export default AppAlert; diff --git a/src/components/shared/modals/contributeForm.tsx b/src/components/shared/modals/contributeForm.tsx new file mode 100644 index 000000000..00fdf9e05 --- /dev/null +++ b/src/components/shared/modals/contributeForm.tsx @@ -0,0 +1,116 @@ +import React, { useState, ChangeEvent, FormEvent } from 'react'; +import { + Modal, + Box, + Typography, + TextField, + Button, + Autocomplete, + Chip, + IconButton, + Link, +} from '@mui/material'; +import { Iconify } from 'src/components/iconify'; + +const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + +interface PaymentFormModalProps { + open: boolean; + amount: string; + handleClose: () => void; +} + +const PaymentFormModal: React.FC = ({ + open, + amount: pledge, + handleClose, +}) => { + const [amount, setAmount] = useState(pledge); + const [selectedMonths, setSelectedMonths] = useState([]); + + const handleAmountChange = (event: ChangeEvent) => { + setAmount(event.target.value); + }; + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + console.log('Amount:', amount); + console.log('Selected Months:', selectedMonths); + handleClose(); + }; + + return ( + + + + + + + Contribute + +
+ Change pledge amount?} + /> + setSelectedMonths(newValue)} + renderTags={(value, getTagProps) => + value.map((option, index) => ( + + )) + } + renderInput={(params) => ( + + )} + sx={{ mb: 3 }} + /> + + + + +
+
+ ); +}; + +export default PaymentFormModal; diff --git a/src/config-global.ts b/src/config-global.ts index 49eefa7f0..1ef641acb 100644 --- a/src/config-global.ts +++ b/src/config-global.ts @@ -10,6 +10,6 @@ export type ConfigValue = { // ---------------------------------------------------------------------- export const CONFIG: ConfigValue = { - appName: 'Minimal UI', + appName: 'PABGM Partnership', appVersion: packageJson.version, }; diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts new file mode 100644 index 000000000..3c8c65728 --- /dev/null +++ b/src/configs/firebase.ts @@ -0,0 +1,77 @@ +// Import the functions you need from the SDKs you need +import { initializeApp } from 'firebase/app'; +import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'; +import { connectFunctionsEmulator, getFunctions, httpsCallable } from 'firebase/functions'; +import { + getAuth, + createUserWithEmailAndPassword, + signInWithEmailAndPassword, + signOut, + sendPasswordResetEmail, + confirmPasswordReset, + connectAuthEmulator, + onAuthStateChanged, + User, +} from 'firebase/auth'; + +const USE_EMULATORS = true; + +const firebaseConfig = { + apiKey: 'AIzaSyDY-1FezjbzGmq1j3WHWurbniF3IIdYmEY', + authDomain: 'pabgm-39720.firebaseapp.com', + projectId: 'pabgm-39720', + storageBucket: 'pabgm-39720.firebasestorage.app', + messagingSenderId: '557051436284', + appId: '1:557051436284:web:96f2e80c4cc4c927638b79', + measurementId: 'G-VTGQQYSTP1', +}; + +// Initialize Firebase +const app = initializeApp(firebaseConfig); + +const appAuth = getAuth(); + +const auth = { + createUser(email: string, password: string) { + return createUserWithEmailAndPassword(appAuth, email, password); + }, + signIn(email: string, password: string) { + return signInWithEmailAndPassword(appAuth, email, password); + }, + resetPassword(email: string) { + return sendPasswordResetEmail(appAuth, email); + }, + confirmPassReset(code: string, newPass: string) { + return confirmPasswordReset(appAuth, code, newPass); + }, + logout() { + return signOut(appAuth); + }, + listen(cb: (val: User | null) => void) { + onAuthStateChanged(appAuth, cb); + }, +}; + +const db = getFirestore(app); +const fxns = getFunctions(app); + +const fx = { + async call(path: string, data: T) { + const callable = httpsCallable(fxns, path); + const result = await callable(data); + return result.data; + }, +}; + +const runEmulators = (val: boolean = USE_EMULATORS) => { + const local = '127.0.0.1'; + if (val) { + connectFirestoreEmulator(db, local, 8080); + connectAuthEmulator(appAuth, `http://${local}:9099`); + connectFunctionsEmulator(fxns, local, 5001); + } +}; + +runEmulators(); + +export { app, db, auth, fx }; diff --git a/src/configs/index.tsx b/src/configs/index.tsx new file mode 100644 index 000000000..5588511bf --- /dev/null +++ b/src/configs/index.tsx @@ -0,0 +1 @@ +export * from './firebase'; diff --git a/src/constants/factory.ts b/src/constants/factory.ts new file mode 100644 index 000000000..97899b13d --- /dev/null +++ b/src/constants/factory.ts @@ -0,0 +1,7 @@ +export enum Collection { + Users = 'USERS', + Contributions = 'CONTRIBUTIONS', + Transactions = 'TRXS', + AdminStats = 'ADMIN_STATS', + PartnerStats = 'PARTNER_STATS', +} diff --git a/src/constants/fxns.ts b/src/constants/fxns.ts new file mode 100644 index 000000000..0bd8bbd01 --- /dev/null +++ b/src/constants/fxns.ts @@ -0,0 +1,6 @@ +export enum ApiRoute { + Donate = 'contribute', + InitPayment = 'initPay', + PaymentHook = 'payHook', + GetUser = 'getUser', +} diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 000000000..e46b36118 --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1,2 @@ +export * from './factory'; +export * from './urls'; diff --git a/src/constants/urls.ts b/src/constants/urls.ts new file mode 100644 index 000000000..7995183aa --- /dev/null +++ b/src/constants/urls.ts @@ -0,0 +1 @@ +export const API_URL = ''; diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts new file mode 100644 index 000000000..710263654 --- /dev/null +++ b/src/hooks/useAuth.ts @@ -0,0 +1,30 @@ +import { User } from 'firebase/auth'; +import React, { useEffect, useState } from 'react'; +import AuthService from 'src/services/auth'; + +const useAuth = () => { + const [data, setData] = useState<{ userExists: boolean; user: User | null }>({ + userExists: false, + user: null, + }); + + const checkCurrentUser = (user: User | null) => { + if (user) { + setData({ userExists: true, user }); + } else { + AuthService.setToken(null); + setData({ + userExists: false, + user: null, + }); + } + }; + + useEffect(() => { + AuthService.listen(checkCurrentUser); + }, []); + + return data; +}; + +export default useAuth; diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts new file mode 100644 index 000000000..26d523981 --- /dev/null +++ b/src/hooks/useUser.ts @@ -0,0 +1,9 @@ +import { useContext } from 'react'; +import { UserContext } from 'src/components/provider'; + +const useUser = () => { + const data = useContext(UserContext); + return data; +}; + +export default useUser; diff --git a/src/layouts/components/account-popover.tsx b/src/layouts/components/account-popover.tsx index 995efce0a..72b0c7c3a 100644 --- a/src/layouts/components/account-popover.tsx +++ b/src/layouts/components/account-popover.tsx @@ -125,14 +125,6 @@ export function AccountPopover({ data = [], sx, ...other }: AccountPopoverProps) ))} - - - - - - ); diff --git a/src/layouts/config-nav-dashboard.tsx b/src/layouts/config-nav-dashboard.tsx index 2acb80796..86b9146ed 100644 --- a/src/layouts/config-nav-dashboard.tsx +++ b/src/layouts/config-nav-dashboard.tsx @@ -14,33 +14,43 @@ export const navData = [ icon: icon('ic-analytics'), }, { - title: 'User', - path: '/user', - icon: icon('ic-user'), - }, - { - title: 'Product', - path: '/products', - icon: icon('ic-cart'), - info: ( - - ), + title: 'Contributions', + path: '/contributions', + icon: icon('ic-donate'), }, { - title: 'Blog', - path: '/blog', - icon: icon('ic-blog'), - }, - { - title: 'Sign in', - path: '/sign-in', - icon: icon('ic-lock'), + title: 'Partners', + path: '/user', + icon: icon('ic-user'), }, { - title: 'Not found', - path: '/404', - icon: icon('ic-disabled'), + title: 'Logout', + path: '/logout', + icon: icon('ic-exit'), }, + // { + // title: 'Product', + // path: '/products', + // icon: icon('ic-cart'), + // info: ( + // + // ), + // }, + // { + // title: 'Blog', + // path: '/blog', + // icon: icon('ic-blog'), + // }, + // { + // title: 'Sign in', + // path: '/sign-in', + // icon: icon('ic-lock'), + // }, + // { + // title: 'Not found', + // path: '/404', + // icon: icon('ic-disabled'), + // }, ]; diff --git a/src/layouts/dashboard/layout.tsx b/src/layouts/dashboard/layout.tsx index 281305821..69931b02c 100644 --- a/src/layouts/dashboard/layout.tsx +++ b/src/layouts/dashboard/layout.tsx @@ -1,27 +1,28 @@ -import type { Theme, SxProps, Breakpoint } from '@mui/material/styles'; +import type { Breakpoint, SxProps, Theme } from '@mui/material/styles'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; -import Box from '@mui/material/Box'; import Alert from '@mui/material/Alert'; +import Box from '@mui/material/Box'; import { useTheme } from '@mui/material/styles'; -import { _langs, _notifications } from 'src/_mock'; +import { _notifications } from 'src/_mock'; import { Iconify } from 'src/components/iconify'; -import { Main } from './main'; +import useAuth from 'src/hooks/useAuth'; +import { useRouter } from 'src/routes/hooks'; +import AuthService from 'src/services/auth'; import { layoutClasses } from '../classes'; -import { NavMobile, NavDesktop } from './nav'; +import { AccountPopover } from '../components/account-popover'; +import { MenuButton } from '../components/menu-button'; +import { NotificationsPopover } from '../components/notifications-popover'; import { navData } from '../config-nav-dashboard'; -import { Searchbar } from '../components/searchbar'; import { _workspaces } from '../config-nav-workspace'; -import { MenuButton } from '../components/menu-button'; -import { LayoutSection } from '../core/layout-section'; import { HeaderSection } from '../core/header-section'; -import { AccountPopover } from '../components/account-popover'; -import { LanguagePopover } from '../components/language-popover'; -import { NotificationsPopover } from '../components/notifications-popover'; +import { LayoutSection } from '../core/layout-section'; +import { Main } from './main'; +import { NavDesktop, NavMobile } from './nav'; // ---------------------------------------------------------------------- @@ -35,11 +36,19 @@ export type DashboardLayoutProps = { export function DashboardLayout({ sx, children, header }: DashboardLayoutProps) { const theme = useTheme(); + const { userExists } = useAuth(); + const router = useRouter(); const [navOpen, setNavOpen] = useState(false); const layoutQuery: Breakpoint = 'lg'; + useEffect(() => { + if (!AuthService.hasToken()) { + router.replace('/signin'); + } + }, [userExists, router]); + return ( - - , - }, { label: 'Profile', href: '#', diff --git a/src/layouts/dashboard/nav.tsx b/src/layouts/dashboard/nav.tsx index 3b19cb940..cc905ed15 100644 --- a/src/layouts/dashboard/nav.tsx +++ b/src/layouts/dashboard/nav.tsx @@ -16,9 +16,6 @@ import { varAlpha } from 'src/theme/styles'; import { Logo } from 'src/components/logo'; import { Scrollbar } from 'src/components/scrollbar'; -import { NavUpgrade } from '../components/nav-upgrade'; -import { WorkspacesPopover } from '../components/workspaces-popover'; - import type { WorkspacesPopoverProps } from '../components/workspaces-popover'; // ---------------------------------------------------------------------- @@ -120,16 +117,20 @@ export function NavContent({ data, slots, workspaces, sx }: NavContentProps) { return ( <> - {slots?.topArea} - - - - + {data.map((item) => { const isActived = item.path === pathname; + if (item.path === '/logout') return null; return ( @@ -173,10 +174,32 @@ export function NavContent({ data, slots, workspaces, sx }: NavContentProps) { - {slots?.bottomArea} + + + {data[data.length - 1].icon} + - + + {data[data.length - 1].title} + + ); } diff --git a/src/pages/contributions.tsx b/src/pages/contributions.tsx new file mode 100644 index 000000000..d9f0dda08 --- /dev/null +++ b/src/pages/contributions.tsx @@ -0,0 +1,18 @@ +import { Typography } from '@mui/material'; +import { Helmet } from 'react-helmet-async'; +import { CONFIG } from 'src/config-global'; +import { DashboardContent } from 'src/layouts/dashboard'; +import { ContributionsView } from 'src/sections/contributions/view'; + +function Contributions() { + return ( + <> + + {`Contributions - ${CONFIG.appName}`} + + + + ); +} + +export default Contributions; diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 53838c922..26d612b38 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -1,6 +1,10 @@ +import { Fab } from '@mui/material'; +import { useEffect } from 'react'; import { Helmet } from 'react-helmet-async'; +import { Iconify } from 'src/components/iconify'; import { CONFIG } from 'src/config-global'; +import { fx } from 'src/configs'; import { OverviewAnalyticsView } from 'src/sections/overview/view'; @@ -11,11 +15,8 @@ export default function Page() { <> {`Dashboard - ${CONFIG.appName}`} - - + + diff --git a/src/pages/logout.tsx b/src/pages/logout.tsx new file mode 100644 index 000000000..511f406ea --- /dev/null +++ b/src/pages/logout.tsx @@ -0,0 +1,20 @@ +import { useCallback, useEffect } from 'react'; +import { useRouter } from 'src/routes/hooks'; +import AuthService from 'src/services/auth'; + +function Logout() { + const { replace } = useRouter(); + + const logout = useCallback(async () => { + await AuthService.logout(); + replace('/signin'); + }, [replace]); + + useEffect(() => { + logout(); + }, [logout]); + + return null; +} + +export default Logout; diff --git a/src/routes/sections.tsx b/src/routes/sections.tsx index 34a673b10..48c3757b8 100644 --- a/src/routes/sections.tsx +++ b/src/routes/sections.tsx @@ -1,12 +1,17 @@ -import { lazy, Suspense } from 'react'; -import { Outlet, Navigate, useRoutes } from 'react-router-dom'; +import { lazy, Suspense, useState } from 'react'; +import { Navigate, Outlet, useRoutes } from 'react-router-dom'; import Box from '@mui/material/Box'; import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress'; -import { varAlpha } from 'src/theme/styles'; +import { Fab } from '@mui/material'; +import { Iconify } from 'src/components/iconify'; +import PaymentFormModal from 'src/components/shared/modals/contributeForm'; import { AuthLayout } from 'src/layouts/auth'; import { DashboardLayout } from 'src/layouts/dashboard'; +import { varAlpha } from 'src/theme/styles'; + +const AppProvider = lazy(() => import('src/components/provider')); // ---------------------------------------------------------------------- @@ -15,6 +20,8 @@ export const BlogPage = lazy(() => import('src/pages/blog')); export const UserPage = lazy(() => import('src/pages/user')); export const SignInPage = lazy(() => import('src/pages/sign-in')); export const ProductsPage = lazy(() => import('src/pages/products')); +export const ContributionsPage = lazy(() => import('src/pages/contributions')); +export const LogoutPage = lazy(() => import('src/pages/logout')); export const Page404 = lazy(() => import('src/pages/page-not-found')); // ---------------------------------------------------------------------- @@ -33,30 +40,69 @@ const renderFallback = ( ); export function Router() { + const [open, setOpen] = useState(false); + + const onOpen = () => { + setOpen(true); + }; + + const onClose = () => { + setOpen(false); + }; + + const contributeBtn = ( + + + + ); + return useRoutes([ { element: ( - - - - - + + + + + + + {contributeBtn} + + + + ), children: [ { element: , index: true }, { path: 'user', element: }, { path: 'products', element: }, { path: 'blog', element: }, + { path: 'contributions', element: }, ], }, { - path: 'sign-in', + path: 'signin', element: ( ), }, + { + path: 'logout', + element: , + }, { path: '404', element: , diff --git a/src/sections/auth/sign-in-view.tsx b/src/sections/auth/sign-in-view.tsx index 52f619215..e071187bf 100644 --- a/src/sections/auth/sign-in-view.tsx +++ b/src/sections/auth/sign-in-view.tsx @@ -1,55 +1,184 @@ -import { useState, useCallback } from 'react'; +import { HTMLAttributes, useCallback, useEffect, useState } from 'react'; +import LoadingButton from '@mui/lab/LoadingButton'; import Box from '@mui/material/Box'; -import Link from '@mui/material/Link'; import Divider from '@mui/material/Divider'; -import TextField from '@mui/material/TextField'; import IconButton from '@mui/material/IconButton'; -import Typography from '@mui/material/Typography'; -import LoadingButton from '@mui/lab/LoadingButton'; import InputAdornment from '@mui/material/InputAdornment'; +import Link from '@mui/material/Link'; +import TextField from '@mui/material/TextField'; +import Typography from '@mui/material/Typography'; import { useRouter } from 'src/routes/hooks'; +import { Button } from '@mui/material'; +import CountrySelect from 'src/components/country-select'; import { Iconify } from 'src/components/iconify'; +import { CreateUserBody } from 'src/services/auth/auth.dto'; +import AuthService from 'src/services/auth'; +import { errCb } from 'src/utils'; // ---------------------------------------------------------------------- +const SIGN_IN = { + email: '', + password: '', +}; + +const SIGN_UP = { + fname: '', + lname: '', + country: '', + email: '', + password: '', + pledgeAmount: '', +}; + export function SignInView() { const router = useRouter(); const [showPassword, setShowPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); + const [isSignin, setIsSignin] = useState(true); + const [authenticating, setAuthenticating] = useState(false); + const [confirmPass, setConfirmPass] = useState(''); + const [data, setData] = useState>(SIGN_IN); - const handleSignIn = useCallback(() => { - router.push('/'); - }, [router]); + const onGetStarted = () => { + setIsSignin((val) => !val); + }; + + const onAuthenticate = async () => { + try { + setAuthenticating(true); + if (isSignin) { + if (!data.email || !data.password) { + throw new Error('Email and password is required'); + } else { + await AuthService.login({ + email: data.email!, + password: data.password!, + }); + } + } else { + const user = await AuthService.register(data as CreateUserBody); + console.log(user); + } + router.replace('/'); + } catch (error) { + errCb(error.message); + } finally { + setAuthenticating(false); + } + }; + + const updateField = (field: keyof CreateUserBody, val: string) => { + setData((value) => ({ ...value, [field]: val })); + }; + + const checkPass = useCallback(() => { + console.log(data.password, confirmPass); + if (data.password !== confirmPass && !isSignin) { + return 'Passwords do not match'; + } + return null; + }, [data.password, confirmPass, isSignin]); + + const checkEmptyForm = useCallback( + () => [...Object.values(data), !isSignin ? confirmPass : 'true'].some((val) => val === ''), + [data, confirmPass, isSignin] + ); + + useEffect(() => { + if (isSignin) { + setData(SIGN_IN); + } else { + setData(SIGN_UP); + } + }, [isSignin]); + + const passErr = checkPass(); + const emptyForm = checkEmptyForm(); + + console.log(emptyForm, data); const renderForm = ( + {!isSignin && ( + + updateField('fname', e.target.value)} + InputLabelProps={{ shrink: true }} + sx={{ mb: 3 }} + /> + updateField('lname', e.target.value)} + InputLabelProps={{ shrink: true }} + sx={{ mb: 3 }} + /> + + )} updateField('email', e.target.value)} InputLabelProps={{ shrink: true }} sx={{ mb: 3 }} /> + {!isSignin && ( + <> + updateField('pledgeAmount', e.target.value)} + InputLabelProps={{ shrink: true }} + sx={{ mb: 3 }} + /> + + updateField('country', e.target.value as string)} + required + /> + + + )} - - Forgot password? - + {isSignin && ( + + Forgot password? + + )} updateField('password', e.target.value)} InputProps={{ endAdornment: ( - setShowPassword(!showPassword)} edge="end"> + setShowPassword((val) => !val)} edge="end"> @@ -57,16 +186,44 @@ export function SignInView() { }} sx={{ mb: 3 }} /> + {!isSignin && ( + setConfirmPass(e.target.value)} + InputProps={{ + endAdornment: ( + + setShowConfirmPassword((val) => !val)} edge="end"> + + + + ), + }} + sx={{ mb: 3 }} + /> + )} - Sign in + {isSignin ? 'Sign in' : 'Sign up'} ); @@ -74,37 +231,34 @@ export function SignInView() { return ( <> - Sign in + {!isSignin ? 'Sign up' : 'Sign in'} Don’t have an account? - - Get started - + +
{renderForm}
- {renderForm} + {isSignin && ( + <> + + + OR + + - - - OR - - - - - - - - - - - - - - + + + + + + + )} ); } diff --git a/src/sections/contributions/contributions-table-head.tsx b/src/sections/contributions/contributions-table-head.tsx new file mode 100644 index 000000000..23c2c05fb --- /dev/null +++ b/src/sections/contributions/contributions-table-head.tsx @@ -0,0 +1,73 @@ +import Box from '@mui/material/Box'; +import TableRow from '@mui/material/TableRow'; +import Checkbox from '@mui/material/Checkbox'; +import TableHead from '@mui/material/TableHead'; +import TableCell from '@mui/material/TableCell'; +import TableSortLabel from '@mui/material/TableSortLabel'; + +import { visuallyHidden } from './utils'; + +// ---------------------------------------------------------------------- + +type ContributionTableHeadProps = { + orderBy: string; + rowCount: number; + numSelected: number; + noMultiSelect?: boolean; + order: 'asc' | 'desc'; + onSort: (id: string) => void; + headLabel: Record[]; + onSelectAllRows: (checked: boolean) => void; +}; + +export function ContributionTableHead({ + order, + onSort, + orderBy, + rowCount, + headLabel, + numSelected, + noMultiSelect = false, + onSelectAllRows, +}: ContributionTableHeadProps) { + return ( + + + {!noMultiSelect && ( + + 0 && numSelected < rowCount} + checked={rowCount > 0 && numSelected === rowCount} + onChange={(event: React.ChangeEvent) => + onSelectAllRows(event.target.checked) + } + /> + + )} + + {headLabel.map((headCell) => ( + + onSort(headCell.id)} + > + {headCell.label} + {orderBy === headCell.id ? ( + + {order === 'desc' ? 'sorted descending' : 'sorted ascending'} + + ) : null} + + + ))} + + + ); +} diff --git a/src/sections/contributions/contributions-table-row.tsx b/src/sections/contributions/contributions-table-row.tsx new file mode 100644 index 000000000..a9ddfd34e --- /dev/null +++ b/src/sections/contributions/contributions-table-row.tsx @@ -0,0 +1,114 @@ +import { useCallback, useState } from 'react'; + +import Box from '@mui/material/Box'; +import Checkbox from '@mui/material/Checkbox'; +import MenuItem, { menuItemClasses } from '@mui/material/MenuItem'; +import MenuList from '@mui/material/MenuList'; +import Popover from '@mui/material/Popover'; +import TableCell from '@mui/material/TableCell'; +import TableRow from '@mui/material/TableRow'; + +import { Iconify } from 'src/components/iconify'; +import { Label } from 'src/components/label'; +import { fDateTime } from 'src/utils/format-time'; + +// ---------------------------------------------------------------------- + +export type ContributionProps = { + id: string; + sender: { + id: string; + name: string; + }; + amount: string; + timestamp: string; + status: 'pending' | 'success' | 'failed'; + months: string[]; +}; + +type ContributionsTableRowProps = { + row: ContributionProps; + selected: boolean; + noSelection?: boolean; + onSelectRow: () => void; +}; + +export function ContributionsTableRow({ + row, + selected, + noSelection, + onSelectRow, +}: ContributionsTableRowProps) { + const [openPopover, setOpenPopover] = useState(null); + + const handleOpenPopover = useCallback((event: React.MouseEvent) => { + setOpenPopover(event.currentTarget); + }, []); + + const handleClosePopover = useCallback(() => { + setOpenPopover(null); + }, []); + + return ( + <> + + {!noSelection && ( + + + + )} + + + + {row.sender.name} + + + + {row.months.join(', ')} + + {`GHS ${row.amount}`} + + {fDateTime(row.timestamp)} + + + + + + + + + + + Edit + + + + + Delete + + + + + ); +} diff --git a/src/sections/contributions/contributions-table-toolbar.tsx b/src/sections/contributions/contributions-table-toolbar.tsx new file mode 100644 index 000000000..ad8d90770 --- /dev/null +++ b/src/sections/contributions/contributions-table-toolbar.tsx @@ -0,0 +1,70 @@ +import Tooltip from '@mui/material/Tooltip'; +import Toolbar from '@mui/material/Toolbar'; +import Typography from '@mui/material/Typography'; +import IconButton from '@mui/material/IconButton'; +import OutlinedInput from '@mui/material/OutlinedInput'; +import InputAdornment from '@mui/material/InputAdornment'; + +import { Iconify } from 'src/components/iconify'; + +// ---------------------------------------------------------------------- + +type ContributionsTableToolbarProps = { + numSelected: number; + filterName: string; + onFilterName: (event: React.ChangeEvent) => void; +}; + +export function ContributionsTableToolbar({ + numSelected, + filterName, + onFilterName, +}: ContributionsTableToolbarProps) { + return ( + theme.spacing(0, 1, 0, 3), + ...(numSelected > 0 && { + color: 'primary.main', + bgcolor: 'primary.lighter', + }), + }} + > + {/* {numSelected > 0 ? ( + + {numSelected} selected + + ) : ( */} + + + + } + sx={{ maxWidth: 320 }} + /> + {/* )} */} + + {/* {numSelected > 0 ? ( + + + + + + ) : ( + + + + + + )} */} + + ); +} diff --git a/src/sections/contributions/table-empty-rows.tsx b/src/sections/contributions/table-empty-rows.tsx new file mode 100644 index 000000000..4127993fb --- /dev/null +++ b/src/sections/contributions/table-empty-rows.tsx @@ -0,0 +1,31 @@ +import type { TableRowProps } from '@mui/material/TableRow'; + +import TableRow from '@mui/material/TableRow'; +import TableCell from '@mui/material/TableCell'; + +// ---------------------------------------------------------------------- + +type TableEmptyRowsProps = TableRowProps & { + emptyRows: number; + height?: number; +}; + +export function TableEmptyRows({ emptyRows, height, sx, ...other }: TableEmptyRowsProps) { + if (!emptyRows) { + return null; + } + + return ( + + + + ); +} diff --git a/src/sections/contributions/table-no-data.tsx b/src/sections/contributions/table-no-data.tsx new file mode 100644 index 000000000..914e23f38 --- /dev/null +++ b/src/sections/contributions/table-no-data.tsx @@ -0,0 +1,32 @@ +import type { TableRowProps } from '@mui/material/TableRow'; + +import Box from '@mui/material/Box'; +import TableRow from '@mui/material/TableRow'; +import TableCell from '@mui/material/TableCell'; +import Typography from '@mui/material/Typography'; + +// ---------------------------------------------------------------------- + +type TableNoDataProps = TableRowProps & { + searchQuery: string; +}; + +export function TableNoData({ searchQuery, ...other }: TableNoDataProps) { + return ( + + + + + Not found + + + + No results found for   + "{searchQuery}". +
Try checking for typos or using complete words. +
+
+
+
+ ); +} diff --git a/src/sections/contributions/utils.ts b/src/sections/contributions/utils.ts new file mode 100644 index 000000000..0a275e8eb --- /dev/null +++ b/src/sections/contributions/utils.ts @@ -0,0 +1,80 @@ +import type { ContributionProps } from './contributions-table-row'; + +// ---------------------------------------------------------------------- + +export const visuallyHidden = { + border: 0, + margin: -1, + padding: 0, + width: '1px', + height: '1px', + overflow: 'hidden', + position: 'absolute', + whiteSpace: 'nowrap', + clip: 'rect(0 0 0 0)', +} as const; + +// ---------------------------------------------------------------------- + +export function emptyRows(page: number, rowsPerPage: number, arrayLength: number) { + return page ? Math.max(0, (1 + page) * rowsPerPage - arrayLength) : 0; +} + +// ---------------------------------------------------------------------- + +function descendingComparator(a: T, b: T, orderBy: keyof T) { + if (b[orderBy] < a[orderBy]) { + return -1; + } + if (b[orderBy] > a[orderBy]) { + return 1; + } + return 0; +} + +// ---------------------------------------------------------------------- + +export function getComparator( + order: 'asc' | 'desc', + orderBy: Key +): ( + a: { + [key in Key]: number | string; + }, + b: { + [key in Key]: number | string; + } +) => number { + return order === 'desc' + ? (a, b) => descendingComparator(a, b, orderBy) + : (a, b) => -descendingComparator(a, b, orderBy); +} + +// ---------------------------------------------------------------------- + +type ApplyFilterProps = { + inputData: ContributionProps[]; + filterName: string; + comparator: (a: any, b: any) => number; +}; + +export function applyFilter({ inputData, comparator, filterName }: ApplyFilterProps) { + const stabilizedThis = inputData.map((el, index) => [el, index] as const); + + stabilizedThis.sort((a, b) => { + const order = comparator(a[0], b[0]); + if (order !== 0) return order; + return a[1] - b[1]; + }); + + inputData = stabilizedThis.map((el) => el[0]); + + if (filterName) { + inputData = inputData.filter( + (contribution) => + contribution.sender.name.toLowerCase().indexOf(filterName.toLowerCase()) !== -1 + ); + } + + return inputData; +} diff --git a/src/sections/contributions/view/contributions-view.tsx b/src/sections/contributions/view/contributions-view.tsx new file mode 100644 index 000000000..4f0d61bc5 --- /dev/null +++ b/src/sections/contributions/view/contributions-view.tsx @@ -0,0 +1,216 @@ +import { useCallback, useState } from 'react'; + +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Card from '@mui/material/Card'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableContainer from '@mui/material/TableContainer'; +import TablePagination from '@mui/material/TablePagination'; +import Typography from '@mui/material/Typography'; + +import { _contributions, _users } from 'src/_mock'; +import { DashboardContent } from 'src/layouts/dashboard'; + +import { Iconify } from 'src/components/iconify'; +import { Scrollbar } from 'src/components/scrollbar'; + +import { ContributionTableHead } from '../contributions-table-head'; +import { TableEmptyRows } from '../table-empty-rows'; +import { TableNoData } from '../table-no-data'; +import { applyFilter, emptyRows, getComparator } from '../utils'; + +import { ContributionsTableRow, type ContributionProps } from '../contributions-table-row'; +import { ContributionsTableToolbar } from '../contributions-table-toolbar'; + +// ---------------------------------------------------------------------- + +interface ContributionsViewProps { + ignoreDashContent?: boolean; + noMultiSelect?: boolean; + noToolbar?: boolean; + hideBtn?: boolean; + title?: string; + noPagination?: boolean; +} + +export function ContributionsView({ + ignoreDashContent, + noMultiSelect, + noToolbar, + hideBtn, + noPagination, + title = 'Contributions', +}: ContributionsViewProps) { + const table = useTable(); + + const [filterName, setFilterName] = useState(''); + + const dataFiltered: ContributionProps[] = applyFilter({ + inputData: _contributions, + comparator: getComparator(table.order, table.orderBy), + filterName, + }); + + const notFound = !dataFiltered.length && !!filterName; + + const content = ( + <> + + + {title} + + {!hideBtn && ( + + )} + + + {!noToolbar && ( + ) => { + setFilterName(event.target.value); + table.onResetPage(); + }} + /> + )} + + + + + + table.onSelectAllRows( + checked, + _users.map((user) => user.id) + ) + } + headLabel={[ + { id: 'name', label: 'Name' }, + { id: 'months', label: 'Months' }, + { id: 'amount', label: 'Amount' }, + { id: 'date', label: 'Date' }, + { id: 'status', label: 'Status' }, + ]} + /> + + {dataFiltered + .slice( + table.page * table.rowsPerPage, + table.page * table.rowsPerPage + table.rowsPerPage + ) + .map((row) => ( + table.onSelectRow(row.id)} + /> + ))} + + + + {notFound && } + +
+
+
+ + {!noPagination && ( + + )} +
+ + ); + + return ignoreDashContent ? content : {content}; +} + +// ---------------------------------------------------------------------- + +export function useTable() { + const [page, setPage] = useState(0); + const [orderBy, setOrderBy] = useState('name'); + const [rowsPerPage, setRowsPerPage] = useState(10); + const [selected, setSelected] = useState([]); + const [order, setOrder] = useState<'asc' | 'desc'>('asc'); + + const onSort = useCallback( + (id: string) => { + const isAsc = orderBy === id && order === 'asc'; + setOrder(isAsc ? 'desc' : 'asc'); + setOrderBy(id); + }, + [order, orderBy] + ); + + const onSelectAllRows = useCallback((checked: boolean, newSelecteds: string[]) => { + if (checked) { + setSelected(newSelecteds); + return; + } + setSelected([]); + }, []); + + const onSelectRow = useCallback( + (inputValue: string) => { + const newSelected = selected.includes(inputValue) + ? selected.filter((value) => value !== inputValue) + : [...selected, inputValue]; + + setSelected(newSelected); + }, + [selected] + ); + + const onResetPage = useCallback(() => { + setPage(0); + }, []); + + const onChangePage = useCallback((event: unknown, newPage: number) => { + setPage(newPage); + }, []); + + const onChangeRowsPerPage = useCallback( + (event: React.ChangeEvent) => { + setRowsPerPage(parseInt(event.target.value, 10)); + onResetPage(); + }, + [onResetPage] + ); + + return { + page, + order, + onSort, + orderBy, + selected, + rowsPerPage, + onSelectRow, + onResetPage, + onChangePage, + onSelectAllRows, + onChangeRowsPerPage, + }; +} diff --git a/src/sections/contributions/view/index.ts b/src/sections/contributions/view/index.ts new file mode 100644 index 000000000..0902724a1 --- /dev/null +++ b/src/sections/contributions/view/index.ts @@ -0,0 +1 @@ +export * from './contributions-view'; diff --git a/src/sections/overview/analytics-widget-summary.tsx b/src/sections/overview/analytics-widget-summary.tsx index 79694c0aa..43ca3decd 100644 --- a/src/sections/overview/analytics-widget-summary.tsx +++ b/src/sections/overview/analytics-widget-summary.tsx @@ -19,7 +19,7 @@ import { Chart, useChart } from 'src/components/chart'; type Props = CardProps & { title: string; total: number; - percent: number; + percent?: number; color?: ColorType; icon: React.ReactNode; chart: { @@ -61,25 +61,6 @@ export function AnalyticsWidgetSummary({ ...chart.options, }); - const renderTrending = ( - - - - {percent > 0 && '+'} - {fPercent(percent)} - - - ); - return ( {icon} - {renderTrending} - - Hi, Welcome back 👋 + Hi, {user?.fname} 👋 } + icon={icon} chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], - series: [22, 8, 35, 50, 82, 84, 77, 12], + series: [], }} /> } chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], - series: [56, 47, 40, 62, 73, 30, 23, 54], + series: [], }} /> } + icon={icon} chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], - series: [40, 70, 50, 28, 70, 75, 7, 64], + series: [], }} /> @@ -68,18 +62,18 @@ export function OverviewAnalyticsView() { } chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], - series: [56, 30, 23, 54, 47, 40, 62, 73], + series: [], }} /> - + {/* - + */} - + {/* - + */} - + {/* + */} + + + - - - - - + {/* - + */} - + {/* - + */} ); diff --git a/src/services/auth/auth.dto.ts b/src/services/auth/auth.dto.ts new file mode 100644 index 000000000..4a32e1e43 --- /dev/null +++ b/src/services/auth/auth.dto.ts @@ -0,0 +1,13 @@ +export interface CreateUserBody { + fname: string; + lname: string; + email: string; + password?: string; + country: string; + pledgeAmount: string; +} + +export interface UserLoginBody { + email: string; + password: string; +} diff --git a/src/services/auth/index.ts b/src/services/auth/index.ts new file mode 100644 index 000000000..9d3237804 --- /dev/null +++ b/src/services/auth/index.ts @@ -0,0 +1,61 @@ +import { User } from 'firebase/auth'; +import { jwtDecode } from 'jwt-decode'; +import { auth } from 'src/configs/firebase'; +import { Cache, CacheKeys } from 'src/utils'; +import { hash } from 'src/utils/encrypt'; +import UserService from '../user'; +import { UserRole } from '../user/user.dto'; +import { CreateUserBody, UserLoginBody } from './auth.dto'; + +export default class AuthService { + private static token: string | null = Cache.get(CacheKeys.Token); + + static async register(data: CreateUserBody) { + const pass = hash(data.password!); + const user = await auth.createUser(data.email, pass); + const token = await user.user.getIdToken(); + this.setToken(token); + delete data.password; + return UserService.create({ + ...data, + id: user.user.uid, + role: [UserRole.Partner], + }); + } + + static async login(data: UserLoginBody) { + const pass = hash(data.password); + const user = await auth.signIn(data.email, pass); + const token = await user.user.getIdToken(); + this.setToken(token); + return UserService.get(user.user.uid); + } + + static async logout() { + return auth.logout(); + } + + static setToken(token: string | null) { + this.token = token; + Cache.set(CacheKeys.Token, token); + } + + static getToken(): string | null { + return this.token || Cache.get(CacheKeys.Token); + } + + static hasToken() { + return !!this.getToken(); + } + + static decodeToken(token = this.getToken()) { + if (!token) return null; + const decoded = jwtDecode(token); + console.log(decoded); + return decoded; + } + + static listen(cb: (val: User | null) => void) { + auth.listen(cb); + } +} diff --git a/src/services/pay/index.ts b/src/services/pay/index.ts new file mode 100644 index 000000000..87e7ac80f --- /dev/null +++ b/src/services/pay/index.ts @@ -0,0 +1,18 @@ +import PaystackPop from '@paystack/inline-js'; +import { fx } from 'src/configs'; +import { ApiRoute } from 'src/constants/fxns'; +import { errCb } from 'src/utils'; +import { ContributeInit } from './pay.dto'; + +export default class PayService { + static async init(amount: string | null = null) { + try { + const res = await fx.call(ApiRoute.InitPayment, { amount }); + const popup = new PaystackPop(); + popup.resumeTransaction(res.code as any); + } catch (error) { + const err = error as Error; + errCb(err.message); + } + } +} diff --git a/src/services/pay/pay.dto.ts b/src/services/pay/pay.dto.ts new file mode 100644 index 000000000..d639a6094 --- /dev/null +++ b/src/services/pay/pay.dto.ts @@ -0,0 +1,3 @@ +export interface ContributeInit { + amount: string | null; +} diff --git a/src/services/trxn/trx.dto.ts b/src/services/trxn/trx.dto.ts new file mode 100644 index 000000000..db9b6e851 --- /dev/null +++ b/src/services/trxn/trx.dto.ts @@ -0,0 +1,30 @@ +import { Timestamp } from 'firebase/firestore'; + +export enum TrxStatus { + Initiated = 'INITIATED', + Pending = 'PENDING', + Completed = 'COMPLETED', + Cancelled = 'CANCELLED', +} + +export interface InitTransactionPayload { + email: string; + amount: string; +} + +export interface Trxn { + id: string; + status: TrxStatus; + initiateAt: Timestamp; + completeAt: Timestamp | null; + modifiedAt: Timestamp | null; + trxRef: string; + trxCode: string; + trxUrl: string; + amount: string; + initiator: { + name: string; + id: string; + email: string; + }; +} diff --git a/src/services/user/index.ts b/src/services/user/index.ts new file mode 100644 index 000000000..5c28d3a24 --- /dev/null +++ b/src/services/user/index.ts @@ -0,0 +1,29 @@ +import { getDoc, setDoc, updateDoc } from 'firebase/firestore'; +import { fx } from 'src/configs'; +import { Collection } from 'src/constants/factory'; +import { ApiRoute } from 'src/constants/fxns'; +import { docRef } from 'src/utils'; +import { User, UserUpdateBody } from './user.dto'; + +export default class UserService { + static async get(id: string): Promise { + const ref = docRef(id, Collection.Users); + const docRes = await getDoc(ref); + return docRes.data() as User; + } + + static async me() { + return fx.call<{}, User>(ApiRoute.GetUser, {}); + } + + static async create(data: User) { + const ref = docRef(data.id, Collection.Users); + await setDoc(ref, data); + return data; + } + + static async update(id: string, data: UserUpdateBody) { + const ref = docRef(id, Collection.Users); + await updateDoc(ref, data); + } +} diff --git a/src/services/user/user.dto.ts b/src/services/user/user.dto.ts new file mode 100644 index 000000000..aa6649899 --- /dev/null +++ b/src/services/user/user.dto.ts @@ -0,0 +1,16 @@ +export enum UserRole { + Admin = 'ADMIN', + Partner = 'PARTNER', +} + +export interface User { + id: string; + fname: string; + lname: string; + email: string; + country: string; + pledgeAmount: string; + role: UserRole[]; +} + +export interface UserUpdateBody extends Omit {} diff --git a/src/utils/alert.ts b/src/utils/alert.ts new file mode 100644 index 000000000..dcc967f1c --- /dev/null +++ b/src/utils/alert.ts @@ -0,0 +1,13 @@ +import { AppAlertMethods } from 'src/components/shared/alert'; + +export class AlertUtil { + private static ref: AppAlertMethods | null; + + public static setRef(_ref: AppAlertMethods | null) { + this.ref = _ref; + } + + public static getRef(): AppAlertMethods | null { + return this.ref; + } +} diff --git a/src/utils/cache.ts b/src/utils/cache.ts new file mode 100644 index 000000000..3a97c94ba --- /dev/null +++ b/src/utils/cache.ts @@ -0,0 +1,30 @@ +import { payloadDeHash, payloadHash } from './encrypt'; + +export enum CacheKeys { + Token = 'my.auth.id.t', +} + +export class Cache { + static set(id: CacheKeys, data: T) { + return localStorage.setItem(id as any, this.parse(data)); + } + + static get(id: CacheKeys) { + const hash = localStorage.getItem(id); + if (!hash) return null; + return this.unparse(hash) as T; + } + + private static parse(data: T) { + if (!data) return ''; + const payloadString = JSON.stringify(data); + return payloadHash(payloadString); + } + + private static unparse(hash: string) { + if (!hash) return null; + const payloadString = payloadDeHash(hash); + console.log('PAYLOAD STRING', payloadString); + return JSON.parse(payloadString); + } +} diff --git a/src/utils/encrypt.ts b/src/utils/encrypt.ts new file mode 100644 index 000000000..149694c1a --- /dev/null +++ b/src/utils/encrypt.ts @@ -0,0 +1,15 @@ +import crypto from 'crypto-js'; + +const KEY = '1NF1U3N51NG11V35'; + +export function hash(plainText: string) { + return crypto.SHA256(KEY + plainText).toString(crypto.enc.Hex); +} + +export function payloadHash(plainText: string) { + return crypto.AES.encrypt(plainText, KEY).toString(); +} + +export function payloadDeHash(hashVal: string) { + return crypto.AES.decrypt(hashVal, KEY).toString(crypto.enc.Utf8); +} diff --git a/src/utils/errors.ts b/src/utils/errors.ts new file mode 100644 index 000000000..b5574ef09 --- /dev/null +++ b/src/utils/errors.ts @@ -0,0 +1,5 @@ +import { AlertUtil } from './alert'; + +export const errCb = (val: string) => { + AlertUtil.getRef()?.show({ label: val, type: 'error' }); +}; diff --git a/src/utils/fstore.ts b/src/utils/fstore.ts new file mode 100644 index 000000000..97e8c7f7d --- /dev/null +++ b/src/utils/fstore.ts @@ -0,0 +1,7 @@ +import { doc } from 'firebase/firestore'; +import { db } from 'src/configs'; +import { Collection } from 'src/constants/factory'; + +export function docRef(id: string, collection: Collection) { + return doc(db, collection, id); +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 000000000..115797d1b --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,5 @@ +export * from './encrypt'; +export * from './fstore'; +export * from './alert'; +export * from './errors'; +export * from './cache'; diff --git a/yarn.lock b/yarn.lock index eb21c020b..b9e7ce203 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,96 +7,87 @@ resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": - version "7.24.7" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz" - integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9": + version "7.26.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== dependencies: - "@babel/highlight" "^7.24.7" + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/generator@^7.25.4": - version "7.25.4" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.25.4.tgz" - integrity sha512-NFtZmZsyzDPJnk9Zg3BbTfKKc9UlHYzD0E//p2Z3B9nCwwtJW9T0gVbCz8+fBngnn4zf1Dr3IK8PHQQHq0lDQw== +"@babel/generator@^7.25.9": + version "7.26.2" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz" + integrity sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw== dependencies: - "@babel/types" "^7.25.4" + "@babel/parser" "^7.26.2" + "@babel/types" "^7.26.0" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" + jsesc "^3.0.2" "@babel/helper-module-imports@^7.16.7": - version "7.24.7" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-string-parser@^7.24.8": - version "7.24.8" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz" - integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== - -"@babel/helper-validator-identifier@^7.24.7": - version "7.24.7" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz" - integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== - -"@babel/highlight@^7.24.7": - version "7.24.7" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz" - integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== - dependencies: - "@babel/helper-validator-identifier" "^7.24.7" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" -"@babel/parser@^7.25.0", "@babel/parser@^7.25.4": - version "7.25.4" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz" - integrity sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA== +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/parser@^7.25.9", "@babel/parser@^7.26.2": + version "7.26.2" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz" + integrity sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ== dependencies: - "@babel/types" "^7.25.4" + "@babel/types" "^7.26.0" "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.7": - version "7.25.4" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz" - integrity sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w== + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz" + integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.25.0": - version "7.25.0" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz" - integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.25.0" - "@babel/types" "^7.25.0" - -"@babel/traverse@^7.24.7": - version "7.25.4" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz" - integrity sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.4" - "@babel/parser" "^7.25.4" - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.4" +"@babel/template@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/traverse@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz" + integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/generator" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/template" "^7.25.9" + "@babel/types" "^7.25.9" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.4": - version "7.25.4" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz" - integrity sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ== +"@babel/types@^7.25.9", "@babel/types@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz" + integrity sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA== dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" "@emotion/babel-plugin@^11.12.0": version "11.12.0" @@ -158,14 +149,14 @@ hoist-non-react-statics "^3.3.1" "@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0", "@emotion/serialize@^1.3.1": - version "1.3.1" - resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz" - integrity sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA== + version "1.3.2" + resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz" + integrity sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA== dependencies: "@emotion/hash" "^0.9.2" "@emotion/memoize" "^0.9.0" "@emotion/unitless" "^0.10.0" - "@emotion/utils" "^1.4.0" + "@emotion/utils" "^1.4.1" csstype "^3.0.2" "@emotion/sheet@^1.4.0": @@ -195,20 +186,20 @@ resolved "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz" integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== -"@emotion/utils@^1.4.0": - version "1.4.0" - resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz" - integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ== +"@emotion/utils@^1.4.0", "@emotion/utils@^1.4.1": + version "1.4.1" + resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz" + integrity sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA== "@emotion/weak-memoize@^0.4.0": version "0.4.0" resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz" integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== -"@esbuild/darwin-arm64@0.21.5": +"@esbuild/win32-x64@0.21.5": version "0.21.5" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" @@ -242,6 +233,396 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@firebase/analytics-compat@0.2.15": + version "0.2.15" + resolved "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.15.tgz" + integrity sha512-C5to422Sr8FkL0MPwXcIecbMnF4o2Ll7MtoWvIm4Q/LPJvvM+tWa1DiU+LzsCdsd1/CYE9EIW9Ma3ko9XnAAYw== + dependencies: + "@firebase/analytics" "0.10.9" + "@firebase/analytics-types" "0.8.2" + "@firebase/component" "0.6.10" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/analytics-types@0.8.2": + version "0.8.2" + resolved "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.2.tgz" + integrity sha512-EnzNNLh+9/sJsimsA/FGqzakmrAUKLeJvjRHlg8df1f97NLUlFidk9600y0ZgWOp3CAxn6Hjtk+08tixlUOWyw== + +"@firebase/analytics@0.10.9": + version "0.10.9" + resolved "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.9.tgz" + integrity sha512-FrvW6u6xDBKXUGYUy1WIUh0J9tvbppMsk90mig0JhHST8iLveKu/dIBVeVE/ZYZhmXy4fkI7SPSWvD1V0O4tXw== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/installations" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/app-check-compat@0.3.16": + version "0.3.16" + resolved "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.16.tgz" + integrity sha512-AxIGzLRXrTFNL+H6V+4BO0w/gERloROfRbWI/FoJUnQd0qPZIzyfdHZBbThFzFGLfDt/mVs2kdjYFx/l9I8NhQ== + dependencies: + "@firebase/app-check" "0.8.9" + "@firebase/app-check-types" "0.5.2" + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/app-check-interop-types@0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz" + integrity sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ== + +"@firebase/app-check-types@0.5.2": + version "0.5.2" + resolved "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.2.tgz" + integrity sha512-FSOEzTzL5bLUbD2co3Zut46iyPWML6xc4x+78TeaXMSuJap5QObfb+rVvZJtla3asN4RwU7elaQaduP+HFizDA== + +"@firebase/app-check@0.8.9": + version "0.8.9" + resolved "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.9.tgz" + integrity sha512-YzVn1mMLzD2JboMPVVO0Pe20YOgWzrF+aXoAmmd0v3xec051n83YpxSUZbacL69uYvk0dHrEsbea44QtQ5WPDA== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/app-compat@0.2.45", "@firebase/app-compat@0.x": + version "0.2.45" + resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.45.tgz" + integrity sha512-5rYbXq1ndtMTg+07oH4WrkYuP+NZq61uzVwW1hlmybp/gr4cXq2SfaP9fc6/9IzTKmu3dh3H0fjj++HG7Z7o/w== + dependencies: + "@firebase/app" "0.10.15" + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/app-types@0.9.2", "@firebase/app-types@0.x": + version "0.9.2" + resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.2.tgz" + integrity sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ== + +"@firebase/app@0.10.15", "@firebase/app@0.x": + version "0.10.15" + resolved "https://registry.npmjs.org/@firebase/app/-/app-0.10.15.tgz" + integrity sha512-he6qlG3pmwL+LHdG/BrSMBQeJzzutciq4fpXN3lGa1uSwYSijJ24VtakS/bP2X9SiDf8jGywJ4u+OgXAenJsNg== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/auth-compat@0.5.15": + version "0.5.15" + resolved "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.15.tgz" + integrity sha512-jz6k1ridPiecKI8CBRiqCM6IMOhwYp2MD+YvoxnMiK8nQLSTm57GvHETlPNX3WlbyQnCjMCOvrAhe27whyxAEg== + dependencies: + "@firebase/auth" "1.8.0" + "@firebase/auth-types" "0.12.2" + "@firebase/component" "0.6.10" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/auth-interop-types@0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz" + integrity sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ== + +"@firebase/auth-types@0.12.2": + version "0.12.2" + resolved "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.2.tgz" + integrity sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w== + +"@firebase/auth@1.8.0": + version "1.8.0" + resolved "https://registry.npmjs.org/@firebase/auth/-/auth-1.8.0.tgz" + integrity sha512-/O7UDWE5S5ux456fzNHSLx/0YN/Kykw/WyAzgDQ6wvkddZhSEmPX19EzxgsFldzhuFjsl5uOZTz8kzlosCiJjg== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/component@0.6.10": + version "0.6.10" + resolved "https://registry.npmjs.org/@firebase/component/-/component-0.6.10.tgz" + integrity sha512-OsNbEKyz9iLZSmMUhsl6+kCADzte00iisJIRUspnUqvDCX+RSGZOBIqekukv/jN177ovjApBQNFaxSYIDc/SyQ== + dependencies: + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/data-connect@0.1.1": + version "0.1.1" + resolved "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.1.1.tgz" + integrity sha512-RBJ7XE/a3oXFv31Jlw8cbMRdsxQoI8F3L7xm4n93ab+bIr1NQUiYGgW9L7TTw7obdNev91ZnW0xfqJtXcPA5yA== + dependencies: + "@firebase/auth-interop-types" "0.2.3" + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/database-compat@2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.0.tgz" + integrity sha512-2xlODKWwf/vNAxCmou0GFhymx2pqZKkhXMN9B5aiTjZ6+81sOxGim53ELY2lj+qKG2IvgiCYFc4X+ZJA2Ad5vg== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/database" "1.0.9" + "@firebase/database-types" "1.0.6" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/database-types@1.0.6": + version "1.0.6" + resolved "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.6.tgz" + integrity sha512-sMI7IynSZBsyGbUugc8PKE1jwKbnvaieAz/RxuM57PZQNCi6Rteiviwcw/jqZOX6igqYJwXWZ3UzKOZo2nUDRA== + dependencies: + "@firebase/app-types" "0.9.2" + "@firebase/util" "1.10.1" + +"@firebase/database@1.0.9": + version "1.0.9" + resolved "https://registry.npmjs.org/@firebase/database/-/database-1.0.9.tgz" + integrity sha512-EkiPSKSu2TJJGtOjyISASf3UFpFJDil1lMbfqnxilfbmIsilvC8DzgjuLoYD+eOitcug4wtU9Fh1tt2vgBhskA== + dependencies: + "@firebase/app-check-interop-types" "0.3.2" + "@firebase/auth-interop-types" "0.2.3" + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + faye-websocket "0.11.4" + tslib "^2.1.0" + +"@firebase/firestore-compat@0.3.39": + version "0.3.39" + resolved "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.39.tgz" + integrity sha512-CsK8g34jNeHx95LISDRTcArJLonW+zJCqHI1Ez9WNiLAK2X8FeQ4UiD+RwOwxAIR+t2a6xED/5Fe6ZIqx7MuoQ== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/firestore" "4.7.4" + "@firebase/firestore-types" "3.0.2" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/firestore-types@3.0.2": + version "3.0.2" + resolved "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.2.tgz" + integrity sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg== + +"@firebase/firestore@4.7.4": + version "4.7.4" + resolved "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.4.tgz" + integrity sha512-K2nq4w+NF8J1waGawY5OHLawP/Aw5CYxyDstVv1NZemGPcM3U+LZ9EPaXr1PatYIrPA7fS4DxZoWcbB0aGJ8Zg== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + "@firebase/webchannel-wrapper" "1.0.2" + "@grpc/grpc-js" "~1.9.0" + "@grpc/proto-loader" "^0.7.8" + tslib "^2.1.0" + +"@firebase/functions-compat@0.3.15": + version "0.3.15" + resolved "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.15.tgz" + integrity sha512-eiHpc6Sd9Y/SNhBsGi944SapiFbfTPKsiSUQ74QxNSs0yoxvABeIRolVMFk4TokP57NGmstGYpYte02XGNPcYw== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/functions" "0.11.9" + "@firebase/functions-types" "0.6.2" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/functions-types@0.6.2": + version "0.6.2" + resolved "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.2.tgz" + integrity sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w== + +"@firebase/functions@0.11.9": + version "0.11.9" + resolved "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.9.tgz" + integrity sha512-dhO5IUfQRCsrc20YD20nSOX+QCT+cH6N86HlZOLz2XgyEFgzOdBQnUot4EabBJQRkMBI7fZWUrbYfRcnov53ug== + dependencies: + "@firebase/app-check-interop-types" "0.3.2" + "@firebase/auth-interop-types" "0.2.3" + "@firebase/component" "0.6.10" + "@firebase/messaging-interop-types" "0.2.2" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/installations-compat@0.2.10": + version "0.2.10" + resolved "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.10.tgz" + integrity sha512-YTonkcVz3AK7RF8xFhvs5CwDuJ0xbzzCJIwXoV14gnzdYbMgy6vWlUUbzkvbtEDXzPRHB0n7aGZl56oy9dLOFw== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/installations" "0.6.10" + "@firebase/installations-types" "0.5.2" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/installations-types@0.5.2": + version "0.5.2" + resolved "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.2.tgz" + integrity sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA== + +"@firebase/installations@0.6.10": + version "0.6.10" + resolved "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.10.tgz" + integrity sha512-TuGSOMqkFrllxa0X/8VZIqBCRH4POndU/iWKWkRmkh12+/xKSpdp+y/kWaVbsySrelltan6LeYlcYPmLibWbwg== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/util" "1.10.1" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/logger@0.4.3": + version "0.4.3" + resolved "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.3.tgz" + integrity sha512-Th42bWJg18EF5bJwhRosn2M/eYxmbWCwXZr4hHX7ltO0SE3QLrpgiMKeRBR/NW7vJke7i0n3i8esbCW2s93qBw== + dependencies: + tslib "^2.1.0" + +"@firebase/messaging-compat@0.2.13": + version "0.2.13" + resolved "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.13.tgz" + integrity sha512-9ootPClS6m2c2KIzo7AqSHaWzAw28zWcjQPjVv7WeQDu6wjufpbOg+7tuVzb+gqpF9Issa3lDoYOwlO0ZudO3g== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/messaging" "0.12.13" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/messaging-interop-types@0.2.2": + version "0.2.2" + resolved "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.2.tgz" + integrity sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA== + +"@firebase/messaging@0.12.13": + version "0.12.13" + resolved "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.13.tgz" + integrity sha512-YLa8PWl+BgiOVR5WOyzl21fVJFJeBRfniNuN25d9DBrQzppSAahuN6yS+vt1OIjvZNPN4pZ/lcRLYupbGu4W0w== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/installations" "0.6.10" + "@firebase/messaging-interop-types" "0.2.2" + "@firebase/util" "1.10.1" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/performance-compat@0.2.10": + version "0.2.10" + resolved "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.10.tgz" + integrity sha512-0h1qYkF6I79DSSpHfTQFvb91fo8shmmwiPzWFYAPdPK02bSWpKwVssNYlZX2iUnumxerDMbl7dWN+Im/W3bnXA== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/performance" "0.6.10" + "@firebase/performance-types" "0.2.2" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/performance-types@0.2.2": + version "0.2.2" + resolved "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.2.tgz" + integrity sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA== + +"@firebase/performance@0.6.10": + version "0.6.10" + resolved "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.10.tgz" + integrity sha512-x/mNYKGxq7A+QV0EiEZeD2S+E+kw+UcZ8FXuE7qDJyGGt/0Wd+bIIL7RakG/VrFt7/UYc//nKygDc7/Ig7sOmQ== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/installations" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/remote-config-compat@0.2.10": + version "0.2.10" + resolved "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.10.tgz" + integrity sha512-fIi5OB2zk0zpChMV/tTd0oEZcZI8TlwQDlLlcrDpMOV5l5dqd0JNlWKh6Fwmh4izmytk+rZIAIpnak/NjGVesQ== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/remote-config" "0.4.10" + "@firebase/remote-config-types" "0.3.2" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/remote-config-types@0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.2.tgz" + integrity sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA== + +"@firebase/remote-config@0.4.10": + version "0.4.10" + resolved "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.10.tgz" + integrity sha512-jTRjy3TdqzVna19m5a1HEHE5BG4Z3BQTxBgvQRTmMKlHacx4QS0CToAas7R9M9UkxpgFcVuAE7FpWIOWQGCEWw== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/installations" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/storage-compat@0.3.13": + version "0.3.13" + resolved "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.13.tgz" + integrity sha512-15kje7JALswRCBKsCSvKg5FbqUYykaIMqMbZRD7I6uVRWwdyTvez5MBQfMhBia2JcEmPiDpXhJTXH4PAWFiA8g== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/storage" "0.13.3" + "@firebase/storage-types" "0.8.2" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/storage-types@0.8.2": + version "0.8.2" + resolved "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2.tgz" + integrity sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g== + +"@firebase/storage@0.13.3": + version "0.13.3" + resolved "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.3.tgz" + integrity sha512-B5HiJ7isYKaT4dOEV43f2ySdhQxzq+SQEm7lqXebJ8AYCsebdHrgGzrPR0LR962xGjPzJHFKx63gA8Be/P2MCw== + dependencies: + "@firebase/component" "0.6.10" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/util@1.10.1", "@firebase/util@1.x": + version "1.10.1" + resolved "https://registry.npmjs.org/@firebase/util/-/util-1.10.1.tgz" + integrity sha512-AIhFnCCjM8FmCqSNlNPTuOk3+gpHC1RkeNUBLtPbcqGYpN5MxI5q7Yby+rxycweOZOCboDzfIj8WyaY4tpQG/g== + dependencies: + tslib "^2.1.0" + +"@firebase/vertexai@1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.0.0.tgz" + integrity sha512-48N3Lp/9GgiCCRfrSdHS+Y1IiMdYXvnHFO/f+HL1PgUtBq7WQ/fWmYOX3mzAN36zvytq13nb68ImF+GALopp+Q== + dependencies: + "@firebase/app-check-interop-types" "0.3.2" + "@firebase/component" "0.6.10" + "@firebase/logger" "0.4.3" + "@firebase/util" "1.10.1" + tslib "^2.1.0" + +"@firebase/webchannel-wrapper@1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.2.tgz" + integrity sha512-3F4iA2E+NtdMbOU0XC1cHE8q6MqpGIKRj62oGOF38S6AAx5VHR9cXmoDUSj7ejvTAT7m6jxuEeQkHeq0F+mU2w== + "@floating-ui/core@^1.6.0": version "1.6.7" resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz" @@ -279,6 +660,24 @@ resolved "https://registry.npmjs.org/@fontsource/barlow/-/barlow-5.0.14.tgz" integrity sha512-4F+rbfklgWHatFheB3ZQgTFjkqzMiWfHomy69TWSGc0qU+w+QhX9dGz7IVQRksvKciJoXAhxijCxwAJw418g4Q== +"@grpc/grpc-js@~1.9.0": + version "1.9.15" + resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz" + integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ== + dependencies: + "@grpc/proto-loader" "^0.7.8" + "@types/node" ">=12.12.47" + +"@grpc/proto-loader@^0.7.8": + version "0.7.13" + resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz" @@ -425,9 +824,9 @@ prop-types "^15.8.1" "@mui/types@^7.2.14", "@mui/types@^7.2.15": - version "7.2.15" - resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz" - integrity sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q== + version "7.2.19" + resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz" + integrity sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA== "@mui/utils@^5.15.14", "@mui/utils@^5.16.5", "@mui/utils@^5.16.6": version "5.16.6" @@ -462,6 +861,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@paystack/inline-js@^2.22.1": + version "2.22.1" + resolved "https://registry.npmjs.org/@paystack/inline-js/-/inline-js-2.22.1.tgz" + integrity sha512-h9cf+3UbFY/+/GRA5XeWj769KaSHuedqIcuYDdV6voKGnwF9qcmJ3BorpIST45Y3qVXljOXsexL2tS6GZXJbmg== + "@pkgr/core@^0.1.0": version "0.1.1" resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz" @@ -472,20 +876,73 @@ resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@remix-run/router@1.19.1": version "1.19.1" resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz" integrity sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg== -"@rollup/rollup-darwin-arm64@4.21.0": +"@rollup/rollup-win32-x64-msvc@4.21.0": version "4.21.0" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz" - integrity sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA== + resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz" + integrity sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ== -"@swc/core-darwin-arm64@1.7.14": +"@swc/core-win32-x64-msvc@1.7.14": version "1.7.14" - resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.14.tgz" - integrity sha512-V0OUXjOH+hdGxDYG8NkQzy25mKOpcNKFpqtZEzLe5V/CpLJPnpg1+pMz70m14s9ZFda9OxsjlvPbg1FLUwhgIQ== + resolved "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.14.tgz" + integrity sha512-NNrprQCK6d28mG436jVo2TD+vACHseUECacEBGZ9Ef0qfOIWS1XIt2MisQKG0Oea2VvLFl6tF/V4Lnx/H0Sn3Q== "@swc/core@^1.5.7": version "1.7.14" @@ -518,6 +975,16 @@ dependencies: "@swc/counter" "^0.1.3" +"@types/bcryptjs@^2.4.6": + version "2.4.6" + resolved "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz" + integrity sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ== + +"@types/crypto-js@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz" + integrity sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ== + "@types/estree@1.0.5": version "1.0.5" resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz" @@ -540,7 +1007,7 @@ resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz" integrity sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA== -"@types/node@^18.0.0 || >=20.0.0", "@types/node@^22.5.0": +"@types/node@^18.0.0 || >=20.0.0", "@types/node@^22.5.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0": version "22.5.0" resolved "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz" integrity sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg== @@ -552,10 +1019,15 @@ resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz" integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== +"@types/paystack__inline-js@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@types/paystack__inline-js/-/paystack__inline-js-1.0.0.tgz" + integrity sha512-LCU5rSBs3FAG8tkn1hgV9FHTTRk+Kj2s/DupNlJRem5NaVabj6AASjWJ9tBtJX6dt7bcKhkf8c5MzgJUkpOG2g== + "@types/prop-types@*", "@types/prop-types@^15.7.12": - version "15.7.12" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz" - integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + version "15.7.13" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz" + integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== "@types/react-dom@^18.3.0": version "18.3.0" @@ -571,7 +1043,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^17.0.0 || ^18.0.0", "@types/react@^18.3.4": +"@types/react@*", "@types/react@^17.0.0 || ^18.0.0", "@types/react@^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react@^18.3.4": version "18.3.4" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz" integrity sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw== @@ -709,12 +1181,12 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: - color-convert "^1.9.0" + color-convert "^2.0.1" ansi-styles@^4.1.0: version "4.3.0" @@ -887,6 +1359,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bcryptjs@^2.4.3: + version "2.4.3" + resolved "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz" + integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" @@ -930,15 +1407,6 @@ callsites@^3.0.0: resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - chalk@^4.0.0: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" @@ -970,18 +1438,20 @@ chokidar@^3.5.1: optionalDependencies: fsevents "~2.3.2" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clsx@^2.1.0, clsx@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" @@ -994,11 +1464,6 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - commander@^8.0.0: version "8.3.0" resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz" @@ -1039,6 +1504,11 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + csstype@^3.0.2, csstype@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" @@ -1170,6 +1640,11 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + emoji-regex@^9.2.2: version "9.2.2" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" @@ -1350,10 +1825,10 @@ esbuild@^0.21.3: "@esbuild/win32-ia32" "0.21.5" "@esbuild/win32-x64" "0.21.5" -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^4.0.0: version "4.0.0" @@ -1651,6 +2126,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +faye-websocket@0.11.4: + version "0.11.4" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" @@ -1678,6 +2160,40 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" +firebase@^11.0.1: + version "11.0.1" + resolved "https://registry.npmjs.org/firebase/-/firebase-11.0.1.tgz" + integrity sha512-qsFb8dMcQINEDhJteG7RP+GqwgSRvfyiexQqHd5JToDdm87i9I2rGC4XQsGawKGxzKwZ/ISdgwNWxXAFYdCC6A== + dependencies: + "@firebase/analytics" "0.10.9" + "@firebase/analytics-compat" "0.2.15" + "@firebase/app" "0.10.15" + "@firebase/app-check" "0.8.9" + "@firebase/app-check-compat" "0.3.16" + "@firebase/app-compat" "0.2.45" + "@firebase/app-types" "0.9.2" + "@firebase/auth" "1.8.0" + "@firebase/auth-compat" "0.5.15" + "@firebase/data-connect" "0.1.1" + "@firebase/database" "1.0.9" + "@firebase/database-compat" "2.0.0" + "@firebase/firestore" "4.7.4" + "@firebase/firestore-compat" "0.3.39" + "@firebase/functions" "0.11.9" + "@firebase/functions-compat" "0.3.15" + "@firebase/installations" "0.6.10" + "@firebase/installations-compat" "0.2.10" + "@firebase/messaging" "0.12.13" + "@firebase/messaging-compat" "0.2.13" + "@firebase/performance" "0.6.10" + "@firebase/performance-compat" "0.2.10" + "@firebase/remote-config" "0.4.10" + "@firebase/remote-config-compat" "0.2.10" + "@firebase/storage" "0.13.3" + "@firebase/storage-compat" "0.3.13" + "@firebase/util" "1.10.1" + "@firebase/vertexai" "1.0.0" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" @@ -1712,11 +2228,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -1737,6 +2248,11 @@ functions-have-names@^1.2.3: resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" @@ -1850,11 +2366,6 @@ has-bigints@^1.0.1, has-bigints@^1.0.2: resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - has-flag@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" @@ -1905,6 +2416,16 @@ hoist-non-react-statics@^3.3.1: dependencies: react-is "^16.7.0" +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +idb@7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz" + integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== + ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" @@ -2040,6 +2561,11 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-generator-function@^1.0.10: version "1.0.10" resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz" @@ -2175,10 +2701,10 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== json-parse-even-better-errors@^2.3.0: version "2.3.1" @@ -2221,6 +2747,11 @@ jsonfile@^6.0.1: object.assign "^4.1.4" object.values "^1.1.6" +jwt-decode@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz" + integrity sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA== + language-subtag-registry@^0.3.20: version "0.3.23" resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz" @@ -2258,6 +2789,11 @@ lodash-es@^4.17.21: resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" @@ -2268,6 +2804,11 @@ lodash@^4.17.21: resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +long@^5.0.0: + version "5.2.3" + resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -2507,9 +3048,9 @@ path-type@^4.0.0: integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== picocolors@^1.0.0, picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" @@ -2556,6 +3097,24 @@ prop-types@^15.6.2, prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +protobufjs@^7.2.5: + version "7.4.0" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + punycode@^2.1.0: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" @@ -2677,6 +3236,11 @@ regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.1" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" @@ -2759,6 +3323,11 @@ safe-array-concat@^1.1.2: has-symbols "^1.0.3" isarray "^2.0.5" +safe-buffer@>=5.1.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz" @@ -2877,6 +3446,15 @@ stop-iteration-iterator@^1.0.0: dependencies: internal-slot "^1.0.4" +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string.prototype.includes@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz" @@ -2961,13 +3539,6 @@ stylis@4.2.0: resolved "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz" integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" @@ -3058,11 +3629,6 @@ tiny-invariant@^1.1.0: resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz" integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" @@ -3085,7 +3651,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.6.2: +tslib@^2.1.0, tslib@^2.6.2: version "2.6.3" resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== @@ -3258,6 +3824,20 @@ vscode-uri@^3.0.2: resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz" integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== +websocket-driver@>=0.5.1: + version "0.7.4" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" @@ -3315,16 +3895,48 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yaml@^1.10.0: version "1.10.2" resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" From 138585c33c66ff37d93a39703f1c51cc1aa11e96 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 22 Nov 2024 22:12:47 +0000 Subject: [PATCH 02/20] feat: integrated firebase --- .firebaserc | 5 + .github/workflows/firebase-hosting-merge.yml | 20 ++++ .../firebase-hosting-pull-request.yml | 21 +++++ firebase.json | 10 ++ public/404.html | 33 +++++++ public/index.html | 89 ++++++++++++++++++ src/_mock/_data.ts | 2 +- src/components/provider/index.tsx | 1 - .../shared/modals/contributeForm.tsx | 76 +++++++++++---- src/configs/firebase.ts | 27 +++--- src/constants/fxns.ts | 1 + src/hooks/useUser.ts | 10 +- src/pages/home.tsx | 5 - src/routes/sections.tsx | 8 +- .../contributions/contributions-table-row.tsx | 2 +- .../contributions/view/contributions-view.tsx | 4 +- .../overview/analytics-widget-summary.tsx | 2 +- .../overview/view/{index.ts => index.tsx} | 0 .../overview/view/overview-analytics-view.tsx | 92 ++++++++++++++++--- src/services/cont/contribute.dto.ts | 28 ++++++ src/services/cont/index.ts | 36 ++++++++ src/services/pay/index.ts | 7 +- src/services/pay/pay.dto.ts | 1 + src/services/stats/index.ts | 9 ++ src/services/stats/stats.dto.ts | 5 + src/utils/fstore.ts | 10 +- 26 files changed, 445 insertions(+), 59 deletions(-) create mode 100644 .firebaserc create mode 100644 .github/workflows/firebase-hosting-merge.yml create mode 100644 .github/workflows/firebase-hosting-pull-request.yml create mode 100644 firebase.json create mode 100644 public/404.html create mode 100644 public/index.html rename src/sections/overview/view/{index.ts => index.tsx} (100%) create mode 100644 src/services/cont/contribute.dto.ts create mode 100644 src/services/cont/index.ts create mode 100644 src/services/stats/index.ts create mode 100644 src/services/stats/stats.dto.ts diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 000000000..e156400e6 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "pabgm-39720" + } +} diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml new file mode 100644 index 000000000..886402797 --- /dev/null +++ b/.github/workflows/firebase-hosting-merge.yml @@ -0,0 +1,20 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on merge +on: + push: + branches: + - main +jobs: + build_and_deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm ci && npm run build + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: ${{ secrets.GITHUB_TOKEN }} + firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_PABGM_39720 }} + channelId: live + projectId: pabgm-39720 diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml new file mode 100644 index 000000000..710d7aebd --- /dev/null +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -0,0 +1,21 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on PR +on: pull_request +permissions: + checks: write + contents: read + pull-requests: write +jobs: + build_and_preview: + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm ci && npm run build + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: ${{ secrets.GITHUB_TOKEN }} + firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_PABGM_39720 }} + projectId: pabgm-39720 diff --git a/firebase.json b/firebase.json new file mode 100644 index 000000000..e78293923 --- /dev/null +++ b/firebase.json @@ -0,0 +1,10 @@ +{ + "hosting": { + "public": "public", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ] + } +} diff --git a/public/404.html b/public/404.html new file mode 100644 index 000000000..829eda8fd --- /dev/null +++ b/public/404.html @@ -0,0 +1,33 @@ + + + + + + Page Not Found + + + + +
+

404

+

Page Not Found

+

The specified file was not found on this website. Please check the URL for mistakes and try again.

+

Why am I seeing this?

+

This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html file in your project's configured public directory.

+
+ + diff --git a/public/index.html b/public/index.html new file mode 100644 index 000000000..0ebc2eb15 --- /dev/null +++ b/public/index.html @@ -0,0 +1,89 @@ + + + + + + Welcome to Firebase Hosting + + + + + + + + + + + + + + + + + + + +
+

Welcome

+

Firebase Hosting Setup Complete

+

You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!

+ Open Hosting Documentation +
+

Firebase SDK Loading…

+ + + + diff --git a/src/_mock/_data.ts b/src/_mock/_data.ts index 0b59c6e84..872771b0f 100644 --- a/src/_mock/_data.ts +++ b/src/_mock/_data.ts @@ -72,7 +72,7 @@ export const _contributions: ContributionProps[] = [...Array(24)].map((_, index) sender: { id: `${_id(index)}'2'`, name: _fullName(index) }, months: _months(Math.ceil(Math.random() * 3)), status: index % 4 ? 'success' : 'failed', - timestamp: new Date().toISOString(), + timestamp: new Date(), amount: _amount(), })); diff --git a/src/components/provider/index.tsx b/src/components/provider/index.tsx index 03bf37f90..694e12898 100644 --- a/src/components/provider/index.tsx +++ b/src/components/provider/index.tsx @@ -16,7 +16,6 @@ const AppProvider = ({ children }: { children: ReactNode }) => { const fetchUser = useCallback(async () => { try { const res = await UserService.me(); - console.log('USER>>>', res); if (res) { setUser(res); } diff --git a/src/components/shared/modals/contributeForm.tsx b/src/components/shared/modals/contributeForm.tsx index 00fdf9e05..a1a8fc4e4 100644 --- a/src/components/shared/modals/contributeForm.tsx +++ b/src/components/shared/modals/contributeForm.tsx @@ -1,22 +1,24 @@ -import React, { useState, ChangeEvent, FormEvent } from 'react'; +import { LoadingButton } from '@mui/lab'; import { - Modal, - Box, - Typography, - TextField, - Button, Autocomplete, + Box, Chip, IconButton, Link, + Modal, + TextField, + Typography, } from '@mui/material'; +import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react'; import { Iconify } from 'src/components/iconify'; +import useUser from 'src/hooks/useUser'; +import PayService from 'src/services/pay'; const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; interface PaymentFormModalProps { open: boolean; - amount: string; + amount?: string; handleClose: () => void; } @@ -25,24 +27,46 @@ const PaymentFormModal: React.FC = ({ amount: pledge, handleClose, }) => { - const [amount, setAmount] = useState(pledge); + const { user } = useUser(); + + const [amount, setAmount] = useState(user?.pledgeAmount ?? pledge ?? ''); const [selectedMonths, setSelectedMonths] = useState([]); + const [loading, setLoading] = useState(false); const handleAmountChange = (event: ChangeEvent) => { setAmount(event.target.value); }; - const handleSubmit = (event: FormEvent) => { + const handleSubmit = async (event: FormEvent) => { + setLoading(true); event.preventDefault(); - console.log('Amount:', amount); - console.log('Selected Months:', selectedMonths); + await PayService.init(amount, selectedMonths); + closeModal(); + setLoading(false); + }; + + const closeModal = () => { + setAmount(''); + setSelectedMonths([]); handleClose(); }; + useEffect(() => { + setAmount(user?.pledgeAmount ?? ''); + }, [user?.pledgeAmount]); + + useEffect(() => { + if (open) { + setAmount(user?.pledgeAmount ?? ''); + } + }, [open, user?.pledgeAmount]); + + const hasValues = !!amount && !!selectedMonths.length; + return ( @@ -69,13 +93,25 @@ const PaymentFormModal: React.FC = ({ Contribute + {!!selectedMonths.length && amount && ( + + You are making a contribution of{' '} + + GHS{amount} + {' '} + for{' '} + + {selectedMonths.join(', ')} + + + )}
= ({ onChange={(event, newValue) => setSelectedMonths(newValue)} renderTags={(value, getTagProps) => value.map((option, index) => ( - + )) } renderInput={(params) => ( @@ -97,15 +133,21 @@ const PaymentFormModal: React.FC = ({ {...params} label="Select Months" placeholder="Choose one or more months" - required /> )} sx={{ mb: 3 }} /> - +
diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index 3c8c65728..91902fbed 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -1,20 +1,22 @@ // Import the functions you need from the SDKs you need import { initializeApp } from 'firebase/app'; -import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'; -import { connectFunctionsEmulator, getFunctions, httpsCallable } from 'firebase/functions'; import { - getAuth, - createUserWithEmailAndPassword, - signInWithEmailAndPassword, - signOut, - sendPasswordResetEmail, + User, confirmPasswordReset, connectAuthEmulator, + createUserWithEmailAndPassword, + getAuth, onAuthStateChanged, - User, + sendPasswordResetEmail, + signInWithEmailAndPassword, + signOut, } from 'firebase/auth'; +import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'; +import { connectFunctionsEmulator, getFunctions, httpsCallable } from 'firebase/functions'; +import { ApiRoute } from '../constants/fxns'; -const USE_EMULATORS = true; + +const USE_EMULATORS = false; const firebaseConfig = { apiKey: 'AIzaSyDY-1FezjbzGmq1j3WHWurbniF3IIdYmEY', @@ -56,9 +58,9 @@ const db = getFirestore(app); const fxns = getFunctions(app); const fx = { - async call(path: string, data: T) { + async call(path: ApiRoute, data?: T) { const callable = httpsCallable(fxns, path); - const result = await callable(data); + const result = await callable(data??null); return result.data; }, }; @@ -74,4 +76,5 @@ const runEmulators = (val: boolean = USE_EMULATORS) => { runEmulators(); -export { app, db, auth, fx }; +export { app, auth, db, fx }; + diff --git a/src/constants/fxns.ts b/src/constants/fxns.ts index 0bd8bbd01..be4d65129 100644 --- a/src/constants/fxns.ts +++ b/src/constants/fxns.ts @@ -3,4 +3,5 @@ export enum ApiRoute { InitPayment = 'initPay', PaymentHook = 'payHook', GetUser = 'getUser', + GetStats = 'getStats' } diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts index 26d523981..20b40511e 100644 --- a/src/hooks/useUser.ts +++ b/src/hooks/useUser.ts @@ -1,9 +1,15 @@ -import { useContext } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { UserContext } from 'src/components/provider'; const useUser = () => { const data = useContext(UserContext); - return data; + const [userContext, setUserContext] = useState(data); + + useEffect(() => { + setUserContext(data); + }, [data]); + + return userContext; }; export default useUser; diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 26d612b38..35e7cc892 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -1,11 +1,6 @@ -import { Fab } from '@mui/material'; -import { useEffect } from 'react'; import { Helmet } from 'react-helmet-async'; -import { Iconify } from 'src/components/iconify'; import { CONFIG } from 'src/config-global'; -import { fx } from 'src/configs'; - import { OverviewAnalyticsView } from 'src/sections/overview/view'; // ---------------------------------------------------------------------- diff --git a/src/routes/sections.tsx b/src/routes/sections.tsx index 48c3757b8..0325a5447 100644 --- a/src/routes/sections.tsx +++ b/src/routes/sections.tsx @@ -10,6 +10,7 @@ import PaymentFormModal from 'src/components/shared/modals/contributeForm'; import { AuthLayout } from 'src/layouts/auth'; import { DashboardLayout } from 'src/layouts/dashboard'; import { varAlpha } from 'src/theme/styles'; +import useUser from 'src/hooks/useUser'; const AppProvider = lazy(() => import('src/components/provider')); @@ -40,6 +41,7 @@ const renderFallback = ( ); export function Router() { + const { user } = useUser(); const [open, setOpen] = useState(false); const onOpen = () => { @@ -76,7 +78,11 @@ export function Router() { - + {contributeBtn} diff --git a/src/sections/contributions/contributions-table-row.tsx b/src/sections/contributions/contributions-table-row.tsx index a9ddfd34e..16c907d40 100644 --- a/src/sections/contributions/contributions-table-row.tsx +++ b/src/sections/contributions/contributions-table-row.tsx @@ -21,7 +21,7 @@ export type ContributionProps = { name: string; }; amount: string; - timestamp: string; + timestamp: Date; status: 'pending' | 'success' | 'failed'; months: string[]; }; diff --git a/src/sections/contributions/view/contributions-view.tsx b/src/sections/contributions/view/contributions-view.tsx index 4f0d61bc5..9854fb6d4 100644 --- a/src/sections/contributions/view/contributions-view.tsx +++ b/src/sections/contributions/view/contributions-view.tsx @@ -32,6 +32,7 @@ interface ContributionsViewProps { hideBtn?: boolean; title?: string; noPagination?: boolean; + data?:ContributionProps[] } export function ContributionsView({ @@ -41,13 +42,14 @@ export function ContributionsView({ hideBtn, noPagination, title = 'Contributions', + data = [] }: ContributionsViewProps) { const table = useTable(); const [filterName, setFilterName] = useState(''); const dataFiltered: ContributionProps[] = applyFilter({ - inputData: _contributions, + inputData: data, comparator: getComparator(table.order, table.orderBy), filterName, }); diff --git a/src/sections/overview/analytics-widget-summary.tsx b/src/sections/overview/analytics-widget-summary.tsx index 43ca3decd..71e623b40 100644 --- a/src/sections/overview/analytics-widget-summary.tsx +++ b/src/sections/overview/analytics-widget-summary.tsx @@ -18,7 +18,7 @@ import { Chart, useChart } from 'src/components/chart'; type Props = CardProps & { title: string; - total: number; + total: number|string; percent?: number; color?: ColorType; icon: React.ReactNode; diff --git a/src/sections/overview/view/index.ts b/src/sections/overview/view/index.tsx similarity index 100% rename from src/sections/overview/view/index.ts rename to src/sections/overview/view/index.tsx diff --git a/src/sections/overview/view/overview-analytics-view.tsx b/src/sections/overview/view/overview-analytics-view.tsx index cd5f0dea1..880956d23 100644 --- a/src/sections/overview/view/overview-analytics-view.tsx +++ b/src/sections/overview/view/overview-analytics-view.tsx @@ -3,14 +3,84 @@ import Grid from '@mui/material/Unstable_Grid2'; import { DashboardContent } from 'src/layouts/dashboard'; +import { Box, LinearProgress, linearProgressClasses } from '@mui/material'; +import { useCallback, useEffect, useState } from 'react'; import useUser from 'src/hooks/useUser'; +import { ContributionProps } from 'src/sections/contributions/contributions-table-row'; import { ContributionsView } from 'src/sections/contributions/view'; +import ContributionService from 'src/services/cont'; +import { Contribution, ContributionStatus } from 'src/services/cont/contribute.dto'; +import StatsService from 'src/services/stats'; +import { Stats } from 'src/services/stats/stats.dto'; +import { UserRole } from 'src/services/user/user.dto'; +import { varAlpha } from 'src/theme/styles'; +import { errCb } from 'src/utils'; import { AnalyticsWidgetSummary } from '../analytics-widget-summary'; // ---------------------------------------------------------------------- export function OverviewAnalyticsView() { const { user } = useUser(); + const [loading, setLoading] = useState(true) + const [data, setData] = useState<{stats:Stats,cons:ContributionProps[]}>() + + const getStatus = (status: ContributionStatus):ContributionProps['status'] => { + if(status===ContributionStatus.Failed)return 'failed' + if(status === ContributionStatus.Pending) return 'pending' + return 'success' + } + + const getContributions = useCallback((result:Contribution[]):ContributionProps[] => result.map(item=> + ({ + amount:item.amount, + id: item.id, + months: item.months, + sender: item.donor, + status: getStatus(item.status), + timestamp: (item.completedAt||item.createdAt).toDate() + + })),[]) + + const init = useCallback(async () => { + try { + if(!user?.id) return + const isAdmin = user.role.includes(UserRole.Admin) + const [stats,cons] = await Promise.all([ + StatsService.get(), + isAdmin + ? ContributionService.getAllLatest() + : ContributionService.getByUserId(user?.id!) + ]) + setData({ + stats, + cons:getContributions(cons) + }) + } catch (error) { + errCb(error.message) + }finally{ + setLoading(false) + } + + },[user?.id,user?.role, getContributions]) + + useEffect(() => { + init() + }, [init]) + + if(loading){ + return + varAlpha(theme.vars.palette.text.primaryChannel, 0.16), + [`& .${linearProgressClasses.bar}`]: { bgcolor: 'text.primary' }, + }} + /> + + } + + return ( @@ -18,11 +88,10 @@ export function OverviewAnalyticsView() { - + } chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], @@ -31,11 +100,10 @@ export function OverviewAnalyticsView() { /> - + } chart={{ @@ -45,11 +113,10 @@ export function OverviewAnalyticsView() { /> - + } chart={{ @@ -59,7 +126,7 @@ export function OverviewAnalyticsView() { /> - + {/* - + */} {/* diff --git a/src/services/cont/contribute.dto.ts b/src/services/cont/contribute.dto.ts new file mode 100644 index 000000000..20c911d82 --- /dev/null +++ b/src/services/cont/contribute.dto.ts @@ -0,0 +1,28 @@ +import { Timestamp } from "firebase/firestore"; + +export enum ContributionStatus { + Pending = "PENDING", + Failed = "FAILED", + Success = "COMPLETED", +} + +export interface Contribution { + id: string; + months: string[]; + amount: string; + status: ContributionStatus; + trxRef: string; + createdAt: Timestamp; + modifiedAt: Timestamp | null; + completedAt: Timestamp | null; + donor: { + name: string; + id: string; + }; +} + +export interface CreateContributionParams { + amount: string; + months: string[]; + donor: Contribution["donor"]; +} diff --git a/src/services/cont/index.ts b/src/services/cont/index.ts new file mode 100644 index 000000000..e048782d9 --- /dev/null +++ b/src/services/cont/index.ts @@ -0,0 +1,36 @@ +import { getDoc, getDocs, limit, query, where } from "firebase/firestore"; +import { Collection } from "src/constants"; +import { colRef, docRef } from "src/utils"; +import { Contribution, ContributionStatus } from "./contribute.dto"; + +export default class ContributionService { + static async getByUserId(id:string,count=12){ + console.log('ID:>>',id) + const ref = colRef(Collection.Contributions); + const q = query(ref,where('donor.id','==',id), limit(count)) + const docs = await getDocs(q) + const data:Contribution[] = [] + docs.forEach(doc=>{ + data.push(doc.data() as Contribution) + }) + return data + } + + static async get(id: string): Promise { + const ref = docRef(id, Collection.Contributions); + const docRes = await getDoc(ref); + return docRes.data() as Contribution; + } + + static async getAllLatest(){ + const ref = colRef(Collection.Contributions); + const q = query(ref, limit(12)) + const docs = await getDocs(q) + const data:Contribution[] = [] + docs.forEach(doc=>{ + data.push(doc.data() as Contribution) + }) + return data + } + +} \ No newline at end of file diff --git a/src/services/pay/index.ts b/src/services/pay/index.ts index 87e7ac80f..63a25c2c0 100644 --- a/src/services/pay/index.ts +++ b/src/services/pay/index.ts @@ -5,9 +5,12 @@ import { errCb } from 'src/utils'; import { ContributeInit } from './pay.dto'; export default class PayService { - static async init(amount: string | null = null) { + static async init(amount: string, months: string[]) { try { - const res = await fx.call(ApiRoute.InitPayment, { amount }); + const res = await fx.call(ApiRoute.InitPayment, { + amount, + months, + }); const popup = new PaystackPop(); popup.resumeTransaction(res.code as any); } catch (error) { diff --git a/src/services/pay/pay.dto.ts b/src/services/pay/pay.dto.ts index d639a6094..37c7bc515 100644 --- a/src/services/pay/pay.dto.ts +++ b/src/services/pay/pay.dto.ts @@ -1,3 +1,4 @@ export interface ContributeInit { amount: string | null; + months: string[]; } diff --git a/src/services/stats/index.ts b/src/services/stats/index.ts new file mode 100644 index 000000000..4ea52fcd1 --- /dev/null +++ b/src/services/stats/index.ts @@ -0,0 +1,9 @@ +import { fx } from "src/configs"; +import { ApiRoute } from "src/constants/fxns"; +import { Stats } from "./stats.dto"; + +export default class StatsService { + static async get(){ + return fx.call(ApiRoute.GetStats) + } +} \ No newline at end of file diff --git a/src/services/stats/stats.dto.ts b/src/services/stats/stats.dto.ts new file mode 100644 index 000000000..65e94fbed --- /dev/null +++ b/src/services/stats/stats.dto.ts @@ -0,0 +1,5 @@ +export interface Stats { + partnersCount: number; + contributionCount: number; + totalAmount: number; +} diff --git a/src/utils/fstore.ts b/src/utils/fstore.ts index 97e8c7f7d..8c1b265d8 100644 --- a/src/utils/fstore.ts +++ b/src/utils/fstore.ts @@ -1,7 +1,11 @@ -import { doc } from 'firebase/firestore'; +import { doc, collection } from 'firebase/firestore'; import { db } from 'src/configs'; import { Collection } from 'src/constants/factory'; -export function docRef(id: string, collection: Collection) { - return doc(db, collection, id); +export function docRef(id: string, col: Collection) { + return doc(db, col, id); +} + +export function colRef(col:Collection){ + return collection(db,col) } From d42d97b9cdadd600484cd9dfaa06fffaa9020d41 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 29 Nov 2024 18:17:24 +0000 Subject: [PATCH 03/20] fix: removed chart series --- .firebase/hosting.ZGlzdA.cache | 159 ++++++++++++++++++ .firebase/hosting.cHVibGlj.cache | 109 ++++++++++++ apphosting.yaml | 23 +++ firebase.json | 10 -- index.html | 2 +- package.json | 1 + .../shared/modals/contributeForm.tsx | 16 +- src/sections/auth/sign-in-view.tsx | 6 + .../contributions/view/contributions-view.tsx | 2 +- .../overview/analytics-widget-summary.tsx | 38 ++--- .../overview/view/overview-analytics-view.tsx | 6 +- src/services/pay/index.ts | 2 + 12 files changed, 335 insertions(+), 39 deletions(-) create mode 100644 .firebase/hosting.ZGlzdA.cache create mode 100644 .firebase/hosting.cHVibGlj.cache create mode 100644 apphosting.yaml delete mode 100644 firebase.json diff --git a/.firebase/hosting.ZGlzdA.cache b/.firebase/hosting.ZGlzdA.cache new file mode 100644 index 000000000..139fd03b1 --- /dev/null +++ b/.firebase/hosting.ZGlzdA.cache @@ -0,0 +1,159 @@ +index.html,1732573423511,6a1a513b2cba7f7d510760a76eb738caef581b43b797367919dbcf59d2ee508b +favicon.ico,1731094223321,165f2ac821b2a5b2a1638fb8f984164fe22bb8ddab1783942510fe9c594d3b16 +404.html,1732313404551,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 +assets/user-zXaFnVpQ.js,1732573423489,138161701d7bd218f52caa64b2db610b32b09af6c505079168b6c46c0466f683 +assets/TableSortLabel-DqBlcVe1.js,1732573423511,92fb8891453885d55f44466a71fcb21fc5689d604ca8232cb0cf6bd21c9f8d84 +assets/sign-in-Di3yP3uF.js,1732573423489,bc404428cbeb8ee886e749452c67af345e8a424026ae057bd0d6b89e0fce714f +assets/products-BXKsuEoz.js,1732573423511,2991d0f7f2ed8f9434e957ab235fef3d5808a91f8bbcfdb2f46be84675d07b9d +assets/Pagination-BWfUqI6R.js,1732573423510,8fab4191999b8a7b539d3dbe64d522f911021ff1135cedbb8092a52780938053 +assets/page-not-found-D1Yz5ywM.js,1732573423488,7863d2aa3ccfeee39489de883b46f1dab4531f1c77b81665ac00f84a668d52e5 +assets/logout-E8j7iOph.js,1732573423510,57e97312036a7b1f5d293ca372b6da5e05bba9bf559bbd4a4adc41e3dc564488 +assets/LastPage-Dsj5-nL2.js,1732573423492,1b9eb0baa4388d79b3659025efbdf483a17b3af8aad1ce1f8c73fcb7cda3b54a +assets/label-C1HB5QEr.js,1732573423511,079e073948e0c340fe33033547c56e4c46476c5924dcea5033d72e57862bf96b +assets/InputAdornment-CD3_vGQ1.js,1732573423489,7373090ca843d1dc8fc69484626c5b66e83df3a71f1447c41f2ea29ee86fbb11 +assets/index-DkH-hf4B.css,1732573423489,ccc6d3f578d3794f8d281087e3e500fd5f205039e6c539b9ef9b11aadd85f04e +assets/index-C809hq80.js,1732573423512,da8964865ae923d8df4f2f719b2976c5ddbb881990dcbd9df531a7e999de8483 +assets/home-4w9uf3I6.js,1732573423511,2e076ea18137383d10c9e13cfea590cde2656a9f8abdd6ac8e58832d74a8733c +assets/Grid2-CBw_h93Y.js,1732573423511,83778c963341abc62db015d6a03fb7c15a4ff6a07ad9138bc55833822805ff5e +assets/dm-sans-latin-wght-normal-DeBecvsH.woff2,1732573423481,f5a7d6a44f03caeab57eae554572d0bd628c97fcbea5d2c1b4ce2644d1972318 +assets/dm-sans-latin-ext-wght-normal-D1bw2c55.woff2,1732573423481,2bb8d0ca5b8931b9e39fc80c49e510fee75b85c8a123e69e3fca55ec9761f0ab +assets/contributions-view-DsTCM7ml.js,1732573423489,9db5196a5526f5fcecb8e09ec11dd0896fce94709dd67ae69e1dec4504e8d2be +assets/contributions-BSi_CEcP.js,1732573423488,806ee5cea162376a5c2f3433734c69b03d685af7e08052a4edca490975147237 +assets/config-global-vueVacRM.js,1732573423488,5a7bfcc9c7523ce4e1c353b59e17435c6db46b95a5f73e7d7396668951944d8b +assets/blog-CsZ57RXH.js,1732573423510,bb4f100c01366b98c87e84c1c08aa55e6666474f6b922a138ca05c800ed8eb6b +assets/barlow-vietnamese-800-normal-DDiAQIYO.woff2,1732573423482,942800ee41816b1ee6a3040e02653c0cae2bb8a638ac3862cb6add2ea0d3ecdc +assets/barlow-vietnamese-800-normal-B95advN4.woff,1732573423488,c48e15f0e185efd5c021059f0234c6e388fd21528695a07e23cd4531a3a55057 +assets/barlow-vietnamese-700-normal-DQ6dlXpV.woff2,1732573423482,db5ca97c658098d37cc5146b5bacf3273e532df431f0dd7cab21b17c3d14e55a +assets/barlow-vietnamese-700-normal-CtEmPuX0.woff,1732573423488,9cfc29ffb566bd2f9e668989357fcd9949c6170e29750500f1d0c2dc8405840d +assets/barlow-vietnamese-600-normal-gKnznvH6.woff2,1732573423482,e8c7f5df4e7fe6be3e2b378542fe54e5756c2ff24025eda3cf39418056889cd2 +assets/barlow-vietnamese-600-normal--rM-LJkj.woff,1732573423488,6bce8267dac53b9a05b2c9d5890a1ee3db6d4643c070df732aeb4d7bf3d8a0df +assets/barlow-vietnamese-500-normal-OcIDFxwj.woff,1732573423482,f8ecdf88476f28c2a85f9d39c8fc158cce8a7c4436800b9750f48943f3fb2c25 +assets/barlow-vietnamese-500-normal-Ds--_AhX.woff2,1732573423482,18e2b6bd60d057b3c66885b1d71ede300c6c9a64ad0489a502fbe9d8e5797365 +assets/barlow-vietnamese-400-normal-Dcxa7Lg7.woff,1732573423482,4fb96908d195c2f9abc7a4a8ff8f91a91b9d40145e80fd6a9258bedb8be3c9af +assets/barlow-vietnamese-400-normal-B8B3d_DU.woff2,1732573423482,c58372c351e59200dee5b6d5247c3c85d3842570330a611d12d74ef821467b1a +assets/barlow-latin-ext-800-normal-uSolDMqV.woff2,1732573423482,6384af3f59034d2dc5f38d8431523032ece92de6367483a2c50a6e7c5a10ee7a +assets/barlow-latin-ext-800-normal-DHjhf6ta.woff,1732573423488,a14ecc03bb066e9ffff9d75e3b9440d8f187bb58787ea29e5543d3b53e4c7298 +assets/barlow-latin-ext-700-normal-sk8_kpF-.woff2,1732573423482,b9732d83b660f09a40cccc2226db588c2b34a4ff21f2119bee5fec02c77cc091 +assets/barlow-latin-ext-700-normal-BgGd7r2K.woff,1732573423488,a6f04abd02c2eb0ce6ad1d1f34d5f26a3000e29960051a2f0ef83f556e9db75b +assets/barlow-latin-ext-600-normal-DxfNEZIW.woff,1732573423488,022c4f95ade99c144813719bb72e165212c43580b79d94068e7cafb176818aab +assets/barlow-latin-ext-600-normal-Brs4HSvV.woff2,1732573423482,986825b8a2273dc11ddb458639a847c93dcb6d620e1743b215d3d1774a38558a +assets/barlow-latin-ext-500-normal-D9Q9nrG3.woff2,1732573423482,2631a3fa5e7137513e0648a8bc9de234c5740ef46ea47b97113b893fa79129a4 +assets/barlow-latin-ext-500-normal-B8S-Wk_i.woff,1732573423487,15680c9130e84729e68b7b209f4bb1a37cda56b51ce2cce766e91ddeefb69f9d +assets/barlow-latin-ext-400-normal-DsA6LmuC.woff2,1732573423482,acda01528c8e85ece2d41038b2112999a7cba63a0bdd119ed5fce96e06db411f +assets/barlow-latin-ext-400-normal-DGsTVCL_.woff,1732573423482,0808e9223b3c6fd1945fdef69a197bc4b93123c279dcad33372127bad7cec504 +assets/barlow-latin-800-normal-Dp3TYPAo.woff,1732573423489,d8483b7f583ebb1adf24086c4d11d8b57574f66c179526bed1a5cb42b5af640a +assets/barlow-latin-800-normal-B50OFIWa.woff2,1732573423482,7ec9815bb2b5a38a965f83a81450d5700b75cb7631cc2f5b80424baf8acd46ed +assets/barlow-latin-700-normal-Bku5AOSK.woff2,1732573423482,c632885fbaedca07d005d44a7a767649ffdad498c4d4642c76e26b9507a4fa59 +assets/barlow-latin-700-normal-AkmsA7ur.woff,1732573423488,4d49ff23dd1dc1ac33b88d690534fbeef31c79e516a66761ccb5b8924aae2629 +assets/barlow-latin-600-normal-DznpAvW9.woff,1732573423488,61c83e9735dc1f2aa969c65f62dee7285fcb2449b238cd233598796eb02db621 +assets/barlow-latin-600-normal-DMnFtVx9.woff2,1732573423482,1b5fe7676f9341efd7d14c61154b1a000eda7b88d907a309772ac7c5632a2500 +assets/barlow-latin-500-normal-BRhHB0xN.woff2,1732573423482,57bbeeb83dd750be97345420f6515622d1a3c5a5cb923f27f6e552cde3f1199b +assets/barlow-latin-500-normal-BAaAwKGi.woff,1732573423487,af42825f784d1977f5f3977d58437a2dc233c7599854dcce62312349002e3c5f +assets/barlow-latin-400-normal-Gqj0RTbC.woff,1732573423487,08b51a03374472e6035c824092560ad1b54e7605973b9447fca43f073f37d3fc +assets/barlow-latin-400-normal-CtwdMZP0.woff2,1732573423482,bbd209eb92a1160ea1f3862adf82281c99a5a1028d163df5fb9394caf803f52f +assets/images/minimal-free-preview.jpg,1730497678201,4c77f6cb372e292ad231630e473be719443a2e8aea8bb5ddf49efc6bac92e2fd +assets/images/logo.png,1723926015463,83554fa707bbc7e4e3052e26ca8b9f09a4693eb3fb1175afb7f55b9eceba81cf +assets/images/product/product-9.webp,1730497678208,ca203ffdf49f6c038d5e7ceaf942a65d4c374bc96caf2bc2ec3b0c5eed004d94 +assets/images/product/product-8.webp,1730497678208,0c94f706ce17acc95d6a2256036429532545b770323eb060f5c7a92ec96a180e +assets/images/product/product-7.webp,1730497678207,eba409ba937affe9c681280f640172be8ed1dc5a5ee2a3fd59bc9a8aa1ca6d49 +assets/images/product/product-6.webp,1730497678207,be7d13ac2a6af1d875364521efc509f914140d0c43c42e4a1e248874a1e0574c +assets/images/product/product-5.webp,1730497678207,4f2468951a795e5b88e95a750f5d98c02407749037bbc678eee73d94ece1b64b +assets/images/product/product-4.webp,1730497678207,afbe0a607b6178af6eb27c60851f9ee8194c806a1a6bdc633ea5d22aa31dcd59 +assets/images/product/product-3.webp,1730497678206,6dcbb5d8885a999f05a244949d338e6a7db7bd5c17ca975731cd084f35aa5a69 +assets/images/product/product-24.webp,1730497678206,efc398463261d8a24ee7b4a69accb3c02371fbd4b34cc5349e968b6fa8d08462 +assets/images/product/product-23.webp,1730497678206,63bd265a6f4f1ef970050c6fd02e1161c009ebfab1514e9a421e5461776466de +assets/images/product/product-22.webp,1730497678205,334c9944deb81bd4ede260ed3a952216a9f7d54e445d502ded6acbc8c1cbb1a8 +assets/images/product/product-21.webp,1730497678205,512778ade76528c7b54e27188cba913f73cd77b0205b34188cd194b6b7241965 +assets/images/product/product-20.webp,1730497678205,188781420f02eb2af255b057639fa7dd7fc2fe934485a2521523bc5096cdc812 +assets/images/product/product-2.webp,1730497678205,3f75bb21d6f32f9055f0262f1eda042e413444cb12de1133d8d1ae66da88bc5c +assets/images/product/product-19.webp,1730497678204,2c5cd7b22c2efd83335c670d1b39c5297359a1021a958cd73081fe893e5f9d1a +assets/images/product/product-18.webp,1730497678204,057d92d3ffeb3e538d934c0982ef6099ed48b14f60f496080dd7286e7f93f42c +assets/images/product/product-17.webp,1730497678204,ad2054fad16e43349249e9c338f8c40e30a5aa39d20c7a16a4cb37f964d4a8e4 +assets/images/product/product-16.webp,1730497678203,e23e3ecce1b93d4277238212afdf23f52d7ff53642345920daf49dca20ac5a0e +assets/images/product/product-15.webp,1730497678203,2e8dd27240d627a242ee34cf8df790db5eeed047d7f2b954765691b8b1b579ef +assets/images/product/product-14.webp,1730497678203,742fdde0770c298645b7e83c98bee25381bc66733aef9b45d8d75048836effef +assets/images/product/product-13.webp,1730497678203,c3b1aadef6eec00cdad8de94a70c63bbe5ea9274083031b53d674744087f9abc +assets/images/product/product-12.webp,1730497678202,409ea5052137ddff2992451b184a64282f61788c1004e14fc133e0f1744e6574 +assets/images/product/product-11.webp,1730497678202,d45873da256da2d18ca61047844d013e94fa41bd1274cdedbee3551e54fdb51e +assets/images/product/product-10.webp,1730497678202,a4c9ca613959b09e4513f348f5aa92ac1c9e95695402726466fbf9836fa0a56b +assets/images/product/product-1.webp,1730497678201,37be3d1b43b33810044596fc688806fb0aba2df18ab54e617185a74d55046f04 +assets/images/cover/cover-9.webp,1730497678201,b115f8a7861d7f4df5b4a6ec47c0cd8d24f1062e581516647a619bc48978e20b +assets/images/cover/cover-8.webp,1730497678200,45d72293e258133203dbd443039dd8ea23616a4485667ced2f38e2dc7c52bcd3 +assets/images/cover/cover-7.webp,1730497678200,4022dcaff6bcf205e7889dd8c2aad5e516fd2a6c3b6ae3a669e2916cde1a619d +assets/images/cover/cover-6.webp,1730497678200,3e173882f0e2d7f3a50d3d83ebc95407445a813e5864c0f0d3c341aceb8706fa +assets/images/cover/cover-5.webp,1730497678199,635df6309603bec2cd8b2341880d28a21cf38acaf244f0dc47604fb165ec7811 +assets/images/cover/cover-4.webp,1730497678199,cd9d7319997057a3bab84fb0c4b450ffb474293ee11160e0c6dfe3dc67232bf4 +assets/images/cover/cover-3.webp,1730497678198,302bca427c7eab606e337fff52d2dc045f8c7ff31b4a0597c0b97d7a5ca8f8d0 +assets/images/cover/cover-24.webp,1730497678198,d7375b13cb9d7551a5e9e447109aacba25052343426352c5185ba125c3a21c10 +assets/images/cover/cover-23.webp,1730497678198,942ce6096494bc4ff90b16421f0898460413b094b98e6e3ccfee87226074007c +assets/images/cover/cover-22.webp,1730497678197,1d5e0bd87ca66e471fdea9acb178f5b6eedbf5e671eb5b2244b3c5090d384fc3 +assets/images/cover/cover-21.webp,1730497678197,b60491f41a23a92deadeafd153f40f1b4e798b7461b7b0474316770298276d2a +assets/images/cover/cover-20.webp,1730497678197,24eab942876c732470fd2266906c1303b9274749dd848fb77d33c54158b614b1 +assets/images/cover/cover-2.webp,1730497678197,59926fffc9bfd01841edd61459957f3b1ba7fedc6f964a3135ba5e5e31f1de89 +assets/images/cover/cover-19.webp,1730497678197,a0ad43977ac0b238d2641ec3bf909b7bf54101fa242179984e234a414ef5de6b +assets/images/cover/cover-18.webp,1730497678196,6c235e117c6ed3d5ad07035b83314807d89d87fad821e708394410f6c9571136 +assets/images/cover/cover-17.webp,1730497678196,4128aa150c35e997480ccb72ffdc0c163043b8a49995ed3eed30871ca2bd0d93 +assets/images/cover/cover-16.webp,1730497678196,63baabb9d2dd5742f117265fc19608736eb91fe2822ead17ffc6e221bf018285 +assets/images/cover/cover-15.webp,1730497678196,98e785296fffd493891cba8a7d46e925abaa99d757d988394f9e73dcd50a9b92 +assets/images/cover/cover-14.webp,1730497678195,035ef0ef38e80f5b0508b578a4dc622a80186de9a37cc890ea72052ae225034e +assets/images/cover/cover-13.webp,1730497678195,e3cc86a856eb15408e8720f9547cf29f9bd51e27f92a2a4d2b69f312ed08ca07 +assets/images/cover/cover-12.webp,1730497678195,16c3d223174af28c80890c9e3cf7dfae4b27d81f7e69a7d0b4e896043e72c469 +assets/images/cover/cover-11.webp,1730497678194,58dc83e25c4c515751a0ffcb8bc9d08810b27c4b4db0738789c77d463134142d +assets/images/cover/cover-10.webp,1730497678194,4372fcf499efa70470136ea674753f746d8c3f7270a9ff3aa80eda3b4077792c +assets/images/cover/cover-1.webp,1730497678194,b337fa4479d341d4082e0b0c49947d82b77e37a64bd5de489c95b9b3bb7823c7 +assets/images/avatar/avatar-9.webp,1730497678193,e7761af5f170c55691dd6a46068113ba966c542303aed6ff815576c89dd94406 +assets/images/avatar/avatar-8.webp,1730497678193,966859d258df144ebe7e7789c647865d868a58543cbd5599269a1f32769d073d +assets/images/avatar/avatar-7.webp,1730497678193,5feb6f7c2ce0754c6ab93e11366b94767b12e20d82722f4890c6d31a17814530 +assets/images/avatar/avatar-6.webp,1730497678193,8a5e9655fa9c83e02b11a2a9ff7ae408dca60068b966a264eab101fb7637f0a6 +assets/images/avatar/avatar-5.webp,1730497678193,0a3a7763788452a818cd51a8021d842bcb6ec028b21b4fe3ed61d487ca1d59e6 +assets/images/avatar/avatar-4.webp,1730497678193,7bce88a9590e09fb12a4684476a72815ab13584f41991326959049b387a97cd3 +assets/images/avatar/avatar-3.webp,1730497678193,c0aaa16ac65e0637dada06cc129cdb3d688eca72ee04db6ee600e5bb91bed06e +assets/images/avatar/avatar-25.webp,1730497678193,92e1544c1d72a16189e3a697c382367ac20e16e53c168ee8a8ee3b3249ac974f +assets/images/avatar/avatar-24.webp,1730497678192,3bc27ec65537e102adce91fc29836947dc2806d09e5ac11d83bb74957dbf0f86 +assets/images/avatar/avatar-23.webp,1730497678192,89d61322d2d92a0ea82e8271254da4b430dddddd04eb590da57134b917ce4467 +assets/images/avatar/avatar-22.webp,1730497678192,1bc497247991ac7b58b78246867bff2b61ecb5bfb0ab87fe0dbae7a897676f74 +assets/images/avatar/avatar-21.webp,1730497678192,8ea105cb2e88992efc7a58fcb1bfd640c2a4f9853731a629f5c11484bc686819 +assets/images/avatar/avatar-20.webp,1730497678192,3377e455e4e4d3ff20888fc3baf612d233e8f09bd24b918a126dd29be790960b +assets/images/avatar/avatar-2.webp,1730497678192,50e88d816f28e7c386649f8515c685455df36fdfff9321d825627e5b43dadb05 +assets/images/avatar/avatar-19.webp,1730497678191,84a72c87d9f310cb64c51c6abc9d59f6563a8464b29d33b924bf0430a7dde362 +assets/images/avatar/avatar-18.webp,1730497678191,ddba817971c518c999f6cf44c071d70f21bfdb7d34e38715a56c27386baa87a5 +assets/images/avatar/avatar-17.webp,1730497678191,168eccfe2a0ae7446f00c7b2b99d94e8b4d897194cb2efc85ba15ee4ff6946b4 +assets/images/avatar/avatar-16.webp,1730497678191,48ab185e8bc0b540310d02e5da4b3a83220205d79180b83f26bfc8a0a99f1e3a +assets/images/avatar/avatar-15.webp,1730497678191,b3a6fa19dc6fdc6b0f4fa0717515805dbe07f7aed8cdbd8c60f2bddaaa9e3b18 +assets/images/avatar/avatar-14.webp,1730497678191,e2b6df848747e9bbe599501b32998ebdc9a27d45e6f99a067d975e4b9ad38f83 +assets/images/avatar/avatar-13.webp,1730497678191,2fd37533955ee031f8e3fed8c35c896921b012784d22130686d90c01baaba248 +assets/images/avatar/avatar-12.webp,1730497678191,51c0f5bc7e55bffda8b506ae4a716bd2c18032356b0925565df2c1771ee1f17a +assets/images/avatar/avatar-11.webp,1730497678190,27d7e39340af7a0125d29a568a0190480fcc9323ca9d936270152d8227c703df +assets/images/avatar/avatar-10.webp,1730497678190,c15c4a3ec76c5c1375aad3b6a1c20c21ad43e581984ed3c64c2ab7f43738e7c0 +assets/images/avatar/avatar-1.webp,1730497678190,7a07a94e9c40d2833b85462c1d9a2ad6ced2690118b7a08ad048941ac61c5528 +assets/illustrations/illustration-dashboard.webp,1730497678190,e8424723a1e27af60c71414bbfd5ca94ce1dca7c9eee158fb4892ea3123fb2de +assets/illustrations/illustration-404.svg,1730497678189,027ff0d70d0d6ceb54508f0b50c5aa8661481d4a17310fef632ef81601a5ec94 +assets/icons/shape-avatar.svg,1730497678189,fe96f4c1005d3f8ce2c7052870b057f5ee5f2a46670c0db5d83ab051ec489ca7 +assets/icons/workspaces/logo-3.webp,1730497678189,10e2ec8b1ec3fa6d3dd1ba61e1bf9ccd7cd695f97f2a7f1ce37a47727a8d2a70 +assets/icons/workspaces/logo-2.webp,1730497678189,f808597e83e2ac4aca785ea05e500ac00689edc1e90747c3d8cc9c7af7073fd5 +assets/icons/workspaces/logo-1.webp,1730497678189,e117dafe4c11878278585224a10ac3c47bf9b980ceb14d8f8d1db488f60cfd52 +assets/icons/status/ic-success.svg,1730522011312,a31fa9eb430d91ff25ee2b0facf05a066fd761f4aa444175797fd6972682132a +assets/icons/status/ic-pending.svg,1730521948380,0221681d0856f7f6b4373ba8678efd6a20c9fd9b6646fe2f5b4472c857a620a9 +assets/icons/status/ic-failed.svg,1730522089232,ad232b5c225907aa53cb0102533ab8177b02be175805a73110d5460dc23bea56 +assets/icons/notification/ic-notification-shipping.svg,1730497678188,4d22eb0420fa10dcd646313f4ce833f699fa53bc7d3e4869589d30c4b5ed141e +assets/icons/notification/ic-notification-package.svg,1730497678188,9a798aa9f6092ed819f508b7763d6f3384d179e325acaaad63e3c0593521f9f4 +assets/icons/notification/ic-notification-mail.svg,1730497678188,5db56840606875b987d4b865b5964e5c7b5462e543267215e6efe9aceadc61d5 +assets/icons/notification/ic-notification-chat.svg,1730497678188,07001d6d6f8d9979b3c3a71c6bc9a5e0f753daea219bac03aec51666fa91698a +assets/icons/navbar/ic-user.svg,1730497678188,06a7a0bf374f679922e302f3e2894ed0e55756cca97bc140a5413a5510302d44 +assets/icons/navbar/ic-lock.svg,1730497678188,9a22e70b283d2340f94407b85bbfac52555566b9f5587538000b365281128fec +assets/icons/navbar/ic-exit.svg,1730500920359,d5c8d231f3f1540c300b2bdb33d4e79c5e1704e0cde94d9b3ae956bf7b186c5f +assets/icons/navbar/ic-donate.svg,1730517528929,07327ef7502d2f468ff9faa1fecf353104f05f7eb7391cf4c78fbadc4c33a991 +assets/icons/navbar/ic-disabled.svg,1730497678187,54330961ed98db4fa0e955f1f201ddc96a47fc36dd499d65364c680cc2b7444f +assets/icons/navbar/ic-cart.svg,1730497678187,4147c3462c875b47a046e2840b916485c73a43e244b12782e272b8e5de40273a +assets/icons/navbar/ic-blog.svg,1730497678187,aa10a1703fc0df81d97a5e804d1dfac12fa59a8b1d399ae40e5e28bb24c57cbf +assets/icons/navbar/ic-analytics.svg,1730497678187,6a401d9abb256c2454638fb385c90e1b38f0ecfd8b42e9ff2c21b2c683a75ca1 +assets/icons/glass/ic-wallet.svg,1730503008957,f5de62accf55f72e54c201e5735206969f5917ac966587517f5b9c99973e219e +assets/icons/glass/ic-glass-users.svg,1730497678187,eee91092e79a8c94fa24f80126ddec3ceb48774d0f6c1eb287cd9ecbd35bd437 +assets/icons/glass/ic-glass-message.svg,1730497678187,9e4db5146d3c65fd0a3a55633020b97f90f7357a61e9adb3e03e83671a635665 +assets/icons/glass/ic-glass-buy.svg,1730497678186,3b3dba826f809dd4630b130706c468595b7df866da2dfb67fdba9d4f4470e58c +assets/icons/glass/ic-donate.svg,1730502720108,ed3a81af036fa4d88433a24d2abd38d44b0634c05a8d4b2fd5da8051738b381c +assets/icons/flags/ic-flag-fr.svg,1730497678186,a277878f6eeab357465e5e8d8ce0dd78ba02d8f4ed7339467470f82440ab6c2d +assets/icons/flags/ic-flag-en.svg,1730497678186,abc6fdcb3cf6a9252e4a7cf2eb0656140a0d27c5503cca6aa15775ef690c77ae +assets/icons/flags/ic-flag-de.svg,1730497678186,38059eb5d840d3dc87261c954c48a963c7b7cc449a8fde9a062aa9c5fa79ebd8 +assets/background/shape-square.svg,1730497678186,10fa9733a3dd4b2e100f20cea8651eb06dd2dc1d2b424e9283f853f2270a7c05 +assets/background/overlay.jpg,1730497678185,eacfb1c102e43049b710e6671348aae97f0cf90ae0fb4cb15386739a3aa2b527 diff --git a/.firebase/hosting.cHVibGlj.cache b/.firebase/hosting.cHVibGlj.cache new file mode 100644 index 000000000..69c2d9e90 --- /dev/null +++ b/.firebase/hosting.cHVibGlj.cache @@ -0,0 +1,109 @@ +index.html,1732313404911,38aee86a3bae65d47d45915d8e66991582da251402dcf226b46cd78bd0e920bf +favicon.ico,1731094223321,165f2ac821b2a5b2a1638fb8f984164fe22bb8ddab1783942510fe9c594d3b16 +404.html,1732313404551,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 +assets/images/minimal-free-preview.jpg,1730497678201,4c77f6cb372e292ad231630e473be719443a2e8aea8bb5ddf49efc6bac92e2fd +assets/images/logo.png,1723926015463,83554fa707bbc7e4e3052e26ca8b9f09a4693eb3fb1175afb7f55b9eceba81cf +assets/images/product/product-9.webp,1730497678208,ca203ffdf49f6c038d5e7ceaf942a65d4c374bc96caf2bc2ec3b0c5eed004d94 +assets/images/product/product-8.webp,1730497678208,0c94f706ce17acc95d6a2256036429532545b770323eb060f5c7a92ec96a180e +assets/images/product/product-7.webp,1730497678207,eba409ba937affe9c681280f640172be8ed1dc5a5ee2a3fd59bc9a8aa1ca6d49 +assets/images/product/product-6.webp,1730497678207,be7d13ac2a6af1d875364521efc509f914140d0c43c42e4a1e248874a1e0574c +assets/images/product/product-5.webp,1730497678207,4f2468951a795e5b88e95a750f5d98c02407749037bbc678eee73d94ece1b64b +assets/images/product/product-4.webp,1730497678207,afbe0a607b6178af6eb27c60851f9ee8194c806a1a6bdc633ea5d22aa31dcd59 +assets/images/product/product-3.webp,1730497678206,6dcbb5d8885a999f05a244949d338e6a7db7bd5c17ca975731cd084f35aa5a69 +assets/images/product/product-24.webp,1730497678206,efc398463261d8a24ee7b4a69accb3c02371fbd4b34cc5349e968b6fa8d08462 +assets/images/product/product-23.webp,1730497678206,63bd265a6f4f1ef970050c6fd02e1161c009ebfab1514e9a421e5461776466de +assets/images/product/product-22.webp,1730497678205,334c9944deb81bd4ede260ed3a952216a9f7d54e445d502ded6acbc8c1cbb1a8 +assets/images/product/product-21.webp,1730497678205,512778ade76528c7b54e27188cba913f73cd77b0205b34188cd194b6b7241965 +assets/images/product/product-20.webp,1730497678205,188781420f02eb2af255b057639fa7dd7fc2fe934485a2521523bc5096cdc812 +assets/images/product/product-2.webp,1730497678205,3f75bb21d6f32f9055f0262f1eda042e413444cb12de1133d8d1ae66da88bc5c +assets/images/product/product-19.webp,1730497678204,2c5cd7b22c2efd83335c670d1b39c5297359a1021a958cd73081fe893e5f9d1a +assets/images/product/product-18.webp,1730497678204,057d92d3ffeb3e538d934c0982ef6099ed48b14f60f496080dd7286e7f93f42c +assets/images/product/product-17.webp,1730497678204,ad2054fad16e43349249e9c338f8c40e30a5aa39d20c7a16a4cb37f964d4a8e4 +assets/images/product/product-16.webp,1730497678203,e23e3ecce1b93d4277238212afdf23f52d7ff53642345920daf49dca20ac5a0e +assets/images/product/product-15.webp,1730497678203,2e8dd27240d627a242ee34cf8df790db5eeed047d7f2b954765691b8b1b579ef +assets/images/product/product-14.webp,1730497678203,742fdde0770c298645b7e83c98bee25381bc66733aef9b45d8d75048836effef +assets/images/product/product-13.webp,1730497678203,c3b1aadef6eec00cdad8de94a70c63bbe5ea9274083031b53d674744087f9abc +assets/images/product/product-12.webp,1730497678202,409ea5052137ddff2992451b184a64282f61788c1004e14fc133e0f1744e6574 +assets/images/product/product-11.webp,1730497678202,d45873da256da2d18ca61047844d013e94fa41bd1274cdedbee3551e54fdb51e +assets/images/product/product-10.webp,1730497678202,a4c9ca613959b09e4513f348f5aa92ac1c9e95695402726466fbf9836fa0a56b +assets/images/product/product-1.webp,1730497678201,37be3d1b43b33810044596fc688806fb0aba2df18ab54e617185a74d55046f04 +assets/images/cover/cover-9.webp,1730497678201,b115f8a7861d7f4df5b4a6ec47c0cd8d24f1062e581516647a619bc48978e20b +assets/images/cover/cover-8.webp,1730497678200,45d72293e258133203dbd443039dd8ea23616a4485667ced2f38e2dc7c52bcd3 +assets/images/cover/cover-7.webp,1730497678200,4022dcaff6bcf205e7889dd8c2aad5e516fd2a6c3b6ae3a669e2916cde1a619d +assets/images/cover/cover-6.webp,1730497678200,3e173882f0e2d7f3a50d3d83ebc95407445a813e5864c0f0d3c341aceb8706fa +assets/images/cover/cover-5.webp,1730497678199,635df6309603bec2cd8b2341880d28a21cf38acaf244f0dc47604fb165ec7811 +assets/images/cover/cover-4.webp,1730497678199,cd9d7319997057a3bab84fb0c4b450ffb474293ee11160e0c6dfe3dc67232bf4 +assets/images/cover/cover-3.webp,1730497678198,302bca427c7eab606e337fff52d2dc045f8c7ff31b4a0597c0b97d7a5ca8f8d0 +assets/images/cover/cover-24.webp,1730497678198,d7375b13cb9d7551a5e9e447109aacba25052343426352c5185ba125c3a21c10 +assets/images/cover/cover-23.webp,1730497678198,942ce6096494bc4ff90b16421f0898460413b094b98e6e3ccfee87226074007c +assets/images/cover/cover-22.webp,1730497678197,1d5e0bd87ca66e471fdea9acb178f5b6eedbf5e671eb5b2244b3c5090d384fc3 +assets/images/cover/cover-21.webp,1730497678197,b60491f41a23a92deadeafd153f40f1b4e798b7461b7b0474316770298276d2a +assets/images/cover/cover-20.webp,1730497678197,24eab942876c732470fd2266906c1303b9274749dd848fb77d33c54158b614b1 +assets/images/cover/cover-2.webp,1730497678197,59926fffc9bfd01841edd61459957f3b1ba7fedc6f964a3135ba5e5e31f1de89 +assets/images/cover/cover-19.webp,1730497678197,a0ad43977ac0b238d2641ec3bf909b7bf54101fa242179984e234a414ef5de6b +assets/images/cover/cover-18.webp,1730497678196,6c235e117c6ed3d5ad07035b83314807d89d87fad821e708394410f6c9571136 +assets/images/cover/cover-17.webp,1730497678196,4128aa150c35e997480ccb72ffdc0c163043b8a49995ed3eed30871ca2bd0d93 +assets/images/cover/cover-16.webp,1730497678196,63baabb9d2dd5742f117265fc19608736eb91fe2822ead17ffc6e221bf018285 +assets/images/cover/cover-15.webp,1730497678196,98e785296fffd493891cba8a7d46e925abaa99d757d988394f9e73dcd50a9b92 +assets/images/cover/cover-14.webp,1730497678195,035ef0ef38e80f5b0508b578a4dc622a80186de9a37cc890ea72052ae225034e +assets/images/cover/cover-13.webp,1730497678195,e3cc86a856eb15408e8720f9547cf29f9bd51e27f92a2a4d2b69f312ed08ca07 +assets/images/cover/cover-12.webp,1730497678195,16c3d223174af28c80890c9e3cf7dfae4b27d81f7e69a7d0b4e896043e72c469 +assets/images/cover/cover-11.webp,1730497678194,58dc83e25c4c515751a0ffcb8bc9d08810b27c4b4db0738789c77d463134142d +assets/images/cover/cover-10.webp,1730497678194,4372fcf499efa70470136ea674753f746d8c3f7270a9ff3aa80eda3b4077792c +assets/images/cover/cover-1.webp,1730497678194,b337fa4479d341d4082e0b0c49947d82b77e37a64bd5de489c95b9b3bb7823c7 +assets/images/avatar/avatar-9.webp,1730497678193,e7761af5f170c55691dd6a46068113ba966c542303aed6ff815576c89dd94406 +assets/images/avatar/avatar-8.webp,1730497678193,966859d258df144ebe7e7789c647865d868a58543cbd5599269a1f32769d073d +assets/images/avatar/avatar-7.webp,1730497678193,5feb6f7c2ce0754c6ab93e11366b94767b12e20d82722f4890c6d31a17814530 +assets/images/avatar/avatar-6.webp,1730497678193,8a5e9655fa9c83e02b11a2a9ff7ae408dca60068b966a264eab101fb7637f0a6 +assets/images/avatar/avatar-5.webp,1730497678193,0a3a7763788452a818cd51a8021d842bcb6ec028b21b4fe3ed61d487ca1d59e6 +assets/images/avatar/avatar-4.webp,1730497678193,7bce88a9590e09fb12a4684476a72815ab13584f41991326959049b387a97cd3 +assets/images/avatar/avatar-3.webp,1730497678193,c0aaa16ac65e0637dada06cc129cdb3d688eca72ee04db6ee600e5bb91bed06e +assets/images/avatar/avatar-25.webp,1730497678193,92e1544c1d72a16189e3a697c382367ac20e16e53c168ee8a8ee3b3249ac974f +assets/images/avatar/avatar-24.webp,1730497678192,3bc27ec65537e102adce91fc29836947dc2806d09e5ac11d83bb74957dbf0f86 +assets/images/avatar/avatar-23.webp,1730497678192,89d61322d2d92a0ea82e8271254da4b430dddddd04eb590da57134b917ce4467 +assets/images/avatar/avatar-22.webp,1730497678192,1bc497247991ac7b58b78246867bff2b61ecb5bfb0ab87fe0dbae7a897676f74 +assets/images/avatar/avatar-21.webp,1730497678192,8ea105cb2e88992efc7a58fcb1bfd640c2a4f9853731a629f5c11484bc686819 +assets/images/avatar/avatar-20.webp,1730497678192,3377e455e4e4d3ff20888fc3baf612d233e8f09bd24b918a126dd29be790960b +assets/images/avatar/avatar-2.webp,1730497678192,50e88d816f28e7c386649f8515c685455df36fdfff9321d825627e5b43dadb05 +assets/images/avatar/avatar-19.webp,1730497678191,84a72c87d9f310cb64c51c6abc9d59f6563a8464b29d33b924bf0430a7dde362 +assets/images/avatar/avatar-18.webp,1730497678191,ddba817971c518c999f6cf44c071d70f21bfdb7d34e38715a56c27386baa87a5 +assets/images/avatar/avatar-17.webp,1730497678191,168eccfe2a0ae7446f00c7b2b99d94e8b4d897194cb2efc85ba15ee4ff6946b4 +assets/images/avatar/avatar-16.webp,1730497678191,48ab185e8bc0b540310d02e5da4b3a83220205d79180b83f26bfc8a0a99f1e3a +assets/images/avatar/avatar-15.webp,1730497678191,b3a6fa19dc6fdc6b0f4fa0717515805dbe07f7aed8cdbd8c60f2bddaaa9e3b18 +assets/images/avatar/avatar-14.webp,1730497678191,e2b6df848747e9bbe599501b32998ebdc9a27d45e6f99a067d975e4b9ad38f83 +assets/images/avatar/avatar-13.webp,1730497678191,2fd37533955ee031f8e3fed8c35c896921b012784d22130686d90c01baaba248 +assets/images/avatar/avatar-12.webp,1730497678191,51c0f5bc7e55bffda8b506ae4a716bd2c18032356b0925565df2c1771ee1f17a +assets/images/avatar/avatar-11.webp,1730497678190,27d7e39340af7a0125d29a568a0190480fcc9323ca9d936270152d8227c703df +assets/images/avatar/avatar-10.webp,1730497678190,c15c4a3ec76c5c1375aad3b6a1c20c21ad43e581984ed3c64c2ab7f43738e7c0 +assets/images/avatar/avatar-1.webp,1730497678190,7a07a94e9c40d2833b85462c1d9a2ad6ced2690118b7a08ad048941ac61c5528 +assets/illustrations/illustration-dashboard.webp,1730497678190,e8424723a1e27af60c71414bbfd5ca94ce1dca7c9eee158fb4892ea3123fb2de +assets/illustrations/illustration-404.svg,1730497678189,027ff0d70d0d6ceb54508f0b50c5aa8661481d4a17310fef632ef81601a5ec94 +assets/icons/shape-avatar.svg,1730497678189,fe96f4c1005d3f8ce2c7052870b057f5ee5f2a46670c0db5d83ab051ec489ca7 +assets/icons/workspaces/logo-3.webp,1730497678189,10e2ec8b1ec3fa6d3dd1ba61e1bf9ccd7cd695f97f2a7f1ce37a47727a8d2a70 +assets/icons/workspaces/logo-2.webp,1730497678189,f808597e83e2ac4aca785ea05e500ac00689edc1e90747c3d8cc9c7af7073fd5 +assets/icons/workspaces/logo-1.webp,1730497678189,e117dafe4c11878278585224a10ac3c47bf9b980ceb14d8f8d1db488f60cfd52 +assets/icons/status/ic-success.svg,1730522011312,a31fa9eb430d91ff25ee2b0facf05a066fd761f4aa444175797fd6972682132a +assets/icons/status/ic-pending.svg,1730521948380,0221681d0856f7f6b4373ba8678efd6a20c9fd9b6646fe2f5b4472c857a620a9 +assets/icons/status/ic-failed.svg,1730522089232,ad232b5c225907aa53cb0102533ab8177b02be175805a73110d5460dc23bea56 +assets/icons/notification/ic-notification-shipping.svg,1730497678188,4d22eb0420fa10dcd646313f4ce833f699fa53bc7d3e4869589d30c4b5ed141e +assets/icons/notification/ic-notification-package.svg,1730497678188,9a798aa9f6092ed819f508b7763d6f3384d179e325acaaad63e3c0593521f9f4 +assets/icons/notification/ic-notification-mail.svg,1730497678188,5db56840606875b987d4b865b5964e5c7b5462e543267215e6efe9aceadc61d5 +assets/icons/notification/ic-notification-chat.svg,1730497678188,07001d6d6f8d9979b3c3a71c6bc9a5e0f753daea219bac03aec51666fa91698a +assets/icons/navbar/ic-user.svg,1730497678188,06a7a0bf374f679922e302f3e2894ed0e55756cca97bc140a5413a5510302d44 +assets/icons/navbar/ic-lock.svg,1730497678188,9a22e70b283d2340f94407b85bbfac52555566b9f5587538000b365281128fec +assets/icons/navbar/ic-exit.svg,1730500920359,d5c8d231f3f1540c300b2bdb33d4e79c5e1704e0cde94d9b3ae956bf7b186c5f +assets/icons/navbar/ic-donate.svg,1730517528929,07327ef7502d2f468ff9faa1fecf353104f05f7eb7391cf4c78fbadc4c33a991 +assets/icons/navbar/ic-disabled.svg,1730497678187,54330961ed98db4fa0e955f1f201ddc96a47fc36dd499d65364c680cc2b7444f +assets/icons/navbar/ic-cart.svg,1730497678187,4147c3462c875b47a046e2840b916485c73a43e244b12782e272b8e5de40273a +assets/icons/navbar/ic-blog.svg,1730497678187,aa10a1703fc0df81d97a5e804d1dfac12fa59a8b1d399ae40e5e28bb24c57cbf +assets/icons/navbar/ic-analytics.svg,1730497678187,6a401d9abb256c2454638fb385c90e1b38f0ecfd8b42e9ff2c21b2c683a75ca1 +assets/icons/glass/ic-wallet.svg,1730503008957,f5de62accf55f72e54c201e5735206969f5917ac966587517f5b9c99973e219e +assets/icons/glass/ic-glass-users.svg,1730497678187,eee91092e79a8c94fa24f80126ddec3ceb48774d0f6c1eb287cd9ecbd35bd437 +assets/icons/glass/ic-glass-message.svg,1730497678187,9e4db5146d3c65fd0a3a55633020b97f90f7357a61e9adb3e03e83671a635665 +assets/icons/glass/ic-glass-buy.svg,1730497678186,3b3dba826f809dd4630b130706c468595b7df866da2dfb67fdba9d4f4470e58c +assets/icons/glass/ic-donate.svg,1730502720108,ed3a81af036fa4d88433a24d2abd38d44b0634c05a8d4b2fd5da8051738b381c +assets/icons/flags/ic-flag-fr.svg,1730497678186,a277878f6eeab357465e5e8d8ce0dd78ba02d8f4ed7339467470f82440ab6c2d +assets/icons/flags/ic-flag-en.svg,1730497678186,abc6fdcb3cf6a9252e4a7cf2eb0656140a0d27c5503cca6aa15775ef690c77ae +assets/icons/flags/ic-flag-de.svg,1730497678186,38059eb5d840d3dc87261c954c48a963c7b7cc449a8fde9a062aa9c5fa79ebd8 +assets/background/shape-square.svg,1730497678186,10fa9733a3dd4b2e100f20cea8651eb06dd2dc1d2b424e9283f853f2270a7c05 +assets/background/overlay.jpg,1730497678185,eacfb1c102e43049b710e6671348aae97f0cf90ae0fb4cb15386739a3aa2b527 diff --git a/apphosting.yaml b/apphosting.yaml new file mode 100644 index 000000000..2325bef5d --- /dev/null +++ b/apphosting.yaml @@ -0,0 +1,23 @@ +# Settings for Backend (on Cloud Run). +# See https://firebase.google.com/docs/app-hosting/configure#cloud-run +runConfig: + minInstances: 0 + # maxInstances: 100 + # concurrency: 80 + # cpu: 1 + # memoryMiB: 512 + +# Environment variables and secrets. +# env: + # Configure environment variables. + # See https://firebase.google.com/docs/app-hosting/configure#user-defined-environment + # - variable: MESSAGE + # value: Hello world! + # availability: + # - BUILD + # - RUNTIME + + # Grant access to secrets in Cloud Secret Manager. + # See https://firebase.google.com/docs/app-hosting/configure#secret-parameters + # - variable: MY_SECRET + # secret: mySecretRef diff --git a/firebase.json b/firebase.json deleted file mode 100644 index e78293923..000000000 --- a/firebase.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "hosting": { - "public": "public", - "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" - ] - } -} diff --git a/index.html b/index.html index efb687cbc..0870fcfa9 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ - Minimal UI Kit + PABGM Portal diff --git a/package.json b/package.json index 1e0d5b2b6..969ea8861 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "dev": "vite", "start": "vite preview", "build": "tsc && vite build", + "host": "firebase deploy --only hosting", "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"", "fm:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\"", diff --git a/src/components/shared/modals/contributeForm.tsx b/src/components/shared/modals/contributeForm.tsx index a1a8fc4e4..765c156c9 100644 --- a/src/components/shared/modals/contributeForm.tsx +++ b/src/components/shared/modals/contributeForm.tsx @@ -9,10 +9,13 @@ import { TextField, Typography, } from '@mui/material'; +import PaystackInline from '@paystack/inline-js'; import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react'; import { Iconify } from 'src/components/iconify'; import useUser from 'src/hooks/useUser'; +import { useRouter } from 'src/routes/hooks'; import PayService from 'src/services/pay'; +import { errCb } from 'src/utils'; const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; @@ -28,6 +31,7 @@ const PaymentFormModal: React.FC = ({ handleClose, }) => { const { user } = useUser(); + const {refresh} = useRouter() const [amount, setAmount] = useState(user?.pledgeAmount ?? pledge ?? ''); const [selectedMonths, setSelectedMonths] = useState([]); @@ -38,11 +42,16 @@ const PaymentFormModal: React.FC = ({ }; const handleSubmit = async (event: FormEvent) => { - setLoading(true); + try { + setLoading(true); event.preventDefault(); - await PayService.init(amount, selectedMonths); + const pop = await PayService.init(amount, selectedMonths); closeModal(); setLoading(false); + } catch (error) { + errCb(error.message) + } + }; const closeModal = () => { @@ -84,7 +93,7 @@ const PaymentFormModal: React.FC = ({ }} > @@ -111,7 +120,6 @@ const PaymentFormModal: React.FC = ({ type="number" fullWidth required - // disabled value={amount} onChange={handleAmountChange} sx={{ mb: 3 }} diff --git a/src/sections/auth/sign-in-view.tsx b/src/sections/auth/sign-in-view.tsx index e071187bf..c61f504d7 100644 --- a/src/sections/auth/sign-in-view.tsx +++ b/src/sections/auth/sign-in-view.tsx @@ -113,6 +113,7 @@ export function SignInView() { required placeholder="Akwesi" onChange={(e) => updateField('fname', e.target.value)} + value={data.fname} InputLabelProps={{ shrink: true }} sx={{ mb: 3 }} /> @@ -124,6 +125,7 @@ export function SignInView() { placeholder="Gyamfi" onChange={(e) => updateField('lname', e.target.value)} InputLabelProps={{ shrink: true }} + value={data.lname} sx={{ mb: 3 }} /> @@ -133,6 +135,7 @@ export function SignInView() { name="email" label="Email address" placeholder="hello@gmail.com" + value={data.email} required onChange={(e) => updateField('email', e.target.value)} InputLabelProps={{ shrink: true }} @@ -145,6 +148,7 @@ export function SignInView() { name="pledge" label="Monthly pledge (GHs)" placeholder="5000" + value={data.pledgeAmount} required type="number" onChange={(e) => updateField('pledgeAmount', e.target.value)} @@ -170,6 +174,7 @@ export function SignInView() { fullWidth name="password" label="Password" + value={data.password} placeholder="*********" InputLabelProps={{ shrink: true }} required @@ -192,6 +197,7 @@ export function SignInView() { name="confirmPassword" label="Confirm password" placeholder="*********" + value={confirmPass} required InputLabelProps={{ shrink: true }} FormHelperTextProps={{ sx: { color: 'tomato' } }} diff --git a/src/sections/contributions/view/contributions-view.tsx b/src/sections/contributions/view/contributions-view.tsx index 9854fb6d4..282cb2c16 100644 --- a/src/sections/contributions/view/contributions-view.tsx +++ b/src/sections/contributions/view/contributions-view.tsx @@ -119,7 +119,7 @@ export function ContributionsView({ onSelectRow={() => table.onSelectRow(row.id)} /> ))} - + fNumber(value), title: { formatter: () => '' } }, - }, - ...chart.options, - }); + // const chartOptions = useChart({ + // chart: { sparkline: { enabled: true } }, + // colors: chartColors, + // xaxis: { categories: chart.categories }, + // grid: { + // padding: { + // top: 6, + // left: 6, + // right: 6, + // bottom: 6, + // }, + // }, + // tooltip: { + // y: { formatter: (value: number) => fNumber(value), title: { formatter: () => '' } }, + // }, + // ...chart.options, + // }); return ( {fShortenNumber(total)} - + /> */} { + if(!user?.id) return try { - if(!user?.id) return const isAdmin = user.role.includes(UserRole.Admin) const [stats,cons] = await Promise.all([ StatsService.get(), @@ -60,7 +59,6 @@ export function OverviewAnalyticsView() { }finally{ setLoading(false) } - },[user?.id,user?.role, getContributions]) useEffect(() => { @@ -121,7 +119,7 @@ export function OverviewAnalyticsView() { icon={icon} chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], - series: [], + series: [10,6,9], }} /> diff --git a/src/services/pay/index.ts b/src/services/pay/index.ts index 63a25c2c0..616f74f67 100644 --- a/src/services/pay/index.ts +++ b/src/services/pay/index.ts @@ -13,9 +13,11 @@ export default class PayService { }); const popup = new PaystackPop(); popup.resumeTransaction(res.code as any); + return popup } catch (error) { const err = error as Error; errCb(err.message); + return null; } } } From 1aa07d2e7eaab863b4612a93aa024a7f145c2ad3 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 29 Nov 2024 18:23:31 +0000 Subject: [PATCH 04/20] fix: removed chart series --- .firebase/hosting.ZGlzdA.cache | 159 ------------------ .firebase/hosting.cHVibGlj.cache | 109 ------------ .github/workflows/firebase-hosting-merge.yml | 20 --- .../firebase-hosting-pull-request.yml | 21 --- 4 files changed, 309 deletions(-) delete mode 100644 .firebase/hosting.ZGlzdA.cache delete mode 100644 .firebase/hosting.cHVibGlj.cache delete mode 100644 .github/workflows/firebase-hosting-merge.yml delete mode 100644 .github/workflows/firebase-hosting-pull-request.yml diff --git a/.firebase/hosting.ZGlzdA.cache b/.firebase/hosting.ZGlzdA.cache deleted file mode 100644 index 139fd03b1..000000000 --- a/.firebase/hosting.ZGlzdA.cache +++ /dev/null @@ -1,159 +0,0 @@ -index.html,1732573423511,6a1a513b2cba7f7d510760a76eb738caef581b43b797367919dbcf59d2ee508b -favicon.ico,1731094223321,165f2ac821b2a5b2a1638fb8f984164fe22bb8ddab1783942510fe9c594d3b16 -404.html,1732313404551,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 -assets/user-zXaFnVpQ.js,1732573423489,138161701d7bd218f52caa64b2db610b32b09af6c505079168b6c46c0466f683 -assets/TableSortLabel-DqBlcVe1.js,1732573423511,92fb8891453885d55f44466a71fcb21fc5689d604ca8232cb0cf6bd21c9f8d84 -assets/sign-in-Di3yP3uF.js,1732573423489,bc404428cbeb8ee886e749452c67af345e8a424026ae057bd0d6b89e0fce714f -assets/products-BXKsuEoz.js,1732573423511,2991d0f7f2ed8f9434e957ab235fef3d5808a91f8bbcfdb2f46be84675d07b9d -assets/Pagination-BWfUqI6R.js,1732573423510,8fab4191999b8a7b539d3dbe64d522f911021ff1135cedbb8092a52780938053 -assets/page-not-found-D1Yz5ywM.js,1732573423488,7863d2aa3ccfeee39489de883b46f1dab4531f1c77b81665ac00f84a668d52e5 -assets/logout-E8j7iOph.js,1732573423510,57e97312036a7b1f5d293ca372b6da5e05bba9bf559bbd4a4adc41e3dc564488 -assets/LastPage-Dsj5-nL2.js,1732573423492,1b9eb0baa4388d79b3659025efbdf483a17b3af8aad1ce1f8c73fcb7cda3b54a -assets/label-C1HB5QEr.js,1732573423511,079e073948e0c340fe33033547c56e4c46476c5924dcea5033d72e57862bf96b -assets/InputAdornment-CD3_vGQ1.js,1732573423489,7373090ca843d1dc8fc69484626c5b66e83df3a71f1447c41f2ea29ee86fbb11 -assets/index-DkH-hf4B.css,1732573423489,ccc6d3f578d3794f8d281087e3e500fd5f205039e6c539b9ef9b11aadd85f04e -assets/index-C809hq80.js,1732573423512,da8964865ae923d8df4f2f719b2976c5ddbb881990dcbd9df531a7e999de8483 -assets/home-4w9uf3I6.js,1732573423511,2e076ea18137383d10c9e13cfea590cde2656a9f8abdd6ac8e58832d74a8733c -assets/Grid2-CBw_h93Y.js,1732573423511,83778c963341abc62db015d6a03fb7c15a4ff6a07ad9138bc55833822805ff5e -assets/dm-sans-latin-wght-normal-DeBecvsH.woff2,1732573423481,f5a7d6a44f03caeab57eae554572d0bd628c97fcbea5d2c1b4ce2644d1972318 -assets/dm-sans-latin-ext-wght-normal-D1bw2c55.woff2,1732573423481,2bb8d0ca5b8931b9e39fc80c49e510fee75b85c8a123e69e3fca55ec9761f0ab -assets/contributions-view-DsTCM7ml.js,1732573423489,9db5196a5526f5fcecb8e09ec11dd0896fce94709dd67ae69e1dec4504e8d2be -assets/contributions-BSi_CEcP.js,1732573423488,806ee5cea162376a5c2f3433734c69b03d685af7e08052a4edca490975147237 -assets/config-global-vueVacRM.js,1732573423488,5a7bfcc9c7523ce4e1c353b59e17435c6db46b95a5f73e7d7396668951944d8b -assets/blog-CsZ57RXH.js,1732573423510,bb4f100c01366b98c87e84c1c08aa55e6666474f6b922a138ca05c800ed8eb6b -assets/barlow-vietnamese-800-normal-DDiAQIYO.woff2,1732573423482,942800ee41816b1ee6a3040e02653c0cae2bb8a638ac3862cb6add2ea0d3ecdc -assets/barlow-vietnamese-800-normal-B95advN4.woff,1732573423488,c48e15f0e185efd5c021059f0234c6e388fd21528695a07e23cd4531a3a55057 -assets/barlow-vietnamese-700-normal-DQ6dlXpV.woff2,1732573423482,db5ca97c658098d37cc5146b5bacf3273e532df431f0dd7cab21b17c3d14e55a -assets/barlow-vietnamese-700-normal-CtEmPuX0.woff,1732573423488,9cfc29ffb566bd2f9e668989357fcd9949c6170e29750500f1d0c2dc8405840d -assets/barlow-vietnamese-600-normal-gKnznvH6.woff2,1732573423482,e8c7f5df4e7fe6be3e2b378542fe54e5756c2ff24025eda3cf39418056889cd2 -assets/barlow-vietnamese-600-normal--rM-LJkj.woff,1732573423488,6bce8267dac53b9a05b2c9d5890a1ee3db6d4643c070df732aeb4d7bf3d8a0df -assets/barlow-vietnamese-500-normal-OcIDFxwj.woff,1732573423482,f8ecdf88476f28c2a85f9d39c8fc158cce8a7c4436800b9750f48943f3fb2c25 -assets/barlow-vietnamese-500-normal-Ds--_AhX.woff2,1732573423482,18e2b6bd60d057b3c66885b1d71ede300c6c9a64ad0489a502fbe9d8e5797365 -assets/barlow-vietnamese-400-normal-Dcxa7Lg7.woff,1732573423482,4fb96908d195c2f9abc7a4a8ff8f91a91b9d40145e80fd6a9258bedb8be3c9af -assets/barlow-vietnamese-400-normal-B8B3d_DU.woff2,1732573423482,c58372c351e59200dee5b6d5247c3c85d3842570330a611d12d74ef821467b1a -assets/barlow-latin-ext-800-normal-uSolDMqV.woff2,1732573423482,6384af3f59034d2dc5f38d8431523032ece92de6367483a2c50a6e7c5a10ee7a -assets/barlow-latin-ext-800-normal-DHjhf6ta.woff,1732573423488,a14ecc03bb066e9ffff9d75e3b9440d8f187bb58787ea29e5543d3b53e4c7298 -assets/barlow-latin-ext-700-normal-sk8_kpF-.woff2,1732573423482,b9732d83b660f09a40cccc2226db588c2b34a4ff21f2119bee5fec02c77cc091 -assets/barlow-latin-ext-700-normal-BgGd7r2K.woff,1732573423488,a6f04abd02c2eb0ce6ad1d1f34d5f26a3000e29960051a2f0ef83f556e9db75b -assets/barlow-latin-ext-600-normal-DxfNEZIW.woff,1732573423488,022c4f95ade99c144813719bb72e165212c43580b79d94068e7cafb176818aab -assets/barlow-latin-ext-600-normal-Brs4HSvV.woff2,1732573423482,986825b8a2273dc11ddb458639a847c93dcb6d620e1743b215d3d1774a38558a -assets/barlow-latin-ext-500-normal-D9Q9nrG3.woff2,1732573423482,2631a3fa5e7137513e0648a8bc9de234c5740ef46ea47b97113b893fa79129a4 -assets/barlow-latin-ext-500-normal-B8S-Wk_i.woff,1732573423487,15680c9130e84729e68b7b209f4bb1a37cda56b51ce2cce766e91ddeefb69f9d -assets/barlow-latin-ext-400-normal-DsA6LmuC.woff2,1732573423482,acda01528c8e85ece2d41038b2112999a7cba63a0bdd119ed5fce96e06db411f -assets/barlow-latin-ext-400-normal-DGsTVCL_.woff,1732573423482,0808e9223b3c6fd1945fdef69a197bc4b93123c279dcad33372127bad7cec504 -assets/barlow-latin-800-normal-Dp3TYPAo.woff,1732573423489,d8483b7f583ebb1adf24086c4d11d8b57574f66c179526bed1a5cb42b5af640a -assets/barlow-latin-800-normal-B50OFIWa.woff2,1732573423482,7ec9815bb2b5a38a965f83a81450d5700b75cb7631cc2f5b80424baf8acd46ed -assets/barlow-latin-700-normal-Bku5AOSK.woff2,1732573423482,c632885fbaedca07d005d44a7a767649ffdad498c4d4642c76e26b9507a4fa59 -assets/barlow-latin-700-normal-AkmsA7ur.woff,1732573423488,4d49ff23dd1dc1ac33b88d690534fbeef31c79e516a66761ccb5b8924aae2629 -assets/barlow-latin-600-normal-DznpAvW9.woff,1732573423488,61c83e9735dc1f2aa969c65f62dee7285fcb2449b238cd233598796eb02db621 -assets/barlow-latin-600-normal-DMnFtVx9.woff2,1732573423482,1b5fe7676f9341efd7d14c61154b1a000eda7b88d907a309772ac7c5632a2500 -assets/barlow-latin-500-normal-BRhHB0xN.woff2,1732573423482,57bbeeb83dd750be97345420f6515622d1a3c5a5cb923f27f6e552cde3f1199b -assets/barlow-latin-500-normal-BAaAwKGi.woff,1732573423487,af42825f784d1977f5f3977d58437a2dc233c7599854dcce62312349002e3c5f -assets/barlow-latin-400-normal-Gqj0RTbC.woff,1732573423487,08b51a03374472e6035c824092560ad1b54e7605973b9447fca43f073f37d3fc -assets/barlow-latin-400-normal-CtwdMZP0.woff2,1732573423482,bbd209eb92a1160ea1f3862adf82281c99a5a1028d163df5fb9394caf803f52f -assets/images/minimal-free-preview.jpg,1730497678201,4c77f6cb372e292ad231630e473be719443a2e8aea8bb5ddf49efc6bac92e2fd -assets/images/logo.png,1723926015463,83554fa707bbc7e4e3052e26ca8b9f09a4693eb3fb1175afb7f55b9eceba81cf -assets/images/product/product-9.webp,1730497678208,ca203ffdf49f6c038d5e7ceaf942a65d4c374bc96caf2bc2ec3b0c5eed004d94 -assets/images/product/product-8.webp,1730497678208,0c94f706ce17acc95d6a2256036429532545b770323eb060f5c7a92ec96a180e -assets/images/product/product-7.webp,1730497678207,eba409ba937affe9c681280f640172be8ed1dc5a5ee2a3fd59bc9a8aa1ca6d49 -assets/images/product/product-6.webp,1730497678207,be7d13ac2a6af1d875364521efc509f914140d0c43c42e4a1e248874a1e0574c -assets/images/product/product-5.webp,1730497678207,4f2468951a795e5b88e95a750f5d98c02407749037bbc678eee73d94ece1b64b -assets/images/product/product-4.webp,1730497678207,afbe0a607b6178af6eb27c60851f9ee8194c806a1a6bdc633ea5d22aa31dcd59 -assets/images/product/product-3.webp,1730497678206,6dcbb5d8885a999f05a244949d338e6a7db7bd5c17ca975731cd084f35aa5a69 -assets/images/product/product-24.webp,1730497678206,efc398463261d8a24ee7b4a69accb3c02371fbd4b34cc5349e968b6fa8d08462 -assets/images/product/product-23.webp,1730497678206,63bd265a6f4f1ef970050c6fd02e1161c009ebfab1514e9a421e5461776466de -assets/images/product/product-22.webp,1730497678205,334c9944deb81bd4ede260ed3a952216a9f7d54e445d502ded6acbc8c1cbb1a8 -assets/images/product/product-21.webp,1730497678205,512778ade76528c7b54e27188cba913f73cd77b0205b34188cd194b6b7241965 -assets/images/product/product-20.webp,1730497678205,188781420f02eb2af255b057639fa7dd7fc2fe934485a2521523bc5096cdc812 -assets/images/product/product-2.webp,1730497678205,3f75bb21d6f32f9055f0262f1eda042e413444cb12de1133d8d1ae66da88bc5c -assets/images/product/product-19.webp,1730497678204,2c5cd7b22c2efd83335c670d1b39c5297359a1021a958cd73081fe893e5f9d1a -assets/images/product/product-18.webp,1730497678204,057d92d3ffeb3e538d934c0982ef6099ed48b14f60f496080dd7286e7f93f42c -assets/images/product/product-17.webp,1730497678204,ad2054fad16e43349249e9c338f8c40e30a5aa39d20c7a16a4cb37f964d4a8e4 -assets/images/product/product-16.webp,1730497678203,e23e3ecce1b93d4277238212afdf23f52d7ff53642345920daf49dca20ac5a0e -assets/images/product/product-15.webp,1730497678203,2e8dd27240d627a242ee34cf8df790db5eeed047d7f2b954765691b8b1b579ef -assets/images/product/product-14.webp,1730497678203,742fdde0770c298645b7e83c98bee25381bc66733aef9b45d8d75048836effef -assets/images/product/product-13.webp,1730497678203,c3b1aadef6eec00cdad8de94a70c63bbe5ea9274083031b53d674744087f9abc -assets/images/product/product-12.webp,1730497678202,409ea5052137ddff2992451b184a64282f61788c1004e14fc133e0f1744e6574 -assets/images/product/product-11.webp,1730497678202,d45873da256da2d18ca61047844d013e94fa41bd1274cdedbee3551e54fdb51e -assets/images/product/product-10.webp,1730497678202,a4c9ca613959b09e4513f348f5aa92ac1c9e95695402726466fbf9836fa0a56b -assets/images/product/product-1.webp,1730497678201,37be3d1b43b33810044596fc688806fb0aba2df18ab54e617185a74d55046f04 -assets/images/cover/cover-9.webp,1730497678201,b115f8a7861d7f4df5b4a6ec47c0cd8d24f1062e581516647a619bc48978e20b -assets/images/cover/cover-8.webp,1730497678200,45d72293e258133203dbd443039dd8ea23616a4485667ced2f38e2dc7c52bcd3 -assets/images/cover/cover-7.webp,1730497678200,4022dcaff6bcf205e7889dd8c2aad5e516fd2a6c3b6ae3a669e2916cde1a619d -assets/images/cover/cover-6.webp,1730497678200,3e173882f0e2d7f3a50d3d83ebc95407445a813e5864c0f0d3c341aceb8706fa -assets/images/cover/cover-5.webp,1730497678199,635df6309603bec2cd8b2341880d28a21cf38acaf244f0dc47604fb165ec7811 -assets/images/cover/cover-4.webp,1730497678199,cd9d7319997057a3bab84fb0c4b450ffb474293ee11160e0c6dfe3dc67232bf4 -assets/images/cover/cover-3.webp,1730497678198,302bca427c7eab606e337fff52d2dc045f8c7ff31b4a0597c0b97d7a5ca8f8d0 -assets/images/cover/cover-24.webp,1730497678198,d7375b13cb9d7551a5e9e447109aacba25052343426352c5185ba125c3a21c10 -assets/images/cover/cover-23.webp,1730497678198,942ce6096494bc4ff90b16421f0898460413b094b98e6e3ccfee87226074007c -assets/images/cover/cover-22.webp,1730497678197,1d5e0bd87ca66e471fdea9acb178f5b6eedbf5e671eb5b2244b3c5090d384fc3 -assets/images/cover/cover-21.webp,1730497678197,b60491f41a23a92deadeafd153f40f1b4e798b7461b7b0474316770298276d2a -assets/images/cover/cover-20.webp,1730497678197,24eab942876c732470fd2266906c1303b9274749dd848fb77d33c54158b614b1 -assets/images/cover/cover-2.webp,1730497678197,59926fffc9bfd01841edd61459957f3b1ba7fedc6f964a3135ba5e5e31f1de89 -assets/images/cover/cover-19.webp,1730497678197,a0ad43977ac0b238d2641ec3bf909b7bf54101fa242179984e234a414ef5de6b -assets/images/cover/cover-18.webp,1730497678196,6c235e117c6ed3d5ad07035b83314807d89d87fad821e708394410f6c9571136 -assets/images/cover/cover-17.webp,1730497678196,4128aa150c35e997480ccb72ffdc0c163043b8a49995ed3eed30871ca2bd0d93 -assets/images/cover/cover-16.webp,1730497678196,63baabb9d2dd5742f117265fc19608736eb91fe2822ead17ffc6e221bf018285 -assets/images/cover/cover-15.webp,1730497678196,98e785296fffd493891cba8a7d46e925abaa99d757d988394f9e73dcd50a9b92 -assets/images/cover/cover-14.webp,1730497678195,035ef0ef38e80f5b0508b578a4dc622a80186de9a37cc890ea72052ae225034e -assets/images/cover/cover-13.webp,1730497678195,e3cc86a856eb15408e8720f9547cf29f9bd51e27f92a2a4d2b69f312ed08ca07 -assets/images/cover/cover-12.webp,1730497678195,16c3d223174af28c80890c9e3cf7dfae4b27d81f7e69a7d0b4e896043e72c469 -assets/images/cover/cover-11.webp,1730497678194,58dc83e25c4c515751a0ffcb8bc9d08810b27c4b4db0738789c77d463134142d -assets/images/cover/cover-10.webp,1730497678194,4372fcf499efa70470136ea674753f746d8c3f7270a9ff3aa80eda3b4077792c -assets/images/cover/cover-1.webp,1730497678194,b337fa4479d341d4082e0b0c49947d82b77e37a64bd5de489c95b9b3bb7823c7 -assets/images/avatar/avatar-9.webp,1730497678193,e7761af5f170c55691dd6a46068113ba966c542303aed6ff815576c89dd94406 -assets/images/avatar/avatar-8.webp,1730497678193,966859d258df144ebe7e7789c647865d868a58543cbd5599269a1f32769d073d -assets/images/avatar/avatar-7.webp,1730497678193,5feb6f7c2ce0754c6ab93e11366b94767b12e20d82722f4890c6d31a17814530 -assets/images/avatar/avatar-6.webp,1730497678193,8a5e9655fa9c83e02b11a2a9ff7ae408dca60068b966a264eab101fb7637f0a6 -assets/images/avatar/avatar-5.webp,1730497678193,0a3a7763788452a818cd51a8021d842bcb6ec028b21b4fe3ed61d487ca1d59e6 -assets/images/avatar/avatar-4.webp,1730497678193,7bce88a9590e09fb12a4684476a72815ab13584f41991326959049b387a97cd3 -assets/images/avatar/avatar-3.webp,1730497678193,c0aaa16ac65e0637dada06cc129cdb3d688eca72ee04db6ee600e5bb91bed06e -assets/images/avatar/avatar-25.webp,1730497678193,92e1544c1d72a16189e3a697c382367ac20e16e53c168ee8a8ee3b3249ac974f -assets/images/avatar/avatar-24.webp,1730497678192,3bc27ec65537e102adce91fc29836947dc2806d09e5ac11d83bb74957dbf0f86 -assets/images/avatar/avatar-23.webp,1730497678192,89d61322d2d92a0ea82e8271254da4b430dddddd04eb590da57134b917ce4467 -assets/images/avatar/avatar-22.webp,1730497678192,1bc497247991ac7b58b78246867bff2b61ecb5bfb0ab87fe0dbae7a897676f74 -assets/images/avatar/avatar-21.webp,1730497678192,8ea105cb2e88992efc7a58fcb1bfd640c2a4f9853731a629f5c11484bc686819 -assets/images/avatar/avatar-20.webp,1730497678192,3377e455e4e4d3ff20888fc3baf612d233e8f09bd24b918a126dd29be790960b -assets/images/avatar/avatar-2.webp,1730497678192,50e88d816f28e7c386649f8515c685455df36fdfff9321d825627e5b43dadb05 -assets/images/avatar/avatar-19.webp,1730497678191,84a72c87d9f310cb64c51c6abc9d59f6563a8464b29d33b924bf0430a7dde362 -assets/images/avatar/avatar-18.webp,1730497678191,ddba817971c518c999f6cf44c071d70f21bfdb7d34e38715a56c27386baa87a5 -assets/images/avatar/avatar-17.webp,1730497678191,168eccfe2a0ae7446f00c7b2b99d94e8b4d897194cb2efc85ba15ee4ff6946b4 -assets/images/avatar/avatar-16.webp,1730497678191,48ab185e8bc0b540310d02e5da4b3a83220205d79180b83f26bfc8a0a99f1e3a -assets/images/avatar/avatar-15.webp,1730497678191,b3a6fa19dc6fdc6b0f4fa0717515805dbe07f7aed8cdbd8c60f2bddaaa9e3b18 -assets/images/avatar/avatar-14.webp,1730497678191,e2b6df848747e9bbe599501b32998ebdc9a27d45e6f99a067d975e4b9ad38f83 -assets/images/avatar/avatar-13.webp,1730497678191,2fd37533955ee031f8e3fed8c35c896921b012784d22130686d90c01baaba248 -assets/images/avatar/avatar-12.webp,1730497678191,51c0f5bc7e55bffda8b506ae4a716bd2c18032356b0925565df2c1771ee1f17a -assets/images/avatar/avatar-11.webp,1730497678190,27d7e39340af7a0125d29a568a0190480fcc9323ca9d936270152d8227c703df -assets/images/avatar/avatar-10.webp,1730497678190,c15c4a3ec76c5c1375aad3b6a1c20c21ad43e581984ed3c64c2ab7f43738e7c0 -assets/images/avatar/avatar-1.webp,1730497678190,7a07a94e9c40d2833b85462c1d9a2ad6ced2690118b7a08ad048941ac61c5528 -assets/illustrations/illustration-dashboard.webp,1730497678190,e8424723a1e27af60c71414bbfd5ca94ce1dca7c9eee158fb4892ea3123fb2de -assets/illustrations/illustration-404.svg,1730497678189,027ff0d70d0d6ceb54508f0b50c5aa8661481d4a17310fef632ef81601a5ec94 -assets/icons/shape-avatar.svg,1730497678189,fe96f4c1005d3f8ce2c7052870b057f5ee5f2a46670c0db5d83ab051ec489ca7 -assets/icons/workspaces/logo-3.webp,1730497678189,10e2ec8b1ec3fa6d3dd1ba61e1bf9ccd7cd695f97f2a7f1ce37a47727a8d2a70 -assets/icons/workspaces/logo-2.webp,1730497678189,f808597e83e2ac4aca785ea05e500ac00689edc1e90747c3d8cc9c7af7073fd5 -assets/icons/workspaces/logo-1.webp,1730497678189,e117dafe4c11878278585224a10ac3c47bf9b980ceb14d8f8d1db488f60cfd52 -assets/icons/status/ic-success.svg,1730522011312,a31fa9eb430d91ff25ee2b0facf05a066fd761f4aa444175797fd6972682132a -assets/icons/status/ic-pending.svg,1730521948380,0221681d0856f7f6b4373ba8678efd6a20c9fd9b6646fe2f5b4472c857a620a9 -assets/icons/status/ic-failed.svg,1730522089232,ad232b5c225907aa53cb0102533ab8177b02be175805a73110d5460dc23bea56 -assets/icons/notification/ic-notification-shipping.svg,1730497678188,4d22eb0420fa10dcd646313f4ce833f699fa53bc7d3e4869589d30c4b5ed141e -assets/icons/notification/ic-notification-package.svg,1730497678188,9a798aa9f6092ed819f508b7763d6f3384d179e325acaaad63e3c0593521f9f4 -assets/icons/notification/ic-notification-mail.svg,1730497678188,5db56840606875b987d4b865b5964e5c7b5462e543267215e6efe9aceadc61d5 -assets/icons/notification/ic-notification-chat.svg,1730497678188,07001d6d6f8d9979b3c3a71c6bc9a5e0f753daea219bac03aec51666fa91698a -assets/icons/navbar/ic-user.svg,1730497678188,06a7a0bf374f679922e302f3e2894ed0e55756cca97bc140a5413a5510302d44 -assets/icons/navbar/ic-lock.svg,1730497678188,9a22e70b283d2340f94407b85bbfac52555566b9f5587538000b365281128fec -assets/icons/navbar/ic-exit.svg,1730500920359,d5c8d231f3f1540c300b2bdb33d4e79c5e1704e0cde94d9b3ae956bf7b186c5f -assets/icons/navbar/ic-donate.svg,1730517528929,07327ef7502d2f468ff9faa1fecf353104f05f7eb7391cf4c78fbadc4c33a991 -assets/icons/navbar/ic-disabled.svg,1730497678187,54330961ed98db4fa0e955f1f201ddc96a47fc36dd499d65364c680cc2b7444f -assets/icons/navbar/ic-cart.svg,1730497678187,4147c3462c875b47a046e2840b916485c73a43e244b12782e272b8e5de40273a -assets/icons/navbar/ic-blog.svg,1730497678187,aa10a1703fc0df81d97a5e804d1dfac12fa59a8b1d399ae40e5e28bb24c57cbf -assets/icons/navbar/ic-analytics.svg,1730497678187,6a401d9abb256c2454638fb385c90e1b38f0ecfd8b42e9ff2c21b2c683a75ca1 -assets/icons/glass/ic-wallet.svg,1730503008957,f5de62accf55f72e54c201e5735206969f5917ac966587517f5b9c99973e219e -assets/icons/glass/ic-glass-users.svg,1730497678187,eee91092e79a8c94fa24f80126ddec3ceb48774d0f6c1eb287cd9ecbd35bd437 -assets/icons/glass/ic-glass-message.svg,1730497678187,9e4db5146d3c65fd0a3a55633020b97f90f7357a61e9adb3e03e83671a635665 -assets/icons/glass/ic-glass-buy.svg,1730497678186,3b3dba826f809dd4630b130706c468595b7df866da2dfb67fdba9d4f4470e58c -assets/icons/glass/ic-donate.svg,1730502720108,ed3a81af036fa4d88433a24d2abd38d44b0634c05a8d4b2fd5da8051738b381c -assets/icons/flags/ic-flag-fr.svg,1730497678186,a277878f6eeab357465e5e8d8ce0dd78ba02d8f4ed7339467470f82440ab6c2d -assets/icons/flags/ic-flag-en.svg,1730497678186,abc6fdcb3cf6a9252e4a7cf2eb0656140a0d27c5503cca6aa15775ef690c77ae -assets/icons/flags/ic-flag-de.svg,1730497678186,38059eb5d840d3dc87261c954c48a963c7b7cc449a8fde9a062aa9c5fa79ebd8 -assets/background/shape-square.svg,1730497678186,10fa9733a3dd4b2e100f20cea8651eb06dd2dc1d2b424e9283f853f2270a7c05 -assets/background/overlay.jpg,1730497678185,eacfb1c102e43049b710e6671348aae97f0cf90ae0fb4cb15386739a3aa2b527 diff --git a/.firebase/hosting.cHVibGlj.cache b/.firebase/hosting.cHVibGlj.cache deleted file mode 100644 index 69c2d9e90..000000000 --- a/.firebase/hosting.cHVibGlj.cache +++ /dev/null @@ -1,109 +0,0 @@ -index.html,1732313404911,38aee86a3bae65d47d45915d8e66991582da251402dcf226b46cd78bd0e920bf -favicon.ico,1731094223321,165f2ac821b2a5b2a1638fb8f984164fe22bb8ddab1783942510fe9c594d3b16 -404.html,1732313404551,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 -assets/images/minimal-free-preview.jpg,1730497678201,4c77f6cb372e292ad231630e473be719443a2e8aea8bb5ddf49efc6bac92e2fd -assets/images/logo.png,1723926015463,83554fa707bbc7e4e3052e26ca8b9f09a4693eb3fb1175afb7f55b9eceba81cf -assets/images/product/product-9.webp,1730497678208,ca203ffdf49f6c038d5e7ceaf942a65d4c374bc96caf2bc2ec3b0c5eed004d94 -assets/images/product/product-8.webp,1730497678208,0c94f706ce17acc95d6a2256036429532545b770323eb060f5c7a92ec96a180e -assets/images/product/product-7.webp,1730497678207,eba409ba937affe9c681280f640172be8ed1dc5a5ee2a3fd59bc9a8aa1ca6d49 -assets/images/product/product-6.webp,1730497678207,be7d13ac2a6af1d875364521efc509f914140d0c43c42e4a1e248874a1e0574c -assets/images/product/product-5.webp,1730497678207,4f2468951a795e5b88e95a750f5d98c02407749037bbc678eee73d94ece1b64b -assets/images/product/product-4.webp,1730497678207,afbe0a607b6178af6eb27c60851f9ee8194c806a1a6bdc633ea5d22aa31dcd59 -assets/images/product/product-3.webp,1730497678206,6dcbb5d8885a999f05a244949d338e6a7db7bd5c17ca975731cd084f35aa5a69 -assets/images/product/product-24.webp,1730497678206,efc398463261d8a24ee7b4a69accb3c02371fbd4b34cc5349e968b6fa8d08462 -assets/images/product/product-23.webp,1730497678206,63bd265a6f4f1ef970050c6fd02e1161c009ebfab1514e9a421e5461776466de -assets/images/product/product-22.webp,1730497678205,334c9944deb81bd4ede260ed3a952216a9f7d54e445d502ded6acbc8c1cbb1a8 -assets/images/product/product-21.webp,1730497678205,512778ade76528c7b54e27188cba913f73cd77b0205b34188cd194b6b7241965 -assets/images/product/product-20.webp,1730497678205,188781420f02eb2af255b057639fa7dd7fc2fe934485a2521523bc5096cdc812 -assets/images/product/product-2.webp,1730497678205,3f75bb21d6f32f9055f0262f1eda042e413444cb12de1133d8d1ae66da88bc5c -assets/images/product/product-19.webp,1730497678204,2c5cd7b22c2efd83335c670d1b39c5297359a1021a958cd73081fe893e5f9d1a -assets/images/product/product-18.webp,1730497678204,057d92d3ffeb3e538d934c0982ef6099ed48b14f60f496080dd7286e7f93f42c -assets/images/product/product-17.webp,1730497678204,ad2054fad16e43349249e9c338f8c40e30a5aa39d20c7a16a4cb37f964d4a8e4 -assets/images/product/product-16.webp,1730497678203,e23e3ecce1b93d4277238212afdf23f52d7ff53642345920daf49dca20ac5a0e -assets/images/product/product-15.webp,1730497678203,2e8dd27240d627a242ee34cf8df790db5eeed047d7f2b954765691b8b1b579ef -assets/images/product/product-14.webp,1730497678203,742fdde0770c298645b7e83c98bee25381bc66733aef9b45d8d75048836effef -assets/images/product/product-13.webp,1730497678203,c3b1aadef6eec00cdad8de94a70c63bbe5ea9274083031b53d674744087f9abc -assets/images/product/product-12.webp,1730497678202,409ea5052137ddff2992451b184a64282f61788c1004e14fc133e0f1744e6574 -assets/images/product/product-11.webp,1730497678202,d45873da256da2d18ca61047844d013e94fa41bd1274cdedbee3551e54fdb51e -assets/images/product/product-10.webp,1730497678202,a4c9ca613959b09e4513f348f5aa92ac1c9e95695402726466fbf9836fa0a56b -assets/images/product/product-1.webp,1730497678201,37be3d1b43b33810044596fc688806fb0aba2df18ab54e617185a74d55046f04 -assets/images/cover/cover-9.webp,1730497678201,b115f8a7861d7f4df5b4a6ec47c0cd8d24f1062e581516647a619bc48978e20b -assets/images/cover/cover-8.webp,1730497678200,45d72293e258133203dbd443039dd8ea23616a4485667ced2f38e2dc7c52bcd3 -assets/images/cover/cover-7.webp,1730497678200,4022dcaff6bcf205e7889dd8c2aad5e516fd2a6c3b6ae3a669e2916cde1a619d -assets/images/cover/cover-6.webp,1730497678200,3e173882f0e2d7f3a50d3d83ebc95407445a813e5864c0f0d3c341aceb8706fa -assets/images/cover/cover-5.webp,1730497678199,635df6309603bec2cd8b2341880d28a21cf38acaf244f0dc47604fb165ec7811 -assets/images/cover/cover-4.webp,1730497678199,cd9d7319997057a3bab84fb0c4b450ffb474293ee11160e0c6dfe3dc67232bf4 -assets/images/cover/cover-3.webp,1730497678198,302bca427c7eab606e337fff52d2dc045f8c7ff31b4a0597c0b97d7a5ca8f8d0 -assets/images/cover/cover-24.webp,1730497678198,d7375b13cb9d7551a5e9e447109aacba25052343426352c5185ba125c3a21c10 -assets/images/cover/cover-23.webp,1730497678198,942ce6096494bc4ff90b16421f0898460413b094b98e6e3ccfee87226074007c -assets/images/cover/cover-22.webp,1730497678197,1d5e0bd87ca66e471fdea9acb178f5b6eedbf5e671eb5b2244b3c5090d384fc3 -assets/images/cover/cover-21.webp,1730497678197,b60491f41a23a92deadeafd153f40f1b4e798b7461b7b0474316770298276d2a -assets/images/cover/cover-20.webp,1730497678197,24eab942876c732470fd2266906c1303b9274749dd848fb77d33c54158b614b1 -assets/images/cover/cover-2.webp,1730497678197,59926fffc9bfd01841edd61459957f3b1ba7fedc6f964a3135ba5e5e31f1de89 -assets/images/cover/cover-19.webp,1730497678197,a0ad43977ac0b238d2641ec3bf909b7bf54101fa242179984e234a414ef5de6b -assets/images/cover/cover-18.webp,1730497678196,6c235e117c6ed3d5ad07035b83314807d89d87fad821e708394410f6c9571136 -assets/images/cover/cover-17.webp,1730497678196,4128aa150c35e997480ccb72ffdc0c163043b8a49995ed3eed30871ca2bd0d93 -assets/images/cover/cover-16.webp,1730497678196,63baabb9d2dd5742f117265fc19608736eb91fe2822ead17ffc6e221bf018285 -assets/images/cover/cover-15.webp,1730497678196,98e785296fffd493891cba8a7d46e925abaa99d757d988394f9e73dcd50a9b92 -assets/images/cover/cover-14.webp,1730497678195,035ef0ef38e80f5b0508b578a4dc622a80186de9a37cc890ea72052ae225034e -assets/images/cover/cover-13.webp,1730497678195,e3cc86a856eb15408e8720f9547cf29f9bd51e27f92a2a4d2b69f312ed08ca07 -assets/images/cover/cover-12.webp,1730497678195,16c3d223174af28c80890c9e3cf7dfae4b27d81f7e69a7d0b4e896043e72c469 -assets/images/cover/cover-11.webp,1730497678194,58dc83e25c4c515751a0ffcb8bc9d08810b27c4b4db0738789c77d463134142d -assets/images/cover/cover-10.webp,1730497678194,4372fcf499efa70470136ea674753f746d8c3f7270a9ff3aa80eda3b4077792c -assets/images/cover/cover-1.webp,1730497678194,b337fa4479d341d4082e0b0c49947d82b77e37a64bd5de489c95b9b3bb7823c7 -assets/images/avatar/avatar-9.webp,1730497678193,e7761af5f170c55691dd6a46068113ba966c542303aed6ff815576c89dd94406 -assets/images/avatar/avatar-8.webp,1730497678193,966859d258df144ebe7e7789c647865d868a58543cbd5599269a1f32769d073d -assets/images/avatar/avatar-7.webp,1730497678193,5feb6f7c2ce0754c6ab93e11366b94767b12e20d82722f4890c6d31a17814530 -assets/images/avatar/avatar-6.webp,1730497678193,8a5e9655fa9c83e02b11a2a9ff7ae408dca60068b966a264eab101fb7637f0a6 -assets/images/avatar/avatar-5.webp,1730497678193,0a3a7763788452a818cd51a8021d842bcb6ec028b21b4fe3ed61d487ca1d59e6 -assets/images/avatar/avatar-4.webp,1730497678193,7bce88a9590e09fb12a4684476a72815ab13584f41991326959049b387a97cd3 -assets/images/avatar/avatar-3.webp,1730497678193,c0aaa16ac65e0637dada06cc129cdb3d688eca72ee04db6ee600e5bb91bed06e -assets/images/avatar/avatar-25.webp,1730497678193,92e1544c1d72a16189e3a697c382367ac20e16e53c168ee8a8ee3b3249ac974f -assets/images/avatar/avatar-24.webp,1730497678192,3bc27ec65537e102adce91fc29836947dc2806d09e5ac11d83bb74957dbf0f86 -assets/images/avatar/avatar-23.webp,1730497678192,89d61322d2d92a0ea82e8271254da4b430dddddd04eb590da57134b917ce4467 -assets/images/avatar/avatar-22.webp,1730497678192,1bc497247991ac7b58b78246867bff2b61ecb5bfb0ab87fe0dbae7a897676f74 -assets/images/avatar/avatar-21.webp,1730497678192,8ea105cb2e88992efc7a58fcb1bfd640c2a4f9853731a629f5c11484bc686819 -assets/images/avatar/avatar-20.webp,1730497678192,3377e455e4e4d3ff20888fc3baf612d233e8f09bd24b918a126dd29be790960b -assets/images/avatar/avatar-2.webp,1730497678192,50e88d816f28e7c386649f8515c685455df36fdfff9321d825627e5b43dadb05 -assets/images/avatar/avatar-19.webp,1730497678191,84a72c87d9f310cb64c51c6abc9d59f6563a8464b29d33b924bf0430a7dde362 -assets/images/avatar/avatar-18.webp,1730497678191,ddba817971c518c999f6cf44c071d70f21bfdb7d34e38715a56c27386baa87a5 -assets/images/avatar/avatar-17.webp,1730497678191,168eccfe2a0ae7446f00c7b2b99d94e8b4d897194cb2efc85ba15ee4ff6946b4 -assets/images/avatar/avatar-16.webp,1730497678191,48ab185e8bc0b540310d02e5da4b3a83220205d79180b83f26bfc8a0a99f1e3a -assets/images/avatar/avatar-15.webp,1730497678191,b3a6fa19dc6fdc6b0f4fa0717515805dbe07f7aed8cdbd8c60f2bddaaa9e3b18 -assets/images/avatar/avatar-14.webp,1730497678191,e2b6df848747e9bbe599501b32998ebdc9a27d45e6f99a067d975e4b9ad38f83 -assets/images/avatar/avatar-13.webp,1730497678191,2fd37533955ee031f8e3fed8c35c896921b012784d22130686d90c01baaba248 -assets/images/avatar/avatar-12.webp,1730497678191,51c0f5bc7e55bffda8b506ae4a716bd2c18032356b0925565df2c1771ee1f17a -assets/images/avatar/avatar-11.webp,1730497678190,27d7e39340af7a0125d29a568a0190480fcc9323ca9d936270152d8227c703df -assets/images/avatar/avatar-10.webp,1730497678190,c15c4a3ec76c5c1375aad3b6a1c20c21ad43e581984ed3c64c2ab7f43738e7c0 -assets/images/avatar/avatar-1.webp,1730497678190,7a07a94e9c40d2833b85462c1d9a2ad6ced2690118b7a08ad048941ac61c5528 -assets/illustrations/illustration-dashboard.webp,1730497678190,e8424723a1e27af60c71414bbfd5ca94ce1dca7c9eee158fb4892ea3123fb2de -assets/illustrations/illustration-404.svg,1730497678189,027ff0d70d0d6ceb54508f0b50c5aa8661481d4a17310fef632ef81601a5ec94 -assets/icons/shape-avatar.svg,1730497678189,fe96f4c1005d3f8ce2c7052870b057f5ee5f2a46670c0db5d83ab051ec489ca7 -assets/icons/workspaces/logo-3.webp,1730497678189,10e2ec8b1ec3fa6d3dd1ba61e1bf9ccd7cd695f97f2a7f1ce37a47727a8d2a70 -assets/icons/workspaces/logo-2.webp,1730497678189,f808597e83e2ac4aca785ea05e500ac00689edc1e90747c3d8cc9c7af7073fd5 -assets/icons/workspaces/logo-1.webp,1730497678189,e117dafe4c11878278585224a10ac3c47bf9b980ceb14d8f8d1db488f60cfd52 -assets/icons/status/ic-success.svg,1730522011312,a31fa9eb430d91ff25ee2b0facf05a066fd761f4aa444175797fd6972682132a -assets/icons/status/ic-pending.svg,1730521948380,0221681d0856f7f6b4373ba8678efd6a20c9fd9b6646fe2f5b4472c857a620a9 -assets/icons/status/ic-failed.svg,1730522089232,ad232b5c225907aa53cb0102533ab8177b02be175805a73110d5460dc23bea56 -assets/icons/notification/ic-notification-shipping.svg,1730497678188,4d22eb0420fa10dcd646313f4ce833f699fa53bc7d3e4869589d30c4b5ed141e -assets/icons/notification/ic-notification-package.svg,1730497678188,9a798aa9f6092ed819f508b7763d6f3384d179e325acaaad63e3c0593521f9f4 -assets/icons/notification/ic-notification-mail.svg,1730497678188,5db56840606875b987d4b865b5964e5c7b5462e543267215e6efe9aceadc61d5 -assets/icons/notification/ic-notification-chat.svg,1730497678188,07001d6d6f8d9979b3c3a71c6bc9a5e0f753daea219bac03aec51666fa91698a -assets/icons/navbar/ic-user.svg,1730497678188,06a7a0bf374f679922e302f3e2894ed0e55756cca97bc140a5413a5510302d44 -assets/icons/navbar/ic-lock.svg,1730497678188,9a22e70b283d2340f94407b85bbfac52555566b9f5587538000b365281128fec -assets/icons/navbar/ic-exit.svg,1730500920359,d5c8d231f3f1540c300b2bdb33d4e79c5e1704e0cde94d9b3ae956bf7b186c5f -assets/icons/navbar/ic-donate.svg,1730517528929,07327ef7502d2f468ff9faa1fecf353104f05f7eb7391cf4c78fbadc4c33a991 -assets/icons/navbar/ic-disabled.svg,1730497678187,54330961ed98db4fa0e955f1f201ddc96a47fc36dd499d65364c680cc2b7444f -assets/icons/navbar/ic-cart.svg,1730497678187,4147c3462c875b47a046e2840b916485c73a43e244b12782e272b8e5de40273a -assets/icons/navbar/ic-blog.svg,1730497678187,aa10a1703fc0df81d97a5e804d1dfac12fa59a8b1d399ae40e5e28bb24c57cbf -assets/icons/navbar/ic-analytics.svg,1730497678187,6a401d9abb256c2454638fb385c90e1b38f0ecfd8b42e9ff2c21b2c683a75ca1 -assets/icons/glass/ic-wallet.svg,1730503008957,f5de62accf55f72e54c201e5735206969f5917ac966587517f5b9c99973e219e -assets/icons/glass/ic-glass-users.svg,1730497678187,eee91092e79a8c94fa24f80126ddec3ceb48774d0f6c1eb287cd9ecbd35bd437 -assets/icons/glass/ic-glass-message.svg,1730497678187,9e4db5146d3c65fd0a3a55633020b97f90f7357a61e9adb3e03e83671a635665 -assets/icons/glass/ic-glass-buy.svg,1730497678186,3b3dba826f809dd4630b130706c468595b7df866da2dfb67fdba9d4f4470e58c -assets/icons/glass/ic-donate.svg,1730502720108,ed3a81af036fa4d88433a24d2abd38d44b0634c05a8d4b2fd5da8051738b381c -assets/icons/flags/ic-flag-fr.svg,1730497678186,a277878f6eeab357465e5e8d8ce0dd78ba02d8f4ed7339467470f82440ab6c2d -assets/icons/flags/ic-flag-en.svg,1730497678186,abc6fdcb3cf6a9252e4a7cf2eb0656140a0d27c5503cca6aa15775ef690c77ae -assets/icons/flags/ic-flag-de.svg,1730497678186,38059eb5d840d3dc87261c954c48a963c7b7cc449a8fde9a062aa9c5fa79ebd8 -assets/background/shape-square.svg,1730497678186,10fa9733a3dd4b2e100f20cea8651eb06dd2dc1d2b424e9283f853f2270a7c05 -assets/background/overlay.jpg,1730497678185,eacfb1c102e43049b710e6671348aae97f0cf90ae0fb4cb15386739a3aa2b527 diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml deleted file mode 100644 index 886402797..000000000 --- a/.github/workflows/firebase-hosting-merge.yml +++ /dev/null @@ -1,20 +0,0 @@ -# This file was auto-generated by the Firebase CLI -# https://github.com/firebase/firebase-tools - -name: Deploy to Firebase Hosting on merge -on: - push: - branches: - - main -jobs: - build_and_deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: npm ci && npm run build - - uses: FirebaseExtended/action-hosting-deploy@v0 - with: - repoToken: ${{ secrets.GITHUB_TOKEN }} - firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_PABGM_39720 }} - channelId: live - projectId: pabgm-39720 diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml deleted file mode 100644 index 710d7aebd..000000000 --- a/.github/workflows/firebase-hosting-pull-request.yml +++ /dev/null @@ -1,21 +0,0 @@ -# This file was auto-generated by the Firebase CLI -# https://github.com/firebase/firebase-tools - -name: Deploy to Firebase Hosting on PR -on: pull_request -permissions: - checks: write - contents: read - pull-requests: write -jobs: - build_and_preview: - if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: npm ci && npm run build - - uses: FirebaseExtended/action-hosting-deploy@v0 - with: - repoToken: ${{ secrets.GITHUB_TOKEN }} - firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_PABGM_39720 }} - projectId: pabgm-39720 From c7e127a58f386341df0af65b3c248aad9f09589e Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Mon, 13 Jan 2025 20:11:42 +0000 Subject: [PATCH 05/20] feat: added api calls and partners, contribution pages --- src/components/provider/index.tsx | 40 ++++- src/components/shared/alert/index.tsx | 18 +- .../shared/modals/contributeForm.tsx | 19 +-- src/components/shared/switch/toggle/index.tsx | 17 ++ src/configs/firebase.ts | 4 +- src/constants/fxns.ts | 4 +- src/hooks/useAdmin.ts | 15 ++ src/layouts/components/account-popover.tsx | 6 +- src/layouts/dashboard/layout.tsx | 49 ++++-- src/pages/contributions.tsx | 6 +- src/pages/user.tsx | 6 +- src/routes/sections.tsx | 22 ++- src/sections/auth/sign-in-view.tsx | 2 +- .../contributions/contributions-table-row.tsx | 10 +- .../contributions/view/contributions-list.tsx | 59 +++++++ .../contributions/view/contributions-view.tsx | 43 +++-- .../overview/view/overview-analytics-view.tsx | 160 +++++++++++------- src/sections/user/user-table-head.tsx | 4 +- src/sections/user/user-table-row.tsx | 96 +++++++---- src/sections/user/view/patners-view.tsx | 22 +++ src/sections/user/view/user-view.tsx | 53 +++--- src/services/auth/auth.dto.ts | 2 +- src/services/auth/index.ts | 3 +- src/services/cont/contribute.dto.ts | 17 +- src/services/cont/index.ts | 110 ++++++++---- src/services/pay/index.ts | 6 +- src/services/pay/pay.dto.ts | 3 +- src/services/stats/index.ts | 18 +- src/services/stats/stats.dto.ts | 7 + src/services/user/index.ts | 15 +- src/services/user/user.dto.ts | 2 +- src/utils/cache.ts | 11 +- src/utils/format-number.ts | 2 +- 33 files changed, 597 insertions(+), 254 deletions(-) create mode 100644 src/components/shared/switch/toggle/index.tsx create mode 100644 src/hooks/useAdmin.ts create mode 100644 src/sections/contributions/view/contributions-list.tsx create mode 100644 src/sections/user/view/patners-view.tsx diff --git a/src/components/provider/index.tsx b/src/components/provider/index.tsx index 694e12898..152993c11 100644 --- a/src/components/provider/index.tsx +++ b/src/components/provider/index.tsx @@ -1,17 +1,30 @@ import React, { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; +import { useRouter } from 'src/routes/hooks'; import UserService from 'src/services/user'; import { User } from 'src/services/user/user.dto'; +import { Cache, CacheKeys } from 'src/utils'; -export const UserContext = React.createContext<{ +const IS_ADMIN_MODE = !!Cache.get(CacheKeys.AdminMode); + +interface IUserContext { user?: User; - refetchUser?: () => void; -}>({ + isAdminMode: boolean; + pay: () => void; + reFetchUser: () => void; + setIsAdmin: (val: boolean) => void; +} + +export const UserContext = React.createContext({ + isAdminMode: IS_ADMIN_MODE, user: undefined, - refetchUser: undefined, + pay: () => {}, + reFetchUser: () => {}, + setIsAdmin: () => {}, }); -const AppProvider = ({ children }: { children: ReactNode }) => { +const AppProvider = ({ children, pay }: { children: ReactNode; pay: () => void }) => { const [user, setUser] = useState(); + const { replace } = useRouter(); const fetchUser = useCallback(async () => { try { @@ -24,19 +37,32 @@ const AppProvider = ({ children }: { children: ReactNode }) => { } }, []); + const updateAdminMode = useCallback( + async (val: boolean) => { + replace('/'); + Cache.set(CacheKeys.AdminMode, val); + }, + [replace] + ); + useEffect(() => { fetchUser(); }, [fetchUser]); - const contextValues = useMemo( + const contextValues: IUserContext = useMemo( () => ({ user, + isAdminMode: IS_ADMIN_MODE, + pay, + setIsAdmin: updateAdminMode, reFetchUser: fetchUser, }), - [user, fetchUser] + [user, updateAdminMode, fetchUser, pay] ); return {children}; }; export default AppProvider; + +// { user: User | undefined; isAdminMode: boolean; setAdminMode: (val: boolean) => void; reFetchUser: () => Promise; } diff --git a/src/components/shared/alert/index.tsx b/src/components/shared/alert/index.tsx index f4e150e72..a7e69db38 100644 --- a/src/components/shared/alert/index.tsx +++ b/src/components/shared/alert/index.tsx @@ -16,15 +16,17 @@ export interface AppAlertMethods { const AppAlert = forwardRef((_, ref) => { const [visible, setVisible] = useState(false); + const [show, setShow] = useState(visible) const dataRef = useRef(null); const container = useRef(); const handleOpenClose = (open: boolean, data?: AppAlertProps | null) => { if (open) { dataRef.current = data ?? null; - setVisible(true); + setVisible(open); + setShow(open) } else { - setVisible(false); + setVisible(open); dataRef.current = null; } }; @@ -37,6 +39,10 @@ const AppAlert = forwardRef((_, ref) => { setVisible(false); }; + const onExited = () => { + setShow(false) + } + useImperativeHandle( ref, () => ({ @@ -51,9 +57,9 @@ const AppAlert = forwardRef((_, ref) => { ); return ( - - - + show? + + ((_, ref) => { - + :null ); }); diff --git a/src/components/shared/modals/contributeForm.tsx b/src/components/shared/modals/contributeForm.tsx index 765c156c9..2a98e8222 100644 --- a/src/components/shared/modals/contributeForm.tsx +++ b/src/components/shared/modals/contributeForm.tsx @@ -21,7 +21,7 @@ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', ' interface PaymentFormModalProps { open: boolean; - amount?: string; + amount?: string | number; handleClose: () => void; } @@ -31,9 +31,9 @@ const PaymentFormModal: React.FC = ({ handleClose, }) => { const { user } = useUser(); - const {refresh} = useRouter() + const { refresh } = useRouter(); - const [amount, setAmount] = useState(user?.pledgeAmount ?? pledge ?? ''); + const [amount, setAmount] = useState(user?.pledgeAmount ?? pledge ?? ''); const [selectedMonths, setSelectedMonths] = useState([]); const [loading, setLoading] = useState(false); @@ -44,14 +44,13 @@ const PaymentFormModal: React.FC = ({ const handleSubmit = async (event: FormEvent) => { try { setLoading(true); - event.preventDefault(); - const pop = await PayService.init(amount, selectedMonths); - closeModal(); - setLoading(false); + event.preventDefault(); + await PayService.init(Number(amount), selectedMonths); + closeModal(); + setLoading(false); } catch (error) { - errCb(error.message) + errCb(error.message); } - }; const closeModal = () => { @@ -93,7 +92,7 @@ const PaymentFormModal: React.FC = ({ }} > diff --git a/src/components/shared/switch/toggle/index.tsx b/src/components/shared/switch/toggle/index.tsx new file mode 100644 index 000000000..b6c6eef17 --- /dev/null +++ b/src/components/shared/switch/toggle/index.tsx @@ -0,0 +1,17 @@ +import { Box, Switch, SwitchProps, Typography } from '@mui/material' +import { FC } from 'react' + +export interface ToggleSwitchProps extends SwitchProps { + label:string +} + +const ToggleSwitch:FC = ({label, checked, ...props}) => ( + + + {label} + + + +) + +export default ToggleSwitch \ No newline at end of file diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index 91902fbed..e9b3860d2 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -15,7 +15,6 @@ import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'; import { connectFunctionsEmulator, getFunctions, httpsCallable } from 'firebase/functions'; import { ApiRoute } from '../constants/fxns'; - const USE_EMULATORS = false; const firebaseConfig = { @@ -60,7 +59,7 @@ const fxns = getFunctions(app); const fx = { async call(path: ApiRoute, data?: T) { const callable = httpsCallable(fxns, path); - const result = await callable(data??null); + const result = await callable(data ?? null); return result.data; }, }; @@ -77,4 +76,3 @@ const runEmulators = (val: boolean = USE_EMULATORS) => { runEmulators(); export { app, auth, db, fx }; - diff --git a/src/constants/fxns.ts b/src/constants/fxns.ts index be4d65129..41c7335e9 100644 --- a/src/constants/fxns.ts +++ b/src/constants/fxns.ts @@ -3,5 +3,7 @@ export enum ApiRoute { InitPayment = 'initPay', PaymentHook = 'payHook', GetUser = 'getUser', - GetStats = 'getStats' + GetStats = 'getStats', + GetUserStats = 'getUserStats', + GetContributions = 'getContributions', } diff --git a/src/hooks/useAdmin.ts b/src/hooks/useAdmin.ts new file mode 100644 index 000000000..0064aba53 --- /dev/null +++ b/src/hooks/useAdmin.ts @@ -0,0 +1,15 @@ +import { useContext, useEffect } from 'react'; +import { UserContext } from 'src/components/provider'; +import { useRouter } from 'src/routes/hooks'; +import { Cache, CacheKeys } from 'src/utils'; + +const useAdmin = () => { + const { setIsAdmin } = useContext(UserContext); + const isAdminMode = Cache.get(CacheKeys.AdminMode) ?? false; + return { + isAdminMode, + setIsAdmin, + }; +}; + +export default useAdmin; diff --git a/src/layouts/components/account-popover.tsx b/src/layouts/components/account-popover.tsx index 72b0c7c3a..c3406de2e 100644 --- a/src/layouts/components/account-popover.tsx +++ b/src/layouts/components/account-popover.tsx @@ -15,6 +15,7 @@ import MenuItem, { menuItemClasses } from '@mui/material/MenuItem'; import { useRouter, usePathname } from 'src/routes/hooks'; import { _myAccount } from 'src/_mock'; +import useUser from 'src/hooks/useUser'; // ---------------------------------------------------------------------- @@ -31,6 +32,7 @@ export function AccountPopover({ data = [], sx, ...other }: AccountPopoverProps) const router = useRouter(); const pathname = usePathname(); + const { user } = useUser(); const [openPopover, setOpenPopover] = useState(null); @@ -83,11 +85,11 @@ export function AccountPopover({ data = [], sx, ...other }: AccountPopoverProps) > - {_myAccount?.displayName} + {`${user?.fname} ${user?.lname}`} - {_myAccount?.email} + {user?.email} diff --git a/src/layouts/dashboard/layout.tsx b/src/layouts/dashboard/layout.tsx index 69931b02c..81d91dcaf 100644 --- a/src/layouts/dashboard/layout.tsx +++ b/src/layouts/dashboard/layout.tsx @@ -6,17 +6,18 @@ import Alert from '@mui/material/Alert'; import Box from '@mui/material/Box'; import { useTheme } from '@mui/material/styles'; -import { _notifications } from 'src/_mock'; - import { Iconify } from 'src/components/iconify'; +import ToggleSwitch from 'src/components/shared/switch/toggle'; +import useAdmin from 'src/hooks/useAdmin'; import useAuth from 'src/hooks/useAuth'; +import useUser from 'src/hooks/useUser'; import { useRouter } from 'src/routes/hooks'; import AuthService from 'src/services/auth'; +import { UserRole } from 'src/services/user/user.dto'; import { layoutClasses } from '../classes'; import { AccountPopover } from '../components/account-popover'; import { MenuButton } from '../components/menu-button'; -import { NotificationsPopover } from '../components/notifications-popover'; import { navData } from '../config-nav-dashboard'; import { _workspaces } from '../config-nav-workspace'; import { HeaderSection } from '../core/header-section'; @@ -38,17 +39,26 @@ export function DashboardLayout({ sx, children, header }: DashboardLayoutProps) const theme = useTheme(); const { userExists } = useAuth(); const router = useRouter(); + const { user } = useUser(); + const { isAdminMode, setIsAdmin } = useAdmin(); + + const isAdmin = !!user?.role.includes(UserRole.Admin); const [navOpen, setNavOpen] = useState(false); const layoutQuery: Breakpoint = 'lg'; + const onToggleAdmin = (event: React.ChangeEvent) => { + setIsAdmin(event.target.checked); + }; + useEffect(() => { if (!AuthService.hasToken()) { router.replace('/signin'); } }, [userExists, router]); + const navOptions = isAdminMode ? navData : navData.filter((nav) => nav.title !== 'Partners'); return ( - + {isAdmin && ( + + )} + {/* */} , - }, - { - label: 'Settings', - href: '#', - icon: , - }, - ]} + data={ + [ + // { + // label: 'Profile', + // href: '#', + // icon: , + // }, + // { + // label: 'Settings', + // href: '#', + // icon: , + // }, + ] + } /> ), @@ -113,7 +128,7 @@ export function DashboardLayout({ sx, children, header }: DashboardLayoutProps) * Sidebar *************************************** */ sidebarSection={ - + } /** ************************************** * Footer diff --git a/src/pages/contributions.tsx b/src/pages/contributions.tsx index d9f0dda08..80c7e6dbf 100644 --- a/src/pages/contributions.tsx +++ b/src/pages/contributions.tsx @@ -1,8 +1,6 @@ -import { Typography } from '@mui/material'; import { Helmet } from 'react-helmet-async'; import { CONFIG } from 'src/config-global'; -import { DashboardContent } from 'src/layouts/dashboard'; -import { ContributionsView } from 'src/sections/contributions/view'; +import ContributionsList from 'src/sections/contributions/view/contributions-list'; function Contributions() { return ( @@ -10,7 +8,7 @@ function Contributions() { {`Contributions - ${CONFIG.appName}`} - + ); } diff --git a/src/pages/user.tsx b/src/pages/user.tsx index f9b41608a..4201bc534 100644 --- a/src/pages/user.tsx +++ b/src/pages/user.tsx @@ -2,7 +2,7 @@ import { Helmet } from 'react-helmet-async'; import { CONFIG } from 'src/config-global'; -import { UserView } from 'src/sections/user/view'; +import PartnersView from 'src/sections/user/view/patners-view'; // ---------------------------------------------------------------------- @@ -10,10 +10,10 @@ export default function Page() { return ( <> - {`Users - ${CONFIG.appName}`} + {`Partners - ${CONFIG.appName}`} - + ); } diff --git a/src/routes/sections.tsx b/src/routes/sections.tsx index 0325a5447..de8db3b8f 100644 --- a/src/routes/sections.tsx +++ b/src/routes/sections.tsx @@ -11,6 +11,7 @@ import { AuthLayout } from 'src/layouts/auth'; import { DashboardLayout } from 'src/layouts/dashboard'; import { varAlpha } from 'src/theme/styles'; import useUser from 'src/hooks/useUser'; +import useAdmin from 'src/hooks/useAdmin'; const AppProvider = lazy(() => import('src/components/provider')); @@ -43,6 +44,7 @@ const renderFallback = ( export function Router() { const { user } = useUser(); const [open, setOpen] = useState(false); + const { isAdminMode } = useAdmin(); const onOpen = () => { setOpen(true); @@ -70,11 +72,21 @@ export function Router() { ); + const dashRoutes = [ + { element: , index: true }, + { path: 'user', element: }, + { path: 'products', element: }, + { path: 'blog', element: }, + { path: 'contributions', element: }, + ]; + + const routes = !isAdminMode ? dashRoutes.filter((route) => route.path !== 'user') : dashRoutes; + return useRoutes([ { element: ( - + @@ -89,13 +101,7 @@ export function Router() { ), - children: [ - { element: , index: true }, - { path: 'user', element: }, - { path: 'products', element: }, - { path: 'blog', element: }, - { path: 'contributions', element: }, - ], + children: routes, }, { path: 'signin', diff --git a/src/sections/auth/sign-in-view.tsx b/src/sections/auth/sign-in-view.tsx index c61f504d7..0012c0f3e 100644 --- a/src/sections/auth/sign-in-view.tsx +++ b/src/sections/auth/sign-in-view.tsx @@ -31,7 +31,7 @@ const SIGN_UP = { country: '', email: '', password: '', - pledgeAmount: '', + pledgeAmount: 0, }; export function SignInView() { diff --git a/src/sections/contributions/contributions-table-row.tsx b/src/sections/contributions/contributions-table-row.tsx index 16c907d40..c71b785e0 100644 --- a/src/sections/contributions/contributions-table-row.tsx +++ b/src/sections/contributions/contributions-table-row.tsx @@ -9,7 +9,7 @@ import TableCell from '@mui/material/TableCell'; import TableRow from '@mui/material/TableRow'; import { Iconify } from 'src/components/iconify'; -import { Label } from 'src/components/label'; +import { Label, LabelColor } from 'src/components/label'; import { fDateTime } from 'src/utils/format-time'; // ---------------------------------------------------------------------- @@ -49,6 +49,12 @@ export function ContributionsTableRow({ setOpenPopover(null); }, []); + const getStatus = (val: ContributionProps['status']): LabelColor => { + if (val === 'failed') return 'error'; + if (val === 'pending') return 'info'; + return 'success'; + }; + return ( <> @@ -71,7 +77,7 @@ export function ContributionsTableRow({ {fDateTime(row.timestamp)} - + diff --git a/src/sections/contributions/view/contributions-list.tsx b/src/sections/contributions/view/contributions-list.tsx new file mode 100644 index 000000000..73086bd63 --- /dev/null +++ b/src/sections/contributions/view/contributions-list.tsx @@ -0,0 +1,59 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; +import useAdmin from 'src/hooks/useAdmin'; +import useUser from 'src/hooks/useUser'; +import ContributionService from 'src/services/cont'; +import { Contribution, ContributionStatus } from 'src/services/cont/contribute.dto'; +import { ContributionProps } from '../contributions-table-row'; +import { ContributionsView } from './contributions-view'; + +const ContributionsList = () => { + const [data, setData] = useState(); + const [loading, setLoading] = useState(false); + const { isAdminMode } = useAdmin(); + const { user } = useUser(); + + const pageRef = useRef(new Map()); + + const getStatus = (status: ContributionStatus): ContributionProps['status'] => { + if (status === ContributionStatus.Failed) return 'failed'; + if (status === ContributionStatus.Pending) return 'pending'; + return 'success'; + }; + + const getContributions = useCallback( + (result: Contribution[]): ContributionProps[] => + result.map((item) => ({ + amount: item.amount, + id: item.id, + months: item.months, + sender: item.donor, + status: getStatus(item.status), + timestamp: (item.completedAt || item.createdAt).toDate(), + })), + [] + ); + + const init = useCallback(async () => { + setLoading(true); + const promise = isAdminMode + ? ContributionService.getList({ count: 20, page: 1 }) + : ContributionService.getByUserId(user?.id!, 20); + const res = await promise; + + // TODO: Implement pagination + // pageRef.current.set(res.metadata.page, res.data[res.data.length - 1].id); + + const result = 'metadata' in res ? res.data : res; + const contributions = getContributions(result); + setData(contributions); + setLoading(false); + }, [getContributions, isAdminMode, user?.id]); + + useEffect(() => { + init(); + }, [init]); + + return ; +}; + +export default ContributionsList; diff --git a/src/sections/contributions/view/contributions-view.tsx b/src/sections/contributions/view/contributions-view.tsx index 282cb2c16..b73c06a92 100644 --- a/src/sections/contributions/view/contributions-view.tsx +++ b/src/sections/contributions/view/contributions-view.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState } from 'react'; +import { useCallback, useContext, useMemo, useState } from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; @@ -9,11 +9,12 @@ import TableContainer from '@mui/material/TableContainer'; import TablePagination from '@mui/material/TablePagination'; import Typography from '@mui/material/Typography'; -import { _contributions, _users } from 'src/_mock'; +import { _users } from 'src/_mock'; import { DashboardContent } from 'src/layouts/dashboard'; import { Iconify } from 'src/components/iconify'; import { Scrollbar } from 'src/components/scrollbar'; +import { UserContext } from 'src/components/provider'; import { ContributionTableHead } from '../contributions-table-head'; import { TableEmptyRows } from '../table-empty-rows'; @@ -32,7 +33,8 @@ interface ContributionsViewProps { hideBtn?: boolean; title?: string; noPagination?: boolean; - data?:ContributionProps[] + data?: ContributionProps[]; + loading?: boolean; } export function ContributionsView({ @@ -42,19 +44,26 @@ export function ContributionsView({ hideBtn, noPagination, title = 'Contributions', - data = [] + loading, + data = [], }: ContributionsViewProps) { const table = useTable(); const [filterName, setFilterName] = useState(''); + const { pay } = useContext(UserContext); + + const dataFiltered: ContributionProps[] = useMemo( + () => + applyFilter({ + inputData: data, + comparator: getComparator(table.order, table.orderBy), + filterName, + }), + [filterName, data, table.order, table.orderBy] + ); - const dataFiltered: ContributionProps[] = applyFilter({ - inputData: data, - comparator: getComparator(table.order, table.orderBy), - filterName, - }); - - const notFound = !dataFiltered.length && !!filterName; + const notFound = + ((!dataFiltered.length && !!filterName) || (!dataFiltered.length && !filterName)) && !loading; const content = ( <> @@ -63,7 +72,12 @@ export function ContributionsView({ {title} {!hideBtn && ( - )} @@ -98,7 +112,7 @@ export function ContributionsView({ } headLabel={[ { id: 'name', label: 'Name' }, - { id: 'months', label: 'Months' }, + { id: 'months', label: 'Month(s)' }, { id: 'amount', label: 'Amount' }, { id: 'date', label: 'Date' }, { id: 'status', label: 'Status' }, @@ -119,7 +133,7 @@ export function ContributionsView({ onSelectRow={() => table.onSelectRow(row.id)} /> ))} - + - {!noPagination && ( () + const isAdminMode = Cache.get(CacheKeys.AdminMode); + const { refresh } = useRouter(); + console.log('ISS', isAdminMode); + const [loading, setLoading] = useState(true); + const [data, setData] = useState<{ stats?: Stats | UserStats; cons?: ContributionProps[] }>(); - const getStatus = (status: ContributionStatus):ContributionProps['status'] => { - if(status===ContributionStatus.Failed)return 'failed' - if(status === ContributionStatus.Pending) return 'pending' - return 'success' - } + const getStatus = (status: ContributionStatus): ContributionProps['status'] => { + if (status === ContributionStatus.Failed) return 'failed'; + if (status === ContributionStatus.Pending) return 'pending'; + return 'success'; + }; + + const getContributions = useCallback( + (result: Contribution[]): ContributionProps[] => + result.map((item) => ({ + amount: item.amount, + id: item.id, + months: item.months, + sender: item.donor, + status: getStatus(item.status), + timestamp: (item.completedAt || item.createdAt).toDate(), + })), + [] + ); - const getContributions = useCallback((result:Contribution[]):ContributionProps[] => result.map(item=> - ({ - amount:item.amount, - id: item.id, - months: item.months, - sender: item.donor, - status: getStatus(item.status), - timestamp: (item.completedAt||item.createdAt).toDate() - })),[]) + const getStats = useCallback(async () => { + const stats = isAdminMode ? await StatsService.get() : await StatsService.getByUser(); + setData((val) => (val ? { ...val, stats } : { stats })); + }, [isAdminMode]); + + const onLatestContribution = useCallback( + (value: Contribution[]) => { + console.log(value); + const cons = getContributions(value); + setData((val) => (val ? { ...val, cons } : { cons })); + getStats(); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [getContributions, getStats] + ); const init = useCallback(async () => { - if(!user?.id) return + if (!user?.id) return; try { - const isAdmin = user.role.includes(UserRole.Admin) - const [stats,cons] = await Promise.all([ - StatsService.get(), - isAdmin - ? ContributionService.getAllLatest() - : ContributionService.getByUserId(user?.id!) - ]) - setData({ - stats, - cons:getContributions(cons) - }) + ContributionService.listenLatest(onLatestContribution, isAdminMode ? undefined : user.id); + await getStats(); } catch (error) { - errCb(error.message) - }finally{ - setLoading(false) + errCb(error.message); + } finally { + setLoading(false); } - },[user?.id,user?.role, getContributions]) + }, [user?.id, onLatestContribution, isAdminMode, getStats]); useEffect(() => { - init() - }, [init]) - - if(loading){ - return - varAlpha(theme.vars.palette.text.primaryChannel, 0.16), - [`& .${linearProgressClasses.bar}`]: { bgcolor: 'text.primary' }, - }} - /> - + init(); + }, [init]); + + if (loading) { + return ( + + varAlpha(theme.vars.palette.text.primaryChannel, 0.16), + [`& .${linearProgressClasses.bar}`]: { bgcolor: 'text.primary' }, + }} + /> + + ); } - + + const mdQuery = isAdminMode ? 3 : 4; return ( @@ -86,10 +103,10 @@ export function OverviewAnalyticsView() { - + } chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], @@ -98,10 +115,14 @@ export function OverviewAnalyticsView() { /> - + } chart={{ @@ -111,15 +132,30 @@ export function OverviewAnalyticsView() { /> - + {isAdminMode ? ( + + } + chart={{ + categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], + series: [10, 6, 9], + }} + /> + + ) : null} + + } chart={{ categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], - series: [10,6,9], + series: [10, 6, 9], }} /> @@ -137,7 +173,6 @@ export function OverviewAnalyticsView() { }} /> */} - {/* */} - {/* */} - {/* */} - - {/* */} - {/* - + {/* 0 && numSelected < rowCount} checked={rowCount > 0 && numSelected === rowCount} @@ -39,7 +39,7 @@ export function UserTableHead({ onSelectAllRows(event.target.checked) } /> - + */} {headLabel.map((headCell) => ( (null); + const [updating, setUpdating] = useState(false); + const { refresh } = useRouter(); + + const user = useUser(); const handleOpenPopover = useCallback((event: React.MouseEvent) => { setOpenPopover(event.currentTarget); @@ -42,25 +48,44 @@ export function UserTableRow({ row, selected, onSelectRow }: UserTableRowProps) setOpenPopover(null); }, []); + const onClick = useCallback( + async (val: 'makeAdmin' | 'delete') => { + setOpenPopover(null); + if (val === 'makeAdmin') { + setUpdating(true); + const userData = await UserService.get(row.id); + if (userData) { + const { role } = userData; + if (!role.includes(UserRole.Admin)) { + await UserService.update(row.id, { role: [...role, UserRole.Admin] }); + } + } + } + refresh(); + setUpdating(false); + }, + [row.id, refresh] + ); + return ( <> - - + + {/* - + */} - + - - {row.name} + + {row.name} {row.email === user.user?.email ? '(You)' : ''} - {row.company} - {row.role} + {row.email} + {`${fCurrency(row.pledge)}`} - + {/* {row.isVerified ? ( ) : ( @@ -70,12 +95,18 @@ export function UserTableRow({ row, selected, onSelectRow }: UserTableRowProps) - + */} - - - + {updating ? ( + + ) : ( + !row.role.includes(UserRole.Admin) && ( + + + + ) + )} @@ -102,15 +133,18 @@ export function UserTableRow({ row, selected, onSelectRow }: UserTableRowProps) }, }} > - - - Edit - + {!row.role.includes(UserRole.Admin) && ( + onClick('makeAdmin')}> + + Make Admin + + )} - + {/* TODO: Implement delete for collection and auth */} + {/* onClick('delete')} sx={{ color: 'error.main' }}> Delete - + */} diff --git a/src/sections/user/view/patners-view.tsx b/src/sections/user/view/patners-view.tsx new file mode 100644 index 000000000..275cb0759 --- /dev/null +++ b/src/sections/user/view/patners-view.tsx @@ -0,0 +1,22 @@ +import { useEffect, useState } from 'react'; +import UserService from 'src/services/user'; +import { User } from 'src/services/user/user.dto'; +import { UserView } from './user-view'; + +const PartnersView = () => { + const [data, setData] = useState(); + + const init = async () => { + const list = await UserService.list(); + console.log(list); + setData(list); + }; + + useEffect(() => { + init(); + }, []); + + return ; +}; + +export default PartnersView; diff --git a/src/sections/user/view/user-view.tsx b/src/sections/user/view/user-view.tsx index 5c5e96a2f..d91c4b366 100644 --- a/src/sections/user/view/user-view.tsx +++ b/src/sections/user/view/user-view.tsx @@ -1,68 +1,76 @@ -import { useState, useCallback } from 'react'; +import { useCallback, useState } from 'react'; import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; import Table from '@mui/material/Table'; -import Button from '@mui/material/Button'; import TableBody from '@mui/material/TableBody'; -import Typography from '@mui/material/Typography'; import TableContainer from '@mui/material/TableContainer'; import TablePagination from '@mui/material/TablePagination'; +import Typography from '@mui/material/Typography'; import { _users } from 'src/_mock'; import { DashboardContent } from 'src/layouts/dashboard'; import { Iconify } from 'src/components/iconify'; import { Scrollbar } from 'src/components/scrollbar'; +import { User } from 'src/services/user/user.dto'; +import { TableEmptyRows } from '../table-empty-rows'; import { TableNoData } from '../table-no-data'; -import { UserTableRow } from '../user-table-row'; import { UserTableHead } from '../user-table-head'; -import { TableEmptyRows } from '../table-empty-rows'; +import { UserTableRow } from '../user-table-row'; import { UserTableToolbar } from '../user-table-toolbar'; -import { emptyRows, applyFilter, getComparator } from '../utils'; - -import type { UserProps } from '../user-table-row'; +import { applyFilter, emptyRows, getComparator } from '../utils'; // ---------------------------------------------------------------------- -export function UserView() { +interface PartnersViewProps { + data?: User[]; +} + +export function UserView({ data = [] }: PartnersViewProps) { const table = useTable(); const [filterName, setFilterName] = useState(''); - const dataFiltered: UserProps[] = applyFilter({ - inputData: _users, + const dataFiltered = applyFilter({ + inputData: data.map((item) => ({ + id: item.id, + name: `${item.fname} ${item.lname}`, + role: item.role.join(', '), + email: item.email, + pledge: item.pledgeAmount, + })), comparator: getComparator(table.order, table.orderBy), filterName, }); - const notFound = !dataFiltered.length && !!filterName; return ( - Users + Partners - ) => { setFilterName(event.target.value); table.onResetPage(); }} - /> + /> */} @@ -76,16 +84,15 @@ export function UserView() { onSelectAllRows={(checked) => table.onSelectAllRows( checked, - _users.map((user) => user.id) + data.map((user) => user.id) ) } headLabel={[ { id: 'name', label: 'Name' }, - { id: 'company', label: 'Company' }, { id: 'role', label: 'Role' }, - { id: 'isVerified', label: 'Verified', align: 'center' }, - { id: 'status', label: 'Status' }, - { id: '' }, + { id: 'email', label: 'Email' }, + { id: 'pledge', label: 'Pledge' }, + { id: 'action', label: '' }, ]} /> @@ -114,7 +121,7 @@ export function UserView() { - + /> */} ); diff --git a/src/services/auth/auth.dto.ts b/src/services/auth/auth.dto.ts index 4a32e1e43..80938ce9a 100644 --- a/src/services/auth/auth.dto.ts +++ b/src/services/auth/auth.dto.ts @@ -4,7 +4,7 @@ export interface CreateUserBody { email: string; password?: string; country: string; - pledgeAmount: string; + pledgeAmount: number; } export interface UserLoginBody { diff --git a/src/services/auth/index.ts b/src/services/auth/index.ts index 9d3237804..888d98626 100644 --- a/src/services/auth/index.ts +++ b/src/services/auth/index.ts @@ -32,7 +32,8 @@ export default class AuthService { } static async logout() { - return auth.logout(); + await auth.logout(); + Cache.clear(); } static setToken(token: string | null) { diff --git a/src/services/cont/contribute.dto.ts b/src/services/cont/contribute.dto.ts index 20c911d82..b7d85e74a 100644 --- a/src/services/cont/contribute.dto.ts +++ b/src/services/cont/contribute.dto.ts @@ -1,9 +1,9 @@ -import { Timestamp } from "firebase/firestore"; +import { Timestamp } from 'firebase/firestore'; export enum ContributionStatus { - Pending = "PENDING", - Failed = "FAILED", - Success = "COMPLETED", + Pending = 'PENDING', + Failed = 'FAILED', + Success = 'COMPLETED', } export interface Contribution { @@ -21,8 +21,15 @@ export interface Contribution { }; } +export interface ContributionResponse + extends Omit { + createdAt: { _seconds: number; _nanoseconds: number }; + modifiedAt: { _seconds: number; _nanoseconds: number } | null; + completedAt: { _seconds: number; _nanoseconds: number } | null; +} + export interface CreateContributionParams { amount: string; months: string[]; - donor: Contribution["donor"]; + donor: Contribution['donor']; } diff --git a/src/services/cont/index.ts b/src/services/cont/index.ts index e048782d9..169518976 100644 --- a/src/services/cont/index.ts +++ b/src/services/cont/index.ts @@ -1,36 +1,84 @@ -import { getDoc, getDocs, limit, query, where } from "firebase/firestore"; -import { Collection } from "src/constants"; -import { colRef, docRef } from "src/utils"; -import { Contribution, ContributionStatus } from "./contribute.dto"; +import { + Timestamp, + getDoc, + getDocs, + limit, + onSnapshot, + orderBy, + query, + where, +} from 'firebase/firestore'; +import { fx } from 'src/configs'; +import { Collection } from 'src/constants'; +import { ApiRoute } from 'src/constants/fxns'; +import { colRef, docRef } from 'src/utils'; +import { Contribution, ContributionResponse, ContributionStatus } from './contribute.dto'; export default class ContributionService { - static async getByUserId(id:string,count=12){ - console.log('ID:>>',id) - const ref = colRef(Collection.Contributions); - const q = query(ref,where('donor.id','==',id), limit(count)) - const docs = await getDocs(q) - const data:Contribution[] = [] - docs.forEach(doc=>{ - data.push(doc.data() as Contribution) - }) - return data - } + private static ref = colRef(Collection.Contributions); - static async get(id: string): Promise { - const ref = docRef(id, Collection.Contributions); - const docRes = await getDoc(ref); - return docRes.data() as Contribution; - } + static async getByUserId(id: string, count = 15) { + const q = query( + this.ref, + where('donor.id', '==', id), + limit(count), + orderBy('createdAt', 'desc') + ); + const docs = await getDocs(q); + const data: Contribution[] = []; + docs.forEach((doc) => { + data.push(doc.data() as Contribution); + }); + return data; + } - static async getAllLatest(){ - const ref = colRef(Collection.Contributions); - const q = query(ref, limit(12)) - const docs = await getDocs(q) - const data:Contribution[] = [] - docs.forEach(doc=>{ - data.push(doc.data() as Contribution) - }) - return data - } + static async listenLatest(cb: (val: Contribution[]) => void, id?: string, count = 15) { + const q = query( + this.ref, + id ? where('donor.id', '==', id) : where('status', '==', ContributionStatus.Success), + orderBy('createdAt', 'desc'), + limit(count) + ); -} \ No newline at end of file + return onSnapshot(q, ({ docs }) => { + const data: Contribution[] = docs.map((doc) => doc.data() as Contribution); + cb(data); + }); + } + + static async get(id: string): Promise { + const ref = docRef(id, Collection.Contributions); + const docRes = await getDoc(ref); + return docRes.data() as Contribution; + } + + static async getAllLatest() { + const q = query(this.ref, limit(15)); + const docs = await getDocs(q); + const data: Contribution[] = []; + docs.forEach((doc) => { + data.push(doc.data() as Contribution); + }); + return data; + } + + static async getList(data?: { page: number; count: number }) { + const res = await fx.call< + typeof data, + { + data: ContributionResponse[]; + metadata: { page: number; next: boolean; prev: boolean; pages: number; rows: number }; + } + >(ApiRoute.GetContributions, data); + return { + metadata: res.metadata, + data: res.data.map(({ createdAt, completedAt, ...item }) => ({ + ...item, + createdAt: new Timestamp(createdAt._seconds, createdAt._nanoseconds), + completedAt: completedAt + ? new Timestamp(completedAt._seconds, completedAt._nanoseconds) + : completedAt, + })) as Contribution[], + }; + } +} diff --git a/src/services/pay/index.ts b/src/services/pay/index.ts index 616f74f67..b4345a8d0 100644 --- a/src/services/pay/index.ts +++ b/src/services/pay/index.ts @@ -5,15 +5,17 @@ import { errCb } from 'src/utils'; import { ContributeInit } from './pay.dto'; export default class PayService { - static async init(amount: string, months: string[]) { + static async init(amount: number, months: string[]) { try { + console.log(window.location); const res = await fx.call(ApiRoute.InitPayment, { amount, months, + callbackUrl: window.location.href, }); const popup = new PaystackPop(); popup.resumeTransaction(res.code as any); - return popup + return popup; } catch (error) { const err = error as Error; errCb(err.message); diff --git a/src/services/pay/pay.dto.ts b/src/services/pay/pay.dto.ts index 37c7bc515..b0d1087c1 100644 --- a/src/services/pay/pay.dto.ts +++ b/src/services/pay/pay.dto.ts @@ -1,4 +1,5 @@ export interface ContributeInit { - amount: string | null; + amount: number | null; months: string[]; + callbackUrl?: string; } diff --git a/src/services/stats/index.ts b/src/services/stats/index.ts index 4ea52fcd1..aa8f85979 100644 --- a/src/services/stats/index.ts +++ b/src/services/stats/index.ts @@ -1,9 +1,13 @@ -import { fx } from "src/configs"; -import { ApiRoute } from "src/constants/fxns"; -import { Stats } from "./stats.dto"; +import { fx } from 'src/configs'; +import { ApiRoute } from 'src/constants/fxns'; +import { Stats, UserStats } from './stats.dto'; export default class StatsService { - static async get(){ - return fx.call(ApiRoute.GetStats) - } -} \ No newline at end of file + static async get() { + return fx.call<{}, Stats>(ApiRoute.GetStats); + } + + static async getByUser() { + return fx.call<{}, UserStats>(ApiRoute.GetUserStats); + } +} diff --git a/src/services/stats/stats.dto.ts b/src/services/stats/stats.dto.ts index 65e94fbed..c37799cc9 100644 --- a/src/services/stats/stats.dto.ts +++ b/src/services/stats/stats.dto.ts @@ -2,4 +2,11 @@ export interface Stats { partnersCount: number; contributionCount: number; totalAmount: number; + expectedMonthly: number; +} + +export interface UserStats { + contributionCount: number; + totalContribution: number; + pledge: number; } diff --git a/src/services/user/index.ts b/src/services/user/index.ts index 5c28d3a24..e3408355a 100644 --- a/src/services/user/index.ts +++ b/src/services/user/index.ts @@ -1,8 +1,8 @@ -import { getDoc, setDoc, updateDoc } from 'firebase/firestore'; +import { getDoc, getDocs, setDoc, updateDoc } from 'firebase/firestore'; import { fx } from 'src/configs'; import { Collection } from 'src/constants/factory'; import { ApiRoute } from 'src/constants/fxns'; -import { docRef } from 'src/utils'; +import { colRef, docRef } from 'src/utils'; import { User, UserUpdateBody } from './user.dto'; export default class UserService { @@ -22,8 +22,17 @@ export default class UserService { return data; } - static async update(id: string, data: UserUpdateBody) { + static async update(id: string, data: Partial) { const ref = docRef(id, Collection.Users); await updateDoc(ref, data); } + + static async list() { + const ref = colRef(Collection.Users); + const { docs, empty } = await getDocs(ref); + if (!empty) { + return docs.map((doc) => doc.data() as User); + } + return []; + } } diff --git a/src/services/user/user.dto.ts b/src/services/user/user.dto.ts index aa6649899..d14f7fcbd 100644 --- a/src/services/user/user.dto.ts +++ b/src/services/user/user.dto.ts @@ -9,7 +9,7 @@ export interface User { lname: string; email: string; country: string; - pledgeAmount: string; + pledgeAmount: number; role: UserRole[]; } diff --git a/src/utils/cache.ts b/src/utils/cache.ts index 3a97c94ba..f5a12c413 100644 --- a/src/utils/cache.ts +++ b/src/utils/cache.ts @@ -2,6 +2,8 @@ import { payloadDeHash, payloadHash } from './encrypt'; export enum CacheKeys { Token = 'my.auth.id.t', + Admin = 'dash.admin.mode', + AdminMode = 'dash.is.admin.mode', } export class Cache { @@ -24,7 +26,14 @@ export class Cache { private static unparse(hash: string) { if (!hash) return null; const payloadString = payloadDeHash(hash); - console.log('PAYLOAD STRING', payloadString); return JSON.parse(payloadString); } + + static delete(id: CacheKeys) { + localStorage.removeItem(id); + } + + static clear() { + localStorage.clear(); + } } diff --git a/src/utils/format-number.ts b/src/utils/format-number.ts index e0c5198b9..ecc799396 100644 --- a/src/utils/format-number.ts +++ b/src/utils/format-number.ts @@ -7,7 +7,7 @@ export type InputNumberValue = string | number | null | undefined; type Options = Intl.NumberFormatOptions | undefined; -const DEFAULT_LOCALE = { code: 'en-US', currency: 'USD' }; +const DEFAULT_LOCALE = { code: 'en-US', currency: 'GHS' }; function processInput(inputValue: InputNumberValue): number | null { if (inputValue == null || Number.isNaN(inputValue)) return null; From 9ed9097bb6c298117c2619907e708b6802d63517 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Thu, 23 Jan 2025 16:23:43 +0000 Subject: [PATCH 06/20] feat: added env variables for prod and deb --- .env.development | 7 + .env.production | 7 + .firebaserc | 5 - env.d.ts | 12 ++ src/_mock/_data.ts | 1 + src/components/loader/index.tsx | 21 +++ src/components/shared/alert/index.tsx | 56 +++--- src/configs/firebase.ts | 2 +- src/constants/factory.ts | 1 + src/layouts/components/account-popover.tsx | 4 +- src/pages/user.tsx | 2 +- src/sections/auth/sign-in-view.tsx | 24 ++- .../contributions/contributions-table-row.tsx | 21 +++ src/sections/contributions/table-no-data.tsx | 19 +- .../contributions/view/contributions-list.tsx | 8 +- .../contributions/view/contributions-view.tsx | 168 ++++++++++-------- .../overview/view/overview-analytics-view.tsx | 5 +- src/sections/user/table-no-data.tsx | 14 +- .../{patners-view.tsx => partners-view.tsx} | 5 +- src/sections/user/view/user-view.tsx | 110 ++++++------ src/services/auth/auth.dto.ts | 1 + src/services/auth/index.ts | 2 + src/services/cont/contribute.dto.ts | 1 + src/services/pay/index.ts | 15 +- src/services/user/index.ts | 10 +- tsconfig.json | 2 +- 26 files changed, 336 insertions(+), 187 deletions(-) create mode 100644 .env.development create mode 100644 .env.production delete mode 100644 .firebaserc create mode 100644 env.d.ts create mode 100644 src/components/loader/index.tsx rename src/sections/user/view/{patners-view.tsx => partners-view.tsx} (77%) diff --git a/.env.development b/.env.development new file mode 100644 index 000000000..8d8426fe1 --- /dev/null +++ b/.env.development @@ -0,0 +1,7 @@ +FIREBASE_API_KEY = AIzaSyDY-1FezjbzGmq1j3WHWurbniF3IIdYmEY +FIREBASE_AUTH_DOMAIN = pabgm-39720.firebaseapp.com +FIREBASE_PROJECT_ID = pabgm-39720 +FIREBASE_STORAGE_BUCKET = pabgm-39720.firebasestorage.app +FIREBASE_MESSAGE_SENDER_ID = 557051436284 +FIREBASE_APP_ID = 1:557051436284:web:96f2e80c4cc4c927638b79 +FIREBASE_MEASUREMENT_ID = G-VTGQQYSTP1 diff --git a/.env.production b/.env.production new file mode 100644 index 000000000..dd531cf5b --- /dev/null +++ b/.env.production @@ -0,0 +1,7 @@ +FIREBASE_API_KEY = AIzaSyDFWGNo8407oOfIFdQG6l3g7QAwEJIXChs +FIREBASE_AUTH_DOMAIN = pabgm-prod-cf8ec.firebaseapp.com +FIREBASE_PROJECT_ID = pabgm-prod-cf8ec +FIREBASE_STORAGE_BUCKET = pabgm-prod-cf8ec.firebasestorage.app +FIREBASE_MESSAGE_SENDER_ID = 804867831086 +FIREBASE_APP_ID = 1:804867831086:web:644d67756ec3dea65cb6bf +FIREBASE_MEASUREMENT_ID = G-T3GNEJNC7V diff --git a/.firebaserc b/.firebaserc deleted file mode 100644 index e156400e6..000000000 --- a/.firebaserc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "projects": { - "default": "pabgm-39720" - } -} diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 000000000..8c710d748 --- /dev/null +++ b/env.d.ts @@ -0,0 +1,12 @@ +declare namespace NodeJS { + interface ProcessEnv { + //FIREBASE CONFIGS + FIREBASE_API_KEY: string; + FIREBASE_AUTH_DOMAIN: string; + FIREBASE_PROJECT_ID: string; + FIREBASE_STORAGE_BUCKET: string; + FIREBASE_MESSAGE_SENDER_ID: string; + FIREBASE_APP_ID: string; + FIREBASE_MEASUREMENT_ID: string; + } +} diff --git a/src/_mock/_data.ts b/src/_mock/_data.ts index 872771b0f..42140b5df 100644 --- a/src/_mock/_data.ts +++ b/src/_mock/_data.ts @@ -74,6 +74,7 @@ export const _contributions: ContributionProps[] = [...Array(24)].map((_, index) status: index % 4 ? 'success' : 'failed', timestamp: new Date(), amount: _amount(), + code: 's', })); // ---------------------------------------------------------------------- diff --git a/src/components/loader/index.tsx b/src/components/loader/index.tsx new file mode 100644 index 000000000..3c674c635 --- /dev/null +++ b/src/components/loader/index.tsx @@ -0,0 +1,21 @@ +import { Box, LinearProgress, linearProgressClasses } from '@mui/material'; +import { BoxProps } from '@mui/material/Box'; +import { FC } from 'react'; +import { varAlpha } from 'src/theme/styles'; + +interface LoaderProps extends BoxProps {} + +const Loader: FC = (props) => ( + + varAlpha(theme.vars.palette.text.primaryChannel, 0.16), + [`& .${linearProgressClasses.bar}`]: { bgcolor: 'text.primary' }, + }} + /> + +); + +export default Loader; diff --git a/src/components/shared/alert/index.tsx b/src/components/shared/alert/index.tsx index a7e69db38..49123dbee 100644 --- a/src/components/shared/alert/index.tsx +++ b/src/components/shared/alert/index.tsx @@ -1,5 +1,5 @@ import { Alert, AlertProps, Box, IconButton, Portal, Slide } from '@mui/material'; -import { forwardRef, useImperativeHandle, useRef, useState } from 'react'; +import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react'; import { Iconify, IconifyProps } from 'src/components/iconify'; export interface AppAlertProps { @@ -7,6 +7,7 @@ export interface AppAlertProps { label: string; icon?: IconifyProps['icon']; type: AlertProps['severity']; + duration?: number; } export interface AppAlertMethods { @@ -16,32 +17,40 @@ export interface AppAlertMethods { const AppAlert = forwardRef((_, ref) => { const [visible, setVisible] = useState(false); - const [show, setShow] = useState(visible) + const [show, setShow] = useState(visible); const dataRef = useRef(null); + const [value, setValue] = useState(null); + const container = useRef(); - const handleOpenClose = (open: boolean, data?: AppAlertProps | null) => { + const clearData = () => { + setValue(null); + }; + + const handleOpenClose = useCallback((open: boolean, data?: AppAlertProps | null) => { if (open) { - dataRef.current = data ?? null; + setValue(data ?? null); setVisible(open); - setShow(open) + setShow(open); + setTimeout( + () => { + setVisible(false); + }, + (data?.duration ?? 5) * 1000 + ); } else { setVisible(open); - dataRef.current = null; + clearData(); } - }; - - const clearData = () => { - dataRef.current = null; - }; + }, []); const onClose = () => { setVisible(false); }; const onExited = () => { - setShow(false) - } + setShow(false); + }; useImperativeHandle( ref, @@ -53,13 +62,18 @@ const AppAlert = forwardRef((_, ref) => { handleOpenClose(false); }, }), - [] + [handleOpenClose] ); - return ( - show? - - + return show ? ( + + + ((_, ref) => { } > - {dataRef.current?.label} + {value?.label} - :null - ); + + ) : null; }); export default AppAlert; diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index e9b3860d2..786304300 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -18,7 +18,7 @@ import { ApiRoute } from '../constants/fxns'; const USE_EMULATORS = false; const firebaseConfig = { - apiKey: 'AIzaSyDY-1FezjbzGmq1j3WHWurbniF3IIdYmEY', + apiKey: process.env.FIREBASE_API_KEY, authDomain: 'pabgm-39720.firebaseapp.com', projectId: 'pabgm-39720', storageBucket: 'pabgm-39720.firebasestorage.app', diff --git a/src/constants/factory.ts b/src/constants/factory.ts index 97899b13d..5fd2ddae9 100644 --- a/src/constants/factory.ts +++ b/src/constants/factory.ts @@ -4,4 +4,5 @@ export enum Collection { Transactions = 'TRXS', AdminStats = 'ADMIN_STATS', PartnerStats = 'PARTNER_STATS', + Secret = 'SECRET', } diff --git a/src/layouts/components/account-popover.tsx b/src/layouts/components/account-popover.tsx index c3406de2e..f352fbb46 100644 --- a/src/layouts/components/account-popover.tsx +++ b/src/layouts/components/account-popover.tsx @@ -66,8 +66,8 @@ export function AccountPopover({ data = [], sx, ...other }: AccountPopoverProps) }} {...other} > - - {_myAccount.displayName.charAt(0).toUpperCase()} + + {user?.fname.charAt(0).toUpperCase()} diff --git a/src/pages/user.tsx b/src/pages/user.tsx index 4201bc534..76d587a9d 100644 --- a/src/pages/user.tsx +++ b/src/pages/user.tsx @@ -2,7 +2,7 @@ import { Helmet } from 'react-helmet-async'; import { CONFIG } from 'src/config-global'; -import PartnersView from 'src/sections/user/view/patners-view'; +import PartnersView from 'src/sections/user/view/partners-view'; // ---------------------------------------------------------------------- diff --git a/src/sections/auth/sign-in-view.tsx b/src/sections/auth/sign-in-view.tsx index 0012c0f3e..36721132b 100644 --- a/src/sections/auth/sign-in-view.tsx +++ b/src/sections/auth/sign-in-view.tsx @@ -32,6 +32,7 @@ const SIGN_UP = { email: '', password: '', pledgeAmount: 0, + secret: '', }; export function SignInView() { @@ -62,7 +63,6 @@ export function SignInView() { } } else { const user = await AuthService.register(data as CreateUserBody); - console.log(user); } router.replace('/'); } catch (error) { @@ -77,7 +77,6 @@ export function SignInView() { }; const checkPass = useCallback(() => { - console.log(data.password, confirmPass); if (data.password !== confirmPass && !isSignin) { return 'Passwords do not match'; } @@ -100,10 +99,27 @@ export function SignInView() { const passErr = checkPass(); const emptyForm = checkEmptyForm(); - console.log(emptyForm, data); - const renderForm = ( + {!isSignin && ( + updateField('secret', e.target.value)} + InputLabelProps={{ shrink: true }} + sx={{ mb: 3 }} + helperText={ + + Enter the secret code provided in your invite message. + + } + /> + )} {!isSignin && ( (null); + const { user } = useUser(); const handleOpenPopover = useCallback((event: React.MouseEvent) => { setOpenPopover(event.currentTarget); @@ -55,6 +60,10 @@ export function ContributionsTableRow({ return 'success'; }; + const onResume = (code: string) => { + PayService.resume(code); + }; + return ( <> @@ -79,6 +88,18 @@ export function ContributionsTableRow({ + + + + {row.status === 'pending' && row.sender.id === user?.id ? ( + + ) : ( + '' + )} + + - Not found + {label} - - No results found for   - "{searchQuery}". -
Try checking for typos or using complete words. -
+ {false && ( + + No results found for   + "{searchQuery}". +
Try checking for typos or using complete words. +
+ )}
diff --git a/src/sections/contributions/view/contributions-list.tsx b/src/sections/contributions/view/contributions-list.tsx index 73086bd63..42e0ab330 100644 --- a/src/sections/contributions/view/contributions-list.tsx +++ b/src/sections/contributions/view/contributions-list.tsx @@ -8,12 +8,10 @@ import { ContributionsView } from './contributions-view'; const ContributionsList = () => { const [data, setData] = useState(); - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(true); const { isAdminMode } = useAdmin(); const { user } = useUser(); - const pageRef = useRef(new Map()); - const getStatus = (status: ContributionStatus): ContributionProps['status'] => { if (status === ContributionStatus.Failed) return 'failed'; if (status === ContributionStatus.Pending) return 'pending'; @@ -29,12 +27,12 @@ const ContributionsList = () => { sender: item.donor, status: getStatus(item.status), timestamp: (item.completedAt || item.createdAt).toDate(), + code: item?.trxCode, })), [] ); const init = useCallback(async () => { - setLoading(true); const promise = isAdminMode ? ContributionService.getList({ count: 20, page: 1 }) : ContributionService.getByUserId(user?.id!, 20); @@ -53,7 +51,7 @@ const ContributionsList = () => { init(); }, [init]); - return ; + return ; }; export default ContributionsList; diff --git a/src/sections/contributions/view/contributions-view.tsx b/src/sections/contributions/view/contributions-view.tsx index b73c06a92..baf6dae8b 100644 --- a/src/sections/contributions/view/contributions-view.tsx +++ b/src/sections/contributions/view/contributions-view.tsx @@ -13,8 +13,10 @@ import { _users } from 'src/_mock'; import { DashboardContent } from 'src/layouts/dashboard'; import { Iconify } from 'src/components/iconify'; -import { Scrollbar } from 'src/components/scrollbar'; +import Loader from 'src/components/loader'; import { UserContext } from 'src/components/provider'; +import { Scrollbar } from 'src/components/scrollbar'; +import { useRouter } from 'src/routes/hooks'; import { ContributionTableHead } from '../contributions-table-head'; import { TableEmptyRows } from '../table-empty-rows'; @@ -35,6 +37,7 @@ interface ContributionsViewProps { noPagination?: boolean; data?: ContributionProps[]; loading?: boolean; + viewMore?: boolean; } export function ContributionsView({ @@ -45,12 +48,18 @@ export function ContributionsView({ noPagination, title = 'Contributions', loading, + viewMore, data = [], }: ContributionsViewProps) { const table = useTable(); const [filterName, setFilterName] = useState(''); const { pay } = useContext(UserContext); + const { push } = useRouter(); + + const onViewMore = () => { + push('/contributions'); + }; const dataFiltered: ContributionProps[] = useMemo( () => @@ -62,8 +71,7 @@ export function ContributionsView({ [filterName, data, table.order, table.orderBy] ); - const notFound = - ((!dataFiltered.length && !!filterName) || (!dataFiltered.length && !filterName)) && !loading; + const notFound = (!dataFiltered.length && !!filterName) || (!dataFiltered.length && !filterName); const content = ( <> @@ -81,79 +89,95 @@ export function ContributionsView({ Contribute )} + {viewMore && ( + + )}
- {!noToolbar && ( - ) => { - setFilterName(event.target.value); - table.onResetPage(); - }} - /> - )} - - - - - + ) : ( + <> + {!noToolbar && ( + - table.onSelectAllRows( - checked, - _users.map((user) => user.id) - ) - } - headLabel={[ - { id: 'name', label: 'Name' }, - { id: 'months', label: 'Month(s)' }, - { id: 'amount', label: 'Amount' }, - { id: 'date', label: 'Date' }, - { id: 'status', label: 'Status' }, - ]} + filterName={filterName} + onFilterName={(event: React.ChangeEvent) => { + setFilterName(event.target.value); + table.onResetPage(); + }} + /> + )} + + + +
+ + table.onSelectAllRows( + checked, + _users.map((user) => user.id) + ) + } + headLabel={[ + { id: 'name', label: 'Name' }, + { id: 'months', label: 'Month(s)' }, + { id: 'amount', label: 'Amount' }, + { id: 'date', label: 'Date' }, + { id: 'status', label: 'Status' }, + { id: 'resume', label: '' }, + ]} + /> + + <> + {dataFiltered + .slice( + table.page * table.rowsPerPage, + table.page * table.rowsPerPage + table.rowsPerPage + ) + .map((row) => ( + table.onSelectRow(row.id)} + /> + ))} + + + {notFound && ( + + )} + + +
+
+
+ + {!noPagination && ( + - - {dataFiltered - .slice( - table.page * table.rowsPerPage, - table.page * table.rowsPerPage + table.rowsPerPage - ) - .map((row) => ( - table.onSelectRow(row.id)} - /> - ))} - - - - {notFound && } - - - - - {!noPagination && ( - + )} + )}
diff --git a/src/sections/overview/view/overview-analytics-view.tsx b/src/sections/overview/view/overview-analytics-view.tsx index 49fc88513..d774d9319 100644 --- a/src/sections/overview/view/overview-analytics-view.tsx +++ b/src/sections/overview/view/overview-analytics-view.tsx @@ -24,7 +24,7 @@ export function OverviewAnalyticsView() { const { user } = useUser(); const isAdminMode = Cache.get(CacheKeys.AdminMode); const { refresh } = useRouter(); - console.log('ISS', isAdminMode); + const [loading, setLoading] = useState(true); const [data, setData] = useState<{ stats?: Stats | UserStats; cons?: ContributionProps[] }>(); @@ -43,6 +43,7 @@ export function OverviewAnalyticsView() { sender: item.donor, status: getStatus(item.status), timestamp: (item.completedAt || item.createdAt).toDate(), + code: item?.trxCode, })), [] ); @@ -54,7 +55,6 @@ export function OverviewAnalyticsView() { const onLatestContribution = useCallback( (value: Contribution[]) => { - console.log(value); const cons = getContributions(value); setData((val) => (val ? { ...val, cons } : { cons })); getStats(); @@ -234,6 +234,7 @@ export function OverviewAnalyticsView() { ignoreDashContent noMultiSelect noPagination + viewMore data={data?.cons} />
diff --git a/src/sections/user/table-no-data.tsx b/src/sections/user/table-no-data.tsx index 914e23f38..689d3062b 100644 --- a/src/sections/user/table-no-data.tsx +++ b/src/sections/user/table-no-data.tsx @@ -17,14 +17,16 @@ export function TableNoData({ searchQuery, ...other }: TableNoDataProps) { - Not found + No users available - - No results found for   - "{searchQuery}". -
Try checking for typos or using complete words. -
+ {false && ( + + No results found for   + "{searchQuery}". +
Try checking for typos or using complete words. +
+ )}
diff --git a/src/sections/user/view/patners-view.tsx b/src/sections/user/view/partners-view.tsx similarity index 77% rename from src/sections/user/view/patners-view.tsx rename to src/sections/user/view/partners-view.tsx index 275cb0759..f8440269a 100644 --- a/src/sections/user/view/patners-view.tsx +++ b/src/sections/user/view/partners-view.tsx @@ -5,18 +5,19 @@ import { UserView } from './user-view'; const PartnersView = () => { const [data, setData] = useState(); + const [loading, setLoading] = useState(true); const init = async () => { const list = await UserService.list(); - console.log(list); setData(list); + setLoading(false); }; useEffect(() => { init(); }, []); - return ; + return ; }; export default PartnersView; diff --git a/src/sections/user/view/user-view.tsx b/src/sections/user/view/user-view.tsx index d91c4b366..ad72d056b 100644 --- a/src/sections/user/view/user-view.tsx +++ b/src/sections/user/view/user-view.tsx @@ -1,35 +1,33 @@ import { useCallback, useState } from 'react'; import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableContainer from '@mui/material/TableContainer'; -import TablePagination from '@mui/material/TablePagination'; import Typography from '@mui/material/Typography'; import { _users } from 'src/_mock'; import { DashboardContent } from 'src/layouts/dashboard'; -import { Iconify } from 'src/components/iconify'; import { Scrollbar } from 'src/components/scrollbar'; import { User } from 'src/services/user/user.dto'; +import Loader from 'src/components/loader'; import { TableEmptyRows } from '../table-empty-rows'; import { TableNoData } from '../table-no-data'; import { UserTableHead } from '../user-table-head'; import { UserTableRow } from '../user-table-row'; -import { UserTableToolbar } from '../user-table-toolbar'; import { applyFilter, emptyRows, getComparator } from '../utils'; // ---------------------------------------------------------------------- interface PartnersViewProps { data?: User[]; + loading?: boolean; } -export function UserView({ data = [] }: PartnersViewProps) { +export function UserView({ data = [], loading }: PartnersViewProps) { const table = useTable(); const [filterName, setFilterName] = useState(''); @@ -53,13 +51,13 @@ export function UserView({ data = [] }: PartnersViewProps) { Partners - + */} @@ -72,54 +70,58 @@ export function UserView({ data = [] }: PartnersViewProps) { }} /> */} - - - - - table.onSelectAllRows( - checked, - data.map((user) => user.id) - ) - } - headLabel={[ - { id: 'name', label: 'Name' }, - { id: 'role', label: 'Role' }, - { id: 'email', label: 'Email' }, - { id: 'pledge', label: 'Pledge' }, - { id: 'action', label: '' }, - ]} - /> - - {dataFiltered - .slice( - table.page * table.rowsPerPage, - table.page * table.rowsPerPage + table.rowsPerPage - ) - .map((row) => ( - table.onSelectRow(row.id)} - /> - ))} - - + ) : ( + + +
+ + table.onSelectAllRows( + checked, + data.map((user) => user.id) + ) + } + headLabel={[ + { id: 'name', label: 'Name' }, + { id: 'role', label: 'Role' }, + { id: 'email', label: 'Email' }, + { id: 'pledge', label: 'Pledge' }, + { id: 'action', label: '' }, + ]} /> - - {notFound && } - -
-
-
+ + {dataFiltered + .slice( + table.page * table.rowsPerPage, + table.page * table.rowsPerPage + table.rowsPerPage + ) + .map((row) => ( + table.onSelectRow(row.id)} + /> + ))} + + + + {notFound && } + + + + + )} {/* (ApiRoute.InitPayment, { amount, months, callbackUrl: window.location.href, }); + console.log('RES', res.code); const popup = new PaystackPop(); popup.resumeTransaction(res.code as any); return popup; @@ -22,4 +22,17 @@ export default class PayService { return null; } } + + static async resume(code: string) { + try { + console.log('Sume', code); + const popup = new PaystackPop(); + popup.resumeTransaction(code as any); + return popup; + } catch (error) { + const err = error as Error; + errCb(err.message); + return null; + } + } } diff --git a/src/services/user/index.ts b/src/services/user/index.ts index e3408355a..3d662fc54 100644 --- a/src/services/user/index.ts +++ b/src/services/user/index.ts @@ -1,4 +1,4 @@ -import { getDoc, getDocs, setDoc, updateDoc } from 'firebase/firestore'; +import { doc, getDoc, getDocs, setDoc, updateDoc } from 'firebase/firestore'; import { fx } from 'src/configs'; import { Collection } from 'src/constants/factory'; import { ApiRoute } from 'src/constants/fxns'; @@ -22,6 +22,12 @@ export default class UserService { return data; } + static async validateSecret(val: string) { + const ref = docRef(val, Collection.Secret); + const secretDoc = await getDoc(ref); + return secretDoc.exists(); + } + static async update(id: string, data: Partial) { const ref = docRef(id, Collection.Users); await updateDoc(ref, data); @@ -31,7 +37,7 @@ export default class UserService { const ref = colRef(Collection.Users); const { docs, empty } = await getDocs(ref); if (!empty) { - return docs.map((doc) => doc.data() as User); + return docs.map((document) => document.data() as User); } return []; } diff --git a/tsconfig.json b/tsconfig.json index 9bce082b7..a8aa76b30 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,7 @@ "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true }, - "include": ["src"], + "include": ["src", "env.d.ts"], "exclude": ["node_modules"], "references": [ { From a2ff82959ee2d18221c200bfb48005fc4151a1ee Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Thu, 23 Jan 2025 16:31:37 +0000 Subject: [PATCH 07/20] log: print keys --- src/configs/firebase.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index 786304300..0858e2c50 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -19,14 +19,16 @@ const USE_EMULATORS = false; const firebaseConfig = { apiKey: process.env.FIREBASE_API_KEY, - authDomain: 'pabgm-39720.firebaseapp.com', - projectId: 'pabgm-39720', - storageBucket: 'pabgm-39720.firebasestorage.app', - messagingSenderId: '557051436284', - appId: '1:557051436284:web:96f2e80c4cc4c927638b79', - measurementId: 'G-VTGQQYSTP1', + authDomain: process.env.FIREBASE_AUTH_DOMAIN, + projectId: process.env.FIREBASE_PROJECT_ID, + storageBucket: process.env.FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.FIREBASE_MESSAGE_SENDER_ID, + appId: process.env.FIREBASE_APP_ID, + measurementId: process.env.me, }; +console.log(firebaseConfig); + // Initialize Firebase const app = initializeApp(firebaseConfig); From 84c5a457269ab52e5f920426b962a45b3540aa89 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Thu, 23 Jan 2025 16:49:02 +0000 Subject: [PATCH 08/20] lint: fixed lint --- src/_mock/_data.ts | 9 +++--- src/app.tsx | 2 +- src/components/country-select/index.tsx | 6 +++- src/components/loader/index.tsx | 6 ++-- src/components/logo/logo.tsx | 3 +- src/components/provider/index.tsx | 8 +++-- src/components/shared/alert/index.tsx | 11 +++++-- .../shared/modals/contributeForm.tsx | 20 +++++++----- src/components/shared/switch/toggle/index.tsx | 6 ++-- src/configs/firebase.ts | 21 +++++++------ src/constants/index.ts | 2 +- src/hooks/useAdmin.ts | 7 +++-- src/hooks/useAuth.ts | 6 ++-- src/hooks/useUser.ts | 3 +- src/layouts/components/account-popover.tsx | 3 +- src/layouts/config-nav-dashboard.tsx | 1 - src/layouts/dashboard/layout.tsx | 24 +++++++------- src/pages/contributions.tsx | 2 ++ src/pages/home.tsx | 1 + src/pages/logout.tsx | 4 ++- src/routes/sections.tsx | 16 +++++----- src/sections/auth/sign-in-view.tsx | 22 +++++++------ .../contributions/contributions-table-row.tsx | 21 ++++++++----- .../contributions-table-toolbar.tsx | 3 -- .../contributions/view/contributions-list.tsx | 14 ++++++--- .../contributions/view/contributions-view.tsx | 22 ++++++------- .../overview/analytics-widget-summary.tsx | 4 +-- .../overview/view/overview-analytics-view.tsx | 31 +++++++++++-------- src/sections/user/user-table-head.tsx | 1 - src/sections/user/user-table-row.tsx | 26 +++++++++------- src/sections/user/view/partners-view.tsx | 7 +++-- src/sections/user/view/user-view.tsx | 15 ++++----- src/services/auth/index.ts | 11 +++++-- src/services/cont/contribute.dto.ts | 2 +- src/services/cont/index.ts | 18 ++++++----- src/services/pay/index.ts | 6 ++-- src/services/stats/index.ts | 3 +- src/services/trxn/trx.dto.ts | 2 +- src/services/user/index.ts | 10 +++--- src/utils/alert.ts | 2 +- src/utils/cache.ts | 2 +- src/utils/fstore.ts | 4 ++- src/utils/index.ts | 6 ++-- 43 files changed, 233 insertions(+), 160 deletions(-) diff --git a/src/_mock/_data.ts b/src/_mock/_data.ts index 42140b5df..4455c52c2 100644 --- a/src/_mock/_data.ts +++ b/src/_mock/_data.ts @@ -1,9 +1,12 @@ -import { ContributionProps } from 'src/sections/contributions/contributions-table-row'; -import { fShortenNumber } from 'src/utils/format-number'; + +import type { ContributionProps } from 'src/sections/contributions/contributions-table-row'; + import { _id, _price, _times, + _months, + _amount, _company, _boolean, _fullName, @@ -11,8 +14,6 @@ import { _postTitles, _description, _productNames, - _months, - _amount, } from './_mock'; // ---------------------------------------------------------------------- diff --git a/src/app.tsx b/src/app.tsx index d1be1bc5f..97ac7f115 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -6,8 +6,8 @@ import { useScrollToTop } from 'src/hooks/use-scroll-to-top'; import { ThemeProvider } from 'src/theme/theme-provider'; -import AppAlert from './components/shared/alert'; import { AlertUtil } from './utils'; +import AppAlert from './components/shared/alert'; // ---------------------------------------------------------------------- diff --git a/src/components/country-select/index.tsx b/src/components/country-select/index.tsx index 120f52c15..5cf8d7148 100644 --- a/src/components/country-select/index.tsx +++ b/src/components/country-select/index.tsx @@ -1,5 +1,9 @@ -import { FormControl, InputLabel, MenuItem, Select, SelectProps } from '@mui/material'; +import type { SelectProps } from '@mui/material'; + +import { Select, MenuItem, InputLabel, FormControl } from '@mui/material'; + import _countries from 'src/_mock/_countries'; + import { Iconify } from '../iconify'; function CountrySelect({ label = 'Country', ...props }: SelectProps) { diff --git a/src/components/loader/index.tsx b/src/components/loader/index.tsx index 3c674c635..6582b4be8 100644 --- a/src/components/loader/index.tsx +++ b/src/components/loader/index.tsx @@ -1,6 +1,8 @@ +import type { FC } from 'react'; +import type { BoxProps } from '@mui/material/Box'; + import { Box, LinearProgress, linearProgressClasses } from '@mui/material'; -import { BoxProps } from '@mui/material/Box'; -import { FC } from 'react'; + import { varAlpha } from 'src/theme/styles'; interface LoaderProps extends BoxProps {} diff --git a/src/components/logo/logo.tsx b/src/components/logo/logo.tsx index 8385dbb83..405e21ee4 100644 --- a/src/components/logo/logo.tsx +++ b/src/components/logo/logo.tsx @@ -1,13 +1,12 @@ import type { BoxProps } from '@mui/material/Box'; -import { forwardRef, useId } from 'react'; +import { useId, forwardRef } from 'react'; import Box from '@mui/material/Box'; import { useTheme } from '@mui/material/styles'; import { RouterLink } from 'src/routes/components'; -import logo from 'public/assets/images/logo.png'; import { logoClasses } from './classes'; // ---------------------------------------------------------------------- diff --git a/src/components/provider/index.tsx b/src/components/provider/index.tsx index 152993c11..7cdeaf3cd 100644 --- a/src/components/provider/index.tsx +++ b/src/components/provider/index.tsx @@ -1,7 +1,11 @@ -import React, { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; +import type { ReactNode} from 'react'; +import type { User } from 'src/services/user/user.dto'; + +import React, { useMemo, useState, useEffect, useCallback } from 'react'; + import { useRouter } from 'src/routes/hooks'; + import UserService from 'src/services/user'; -import { User } from 'src/services/user/user.dto'; import { Cache, CacheKeys } from 'src/utils'; const IS_ADMIN_MODE = !!Cache.get(CacheKeys.AdminMode); diff --git a/src/components/shared/alert/index.tsx b/src/components/shared/alert/index.tsx index 49123dbee..1d653bb59 100644 --- a/src/components/shared/alert/index.tsx +++ b/src/components/shared/alert/index.tsx @@ -1,6 +1,11 @@ -import { Alert, AlertProps, Box, IconButton, Portal, Slide } from '@mui/material'; -import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react'; -import { Iconify, IconifyProps } from 'src/components/iconify'; +import type { AlertProps} from '@mui/material'; +import type { IconifyProps } from 'src/components/iconify'; + +import { useRef, useState, forwardRef, useCallback, useImperativeHandle } from 'react'; + +import { Box, Alert, Slide, Portal, IconButton } from '@mui/material'; + +import { Iconify } from 'src/components/iconify'; export interface AppAlertProps { id?: string; diff --git a/src/components/shared/modals/contributeForm.tsx b/src/components/shared/modals/contributeForm.tsx index 2a98e8222..562bfa4c3 100644 --- a/src/components/shared/modals/contributeForm.tsx +++ b/src/components/shared/modals/contributeForm.tsx @@ -1,21 +1,27 @@ +import type { FormEvent, ChangeEvent } from 'react'; + +import React, { useState, useEffect } from 'react'; + import { LoadingButton } from '@mui/lab'; import { - Autocomplete, Box, Chip, - IconButton, Link, Modal, TextField, + IconButton, Typography, + Autocomplete, } from '@mui/material'; -import PaystackInline from '@paystack/inline-js'; -import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react'; -import { Iconify } from 'src/components/iconify'; -import useUser from 'src/hooks/useUser'; + import { useRouter } from 'src/routes/hooks'; -import PayService from 'src/services/pay'; + +import useUser from 'src/hooks/useUser'; + import { errCb } from 'src/utils'; +import PayService from 'src/services/pay'; + +import { Iconify } from 'src/components/iconify'; const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; diff --git a/src/components/shared/switch/toggle/index.tsx b/src/components/shared/switch/toggle/index.tsx index b6c6eef17..57221a0ee 100644 --- a/src/components/shared/switch/toggle/index.tsx +++ b/src/components/shared/switch/toggle/index.tsx @@ -1,5 +1,7 @@ -import { Box, Switch, SwitchProps, Typography } from '@mui/material' -import { FC } from 'react' +import type { FC } from 'react' +import type { SwitchProps} from '@mui/material'; + +import { Box, Switch, Typography } from '@mui/material' export interface ToggleSwitchProps extends SwitchProps { label:string diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index 0858e2c50..914341e9f 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -1,19 +1,22 @@ // Import the functions you need from the SDKs you need +import type { + User} from 'firebase/auth'; + import { initializeApp } from 'firebase/app'; +import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore'; +import { getFunctions, httpsCallable, connectFunctionsEmulator } from 'firebase/functions'; import { - User, - confirmPasswordReset, - connectAuthEmulator, - createUserWithEmailAndPassword, getAuth, + signOut, onAuthStateChanged, + connectAuthEmulator, + confirmPasswordReset, sendPasswordResetEmail, signInWithEmailAndPassword, - signOut, + createUserWithEmailAndPassword, } from 'firebase/auth'; -import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'; -import { connectFunctionsEmulator, getFunctions, httpsCallable } from 'firebase/functions'; -import { ApiRoute } from '../constants/fxns'; + +import type { ApiRoute } from '../constants/fxns'; const USE_EMULATORS = false; @@ -77,4 +80,4 @@ const runEmulators = (val: boolean = USE_EMULATORS) => { runEmulators(); -export { app, auth, db, fx }; +export { db, fx, app, auth }; diff --git a/src/constants/index.ts b/src/constants/index.ts index e46b36118..cc0202961 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1,2 +1,2 @@ -export * from './factory'; export * from './urls'; +export * from './factory'; diff --git a/src/hooks/useAdmin.ts b/src/hooks/useAdmin.ts index 0064aba53..989e73e48 100644 --- a/src/hooks/useAdmin.ts +++ b/src/hooks/useAdmin.ts @@ -1,8 +1,9 @@ -import { useContext, useEffect } from 'react'; -import { UserContext } from 'src/components/provider'; -import { useRouter } from 'src/routes/hooks'; +import { useContext } from 'react'; + import { Cache, CacheKeys } from 'src/utils'; +import { UserContext } from 'src/components/provider'; + const useAdmin = () => { const { setIsAdmin } = useContext(UserContext); const isAdminMode = Cache.get(CacheKeys.AdminMode) ?? false; diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index 710263654..601730401 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -1,5 +1,7 @@ -import { User } from 'firebase/auth'; -import React, { useEffect, useState } from 'react'; +import type { User } from 'firebase/auth'; + +import { useState, useEffect } from 'react'; + import AuthService from 'src/services/auth'; const useAuth = () => { diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts index 20b40511e..0e65640ba 100644 --- a/src/hooks/useUser.ts +++ b/src/hooks/useUser.ts @@ -1,4 +1,5 @@ -import { useContext, useEffect, useState } from 'react'; +import { useState, useEffect, useContext } from 'react'; + import { UserContext } from 'src/components/provider'; const useUser = () => { diff --git a/src/layouts/components/account-popover.tsx b/src/layouts/components/account-popover.tsx index f352fbb46..559b13816 100644 --- a/src/layouts/components/account-popover.tsx +++ b/src/layouts/components/account-popover.tsx @@ -3,7 +3,6 @@ import type { IconButtonProps } from '@mui/material/IconButton'; import { useState, useCallback } from 'react'; import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; import Avatar from '@mui/material/Avatar'; import Popover from '@mui/material/Popover'; import Divider from '@mui/material/Divider'; @@ -14,9 +13,9 @@ import MenuItem, { menuItemClasses } from '@mui/material/MenuItem'; import { useRouter, usePathname } from 'src/routes/hooks'; -import { _myAccount } from 'src/_mock'; import useUser from 'src/hooks/useUser'; + // ---------------------------------------------------------------------- export type AccountPopoverProps = IconButtonProps & { diff --git a/src/layouts/config-nav-dashboard.tsx b/src/layouts/config-nav-dashboard.tsx index 86b9146ed..c4b3bf2db 100644 --- a/src/layouts/config-nav-dashboard.tsx +++ b/src/layouts/config-nav-dashboard.tsx @@ -1,4 +1,3 @@ -import { Label } from 'src/components/label'; import { SvgColor } from 'src/components/svg-color'; // ---------------------------------------------------------------------- diff --git a/src/layouts/dashboard/layout.tsx b/src/layouts/dashboard/layout.tsx index 81d91dcaf..dce538642 100644 --- a/src/layouts/dashboard/layout.tsx +++ b/src/layouts/dashboard/layout.tsx @@ -1,29 +1,31 @@ -import type { Breakpoint, SxProps, Theme } from '@mui/material/styles'; +import type { Theme, SxProps, Breakpoint } from '@mui/material/styles'; -import { useEffect, useState } from 'react'; +import { useState, useEffect } from 'react'; -import Alert from '@mui/material/Alert'; import Box from '@mui/material/Box'; +import Alert from '@mui/material/Alert'; import { useTheme } from '@mui/material/styles'; -import { Iconify } from 'src/components/iconify'; +import { useRouter } from 'src/routes/hooks'; -import ToggleSwitch from 'src/components/shared/switch/toggle'; -import useAdmin from 'src/hooks/useAdmin'; import useAuth from 'src/hooks/useAuth'; import useUser from 'src/hooks/useUser'; -import { useRouter } from 'src/routes/hooks'; +import useAdmin from 'src/hooks/useAdmin'; + import AuthService from 'src/services/auth'; import { UserRole } from 'src/services/user/user.dto'; + +import ToggleSwitch from 'src/components/shared/switch/toggle'; + +import { Main } from './main'; import { layoutClasses } from '../classes'; -import { AccountPopover } from '../components/account-popover'; -import { MenuButton } from '../components/menu-button'; +import { NavMobile, NavDesktop } from './nav'; import { navData } from '../config-nav-dashboard'; import { _workspaces } from '../config-nav-workspace'; +import { MenuButton } from '../components/menu-button'; import { HeaderSection } from '../core/header-section'; import { LayoutSection } from '../core/layout-section'; -import { Main } from './main'; -import { NavDesktop, NavMobile } from './nav'; +import { AccountPopover } from '../components/account-popover'; // ---------------------------------------------------------------------- diff --git a/src/pages/contributions.tsx b/src/pages/contributions.tsx index 80c7e6dbf..98bb80ec0 100644 --- a/src/pages/contributions.tsx +++ b/src/pages/contributions.tsx @@ -1,5 +1,7 @@ import { Helmet } from 'react-helmet-async'; + import { CONFIG } from 'src/config-global'; + import ContributionsList from 'src/sections/contributions/view/contributions-list'; function Contributions() { diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 35e7cc892..ff5a3ebfd 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -1,6 +1,7 @@ import { Helmet } from 'react-helmet-async'; import { CONFIG } from 'src/config-global'; + import { OverviewAnalyticsView } from 'src/sections/overview/view'; // ---------------------------------------------------------------------- diff --git a/src/pages/logout.tsx b/src/pages/logout.tsx index 511f406ea..0cbb0e428 100644 --- a/src/pages/logout.tsx +++ b/src/pages/logout.tsx @@ -1,5 +1,7 @@ -import { useCallback, useEffect } from 'react'; +import { useEffect, useCallback } from 'react'; + import { useRouter } from 'src/routes/hooks'; + import AuthService from 'src/services/auth'; function Logout() { diff --git a/src/routes/sections.tsx b/src/routes/sections.tsx index de8db3b8f..70429663b 100644 --- a/src/routes/sections.tsx +++ b/src/routes/sections.tsx @@ -1,18 +1,20 @@ import { lazy, Suspense, useState } from 'react'; -import { Navigate, Outlet, useRoutes } from 'react-router-dom'; +import { Outlet, Navigate, useRoutes } from 'react-router-dom'; import Box from '@mui/material/Box'; +import { Fab } from '@mui/material'; import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress'; -import { Fab } from '@mui/material'; -import { Iconify } from 'src/components/iconify'; -import PaymentFormModal from 'src/components/shared/modals/contributeForm'; -import { AuthLayout } from 'src/layouts/auth'; -import { DashboardLayout } from 'src/layouts/dashboard'; -import { varAlpha } from 'src/theme/styles'; import useUser from 'src/hooks/useUser'; import useAdmin from 'src/hooks/useAdmin'; +import { varAlpha } from 'src/theme/styles'; +import { AuthLayout } from 'src/layouts/auth'; +import { DashboardLayout } from 'src/layouts/dashboard'; + +import { Iconify } from 'src/components/iconify'; +import PaymentFormModal from 'src/components/shared/modals/contributeForm'; + const AppProvider = lazy(() => import('src/components/provider')); // ---------------------------------------------------------------------- diff --git a/src/sections/auth/sign-in-view.tsx b/src/sections/auth/sign-in-view.tsx index 36721132b..9886125c7 100644 --- a/src/sections/auth/sign-in-view.tsx +++ b/src/sections/auth/sign-in-view.tsx @@ -1,22 +1,24 @@ -import { HTMLAttributes, useCallback, useEffect, useState } from 'react'; +import type { CreateUserBody } from 'src/services/auth/auth.dto'; + +import { useState, useEffect, useCallback } from 'react'; -import LoadingButton from '@mui/lab/LoadingButton'; import Box from '@mui/material/Box'; -import Divider from '@mui/material/Divider'; -import IconButton from '@mui/material/IconButton'; -import InputAdornment from '@mui/material/InputAdornment'; import Link from '@mui/material/Link'; +import { Button } from '@mui/material'; +import Divider from '@mui/material/Divider'; import TextField from '@mui/material/TextField'; +import IconButton from '@mui/material/IconButton'; import Typography from '@mui/material/Typography'; +import LoadingButton from '@mui/lab/LoadingButton'; +import InputAdornment from '@mui/material/InputAdornment'; import { useRouter } from 'src/routes/hooks'; -import { Button } from '@mui/material'; -import CountrySelect from 'src/components/country-select'; -import { Iconify } from 'src/components/iconify'; -import { CreateUserBody } from 'src/services/auth/auth.dto'; -import AuthService from 'src/services/auth'; import { errCb } from 'src/utils'; +import AuthService from 'src/services/auth'; + +import { Iconify } from 'src/components/iconify'; +import CountrySelect from 'src/components/country-select'; // ---------------------------------------------------------------------- diff --git a/src/sections/contributions/contributions-table-row.tsx b/src/sections/contributions/contributions-table-row.tsx index e634f6250..c07d5e115 100644 --- a/src/sections/contributions/contributions-table-row.tsx +++ b/src/sections/contributions/contributions-table-row.tsx @@ -1,19 +1,24 @@ -import { useCallback, useState } from 'react'; +import type { LabelColor } from 'src/components/label'; + +import { useState, useCallback } from 'react'; import Box from '@mui/material/Box'; +import { Button } from '@mui/material'; +import Popover from '@mui/material/Popover'; import Checkbox from '@mui/material/Checkbox'; -import MenuItem, { menuItemClasses } from '@mui/material/MenuItem'; import MenuList from '@mui/material/MenuList'; -import Popover from '@mui/material/Popover'; -import TableCell from '@mui/material/TableCell'; import TableRow from '@mui/material/TableRow'; +import TableCell from '@mui/material/TableCell'; +import MenuItem, { menuItemClasses } from '@mui/material/MenuItem'; + +import useUser from 'src/hooks/useUser'; -import { Iconify } from 'src/components/iconify'; -import { Label, LabelColor } from 'src/components/label'; import { fDateTime } from 'src/utils/format-time'; -import { Button } from '@mui/material'; + import PayService from 'src/services/pay'; -import useUser from 'src/hooks/useUser'; + +import { Label } from 'src/components/label'; +import { Iconify } from 'src/components/iconify'; // ---------------------------------------------------------------------- diff --git a/src/sections/contributions/contributions-table-toolbar.tsx b/src/sections/contributions/contributions-table-toolbar.tsx index ad8d90770..34766ae5e 100644 --- a/src/sections/contributions/contributions-table-toolbar.tsx +++ b/src/sections/contributions/contributions-table-toolbar.tsx @@ -1,7 +1,4 @@ -import Tooltip from '@mui/material/Tooltip'; import Toolbar from '@mui/material/Toolbar'; -import Typography from '@mui/material/Typography'; -import IconButton from '@mui/material/IconButton'; import OutlinedInput from '@mui/material/OutlinedInput'; import InputAdornment from '@mui/material/InputAdornment'; diff --git a/src/sections/contributions/view/contributions-list.tsx b/src/sections/contributions/view/contributions-list.tsx index 42e0ab330..edeef025b 100644 --- a/src/sections/contributions/view/contributions-list.tsx +++ b/src/sections/contributions/view/contributions-list.tsx @@ -1,11 +1,17 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import useAdmin from 'src/hooks/useAdmin'; +import type { Contribution} from 'src/services/cont/contribute.dto'; + +import { useState, useEffect, useCallback } from 'react'; + import useUser from 'src/hooks/useUser'; +import useAdmin from 'src/hooks/useAdmin'; + import ContributionService from 'src/services/cont'; -import { Contribution, ContributionStatus } from 'src/services/cont/contribute.dto'; -import { ContributionProps } from '../contributions-table-row'; +import { ContributionStatus } from 'src/services/cont/contribute.dto'; + import { ContributionsView } from './contributions-view'; +import type { ContributionProps } from '../contributions-table-row'; + const ContributionsList = () => { const [data, setData] = useState(); const [loading, setLoading] = useState(true); diff --git a/src/sections/contributions/view/contributions-view.tsx b/src/sections/contributions/view/contributions-view.tsx index baf6dae8b..ae4755178 100644 --- a/src/sections/contributions/view/contributions-view.tsx +++ b/src/sections/contributions/view/contributions-view.tsx @@ -1,30 +1,30 @@ -import { useCallback, useContext, useMemo, useState } from 'react'; +import { useMemo, useState, useContext, useCallback } from 'react'; import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; import Table from '@mui/material/Table'; +import Button from '@mui/material/Button'; import TableBody from '@mui/material/TableBody'; +import Typography from '@mui/material/Typography'; import TableContainer from '@mui/material/TableContainer'; import TablePagination from '@mui/material/TablePagination'; -import Typography from '@mui/material/Typography'; + +import { useRouter } from 'src/routes/hooks'; import { _users } from 'src/_mock'; import { DashboardContent } from 'src/layouts/dashboard'; -import { Iconify } from 'src/components/iconify'; import Loader from 'src/components/loader'; -import { UserContext } from 'src/components/provider'; +import { Iconify } from 'src/components/iconify'; import { Scrollbar } from 'src/components/scrollbar'; -import { useRouter } from 'src/routes/hooks'; +import { UserContext } from 'src/components/provider'; -import { ContributionTableHead } from '../contributions-table-head'; -import { TableEmptyRows } from '../table-empty-rows'; import { TableNoData } from '../table-no-data'; -import { applyFilter, emptyRows, getComparator } from '../utils'; - -import { ContributionsTableRow, type ContributionProps } from '../contributions-table-row'; +import { TableEmptyRows } from '../table-empty-rows'; +import { emptyRows, applyFilter, getComparator } from '../utils'; +import { ContributionTableHead } from '../contributions-table-head'; import { ContributionsTableToolbar } from '../contributions-table-toolbar'; +import { ContributionsTableRow, type ContributionProps } from '../contributions-table-row'; // ---------------------------------------------------------------------- diff --git a/src/sections/overview/analytics-widget-summary.tsx b/src/sections/overview/analytics-widget-summary.tsx index bd5590ab8..6f271f27c 100644 --- a/src/sections/overview/analytics-widget-summary.tsx +++ b/src/sections/overview/analytics-widget-summary.tsx @@ -6,13 +6,11 @@ import Box from '@mui/material/Box'; import Card from '@mui/material/Card'; import { useTheme } from '@mui/material/styles'; -import { fNumber, fPercent, fShortenNumber } from 'src/utils/format-number'; +import { fShortenNumber } from 'src/utils/format-number'; import { varAlpha, bgGradient } from 'src/theme/styles'; -import { Iconify } from 'src/components/iconify'; import { SvgColor } from 'src/components/svg-color'; -import { Chart, useChart } from 'src/components/chart'; // ---------------------------------------------------------------------- diff --git a/src/sections/overview/view/overview-analytics-view.tsx b/src/sections/overview/view/overview-analytics-view.tsx index d774d9319..b5a4837e4 100644 --- a/src/sections/overview/view/overview-analytics-view.tsx +++ b/src/sections/overview/view/overview-analytics-view.tsx @@ -1,21 +1,26 @@ -import Typography from '@mui/material/Typography'; -import Grid from '@mui/material/Unstable_Grid2'; +import type { Contribution} from 'src/services/cont/contribute.dto'; +import type { Stats, UserStats } from 'src/services/stats/stats.dto'; +import type { ContributionProps } from 'src/sections/contributions/contributions-table-row'; -import { DashboardContent } from 'src/layouts/dashboard'; +import { useState, useEffect, useCallback } from 'react'; +import Grid from '@mui/material/Unstable_Grid2'; +import Typography from '@mui/material/Typography'; import { Box, LinearProgress, linearProgressClasses } from '@mui/material'; -import { useCallback, useEffect, useState } from 'react'; -import useAdmin from 'src/hooks/useAdmin'; -import useUser from 'src/hooks/useUser'; + import { useRouter } from 'src/routes/hooks'; -import { ContributionProps } from 'src/sections/contributions/contributions-table-row'; -import { ContributionsView } from 'src/sections/contributions/view'; -import ContributionService from 'src/services/cont'; -import { Contribution, ContributionStatus } from 'src/services/cont/contribute.dto'; -import StatsService from 'src/services/stats'; -import { Stats, UserStats } from 'src/services/stats/stats.dto'; + +import useUser from 'src/hooks/useUser'; + import { varAlpha } from 'src/theme/styles'; -import { Cache, CacheKeys, errCb } from 'src/utils'; +import StatsService from 'src/services/stats'; +import ContributionService from 'src/services/cont'; +import { Cache, errCb, CacheKeys } from 'src/utils'; +import { DashboardContent } from 'src/layouts/dashboard'; +import { ContributionStatus } from 'src/services/cont/contribute.dto'; + +import { ContributionsView } from 'src/sections/contributions/view'; + import { AnalyticsWidgetSummary } from '../analytics-widget-summary'; // ---------------------------------------------------------------------- diff --git a/src/sections/user/user-table-head.tsx b/src/sections/user/user-table-head.tsx index 475bbc629..204efeedb 100644 --- a/src/sections/user/user-table-head.tsx +++ b/src/sections/user/user-table-head.tsx @@ -1,6 +1,5 @@ import Box from '@mui/material/Box'; import TableRow from '@mui/material/TableRow'; -import Checkbox from '@mui/material/Checkbox'; import TableHead from '@mui/material/TableHead'; import TableCell from '@mui/material/TableCell'; import TableSortLabel from '@mui/material/TableSortLabel'; diff --git a/src/sections/user/user-table-row.tsx b/src/sections/user/user-table-row.tsx index ba375084e..8d6cf411e 100644 --- a/src/sections/user/user-table-row.tsx +++ b/src/sections/user/user-table-row.tsx @@ -1,21 +1,25 @@ -import { useCallback, useState } from 'react'; +import { useState, useCallback } from 'react'; -import Avatar from '@mui/material/Avatar'; import Box from '@mui/material/Box'; -import IconButton from '@mui/material/IconButton'; -import MenuItem, { menuItemClasses } from '@mui/material/MenuItem'; -import MenuList from '@mui/material/MenuList'; +import Avatar from '@mui/material/Avatar'; import Popover from '@mui/material/Popover'; -import TableCell from '@mui/material/TableCell'; +import MenuList from '@mui/material/MenuList'; import TableRow from '@mui/material/TableRow'; +import TableCell from '@mui/material/TableCell'; +import { CircularProgress } from '@mui/material'; +import IconButton from '@mui/material/IconButton'; +import MenuItem, { menuItemClasses } from '@mui/material/MenuItem'; + +import { useRouter } from 'src/routes/hooks'; -import { Iconify } from 'src/components/iconify'; -import { fCurrency, fShortenNumber } from 'src/utils/format-number'; -import { UserRole } from 'src/services/user/user.dto'; import useUser from 'src/hooks/useUser'; + +import { fCurrency } from 'src/utils/format-number'; + import UserService from 'src/services/user'; -import { useRouter } from 'src/routes/hooks'; -import { CircularProgress } from '@mui/material'; +import { UserRole } from 'src/services/user/user.dto'; + +import { Iconify } from 'src/components/iconify'; // ---------------------------------------------------------------------- diff --git a/src/sections/user/view/partners-view.tsx b/src/sections/user/view/partners-view.tsx index f8440269a..574564a5c 100644 --- a/src/sections/user/view/partners-view.tsx +++ b/src/sections/user/view/partners-view.tsx @@ -1,6 +1,9 @@ -import { useEffect, useState } from 'react'; +import type { User } from 'src/services/user/user.dto'; + +import { useState, useEffect } from 'react'; + import UserService from 'src/services/user'; -import { User } from 'src/services/user/user.dto'; + import { UserView } from './user-view'; const PartnersView = () => { diff --git a/src/sections/user/view/user-view.tsx b/src/sections/user/view/user-view.tsx index ad72d056b..eb0b62e6d 100644 --- a/src/sections/user/view/user-view.tsx +++ b/src/sections/user/view/user-view.tsx @@ -1,24 +1,25 @@ -import { useCallback, useState } from 'react'; +import type { User } from 'src/services/user/user.dto'; + +import { useState, useCallback } from 'react'; import Box from '@mui/material/Box'; import Card from '@mui/material/Card'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; -import TableContainer from '@mui/material/TableContainer'; import Typography from '@mui/material/Typography'; +import TableContainer from '@mui/material/TableContainer'; import { _users } from 'src/_mock'; import { DashboardContent } from 'src/layouts/dashboard'; +import Loader from 'src/components/loader'; import { Scrollbar } from 'src/components/scrollbar'; -import { User } from 'src/services/user/user.dto'; -import Loader from 'src/components/loader'; -import { TableEmptyRows } from '../table-empty-rows'; import { TableNoData } from '../table-no-data'; -import { UserTableHead } from '../user-table-head'; import { UserTableRow } from '../user-table-row'; -import { applyFilter, emptyRows, getComparator } from '../utils'; +import { UserTableHead } from '../user-table-head'; +import { TableEmptyRows } from '../table-empty-rows'; +import { emptyRows, applyFilter, getComparator } from '../utils'; // ---------------------------------------------------------------------- diff --git a/src/services/auth/index.ts b/src/services/auth/index.ts index 482760e4b..18da042a8 100644 --- a/src/services/auth/index.ts +++ b/src/services/auth/index.ts @@ -1,11 +1,16 @@ -import { User } from 'firebase/auth'; +import type { User } from 'firebase/auth'; + import { jwtDecode } from 'jwt-decode'; + +import { hash } from 'src/utils/encrypt'; + import { auth } from 'src/configs/firebase'; import { Cache, CacheKeys } from 'src/utils'; -import { hash } from 'src/utils/encrypt'; + import UserService from '../user'; import { UserRole } from '../user/user.dto'; -import { CreateUserBody, UserLoginBody } from './auth.dto'; + +import type { UserLoginBody, CreateUserBody } from './auth.dto'; export default class AuthService { private static token: string | null = Cache.get(CacheKeys.Token); diff --git a/src/services/cont/contribute.dto.ts b/src/services/cont/contribute.dto.ts index 89da8b447..b78a40cdb 100644 --- a/src/services/cont/contribute.dto.ts +++ b/src/services/cont/contribute.dto.ts @@ -1,4 +1,4 @@ -import { Timestamp } from 'firebase/firestore'; +import type { Timestamp } from 'firebase/firestore'; export enum ContributionStatus { Pending = 'PENDING', diff --git a/src/services/cont/index.ts b/src/services/cont/index.ts index 169518976..afb01c9e4 100644 --- a/src/services/cont/index.ts +++ b/src/services/cont/index.ts @@ -1,18 +1,22 @@ import { - Timestamp, - getDoc, - getDocs, limit, - onSnapshot, - orderBy, query, where, + getDoc, + getDocs, + orderBy, + Timestamp, + onSnapshot, } from 'firebase/firestore'; + import { fx } from 'src/configs'; import { Collection } from 'src/constants'; -import { ApiRoute } from 'src/constants/fxns'; import { colRef, docRef } from 'src/utils'; -import { Contribution, ContributionResponse, ContributionStatus } from './contribute.dto'; +import { ApiRoute } from 'src/constants/fxns'; + +import { ContributionStatus } from './contribute.dto'; + +import type { Contribution, ContributionResponse} from './contribute.dto'; export default class ContributionService { private static ref = colRef(Collection.Contributions); diff --git a/src/services/pay/index.ts b/src/services/pay/index.ts index 2c0bf59c3..72ae044ff 100644 --- a/src/services/pay/index.ts +++ b/src/services/pay/index.ts @@ -1,8 +1,10 @@ import PaystackPop from '@paystack/inline-js'; + import { fx } from 'src/configs'; -import { ApiRoute } from 'src/constants/fxns'; import { errCb } from 'src/utils'; -import { ContributeInit } from './pay.dto'; +import { ApiRoute } from 'src/constants/fxns'; + +import type { ContributeInit } from './pay.dto'; export default class PayService { static async init(amount: number, months: string[]) { diff --git a/src/services/stats/index.ts b/src/services/stats/index.ts index aa8f85979..aac377837 100644 --- a/src/services/stats/index.ts +++ b/src/services/stats/index.ts @@ -1,6 +1,7 @@ import { fx } from 'src/configs'; import { ApiRoute } from 'src/constants/fxns'; -import { Stats, UserStats } from './stats.dto'; + +import type { Stats, UserStats } from './stats.dto'; export default class StatsService { static async get() { diff --git a/src/services/trxn/trx.dto.ts b/src/services/trxn/trx.dto.ts index db9b6e851..c7f12165b 100644 --- a/src/services/trxn/trx.dto.ts +++ b/src/services/trxn/trx.dto.ts @@ -1,4 +1,4 @@ -import { Timestamp } from 'firebase/firestore'; +import type { Timestamp } from 'firebase/firestore'; export enum TrxStatus { Initiated = 'INITIATED', diff --git a/src/services/user/index.ts b/src/services/user/index.ts index 3d662fc54..eb61f860b 100644 --- a/src/services/user/index.ts +++ b/src/services/user/index.ts @@ -1,9 +1,11 @@ -import { doc, getDoc, getDocs, setDoc, updateDoc } from 'firebase/firestore'; +import { getDoc, setDoc, getDocs, updateDoc } from 'firebase/firestore'; + import { fx } from 'src/configs'; -import { Collection } from 'src/constants/factory'; -import { ApiRoute } from 'src/constants/fxns'; import { colRef, docRef } from 'src/utils'; -import { User, UserUpdateBody } from './user.dto'; +import { ApiRoute } from 'src/constants/fxns'; +import { Collection } from 'src/constants/factory'; + +import type { User} from './user.dto'; export default class UserService { static async get(id: string): Promise { diff --git a/src/utils/alert.ts b/src/utils/alert.ts index dcc967f1c..29c4dbf7b 100644 --- a/src/utils/alert.ts +++ b/src/utils/alert.ts @@ -1,4 +1,4 @@ -import { AppAlertMethods } from 'src/components/shared/alert'; +import type { AppAlertMethods } from 'src/components/shared/alert'; export class AlertUtil { private static ref: AppAlertMethods | null; diff --git a/src/utils/cache.ts b/src/utils/cache.ts index f5a12c413..96f9b9c57 100644 --- a/src/utils/cache.ts +++ b/src/utils/cache.ts @@ -1,4 +1,4 @@ -import { payloadDeHash, payloadHash } from './encrypt'; +import { payloadHash, payloadDeHash } from './encrypt'; export enum CacheKeys { Token = 'my.auth.id.t', diff --git a/src/utils/fstore.ts b/src/utils/fstore.ts index 8c1b265d8..2da02bc03 100644 --- a/src/utils/fstore.ts +++ b/src/utils/fstore.ts @@ -1,6 +1,8 @@ +import type { Collection } from 'src/constants/factory'; + import { doc, collection } from 'firebase/firestore'; + import { db } from 'src/configs'; -import { Collection } from 'src/constants/factory'; export function docRef(id: string, col: Collection) { return doc(db, col, id); diff --git a/src/utils/index.ts b/src/utils/index.ts index 115797d1b..5d9b03c6b 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,5 @@ -export * from './encrypt'; -export * from './fstore'; export * from './alert'; -export * from './errors'; export * from './cache'; +export * from './fstore'; +export * from './errors'; +export * from './encrypt'; From bccd931b3aced3f98b599ddefb435177305748b0 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Thu, 23 Jan 2025 16:59:55 +0000 Subject: [PATCH 09/20] cleanup: rmoved envs --- .env.development | 7 ------- .env.production | 7 ------- 2 files changed, 14 deletions(-) delete mode 100644 .env.development delete mode 100644 .env.production diff --git a/.env.development b/.env.development deleted file mode 100644 index 8d8426fe1..000000000 --- a/.env.development +++ /dev/null @@ -1,7 +0,0 @@ -FIREBASE_API_KEY = AIzaSyDY-1FezjbzGmq1j3WHWurbniF3IIdYmEY -FIREBASE_AUTH_DOMAIN = pabgm-39720.firebaseapp.com -FIREBASE_PROJECT_ID = pabgm-39720 -FIREBASE_STORAGE_BUCKET = pabgm-39720.firebasestorage.app -FIREBASE_MESSAGE_SENDER_ID = 557051436284 -FIREBASE_APP_ID = 1:557051436284:web:96f2e80c4cc4c927638b79 -FIREBASE_MEASUREMENT_ID = G-VTGQQYSTP1 diff --git a/.env.production b/.env.production deleted file mode 100644 index dd531cf5b..000000000 --- a/.env.production +++ /dev/null @@ -1,7 +0,0 @@ -FIREBASE_API_KEY = AIzaSyDFWGNo8407oOfIFdQG6l3g7QAwEJIXChs -FIREBASE_AUTH_DOMAIN = pabgm-prod-cf8ec.firebaseapp.com -FIREBASE_PROJECT_ID = pabgm-prod-cf8ec -FIREBASE_STORAGE_BUCKET = pabgm-prod-cf8ec.firebasestorage.app -FIREBASE_MESSAGE_SENDER_ID = 804867831086 -FIREBASE_APP_ID = 1:804867831086:web:644d67756ec3dea65cb6bf -FIREBASE_MEASUREMENT_ID = G-T3GNEJNC7V From f02dd63f48713ca2dd1e3525800886beac85d74d Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 24 Jan 2025 14:57:49 +0000 Subject: [PATCH 10/20] ref: renamed envs --- .gitignore | 2 +- env.d.ts | 14 +++++++------- src/configs/firebase.ts | 17 ++++++++--------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 44300dc1f..77ec94cd7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ dist build # environment variables -.env +.env.* .env.local .env.development.local .env.test.local diff --git a/env.d.ts b/env.d.ts index 8c710d748..9fc5cbebd 100644 --- a/env.d.ts +++ b/env.d.ts @@ -1,12 +1,12 @@ declare namespace NodeJS { interface ProcessEnv { //FIREBASE CONFIGS - FIREBASE_API_KEY: string; - FIREBASE_AUTH_DOMAIN: string; - FIREBASE_PROJECT_ID: string; - FIREBASE_STORAGE_BUCKET: string; - FIREBASE_MESSAGE_SENDER_ID: string; - FIREBASE_APP_ID: string; - FIREBASE_MEASUREMENT_ID: string; + REACT_APP_FIREBASE_API_KEY: string; + REACT_APP_FIREBASE_AUTH_DOMAIN: string; + REACT_APP_FIREBASE_PROJECT_ID: string; + REACT_APP_FIREBASE_STORAGE_BUCKET: string; + REACT_APP_FIREBASE_MESSAGE_SENDER_ID: string; + REACT_APP_FIREBASE_APP_ID: string; + REACT_APP_FIREBASE_MEASUREMENT_ID: string; } } diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index 914341e9f..6fd5b30ba 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -1,6 +1,5 @@ // Import the functions you need from the SDKs you need -import type { - User} from 'firebase/auth'; +import type { User } from 'firebase/auth'; import { initializeApp } from 'firebase/app'; import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore'; @@ -21,13 +20,13 @@ import type { ApiRoute } from '../constants/fxns'; const USE_EMULATORS = false; const firebaseConfig = { - apiKey: process.env.FIREBASE_API_KEY, - authDomain: process.env.FIREBASE_AUTH_DOMAIN, - projectId: process.env.FIREBASE_PROJECT_ID, - storageBucket: process.env.FIREBASE_STORAGE_BUCKET, - messagingSenderId: process.env.FIREBASE_MESSAGE_SENDER_ID, - appId: process.env.FIREBASE_APP_ID, - measurementId: process.env.me, + apiKey: process.env.REACT_APP_FIREBASE_API_KEY, + authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN, + projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID, + storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGE_SENDER_ID, + appId: process.env.REACT_APP_FIREBASE_APP_ID, + measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID, }; console.log(firebaseConfig); From dc8a0cdefb5e174d7169e375428cbf93827e4cf2 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 24 Jan 2025 15:59:00 +0000 Subject: [PATCH 11/20] ref: changed to VITE envs --- env.d.ts | 14 +++++++------- src/configs/firebase.ts | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/env.d.ts b/env.d.ts index 9fc5cbebd..6a51b2360 100644 --- a/env.d.ts +++ b/env.d.ts @@ -1,12 +1,12 @@ declare namespace NodeJS { interface ProcessEnv { //FIREBASE CONFIGS - REACT_APP_FIREBASE_API_KEY: string; - REACT_APP_FIREBASE_AUTH_DOMAIN: string; - REACT_APP_FIREBASE_PROJECT_ID: string; - REACT_APP_FIREBASE_STORAGE_BUCKET: string; - REACT_APP_FIREBASE_MESSAGE_SENDER_ID: string; - REACT_APP_FIREBASE_APP_ID: string; - REACT_APP_FIREBASE_MEASUREMENT_ID: string; + VITE_FIREBASE_API_KEY: string; + VITE_FIREBASE_AUTH_DOMAIN: string; + VITE_FIREBASE_PROJECT_ID: string; + VITE_FIREBASE_STORAGE_BUCKET: string; + VITE_FIREBASE_MESSAGE_SENDER_ID: string; + VITE_FIREBASE_APP_ID: string; + VITE_FIREBASE_MEASUREMENT_ID: string; } } diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index 6fd5b30ba..c02ec4b03 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -20,13 +20,13 @@ import type { ApiRoute } from '../constants/fxns'; const USE_EMULATORS = false; const firebaseConfig = { - apiKey: process.env.REACT_APP_FIREBASE_API_KEY, - authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN, - projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID, - storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET, - messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGE_SENDER_ID, - appId: process.env.REACT_APP_FIREBASE_APP_ID, - measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID, + apiKey: process.env.VITE_FIREBASE_API_KEY, + authDomain: process.env.VITE_FIREBASE_AUTH_DOMAIN, + projectId: process.env.VITE_FIREBASE_PROJECT_ID, + storageBucket: process.env.VITE_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.VITE_FIREBASE_MESSAGE_SENDER_ID, + appId: process.env.VITE_FIREBASE_APP_ID, + measurementId: process.env.VITE_FIREBASE_MEASUREMENT_ID, }; console.log(firebaseConfig); From ed915ca7e0499c05ff3b7bc4759c11d1fb4f67d6 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 24 Jan 2025 16:03:49 +0000 Subject: [PATCH 12/20] ref: changed to VITE envs --- src/configs/firebase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index c02ec4b03..3746c2e4c 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -29,7 +29,7 @@ const firebaseConfig = { measurementId: process.env.VITE_FIREBASE_MEASUREMENT_ID, }; -console.log(firebaseConfig); +console.log(process.env); // Initialize Firebase const app = initializeApp(firebaseConfig); From 48239a0b75a6bd06b0b31eb2270be9d6088b5f58 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 24 Jan 2025 16:13:34 +0000 Subject: [PATCH 13/20] ref: changed from process.env to import.meta.env --- env.d.ts | 12 ------------ src/configs/firebase.ts | 16 ++++++++-------- src/vite-env.d.ts | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 20 deletions(-) delete mode 100644 env.d.ts diff --git a/env.d.ts b/env.d.ts deleted file mode 100644 index 6a51b2360..000000000 --- a/env.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -declare namespace NodeJS { - interface ProcessEnv { - //FIREBASE CONFIGS - VITE_FIREBASE_API_KEY: string; - VITE_FIREBASE_AUTH_DOMAIN: string; - VITE_FIREBASE_PROJECT_ID: string; - VITE_FIREBASE_STORAGE_BUCKET: string; - VITE_FIREBASE_MESSAGE_SENDER_ID: string; - VITE_FIREBASE_APP_ID: string; - VITE_FIREBASE_MEASUREMENT_ID: string; - } -} diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index 3746c2e4c..fb1ebcb1f 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -20,16 +20,16 @@ import type { ApiRoute } from '../constants/fxns'; const USE_EMULATORS = false; const firebaseConfig = { - apiKey: process.env.VITE_FIREBASE_API_KEY, - authDomain: process.env.VITE_FIREBASE_AUTH_DOMAIN, - projectId: process.env.VITE_FIREBASE_PROJECT_ID, - storageBucket: process.env.VITE_FIREBASE_STORAGE_BUCKET, - messagingSenderId: process.env.VITE_FIREBASE_MESSAGE_SENDER_ID, - appId: process.env.VITE_FIREBASE_APP_ID, - measurementId: process.env.VITE_FIREBASE_MEASUREMENT_ID, + apiKey: import.meta.env.VITE_FIREBASE_API_KEY, + authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN, + projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID, + storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET, + messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGE_SENDER_ID, + appId: import.meta.env.VITE_FIREBASE_APP_ID, + measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID, }; -console.log(process.env); +console.log(firebaseConfig); // Initialize Firebase const app = initializeApp(firebaseConfig); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 11f02fe2a..d5066fece 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1 +1,16 @@ /// +/// + +interface ImportMetaEnv { + readonly VITE_FIREBASE_API_KEY: string; + readonly VITE_FIREBASE_AUTH_DOMAIN: string; + readonly VITE_FIREBASE_PROJECT_ID: string; + readonly VITE_FIREBASE_STORAGE_BUCKET: string; + readonly VITE_FIREBASE_MESSAGE_SENDER_ID: string; + readonly VITE_FIREBASE_APP_ID: string; + readonly VITE_FIREBASE_MEASUREMENT_ID: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} From 6217a3ef2989f64b3ac69ae902716324a783539d Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 24 Jan 2025 16:16:57 +0000 Subject: [PATCH 14/20] fix: env variables can now be accessed --- src/configs/firebase.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/configs/firebase.ts b/src/configs/firebase.ts index fb1ebcb1f..c2c1f5b49 100644 --- a/src/configs/firebase.ts +++ b/src/configs/firebase.ts @@ -29,8 +29,6 @@ const firebaseConfig = { measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID, }; -console.log(firebaseConfig); - // Initialize Firebase const app = initializeApp(firebaseConfig); From c6b0789ef286a97b3358c9a784278fa578c0831f Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 24 Jan 2025 16:42:12 +0000 Subject: [PATCH 15/20] ref: changed alert from ref to state --- src/components/shared/alert/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/shared/alert/index.tsx b/src/components/shared/alert/index.tsx index 1d653bb59..26f2aa353 100644 --- a/src/components/shared/alert/index.tsx +++ b/src/components/shared/alert/index.tsx @@ -1,4 +1,4 @@ -import type { AlertProps} from '@mui/material'; +import type { AlertProps } from '@mui/material'; import type { IconifyProps } from 'src/components/iconify'; import { useRef, useState, forwardRef, useCallback, useImperativeHandle } from 'react'; @@ -80,9 +80,9 @@ const AppAlert = forwardRef((_, ref) => { container={container.current} > } + icon={value?.icon && } action={ From 04e0f78ea609b30b1ba3683e4bfd19f6c687d855 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Fri, 24 Jan 2025 17:39:30 +0000 Subject: [PATCH 16/20] feat: cancel contributions --- src/sections/auth/sign-in-view.tsx | 2 +- .../contributions/contributions-table-row.tsx | 25 ++++++++++++++++--- src/services/cont/index.ts | 13 ++++++++-- src/services/pay/index.ts | 2 -- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/sections/auth/sign-in-view.tsx b/src/sections/auth/sign-in-view.tsx index 9886125c7..65cd13608 100644 --- a/src/sections/auth/sign-in-view.tsx +++ b/src/sections/auth/sign-in-view.tsx @@ -64,7 +64,7 @@ export function SignInView() { }); } } else { - const user = await AuthService.register(data as CreateUserBody); + await AuthService.register(data as CreateUserBody); } router.replace('/'); } catch (error) { diff --git a/src/sections/contributions/contributions-table-row.tsx b/src/sections/contributions/contributions-table-row.tsx index c07d5e115..a4154153d 100644 --- a/src/sections/contributions/contributions-table-row.tsx +++ b/src/sections/contributions/contributions-table-row.tsx @@ -19,6 +19,8 @@ import PayService from 'src/services/pay'; import { Label } from 'src/components/label'; import { Iconify } from 'src/components/iconify'; +import ContributionService from 'src/services/cont'; +import { LoadingButton } from '@mui/lab'; // ---------------------------------------------------------------------- @@ -49,6 +51,7 @@ export function ContributionsTableRow({ onSelectRow, }: ContributionsTableRowProps) { const [openPopover, setOpenPopover] = useState(null); + const [cancelling, setCancelling] = useState(false); const { user } = useUser(); const handleOpenPopover = useCallback((event: React.MouseEvent) => { @@ -69,6 +72,12 @@ export function ContributionsTableRow({ PayService.resume(code); }; + const onCancel = async (id: string) => { + setCancelling(true); + await ContributionService.cancel(id); + setCancelling(false); + }; + return ( <> @@ -97,9 +106,19 @@ export function ContributionsTableRow({ {row.status === 'pending' && row.sender.id === user?.id ? ( - + + + onCancel(row.id)} + > + Cancel + + ) : ( '' )} diff --git a/src/services/cont/index.ts b/src/services/cont/index.ts index afb01c9e4..e04b073a3 100644 --- a/src/services/cont/index.ts +++ b/src/services/cont/index.ts @@ -7,16 +7,17 @@ import { orderBy, Timestamp, onSnapshot, + deleteDoc, } from 'firebase/firestore'; -import { fx } from 'src/configs'; +import { db, fx } from 'src/configs'; import { Collection } from 'src/constants'; import { colRef, docRef } from 'src/utils'; import { ApiRoute } from 'src/constants/fxns'; import { ContributionStatus } from './contribute.dto'; -import type { Contribution, ContributionResponse} from './contribute.dto'; +import type { Contribution, ContributionResponse } from './contribute.dto'; export default class ContributionService { private static ref = colRef(Collection.Contributions); @@ -85,4 +86,12 @@ export default class ContributionService { })) as Contribution[], }; } + + static async cancel(id: string) { + const data = await this.get(id); + if (data && data.status === ContributionStatus.Pending) { + const doc = docRef(id, Collection.Contributions); + await deleteDoc(doc); + } + } } diff --git a/src/services/pay/index.ts b/src/services/pay/index.ts index 72ae044ff..f6098d654 100644 --- a/src/services/pay/index.ts +++ b/src/services/pay/index.ts @@ -14,7 +14,6 @@ export default class PayService { months, callbackUrl: window.location.href, }); - console.log('RES', res.code); const popup = new PaystackPop(); popup.resumeTransaction(res.code as any); return popup; @@ -27,7 +26,6 @@ export default class PayService { static async resume(code: string) { try { - console.log('Sume', code); const popup = new PaystackPop(); popup.resumeTransaction(code as any); return popup; From cde6898802a9d0c0ae0197d4e89da1ae241cfa6d Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Sat, 25 Jan 2025 18:17:54 +0000 Subject: [PATCH 17/20] cleanup: rm google login --- src/sections/auth/sign-in-view.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sections/auth/sign-in-view.tsx b/src/sections/auth/sign-in-view.tsx index 65cd13608..6682ee0b5 100644 --- a/src/sections/auth/sign-in-view.tsx +++ b/src/sections/auth/sign-in-view.tsx @@ -265,7 +265,7 @@ export function SignInView() {
{renderForm}
- {isSignin && ( + {/* {isSignin && ( <> - )} + )} */} ); } From 599806631ea43ec2a68c5a5b63c0aba7f7607649 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Sun, 26 Jan 2025 03:03:01 +0000 Subject: [PATCH 18/20] ref: rmove secrete field --- src/services/auth/auth.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/auth/auth.dto.ts b/src/services/auth/auth.dto.ts index d2342e41a..f181f2e46 100644 --- a/src/services/auth/auth.dto.ts +++ b/src/services/auth/auth.dto.ts @@ -5,7 +5,7 @@ export interface CreateUserBody { password?: string; country: string; pledgeAmount: number; - secret: string; + secret?: string; } export interface UserLoginBody { From 0642e4b85b7327cca76ee77e70bb08fbff9bc3d9 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Sun, 26 Jan 2025 03:07:05 +0000 Subject: [PATCH 19/20] ref: delete secret key --- src/services/auth/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/auth/index.ts b/src/services/auth/index.ts index 18da042a8..ecb69fcd3 100644 --- a/src/services/auth/index.ts +++ b/src/services/auth/index.ts @@ -16,7 +16,8 @@ export default class AuthService { private static token: string | null = Cache.get(CacheKeys.Token); static async register(data: CreateUserBody) { - const valid = await UserService.validateSecret(data.secret); + const valid = await UserService.validateSecret(data.secret!); + delete data?.secret; if (!valid) throw new Error('INVALID_SECRET_KEY'); const pass = hash(data.password!); const user = await auth.createUser(data.email, pass); From 2d056df5b0cafeb085ecf9fd96ab8343fc0764f9 Mon Sep 17 00:00:00 2001 From: natehubbit007 Date: Sun, 26 Jan 2025 03:17:42 +0000 Subject: [PATCH 20/20] ref: change register pledgeAmount to number --- src/services/auth/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/auth/index.ts b/src/services/auth/index.ts index ecb69fcd3..78078867d 100644 --- a/src/services/auth/index.ts +++ b/src/services/auth/index.ts @@ -26,6 +26,7 @@ export default class AuthService { delete data.password; return UserService.create({ ...data, + pledgeAmount: Number(data.pledgeAmount), id: user.user.uid, role: [UserRole.Partner], });