From 4c141ed30166972acff4ea87c1e8d1aef87f9a75 Mon Sep 17 00:00:00 2001 From: Aamil13 Date: Mon, 23 Sep 2024 13:44:19 +0530 Subject: [PATCH] created v2/register page and implemented their respective api's --- package-lock.json | 465 ++++++++++-------- package.json | 3 + src/app/v2/register/loading.tsx | 11 + src/app/v2/register/page.tsx | 37 ++ src/assets/Indicator.svg | 18 + src/assets/Social icon.svg | 13 + .../atoms/DateSelect/DateSelect.tsx | 75 +++ src/components/atoms/Input/InputBox.tsx | 7 +- src/components/atoms/LoginButtons/index.tsx | 4 +- src/components/atoms/OTP-Input/OTP_Input.tsx | 82 +++ .../atoms/SelectDropdown/SelectDropdown.tsx | 108 ++++ src/components/organism/Login/LoginBox.tsx | 25 +- .../Register/formContainer/FormContainer.tsx | 247 ++++++++++ .../Register/forms/AccountCreationForm.tsx | 158 ++++++ .../Register/forms/ClaimBenefitForm.tsx | 67 +++ .../Register/forms/FinalLoginForm.tsx | 83 ++++ .../Register/forms/ProfileSetupForm.tsx | 109 ++++ .../forms/UniversityVerificationForm.tsx | 141 ++++++ .../Register/forms/VerificationForm.tsx | 116 +++++ .../Register/sidebar/RegisterSIdebar.tsx | 38 ++ .../Register/stepper/RegisterStepper.tsx | 101 ++++ src/services/auth.ts | 92 ++++ src/utils/countriesList.ts | 207 ++++++++ 23 files changed, 2004 insertions(+), 203 deletions(-) create mode 100644 src/app/v2/register/loading.tsx create mode 100644 src/app/v2/register/page.tsx create mode 100644 src/assets/Indicator.svg create mode 100644 src/assets/Social icon.svg create mode 100644 src/components/atoms/DateSelect/DateSelect.tsx create mode 100644 src/components/atoms/OTP-Input/OTP_Input.tsx create mode 100644 src/components/atoms/SelectDropdown/SelectDropdown.tsx create mode 100644 src/components/organism/Register/formContainer/FormContainer.tsx create mode 100644 src/components/organism/Register/forms/AccountCreationForm.tsx create mode 100644 src/components/organism/Register/forms/ClaimBenefitForm.tsx create mode 100644 src/components/organism/Register/forms/FinalLoginForm.tsx create mode 100644 src/components/organism/Register/forms/ProfileSetupForm.tsx create mode 100644 src/components/organism/Register/forms/UniversityVerificationForm.tsx create mode 100644 src/components/organism/Register/forms/VerificationForm.tsx create mode 100644 src/components/organism/Register/sidebar/RegisterSIdebar.tsx create mode 100644 src/components/organism/Register/stepper/RegisterStepper.tsx create mode 100644 src/utils/countriesList.ts diff --git a/package-lock.json b/package-lock.json index 8a25e8a8..7b69d75a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "cors": "^2.8.5", "cross-fetch": "^4.0.0", "crypto-js": "^4.2.0", + "date-fns": "^4.1.0", "dayjs": "^1.11.11", "dotenv": "^16.3.1", "emoji-picker-react": "^4.9.3", @@ -41,6 +42,7 @@ "postcss": "8.4.30", "promises": "^0.2.5", "react": "18.2.0", + "react-date-range": "^2.0.1", "react-dom": "^18.2.0", "react-hook-form": "^7.51.2", "react-icons": "^4.11.0", @@ -75,6 +77,7 @@ "@types/cookie": "^0.6.0", "@types/crypto-js": "^4.2.2", "@types/jest": "^29.5.11", + "@types/react-date-range": "^1.4.9", "@types/react-slick": "^0.23.13", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", @@ -3565,14 +3568,6 @@ "node": ">=8.9.0" } }, - "node_modules/@radix-ui/number": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz", - "integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==", - "dependencies": { - "@babel/runtime": "^7.13.10" - } - }, "node_modules/@radix-ui/primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", @@ -3681,33 +3676,6 @@ } } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz", - "integrity": "sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-callback-ref": "1.0.1", - "@radix-ui/react-use-escape-keydown": "1.0.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz", @@ -3725,31 +3693,6 @@ } } }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.3.tgz", - "integrity": "sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-callback-ref": "1.0.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-id": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz", @@ -3912,61 +3855,6 @@ } } }, - "node_modules/@radix-ui/react-popper": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.2.tgz", - "integrity": "sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.0.3", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-callback-ref": "1.0.1", - "@radix-ui/react-use-layout-effect": "1.0.1", - "@radix-ui/react-use-rect": "1.0.1", - "@radix-ui/react-use-size": "1.0.1", - "@radix-ui/rect": "1.0.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.3.tgz", - "integrity": "sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-presence": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz", @@ -4045,49 +3933,6 @@ } } }, - "node_modules/@radix-ui/react-select": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.2.tgz", - "integrity": "sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/number": "1.0.1", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-collection": "1.0.3", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-direction": "1.0.1", - "@radix-ui/react-dismissable-layer": "1.0.4", - "@radix-ui/react-focus-guards": "1.0.1", - "@radix-ui/react-focus-scope": "1.0.3", - "@radix-ui/react-id": "1.0.1", - "@radix-ui/react-popper": "1.1.2", - "@radix-ui/react-portal": "1.0.3", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-slot": "1.0.2", - "@radix-ui/react-use-callback-ref": "1.0.1", - "@radix-ui/react-use-controllable-state": "1.0.1", - "@radix-ui/react-use-layout-effect": "1.0.1", - "@radix-ui/react-use-previous": "1.0.1", - "@radix-ui/react-visually-hidden": "1.0.3", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.5" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-separator": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz", @@ -4282,23 +4127,6 @@ } } }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz", - "integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-use-rect": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz", @@ -4335,29 +4163,6 @@ } } }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz", - "integrity": "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/rect": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz", @@ -5342,6 +5147,204 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@storybook/components/node_modules/@radix-ui/number": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz", + "integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@storybook/components/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz", + "integrity": "sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-escape-keydown": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/components/node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.3.tgz", + "integrity": "sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/components/node_modules/@radix-ui/react-popper": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.2.tgz", + "integrity": "sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1", + "@radix-ui/react-use-rect": "1.0.1", + "@radix-ui/react-use-size": "1.0.1", + "@radix-ui/rect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/components/node_modules/@radix-ui/react-portal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.3.tgz", + "integrity": "sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/components/node_modules/@radix-ui/react-select": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.2.tgz", + "integrity": "sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/number": "1.0.1", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.4", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.3", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-popper": "1.1.2", + "@radix-ui/react-portal": "1.0.3", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1", + "@radix-ui/react-use-previous": "1.0.1", + "@radix-ui/react-visually-hidden": "1.0.3", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/components/node_modules/@radix-ui/react-use-previous": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz", + "integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@storybook/components/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz", + "integrity": "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@storybook/core-client": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-7.4.4.tgz", @@ -7078,6 +7081,32 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-date-range": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/react-date-range/-/react-date-range-1.4.9.tgz", + "integrity": "sha512-5oVEDW0ElYmY1+YVSzdMUR8stxSI5QrRJCgCFUvuEAV5197t412vimD9aVTW6g4JTaxCnMmB1BdEOT/odpaBxQ==", + "dev": true, + "dependencies": { + "@types/react": "*", + "date-fns": "^2.16.1" + } + }, + "node_modules/@types/react-date-range/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/@types/react-dom": { "version": "18.2.18", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", @@ -10372,6 +10401,15 @@ "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==" }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/dayjs": { "version": "1.11.11", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", @@ -18582,6 +18620,21 @@ "react": "^16.3.0 || ^17.0.1 || ^18.0.0" } }, + "node_modules/react-date-range": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-date-range/-/react-date-range-2.0.1.tgz", + "integrity": "sha512-jwKYc9zcjYMg2hWbPht+6BF2wjGG5DkRVNJLRXn2Y0B/QCOOnvQX6YXziZVujVADWmgsBaoQnILdmzYw+Bwh0g==", + "dependencies": { + "classnames": "^2.2.6", + "prop-types": "^15.7.2", + "react-list": "^0.8.13", + "shallow-equal": "^1.2.1" + }, + "peerDependencies": { + "date-fns": "3.0.6 || >=3.0.0", + "react": "^0.14 || ^15.0.0-rc || >=15.0" + } + }, "node_modules/react-docgen": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", @@ -18692,6 +18745,17 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/react-list": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/react-list/-/react-list-0.8.17.tgz", + "integrity": "sha512-pgmzGi0G5uGrdHzMhgO7KR1wx5ZXVvI3SsJUmkblSAKtewIhMwbQiMuQiTE83ozo04BQJbe0r3WIWzSO0dR1xg==", + "dependencies": { + "prop-types": "15" + }, + "peerDependencies": { + "react": "0.14 || 15 - 18" + } + }, "node_modules/react-parallax": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/react-parallax/-/react-parallax-3.5.1.tgz", @@ -19762,6 +19826,11 @@ "node": ">=8" } }, + "node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, "node_modules/sharp": { "version": "0.33.4", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", diff --git a/package.json b/package.json index 87ca2f99..6a47267b 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "cors": "^2.8.5", "cross-fetch": "^4.0.0", "crypto-js": "^4.2.0", + "date-fns": "^4.1.0", "dayjs": "^1.11.11", "dotenv": "^16.3.1", "emoji-picker-react": "^4.9.3", @@ -59,6 +60,7 @@ "postcss": "8.4.30", "promises": "^0.2.5", "react": "18.2.0", + "react-date-range": "^2.0.1", "react-dom": "^18.2.0", "react-hook-form": "^7.51.2", "react-icons": "^4.11.0", @@ -93,6 +95,7 @@ "@types/cookie": "^0.6.0", "@types/crypto-js": "^4.2.2", "@types/jest": "^29.5.11", + "@types/react-date-range": "^1.4.9", "@types/react-slick": "^0.23.13", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", diff --git a/src/app/v2/register/loading.tsx b/src/app/v2/register/loading.tsx new file mode 100644 index 00000000..95371bbc --- /dev/null +++ b/src/app/v2/register/loading.tsx @@ -0,0 +1,11 @@ +export default function Loading() { + return ( +
+
+ + + +
+
+ ) +} diff --git a/src/app/v2/register/page.tsx b/src/app/v2/register/page.tsx new file mode 100644 index 00000000..0566a52e --- /dev/null +++ b/src/app/v2/register/page.tsx @@ -0,0 +1,37 @@ +'use client' +import FormContainer from '@/components/organism/Register/formContainer/FormContainer' +import RegisterSIdebar from '@/components/organism/Register/sidebar/RegisterSIdebar' +import React, { useEffect, useState } from 'react' +import Loading from './loading' + +const Register = () => { + const [step, setStep] = useState(0) + const [subStep, setSubStep] = useState(0) + const [loading, setLoading] = useState(true) + + useEffect(() => { + if (typeof window !== 'undefined') { + const registerData = localStorage.getItem('registerData') ? JSON.parse(localStorage.getItem('registerData') || '') : null + + if (registerData) { + setStep(registerData.step || 0) + setSubStep(registerData.subStep || 0) + } + setLoading(false) + } + }, []) + return ( +
+ {loading ? ( + + ) : ( + <> + + + + )} +
+ ) +} + +export default Register diff --git a/src/assets/Indicator.svg b/src/assets/Indicator.svg new file mode 100644 index 00000000..b32d7ebf --- /dev/null +++ b/src/assets/Indicator.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/Social icon.svg b/src/assets/Social icon.svg new file mode 100644 index 00000000..1ed7b773 --- /dev/null +++ b/src/assets/Social icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/components/atoms/DateSelect/DateSelect.tsx b/src/components/atoms/DateSelect/DateSelect.tsx new file mode 100644 index 00000000..94f19cd0 --- /dev/null +++ b/src/components/atoms/DateSelect/DateSelect.tsx @@ -0,0 +1,75 @@ +'use client' +import { useEffect, useRef, useState } from 'react' +import { Calendar } from 'react-date-range' +import { addYears } from 'date-fns' +import { enGB } from 'date-fns/locale' +import 'react-date-range/dist/styles.css' // main style file +import 'react-date-range/dist/theme/default.css' // theme css file +import { motion, AnimatePresence } from 'framer-motion' +import { CiCalendar } from 'react-icons/ci' +interface SelectDropdownProps { + onChange: (value: string) => void + value: any + placeholder?: string + + err: boolean +} + +const DateSelect = ({ onChange, value, placeholder, err }: SelectDropdownProps) => { + const [show, setShow] = useState(false) + const dropdownRef = useRef(null) + + const handleDateChange = (data: Date) => { + onChange(new Date(data).toLocaleDateString()) + setShow(false) + } + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setShow(false) + } + } + + document.addEventListener('mousedown', handleClickOutside) + + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, []) + + return ( + +
setShow(!show)} + className={`${ + err ? 'border-red-400' : 'border-neutral-200' + } flex justify-between items-center py-2 px-3 border focus:ring-2 rounded-lg drop-shadow-sm h-10 outline-none`} + > +

{value ? value : placeholder}

+ +
+ + {show && ( + + handleDateChange(item)} + locale={enGB} + minDate={addYears(new Date(), -100)} + maxDate={new Date()} + /> + + )} + +
+ ) +} + +export default DateSelect diff --git a/src/components/atoms/Input/InputBox.tsx b/src/components/atoms/Input/InputBox.tsx index 44254497..9161ef71 100644 --- a/src/components/atoms/Input/InputBox.tsx +++ b/src/components/atoms/Input/InputBox.tsx @@ -4,11 +4,14 @@ type Props = { placeholder?: string className?: string type: string + err: boolean } -const InputBox = forwardRef(({ placeholder, className, type, ...rest }, ref) => { +const InputBox = forwardRef(({ placeholder, className, type, err, ...rest }, ref) => { return ( { className?: string - variant?: 'primary' | 'secondary' | 'danger' | 'shade' + variant?: 'primary' | 'secondary' | 'danger' | 'shade' | 'border' | 'border_primary' } const LoginButtons: React.FC = ({ className = '', variant = 'primary', children, ...props }) => { const variantClasses = { primary: 'bg-primary-500 text-white', secondary: 'bg-gray-500 text-white', + border: 'border border-neutral-200 text-neutral-800 ', + border_primary: 'border border-primary text-primary ', danger: 'bg-red-500 text-white', shade: 'bg-secondary border border-shade-button-border text-primary-500 drop-shadow-sm', } diff --git a/src/components/atoms/OTP-Input/OTP_Input.tsx b/src/components/atoms/OTP-Input/OTP_Input.tsx new file mode 100644 index 00000000..5f29f141 --- /dev/null +++ b/src/components/atoms/OTP-Input/OTP_Input.tsx @@ -0,0 +1,82 @@ +import React, { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from 'react' + +interface OTPInputProps { + length: number + value: string + onChange: (otp: string) => void +} + +const OTPInput: React.FC = ({ length, value, onChange }) => { + const [otp, setOtp] = useState(Array(length).fill('')) + const inputRefs = useRef<(HTMLInputElement | null)[]>(Array(length).fill(null)) + + useEffect(() => { + const formattedValue = value.padEnd(length, ' ').slice(0, length) + setOtp(Array.from(formattedValue)) + }, [value, length]) + + const handleChange = (newOtp: string[]) => { + onChange(newOtp.join('')) + } + + const handleInput = (e: ChangeEvent, index: number) => { + const newValue = e.target.value.slice(-1) + if (/[^0-9]/.test(newValue)) return + + setOtp((prevOtp) => { + const newOtp = [...prevOtp] + newOtp[index] = newValue + + handleChange(newOtp) + + return newOtp + }) + + if (index < length - 1) { + inputRefs.current[index + 1]?.focus() + } + } + + const handleKeyDown = (e: KeyboardEvent, index: number) => { + if (e.key === 'Backspace') { + e.preventDefault() + + setOtp((prevOtp) => { + const newOtp = [...prevOtp] + newOtp[index] = '' + + handleChange(newOtp) + + return newOtp + }) + + if (index > 0) { + inputRefs.current[index - 1]?.focus() + } + } + } + + const handleFocus = (e: React.FocusEvent) => { + e.currentTarget.select() + } + + return ( +
+ {otp.map((data, index) => ( + (inputRefs.current[index] = el)} + type="text" + maxLength={1} + value={data} + onChange={(e: ChangeEvent) => handleInput(e, index)} + onKeyDown={(e: KeyboardEvent) => handleKeyDown(e, index)} + onFocus={handleFocus} + className="w-10 h-12 px-3 py-1 text-2xl text-neutral-400 font-semibold text-center border border-neutral-200 rounded-lg focus:outline-none focus:ring-2" + /> + ))} +
+ ) +} + +export default OTPInput diff --git a/src/components/atoms/SelectDropdown/SelectDropdown.tsx b/src/components/atoms/SelectDropdown/SelectDropdown.tsx new file mode 100644 index 00000000..dc3279e1 --- /dev/null +++ b/src/components/atoms/SelectDropdown/SelectDropdown.tsx @@ -0,0 +1,108 @@ +'use client' +import React, { useEffect, useRef, useState } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import { IoIosArrowDown } from 'react-icons/io' + +interface SelectDropdownProps { + options: string[] + onChange: (value: string) => void + value: string + placeholder?: string + icon: string + search?: boolean + err: boolean +} +const SelectDropdown = ({ options, onChange, value, placeholder, icon, search = false, err }: SelectDropdownProps) => { + const [show, setShow] = useState(false) + const dropdownRef = useRef(null) + const [filteredOptions, setFilteredOptions] = useState(options) + const searchRef = useRef(null) + + const handleSelect = (optionValue: string) => { + onChange(optionValue) + setShow(false) + } + + const handleSearch = () => { + const searchValue = searchRef.current?.value.toLowerCase() || '' + setFilteredOptions(searchValue === '' ? options : options.filter((option: string) => option.toLowerCase().includes(searchValue))) + } + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setShow(false) + } + } + + document.addEventListener('mousedown', handleClickOutside) + + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, []) + + return ( + +
setShow(!show)} + className={`${ + err ? 'border-red-400' : 'border-neutral-200' + } flex justify-between items-center py-2 px-3 border focus:ring-2 rounded-lg drop-shadow-sm text-neutral-400 h-10 outline-none`} + > +

{value || placeholder}

+
+ {icon == 'single' ? ( + + ) : ( + + + + )} +
+
+ + {show && ( + + {search && ( + + )} + {filteredOptions.length > 0 ? ( + filteredOptions.map((item: string, key: number) => ( +

handleSelect(item)} + key={key} + > + {item} +

+ )) + ) : ( +

No results found

+ )} +
+ )} +
+
+ ) +} + +export default SelectDropdown diff --git a/src/components/organism/Login/LoginBox.tsx b/src/components/organism/Login/LoginBox.tsx index 0d2828e5..bd306845 100644 --- a/src/components/organism/Login/LoginBox.tsx +++ b/src/components/organism/Login/LoginBox.tsx @@ -12,6 +12,7 @@ import { LoginForm } from '@/models/auth' import InputWarningText from '@/components/atoms/InputWarningText' import { useHandleLogin } from '@/services/auth' import { useRouter } from 'next/navigation' +import { AxiosError } from 'axios' const LoginBox = () => { const [showPassword, setShowPassword] = useState(false) @@ -20,14 +21,31 @@ const LoginBox = () => { register: registerLogin, handleSubmit: handleSubmitLogin, formState: { errors: loginErrors }, - } = useForm() + setValue, + } = useForm({ + defaultValues: { + email: '', + }, + }) - const { mutate: mutateLogin, isSuccess } = useHandleLogin() + const { mutate: mutateLogin, isSuccess, error } = useHandleLogin() + const isAxiosError = (error: unknown): error is AxiosError => { + return (error as AxiosError)?.isAxiosError === true + } const onSubmit = async (data: LoginForm) => { await mutateLogin(data) } + useEffect(() => { + if (typeof window !== 'undefined') { + const emailValue = localStorage.getItem('registeredEmail') + if (emailValue) { + setValue('email', emailValue) + } + } + }, []) + useEffect(() => { if (isSuccess) { router.push(`/timeline`) @@ -58,6 +76,7 @@ const LoginBox = () => { message: 'Invalid email format', }, })} + err={!!loginErrors.email} /> {loginErrors.email && ( {loginErrors.email.message ? loginErrors.email.message : 'Please enter your email!'} @@ -71,6 +90,7 @@ const LoginBox = () => { placeholder="*******************" type={showPassword ? 'text' : 'password'} {...registerLogin('password', { required: true })} + err={!!loginErrors.password} />
{showPassword ? ( @@ -88,6 +108,7 @@ const LoginBox = () => {

Remember device for 30 days

Log in + {isAxiosError(error) && error.response?.data?.message} + + ) +} + +export default AccountCreationForm diff --git a/src/components/organism/Register/forms/ClaimBenefitForm.tsx b/src/components/organism/Register/forms/ClaimBenefitForm.tsx new file mode 100644 index 00000000..cd0d781c --- /dev/null +++ b/src/components/organism/Register/forms/ClaimBenefitForm.tsx @@ -0,0 +1,67 @@ +import InputBox from '@/components/atoms/Input/InputBox' +import InputWarningText from '@/components/atoms/InputWarningText' +import LoginButtons from '@/components/atoms/LoginButtons' +import SupportingText from '@/components/atoms/SupportingText' +import Title from '@/components/atoms/Title' +import React from 'react' +import { useFormContext } from 'react-hook-form' + +const badgeData = [ + { name: 'Custom Emojis', bg: '#FDF4FF', color: '#C026D3' }, + { name: 'Unlimited AI Prompts', bg: '#ECFEFF', color: '#0891B2' }, + { name: 'Profile Badge', bg: '#F0FDF4', color: '#16A34A' }, + { name: 'Join Up 100 Groups', bg: '#F3F2FF', color: '#6744FF' }, + { name: '500 MB Upload', bg: '#FFFBEB', color: '#D97706' }, +] +const ClaimBenefitForm = () => { + const { + register, + formState: { errors: VerificationFormErrors }, + } = useFormContext() + return ( +
+
+ Claim your benefit + Enter your referral code for these perks: +
+
+ {badgeData.map((item) => ( +

+ {item.name} +

+ ))} +
+
+
+ + + + {VerificationFormErrors.referralCode && ( + + {VerificationFormErrors.referralCode.message + ? VerificationFormErrors.referralCode.message.toString() + : 'Please enter your referral code!'} + + )} + Confirm Code +

Plan will immediately apply to account after confirmation.

+ {/*

Congratulations! You received 1 month of our Upgrade Plan!

*/} +
+
+
+ Complete Sign Up +
+
+ ) +} + +export default ClaimBenefitForm diff --git a/src/components/organism/Register/forms/FinalLoginForm.tsx b/src/components/organism/Register/forms/FinalLoginForm.tsx new file mode 100644 index 00000000..72db4172 --- /dev/null +++ b/src/components/organism/Register/forms/FinalLoginForm.tsx @@ -0,0 +1,83 @@ +'use client' +import InputBox from '@/components/atoms/Input/InputBox' +import InputWarningText from '@/components/atoms/InputWarningText' +import LoginButtons from '@/components/atoms/LoginButtons' +import SupportingText from '@/components/atoms/SupportingText' +import Title from '@/components/atoms/Title' +import Image from 'next/image' +import React, { useState } from 'react' +import { useFormContext } from 'react-hook-form' +import logo from '@/assets/Logo Circle.svg' +import { AiOutlineEye } from 'react-icons/ai' +import { AiOutlineEyeInvisible } from 'react-icons/ai' + +const FinalLoginForm = () => { + const [showPassword, setShowPassword] = useState(false) + const { + register: registerLogin, + formState: { errors: FinalLoginFormErrors }, + } = useFormContext() + return ( +
+ lgog +
+ Congratulations + Enter your details to access your account +
+
+
+ + + + {FinalLoginFormErrors.loginEmail && ( + + {FinalLoginFormErrors.loginEmail.message ? FinalLoginFormErrors.loginEmail.message.toString() : 'Please enter your email!'} + + )} +
+
+ + +
+ {showPassword ? ( + setShowPassword(!showPassword)} /> + ) : ( + setShowPassword(!showPassword)} /> + )} +
+ {FinalLoginFormErrors.loginPassword && Please enter your password!} + +
+
+ +

Remember device for 30 days

+
+ + Log in + +
+
+ ) +} + +export default FinalLoginForm diff --git a/src/components/organism/Register/forms/ProfileSetupForm.tsx b/src/components/organism/Register/forms/ProfileSetupForm.tsx new file mode 100644 index 00000000..a8290076 --- /dev/null +++ b/src/components/organism/Register/forms/ProfileSetupForm.tsx @@ -0,0 +1,109 @@ +'use client' +import InputBox from '@/components/atoms/Input/InputBox' +import React from 'react' +import { useFormContext, Controller } from 'react-hook-form' + +import LoginButtons from '@/components/atoms/LoginButtons' +import Title from '@/components/atoms/Title' +import SupportingText from '@/components/atoms/SupportingText' +import InputWarningText from '@/components/atoms/InputWarningText' + +import SelectDropdown from '@/components/atoms/SelectDropdown/SelectDropdown' +import { country_list } from '@/utils/countriesList' +import DateSelect from '@/components/atoms/DateSelect/DateSelect' +const ProfileSetupForm = () => { + const { + register, + formState: { errors: ProfileFormErrors }, + control, + } = useFormContext() + + const GenderOptions = ['Male', 'Female'] + + return ( +
+
+ Profile Setup + Enter your profile information for networking +
+
+
+ + {ProfileFormErrors.firstName && Please enter your First Name!} +
+
+ + {ProfileFormErrors.lastName && Please enter your Last Name!} +
+
+ ( + + )} + /> + {ProfileFormErrors.birthDate && Please enter your Birthday!} +
+
+ ( + + )} + /> + {ProfileFormErrors.gender && {ProfileFormErrors?.gender?.message?.toString()}} +
+
+ ( + + )} + /> + {ProfileFormErrors.country && {ProfileFormErrors?.country?.message?.toString()}} +
+
+
+ Next Step +
+ +

You can add more profile information later in your profile settings!

+
+ ) +} +export default ProfileSetupForm diff --git a/src/components/organism/Register/forms/UniversityVerificationForm.tsx b/src/components/organism/Register/forms/UniversityVerificationForm.tsx new file mode 100644 index 00000000..66c887b0 --- /dev/null +++ b/src/components/organism/Register/forms/UniversityVerificationForm.tsx @@ -0,0 +1,141 @@ +import InputBox from '@/components/atoms/Input/InputBox' +import InputWarningText from '@/components/atoms/InputWarningText' +import LoginButtons from '@/components/atoms/LoginButtons' +import OTPInput from '@/components/atoms/OTP-Input/OTP_Input' +import SupportingText from '@/components/atoms/SupportingText' +import { useHandleUniversityEmailVerificationGenerate } from '@/services/auth' + +import React from 'react' +import { Controller, useFormContext } from 'react-hook-form' + +interface props { + setStep: (value: number) => void + + setSubStep: (value: number) => void + isVerificationSuccess: boolean +} + +const UniversityVerificationForm = ({ setStep, setSubStep, isVerificationSuccess }: props) => { + const { + register, + formState: { errors: UniversityVerificationFormErrors }, + control, + getValues, + } = useFormContext() + const { mutate: generateUniversityEmailOTP } = useHandleUniversityEmailVerificationGenerate() + const all = getValues() + const handleUniversityEmailSendCode = () => { + const email = getValues('universityEmail') + const data = { email } + generateUniversityEmailOTP(data) + } + + const handleNext = () => { + setStep(3) + setSubStep(0) + localStorage.setItem('registerData', JSON.stringify({ ...all, step: 3, subStep: 0 })) + } + + return ( +
+
+

University Verification

+ Do you have a email provided by your university? +
+
+
+ + + +

Can join private groups in university community

+
+
+ + + +

Can join more than 1 university community

+
+
+ + + +

Can create groups in university community

+
+
+
+
+ + + + {UniversityVerificationFormErrors.universityEmail && ( + + {UniversityVerificationFormErrors.universityEmail.message + ? UniversityVerificationFormErrors.universityEmail.message.toString() + : 'Please enter your email!'} + + )} + handleUniversityEmailSendCode()} type="button" variant="border_primary"> + Send Code + +
+ {/* otp */} +
+ + + value.length === 6 || 'OTP must be 6 digits long!', + }} + render={({ field }) => field.onChange(otp)} />} + /> + {UniversityVerificationFormErrors.UniversityOtp && ( + {UniversityVerificationFormErrors.UniversityOtp.message?.toString() || 'Please enter your OTP!'} + )} + Confirm Code + {isVerificationSuccess &&

University Email verified.

} +
+
+
+ handleNext()} type="button"> + Skip University Verification + + Complete Verification +
+
+ ) +} + +export default UniversityVerificationForm diff --git a/src/components/organism/Register/forms/VerificationForm.tsx b/src/components/organism/Register/forms/VerificationForm.tsx new file mode 100644 index 00000000..258b293d --- /dev/null +++ b/src/components/organism/Register/forms/VerificationForm.tsx @@ -0,0 +1,116 @@ +import InputBox from '@/components/atoms/Input/InputBox' +import InputWarningText from '@/components/atoms/InputWarningText' +import LoginButtons from '@/components/atoms/LoginButtons' +import OTPInput from '@/components/atoms/OTP-Input/OTP_Input' +import SupportingText from '@/components/atoms/SupportingText' +import Title from '@/components/atoms/Title' +import { useHandleLoginEmailVerificationGenerate } from '@/services/auth' +import React, { useEffect, useState } from 'react' +import { Controller, useFormContext } from 'react-hook-form' + +interface props { + isVerificationSuccess: boolean +} + +const VerificationForm = ({ isVerificationSuccess }: props) => { + const { + register, + formState: { errors: VerificationFormErrors }, + control, + getValues, + } = useFormContext() + const { mutate: generateLoginEmailOTP } = useHandleLoginEmailVerificationGenerate() + + const [countdown, setCountdown] = useState(30) + const [isCounting, setIsCounting] = useState(false) + + const handleLoginEmailSendCode = () => { + const email = getValues('email') + const data = { email } + + generateLoginEmailOTP(data) + + handleLoginEmailSendCodeCount() + } + + const handleLoginEmailSendCodeCount = () => { + setIsCounting(true) + setCountdown(30) + } + + useEffect(() => { + let timer: NodeJS.Timeout + if (isCounting && countdown > 0) { + timer = setTimeout(() => setCountdown(countdown - 1), 1000) + } else if (countdown === 0) { + setIsCounting(false) + } + return () => clearTimeout(timer) + }, [countdown, isCounting]) + + return ( +
+
+ Verification + Verify your login credentials. +
+
+
+ + + + {VerificationFormErrors.verificationEmail && ( + + {VerificationFormErrors.verificationEmail.message + ? VerificationFormErrors.verificationEmail.message.toString() + : 'Please enter your email!'} + + )} + handleLoginEmailSendCode()} type="button" variant="border_primary"> + Send Code + + {isCounting &&

Resend Available after {countdown}s

} +
+ {/* otp */} +
+ + + value.length === 6 || 'OTP must be 6 digits long!', + }} + render={({ field }) => field.onChange(otp)} />} + /> + {VerificationFormErrors.verificationOtp && ( + {VerificationFormErrors.verificationOtp.message?.toString() || 'Please enter your OTP!'} + )} + Confirm Code + {isVerificationSuccess &&

Login credentials verified.

} +
+
+
+ Next Step +
+
+ ) +} + +export default VerificationForm diff --git a/src/components/organism/Register/sidebar/RegisterSIdebar.tsx b/src/components/organism/Register/sidebar/RegisterSIdebar.tsx new file mode 100644 index 00000000..90b78be5 --- /dev/null +++ b/src/components/organism/Register/sidebar/RegisterSIdebar.tsx @@ -0,0 +1,38 @@ +import React from 'react' +import unibuzzLogo from '@assets/unibuzz_logo.svg' +import Image from 'next/image' +import RegisterStepper from '../stepper/RegisterStepper' + +interface props { + step: number + subStep: number +} + +const StepHeaders = [ + { header: 'Just a few steps', desc: "We're thrilled to have you on board. First create your account to join your university community!" }, + { header: 'A simple form', desc: 'You can add more to your profile later. We just require the essentials for now!' }, + { header: 'Verify your account', desc: 'To keep our platform safe from bots and exclusive to university students, we require verification.' }, + { header: 'Almost there...', desc: 'Users who verify their university email get additional perks!' }, + { + header: 'Referred by a friend?', + desc: 'Enter your referral code and get 1 month free of our Upgrade Plan! Every user gets 1 referral code to share!', + }, + { header: 'All done.', desc: 'You can now join communities, interact with students and faculty, receive consultation, and more!' }, +] +const RegisterSIdebar = ({ step, subStep }: props) => { + return ( +
+
+ BACPAC LOGO +
+

{StepHeaders[step + subStep].header}

+ +

{StepHeaders[step + subStep].desc}

+
+ +
+
+ ) +} + +export default RegisterSIdebar diff --git a/src/components/organism/Register/stepper/RegisterStepper.tsx b/src/components/organism/Register/stepper/RegisterStepper.tsx new file mode 100644 index 00000000..1092df5f --- /dev/null +++ b/src/components/organism/Register/stepper/RegisterStepper.tsx @@ -0,0 +1,101 @@ +import React from 'react' +import indicator from '@/assets/Indicator.svg' +import Image from 'next/image' + +import { motion } from 'framer-motion' + +const stepVariants = { + hidden: { opacity: 0, y: 20 }, + visible: () => ({ + opacity: 1, + y: 0, + transition: { + delay: 0, + }, + }), +} + +const stepData = [ + { title: 'Account Creation', des: 'Login information' }, + { title: 'Profile Setup', des: 'User Information' }, + { title: 'User Verification', des: 'Sync university email' }, + { title: 'Completion', des: 'Review and finalize account' }, +] + +const CompletedStep = ({ title, des, idx }: any) => { + return ( + +
+ +
+
+ + +
+ {idx !== 3 && } +
+ ) +} + +const UnCompleteStep = ({ title, des, idx }: any) => { + return ( +
  • + + 0{idx + 1} + +
    + + +
    + {idx !== 3 && } +
  • + ) +} +const CurrentStep = ({ title, des, idx }: any) => { + return ( +
    +
    + in +
    +
    + + +
    + {idx !== 3 && } +
    + ) +} + +const Step = ({ data, idx, currentStep, subStep }: any) => { + const isCurrentStep = idx === currentStep && subStep < 2 + + return ( + <> + {idx < currentStep ? ( + + ) : isCurrentStep ? ( + + ) : ( + + )} + + ) +} + +interface props { + step: number + subStep: number +} +const RegisterStepper = ({ step, subStep }: props) => { + return ( +
      + {stepData.map((item, key) => ( + + ))} +
    + ) +} + +export default RegisterStepper diff --git a/src/services/auth.ts b/src/services/auth.ts index 033fa643..2b0e98fa 100644 --- a/src/services/auth.ts +++ b/src/services/auth.ts @@ -4,6 +4,24 @@ import { client } from './api-Client' import { useUniStore } from '@/store/store' import useCookie from '@/hooks/useCookie' +interface data { + email: string + userName: string + password: string + confirmpassword: string + birthDate: string + gender: string + country: string + firstName: string + lastName: string + verificationEmail: string + verificationOtp: string + universityEmail: string + UniversityOtp: string + UniversityOtpOK: string + referralCode: string +} + const login = async (data: LoginForm): Promise => { const result = await client('auth/login', { data }) return result @@ -14,6 +32,34 @@ const register = async (data: Omit): Pr return result } +async function register_v2(data: data) { + const response: { isRegistered: boolean } = await client(`auth/v2/register`, { method: 'POST', data }) + return response +} + +async function userNameAndEmailAvailability(data: { email: string; userName: string }) { + const response: { isAvailable: boolean } = await client(`users/checkAvailability`, { method: 'POST', data }) + return response +} + +async function loginEmailVerificationCodeGenerate(data: { email: string }) { + const response = await client(`useremailverification`, { method: 'POST', data }) + return response +} +async function loginEmailVerification(data: data) { + const response: { isAvailable: boolean } = await client(`useremailverification`, { method: 'PUT', data }) + return response +} + +async function universityEmailVerificationCodeGenerate(data: { email: string }) { + const response = await client(`universityemailverification`, { method: 'POST', data }) + return response +} +async function universityEmailVerification(data: data) { + const response: { isAvailable: boolean } = await client(`universityemailverification`, { method: 'PUT', data }) + return response +} + export const useHandleLogin = () => { const setUserData = useUniStore((state) => state.setUserData) const setUserProfileData = useUniStore((state) => state.setUserProfileData) @@ -49,3 +95,49 @@ export const useHandleRegister = () => { }, }) } + +export const useHandleRegister_v2 = () => { + return useMutation({ + mutationFn: (data: data) => register_v2(data), + }) +} + +// export const useHandleUserEmailAndUserNameAvailability = () => { +// return useMutation({ +// mutationFn: (data: any) => userNameAndEmailAvailability(data), +// onSuccess: (res: any) => { +// console.log(res) +// }, +// onError: (res: any) => { +// console.log(res.response.data, 'res') +// }, +// }) +// } +export const useHandleUserEmailAndUserNameAvailability = () => { + return useMutation({ + mutationFn: (data: { email: string; userName: string }) => userNameAndEmailAvailability(data), + }) +} + +export const useHandleLoginEmailVerificationGenerate = () => { + return useMutation({ + mutationFn: (data: { email: string }) => loginEmailVerificationCodeGenerate(data), + }) +} + +export const useHandleLoginEmailVerification = () => { + return useMutation({ + mutationFn: (data: data) => loginEmailVerification(data), + }) +} +export const useHandleUniversityEmailVerificationGenerate = () => { + return useMutation({ + mutationFn: (data: { email: string }) => universityEmailVerificationCodeGenerate(data), + }) +} + +export const useHandleUniversityEmailVerification = () => { + return useMutation({ + mutationFn: (data: data) => universityEmailVerification(data), + }) +} diff --git a/src/utils/countriesList.ts b/src/utils/countriesList.ts new file mode 100644 index 00000000..6bbe977a --- /dev/null +++ b/src/utils/countriesList.ts @@ -0,0 +1,207 @@ +export const country_list = [ + 'Afghanistan', + 'Albania', + 'Algeria', + 'Andorra', + 'Angola', + 'Anguilla', + 'Antigua & Barbuda', + 'Argentina', + 'Armenia', + 'Aruba', + 'Australia', + 'Austria', + 'Azerbaijan', + 'Bahamas', + 'Bahrain', + 'Bangladesh', + 'Barbados', + 'Belarus', + 'Belgium', + 'Belize', + 'Benin', + 'Bermuda', + 'Bhutan', + 'Bolivia', + 'Bosnia & Herzegovina', + 'Botswana', + 'Brazil', + 'British Virgin Islands', + 'Brunei', + 'Bulgaria', + 'Burkina Faso', + 'Burundi', + 'Cambodia', + 'Cameroon', + 'Cape Verde', + 'Cayman Islands', + 'Chad', + 'Chile', + 'China', + 'Colombia', + 'Congo', + 'Cook Islands', + 'Costa Rica', + 'Cote D Ivoire', + 'Croatia', + 'Cruise Ship', + 'Cuba', + 'Cyprus', + 'Czech Republic', + 'Denmark', + 'Djibouti', + 'Dominica', + 'Dominican Republic', + 'Ecuador', + 'Egypt', + 'El Salvador', + 'Equatorial Guinea', + 'Estonia', + 'Ethiopia', + 'Falkland Islands', + 'Faroe Islands', + 'Fiji', + 'Finland', + 'France', + 'French Polynesia', + 'French West Indies', + 'Gabon', + 'Gambia', + 'Georgia', + 'Germany', + 'Ghana', + 'Gibraltar', + 'Greece', + 'Greenland', + 'Grenada', + 'Guam', + 'Guatemala', + 'Guernsey', + 'Guinea', + 'Guinea Bissau', + 'Guyana', + 'Haiti', + 'Honduras', + 'Hong Kong', + 'Hungary', + 'Iceland', + 'India', + 'Indonesia', + 'Iran', + 'Iraq', + 'Ireland', + 'Isle of Man', + 'Israel', + 'Italy', + 'Jamaica', + 'Japan', + 'Jersey', + 'Jordan', + 'Kazakhstan', + 'Kenya', + 'Kuwait', + 'Kyrgyz Republic', + 'Laos', + 'Latvia', + 'Lebanon', + 'Lesotho', + 'Liberia', + 'Libya', + 'Liechtenstein', + 'Lithuania', + 'Luxembourg', + 'Macau', + 'Macedonia', + 'Madagascar', + 'Malawi', + 'Malaysia', + 'Maldives', + 'Mali', + 'Malta', + 'Mauritania', + 'Mauritius', + 'Mexico', + 'Moldova', + 'Monaco', + 'Mongolia', + 'Montenegro', + 'Montserrat', + 'Morocco', + 'Mozambique', + 'Namibia', + 'Nepal', + 'Netherlands', + 'Netherlands Antilles', + 'New Caledonia', + 'New Zealand', + 'Nicaragua', + 'Niger', + 'Nigeria', + 'Norway', + 'Oman', + 'Pakistan', + 'Palestine', + 'Panama', + 'Papua New Guinea', + 'Paraguay', + 'Peru', + 'Philippines', + 'Poland', + 'Portugal', + 'Puerto Rico', + 'Qatar', + 'Reunion', + 'Romania', + 'Russia', + 'Rwanda', + 'Saint Pierre & Miquelon', + 'Samoa', + 'San Marino', + 'Satellite', + 'Saudi Arabia', + 'Senegal', + 'Serbia', + 'Seychelles', + 'Sierra Leone', + 'Singapore', + 'Slovakia', + 'Slovenia', + 'South Africa', + 'South Korea', + 'Spain', + 'Sri Lanka', + 'St Kitts & Nevis', + 'St Lucia', + 'St Vincent', + 'St. Lucia', + 'Sudan', + 'Suriname', + 'Swaziland', + 'Sweden', + 'Switzerland', + 'Syria', + 'Taiwan', + 'Tajikistan', + 'Tanzania', + 'Thailand', + "Timor L'Este", + 'Togo', + 'Tonga', + 'Trinidad & Tobago', + 'Tunisia', + 'Turkey', + 'Turkmenistan', + 'Turks & Caicos', + 'Uganda', + 'Ukraine', + 'United Arab Emirates', + 'United Kingdom', + 'Uruguay', + 'Uzbekistan', + 'Venezuela', + 'Vietnam', + 'Virgin Islands (US)', + 'Yemen', + 'Zambia', + 'Zimbabwe', +]