From 3e603faee8503fb1e3075dfff3ec1dad3d2648f5 Mon Sep 17 00:00:00 2001 From: ayush Date: Sun, 27 Oct 2024 00:01:47 +0530 Subject: [PATCH] chore: setup registration --- package.json | 1 + src/app/register/page.jsx | 168 ++++++++++++------ src/components/ProfileMenu/ProfileMenu.jsx | 58 ++++-- .../CampusAmbassador/CampusAmbassador.jsx | 14 +- .../Register/SelectField/SelectField.jsx | 23 ++- src/config/content/Registration/details.js | 55 +++++- src/config/zodd/userDetailsSchema.js | 7 +- src/context/auth-context.jsx | 17 +- .../mutations/organizationMutations.js | 9 + src/lib/apollo-client.js | 21 ++- 10 files changed, 284 insertions(+), 89 deletions(-) create mode 100644 src/graphql/mutations/organizationMutations.js diff --git a/package.json b/package.json index aacfccda..9f3f7f0d 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "swiper": "^11.1.14", "three": "^0.168.0", "twin.macro": "^3.4.1", + "uuidv4": "^6.2.13", "zod": "^3.23.8" }, "devDependencies": { diff --git a/src/app/register/page.jsx b/src/app/register/page.jsx index e7937d16..fc77145c 100644 --- a/src/app/register/page.jsx +++ b/src/app/register/page.jsx @@ -1,32 +1,39 @@ 'use client'; -import { useState, useContext } from 'react'; +import { useContext, useEffect, useState } from 'react'; + +import Cookies from 'js-cookie'; +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import toast from 'react-hot-toast'; +import { v4 } from 'uuid'; + +import CampusAmbassador from '@/components/Register/CampusAmbassador/CampusAmbassador'; +import FileInput from '@/components/Register/FileInput/FileInput'; +import CheckBox from '@/components/Register/InputCheckBox/CheckBox'; +import InputField from '@/components/Register/InputField/InputField'; +import SelectField from '@/components/Register/SelectField/SelectField'; +import { PrimaryButton } from '@/components/shared/Typography/Buttons'; +import { formFields, undertakingContent } from '@/config/content/Registration/details'; +import { userSchema } from '@/config/zodd/userDetailsSchema'; +import { AuthContext } from '@/context/auth-context'; +import { REGISTER_ORG } from '@/graphql/mutations/organizationMutations'; +import { REGISTER_USER } from '@/graphql/mutations/userMutations'; +import { useIsLoggedIn } from '@/hooks/useIsLoggedIn'; +import { useUserDetails } from '@/hooks/useUserDetails'; +import handleLoadingAndToast from '@/utils/handleLoadingToast'; +import { uploadToCloudinary } from '@/utils/uploadToCloudinary'; +import { useMutation } from '@apollo/client'; + import { + Moon, + PaymentPolicyInfo, RegisterContainer, RegisterForm, RegisterHeading, - RegsiterButton, RegisterInnerContainer, - Moon, + RegsiterButton, UndertakingLink, - PaymentPolicyInfo, - PaymentHeading, } from './register.styles'; -import Link from 'next/link'; -import InputField from '@/components/Register/InputField/InputField'; -import SelectField from '@/components/Register/SelectField/SelectField'; -import CheckBox from '@/components/Register/InputCheckBox/CheckBox'; -import FileInput from '@/components/Register/FileInput/FileInput'; -import { formFields, undertakingContent } from '@/config/content/Registration/details'; -import { uploadToCloudinary } from '../../utils/uploadToCloudinary'; -import handleLoadingAndToast from '../../utils/handleLoadingToast'; -import { userSchema } from '@/config/zodd/userDetailsSchema'; -import { useIsLoggedIn } from '@/hooks/useIsLoggedIn'; -import CampusAmbassador from '@/components/Register/CampusAmbassador/CampusAmbassador'; -import { PrimaryButton } from '@/components/shared/Typography/Buttons'; -import { AuthContext } from '@/context/auth-context'; -import { RegistrationModal } from './RegistrationModal'; -import toast from 'react-hot-toast'; -import { QrButton } from '@/components/Register/Qrscanner/QrButton'; function Page() { const [userDetails, setUserDetails] = useState({ @@ -34,6 +41,7 @@ function Page() { email: '', phone: '', institute: '', + instituteId: '', university: '', rollNumber: '', idCard: '', @@ -43,27 +51,32 @@ function Page() { payment: '', undertaking: false, campusAmbassador: false, + payment: '', }); - const [loading, setLoading] = useState(false); + const getUserDetails = useUserDetails(); const [errors, setErrors] = useState({}); const isLoggedIn = useIsLoggedIn(); - + const [loading, setLoading] = useState(false); const { handleGoogleSignIn, authLoading } = useContext(AuthContext); + const [registerUser] = useMutation(REGISTER_USER); + const [registerCollege] = useMutation(REGISTER_ORG); + const router = useRouter(); + const storedUserId = getUserDetails().uid; async function handleChange(event) { const { name, value, type, checked } = event.target; if (type === 'file') { try { - // const imageUrl = await handleLoadingAndToast( - // uploadToCloudinary(event.target.files[0]), - // 'Uploading Image...', - // `${name.toUpperCase()} uploaded successfully`, - // `${name.toUpperCase()} upload failed!`, - // setLoading, - // ); + const imageUrl = await handleLoadingAndToast( + uploadToCloudinary(event.target.files[0]), + 'Uploading Image...', + `${name.toUpperCase()} uploaded successfully`, + `${name.toUpperCase()} upload failed!`, + setLoading, + ); setUserDetails((prev) => ({ ...prev, - [name]: 'imageUrl', + [name]: imageUrl, })); setErrors((prev) => ({ ...prev, [name]: '' })); } catch (error) { @@ -83,12 +96,6 @@ function Page() { })); } - function handleSubmit() { - const isFormValid = validateForm(); - if (!isFormValid) return; - console.log(userDetails); - } - function validateForm() { const validationResult = userSchema.safeParse(userDetails); if (!validationResult.success) { @@ -151,13 +158,7 @@ function Page() { error={errors[field.id]} /> ); - case 'button': - return ( - <> - Payment Section - - - ); + case 'checkbox': return ( { + if (Cookies.get('userDataDB')) { + router.push('/'); + toast.success('You have been already registered!', { + duration: 5000, + }); + } + }, []); + return ( - {!isLoggedIn ? ( + {isLoggedIn ? ( Register @@ -209,7 +273,7 @@ function Page() { isCampusAmbassador={userDetails.campusAmbassador} /> - Submit + {loading ? 'Loading...' : 'Register'} ) : ( @@ -217,8 +281,6 @@ function Page() { {authLoading ? 'Loading...' : 'Sign In with Google'} )} - - setModalOpen(false)} /> ); } diff --git a/src/components/ProfileMenu/ProfileMenu.jsx b/src/components/ProfileMenu/ProfileMenu.jsx index bc0de82a..c3fa3598 100644 --- a/src/components/ProfileMenu/ProfileMenu.jsx +++ b/src/components/ProfileMenu/ProfileMenu.jsx @@ -1,26 +1,40 @@ 'use client'; -import { useUserDetails } from '@/hooks/useUserDetails'; +import { useContext, useEffect, useState } from 'react'; + +import Cookies from 'js-cookie'; +import { usePathname, useRouter } from 'next/navigation'; +import { toast } from 'react-hot-toast'; + import { AuthContext } from '@/context/auth-context'; -import { useContext } from 'react'; +import { useUserDetails } from '@/hooks/useUserDetails'; + import { + CloseButton, Container, + LogoutButton, MenuCard, - CloseButton, - UserName, - UserEmail, MenuContent, MenuLinks, - StyledLink, - LogoutButton, - menuVariants, menuTransition, + menuVariants, ProfileImage, + StyledLink, + UserEmail, + UserName, } from './ProfileMenu.styles'; function ProfileMenu({ handleProfileToggle, handleNavClose }) { const { handleSignOut } = useContext(AuthContext); + const [isRegistered, setIsRegistered] = useState(false); const getUserDetails = useUserDetails(); const user = getUserDetails(); + const router = useRouter(); + const path = usePathname(); + + // const { data: userDataInDb } = useSuspenseQuery( + // GET_USER_BY_UID, + // user.uid ? { variables: { uid: user.uid } } : skipToken, + // ); const handleLogout = () => { handleSignOut(); @@ -33,6 +47,24 @@ function ProfileMenu({ handleProfileToggle, handleNavClose }) { handleNavClose(false); }; + useEffect(() => { + const mongoId = Cookies.get('userDataDB'); + + console.log('mongoId:', mongoId); + // userDataInDb?.user.data.length > 0; + if (mongoId) { + if (path === '/register') { + toast.success('You are already registered!'); + router.push('/'); + } + setIsRegistered(true); + } else { + setIsRegistered(false); + } + + // console.log('userDataInDb:', userDataInDb); + }, []); + return ( {user?.name} {user?.email} - - Complete Your Registration - + {isRegistered ? ( +

Your payment is being verified! You will be mailed shortly

+ ) : ( + + Complete Your Registration + + )} Logout
diff --git a/src/components/Register/CampusAmbassador/CampusAmbassador.jsx b/src/components/Register/CampusAmbassador/CampusAmbassador.jsx index fa8b53dc..d310139e 100644 --- a/src/components/Register/CampusAmbassador/CampusAmbassador.jsx +++ b/src/components/Register/CampusAmbassador/CampusAmbassador.jsx @@ -1,16 +1,18 @@ -import CheckBox from '../InputCheckBox/CheckBox'; import { beamImage, - campusAmbassadorInput, campusAbassadorPara, + campusAmbassadorInput, } from '@/config/content/Registration/details'; + +import CheckBox from '../InputCheckBox/CheckBox'; import { - Container, BeamImage, - Title, - Description, CheckBoxWrapper, + Container, + Description, + Title, } from './CampusAmbassador.styles'; + function CampusAmbassador({ handleChange, userReferral, isCampusAmbassador }) { function isUserRefferalCorrect(referralCode) { return referralCode.length === 10 && /^\d+$/.test(String(referralCode)); @@ -38,7 +40,7 @@ function CampusAmbassador({ handleChange, userReferral, isCampusAmbassador }) { > Your referral code is {userReferral}
-

Use this while referring to your peers.

+ Use this while referring to your peers. )}
diff --git a/src/components/Register/SelectField/SelectField.jsx b/src/components/Register/SelectField/SelectField.jsx index 18dc44b5..0c71278e 100644 --- a/src/components/Register/SelectField/SelectField.jsx +++ b/src/components/Register/SelectField/SelectField.jsx @@ -1,6 +1,9 @@ 'use client'; +import { useEffect, useRef, useState } from 'react'; + +import { toast } from 'react-hot-toast'; + import { Label } from '../FileInput/FileInput.styles'; -import { useState, useEffect, useRef } from 'react'; import InputField from '../InputField/InputField'; import { ErrorMessage } from '../InputField/InputField.styles'; import { @@ -40,7 +43,13 @@ function SelectField({ const handleToggle = () => setIsOpen(!isOpen); - const handleSelectChange = (option) => { + const handleSelectChange = (option, id) => { + if (id === 'notAllowed') { + toast.error( + "Students from this institute have been officially barred from participating in INNO'24", + ); + return; + } setSelectedOption(option); setIsOpen(false); setErrors((prevState) => ({ @@ -53,6 +62,11 @@ function SelectField({ [name]: otherInstituteName, })); } else { + handleSelect((prevState) => ({ + ...prevState, + instituteId: id, + })); + handleSelect((prevState) => ({ ...prevState, [name]: option, @@ -116,7 +130,10 @@ function SelectField({ {isOpen && ( {sortedOptions.map((option, index) => ( - handleSelectChange(option.value)}> + handleSelectChange(option.value, option.id)} + > {option.label} ))} diff --git a/src/config/content/Registration/details.js b/src/config/content/Registration/details.js index 21888285..8df40ab4 100644 --- a/src/config/content/Registration/details.js +++ b/src/config/content/Registration/details.js @@ -25,159 +25,199 @@ export const formFields = [ { label: 'Silicon Institute of Technology, Bhubaneswar (SIT-BBSR)', value: 'Silicon Institute of Technology, Bhubaneswar (SIT-BBSR)', + id: '671a5be16748c70b7f893caa', }, { label: 'Odisha University of Technology and Research (OUTR)', value: 'Odisha University of Technology and Research (OUTR)', + id: '671a5be16748c70b7f893cab', }, { label: 'Gandhi Institute of Engineering and Technology, Gunupur (GIET Gunupur)', value: 'Gandhi Institute of Engineering and Technology, Gunupur (GIET Gunupur)', + id: '671a5be16748c70b7f893cac', }, { label: 'Centurion University of Technology and Management', value: 'Centurion University of Technology and Management', + id: '671a5be26748c70b7f893cad', }, { label: 'Biju Patnaik University of Technology (BPUT)', value: 'Biju Patnaik University of Technology (BPUT)', + id: '671a5be26748c70b7f893cae', }, { label: 'National Institute of Science and Technology, Berhampur (NIST Berhampur)', value: 'National Institute of Science and Technology, Berhampur (NIST Berhampur)', + id: '671a5be26748c70b7f893caf', }, { label: 'Kalinga Institute of Industrial Technology, Bhubaneswar (KIIT BBSR)', value: 'Kalinga Institute of Industrial Technology, Bhubaneswar (KIIT BBSR)', + id: '671a5be26748c70b7f893cb0', }, { label: 'C. V. Raman Global University, Bhubaneswar (CV RAMAN)', value: 'C. V. Raman Global University, Bhubaneswar (CV RAMAN)', + id: '671a5be26748c70b7f893cb1', }, { label: 'Parala Maharaja Engineering College', value: 'Parala Maharaja Engineering College', + id: '671a5be36748c70b7f893cb2', }, { label: 'Indira Gandhi Institute of Technology, Sarang', value: 'Indira Gandhi Institute of Technology, Sarang', + id: '671a5be36748c70b7f893cb3', }, { label: 'Veer Surendra Sai University of Technology (VSSUT)', value: 'Veer Surendra Sai University of Technology (VSSUT)', + id: '671a5be36748c70b7f893cb4', }, { label: 'Gandhi Institute for Technological Advancement (GITA)', value: 'Gandhi Institute for Technological Advancement (GITA)', + id: '671a5be36748c70b7f893cb5', }, { label: 'Pragati Maidan Engineering College (PMEC)', value: 'Pragati Maidan Engineering College (PMEC)', + id: '671a5be36748c70b7f893cb6', }, { label: 'Bhubaneswar Engineering College (BEC BBSR)', value: 'Bhubaneswar Engineering College (BEC BBSR)', + id: '671a5be46748c70b7f893cb7', }, { label: 'Indian Institute of Science Education and Research, Berhampur (IISER Berhampur)', value: 'Indian Institute of Science Education and Research, Berhampur (IISER Berhampur)', + id: '671a5be46748c70b7f893cb8', }, { label: 'International Institute of Information Technology, Bhubaneswar (IIIT BBSR)', value: 'International Institute of Information Technology, Bhubaneswar (IIIT BBSR)', + id: '671a5be46748c70b7f893cb9', }, { label: 'Indian Institute of Technology, Bhubaneswar (IIT BBSR)', value: 'Indian Institute of Technology, Bhubaneswar (IIT BBSR)', + id: '671a5be46748c70b7f893cba', }, { label: 'Rajendra Institute of Medical Sciences, Rourkela (RIMS, Rourkela)', value: 'Rajendra Institute of Medical Sciences, Rourkela (RIMS, Rourkela)', + id: '671a5be46748c70b7f893cbb', }, { label: 'Municipal College, Rourkela', value: 'Municipal College, Rourkela', + id: '671a5be56748c70b7f893cbc', }, { label: 'Government Autonomous College, Rourkela', value: 'Government Autonomous College, Rourkela', + id: '671a5be56748c70b7f893cbd', }, { label: 'Badriprasad Institute of Technology, Sambalpur', value: 'Badriprasad Institute of Technology, Sambalpur', + id: '671a5be56748c70b7f893cbe', }, { label: 'Sambalpur University', value: 'Sambalpur University', + id: '671a5be56748c70b7f893cbf', }, { label: 'Utkalmani Gopabandhu College', value: 'Utkalmani Gopabandhu College', + id: '671a5be56748c70b7f893cc0', }, { label: 'Government College of Engineering, Kalahandi, Bhawanipatna (GCEK Bhawanipatna)', value: 'Government College of Engineering, Kalahandi, Bhawanipatna (GCEK Bhawanipatna)', + id: '671a5be66748c70b7f893cc1', }, { label: 'Birla Institute of Technology, Durg (BIT Durg)', value: 'Birla Institute of Technology, Durg (BIT Durg)', + id: '671a5be66748c70b7f893cc2', }, { label: 'Birla Institute of Technology, Mesra (BIT Mesra)', value: 'Birla Institute of Technology, Mesra (BIT Mesra)', + id: '671a5be66748c70b7f893cc3', }, { label: 'National Institute of Technology, Jamshedpur (NIT Jamshedpur)', value: 'National Institute of Technology, Jamshedpur (NIT Jamshedpur)', + id: '671a5be66748c70b7f893cc4', }, { label: 'National Institute of Technology, Durgapur (NIT Durgapur)', value: 'National Institute of Technology, Durgapur (NIT Durgapur)', + id: '671a5be66748c70b7f893cc5', }, { label: 'Indian Institute of Technology, Dhanbad (IIT Dhanbad)', value: 'Indian Institute of Technology, Dhanbad (IIT Dhanbad)', + id: '671a5be66748c70b7f893cc6', }, { label: 'Indian Institute of Technology, Bhilai (IIT Bhilai)', value: 'Indian Institute of Technology, Bhilai (IIT Bhilai)', + id: '671a5be76748c70b7f893cc7', }, { label: 'National Institute of Technology, Raipur (NIT Raipur)', value: 'National Institute of Technology, Raipur (NIT Raipur)', + id: '671a5be76748c70b7f893cc8', }, { label: 'Jadavpur University', value: 'Jadavpur University', + id: '671a5be76748c70b7f893cc9', }, { label: 'National Institute of Technology, Patna (NIT Patna)', value: 'National Institute of Technology, Patna (NIT Patna)', + id: '671a5be76748c70b7f893cca', }, { label: 'National Institute of Technology, Rourkela (NIT Rourkela)', value: 'National Institute of Technology, Rourkela (NIT Rourkela)', + id: '671a5be76748c70b7f893ccb', }, { label: 'National Institute of Technology, Andhra Pradesh (NIT Andhra Pradesh)', value: 'National Institute of Technology, Andhra Pradesh (NIT Andhra Pradesh)', + id: '671a5be76748c70b7f893ccc', }, { label: 'Vellore Institute of Technology, Vellore (VIT Vellore)', value: 'Vellore Institute of Technology, Vellore (VIT Vellore)', + id: '671a5be86748c70b7f893ccc', + }, + { + label: 'Institute of Technical Education and Research SOA', + value: 'Institute of Technical Education and Research SOA', + id: 'notAllowed', }, { label: 'Trident Academy of Technology, Bhubaneswar (Trident BBSR)', value: 'Trident Academy of Technology, Bhubaneswar (Trident BBSR)', + id: '671a5be86748c70b7f893ccd', }, { label: 'Indian Institute of Engineering Science and Technology, Shibpur (IIEST Shibpur)', value: 'Indian Institute of Engineering Science and Technology, Shibpur (IIEST Shibpur)', + id: '671a5be86748c70b7f893cce', }, - { - label: 'Others', - value: 'others', - }, + { label: 'Others', value: 'others' }, ], id: 'institute', className: 'w-full', @@ -194,7 +234,6 @@ export const formFields = [ type: 'text', id: 'rollNumber', }, - { label: 'Upload College ID', type: 'file', @@ -211,11 +250,11 @@ export const formFields = [ type: 'select', options: [ { - value: 'female', + value: 'FEMALE', label: 'Female', }, { - value: 'male', + value: 'MALE', label: 'Male', }, ], @@ -231,7 +270,7 @@ export const formFields = [ { label: 'Upload Payment Screenshot', type: 'file', - id: 'idCard', + id: 'payment', }, { label: 'Transaction ID', diff --git a/src/config/zodd/userDetailsSchema.js b/src/config/zodd/userDetailsSchema.js index c9eb11f5..38eca934 100644 --- a/src/config/zodd/userDetailsSchema.js +++ b/src/config/zodd/userDetailsSchema.js @@ -1,4 +1,5 @@ import { z } from 'zod'; + import { notAllowedInstitutes } from '../content/Registration/details'; export const userSchema = z.object({ @@ -6,7 +7,9 @@ export const userSchema = z.object({ .string() .min(1, 'Name is required') .regex(/^[a-zA-Z\s]+$/, 'Name can only contain letters'), - email: z.string().min(1, 'Email is required').email('Invalid email format'), + email: z.string().regex(/^[a-z0-9](\.?[a-z0-9]){5,}@g(oogle)?mail\.com$/, { + message: 'Invalid email address. Please use your Gmail address', + }), phone: z .string() .length(10, 'Phone number must be exactly 10 digits') @@ -29,7 +32,7 @@ export const userSchema = z.object({ permission: z.boolean().refine((val) => val === true, { message: "You must have permission from your institute's authority", }), - gender: z.enum(['male', 'female'], { + gender: z.enum(['MALE', 'FEMALE'], { errorMap: () => ({ message: 'Gender selection is required and must be either male or female' }), }), undertaking: z.boolean().refine((val) => val === true, { diff --git a/src/context/auth-context.jsx b/src/context/auth-context.jsx index 3567192e..e6cb8505 100644 --- a/src/context/auth-context.jsx +++ b/src/context/auth-context.jsx @@ -1,14 +1,16 @@ import { createContext, useState } from 'react'; + +import Cookies from 'js-cookie'; import { toast } from 'react-hot-toast'; + import { signInWithGoogle, signOutUser } from '@/firebase/auth'; -import Cookies from 'js-cookie'; -import { auth } from '@/firebase/firebase'; export const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [userInfo, setUserInfo] = useState({}); const [authLoading, setAuthLoading] = useState(false); + const [userMongoId, setUserMongoId] = useState(''); const handleGoogleSignIn = async () => { setAuthLoading(true); @@ -46,6 +48,7 @@ export const AuthProvider = ({ children }) => { await signOutUser(); setUserInfo({}); Cookies.remove('userData'); + Cookies.remove('userDataDB'); toast.success('Successfully signed out.'); } catch (error) { console.error('Error signing out:', error); @@ -55,7 +58,15 @@ export const AuthProvider = ({ children }) => { return ( {children} diff --git a/src/graphql/mutations/organizationMutations.js b/src/graphql/mutations/organizationMutations.js new file mode 100644 index 00000000..28124c0e --- /dev/null +++ b/src/graphql/mutations/organizationMutations.js @@ -0,0 +1,9 @@ +import { gql } from '@apollo/client'; + +export const REGISTER_ORG = gql` + mutation CreateMultipleOrgs($orgs: [OrgCreateInputType!]!) { + createMultipleOrgs(orgs: $orgs) { + id + } + } +`; diff --git a/src/lib/apollo-client.js b/src/lib/apollo-client.js index 0478faec..37d159df 100644 --- a/src/lib/apollo-client.js +++ b/src/lib/apollo-client.js @@ -1,7 +1,9 @@ -import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'; -import { setContext } from '@apollo/client/link/context'; import Cookies from 'js-cookie'; +import { ApolloClient, from, HttpLink, InMemoryCache } from '@apollo/client'; +import { setContext } from '@apollo/client/link/context'; +import { onError } from '@apollo/client/link/error'; + const MAX_RETRIES = 3; const RETRY_TIMEOUT = 8000; @@ -21,6 +23,7 @@ const reconnectFetch = async (uri, options, retries = 0) => { throw new Error(`HTTP error! Status: ${response.status}`); } + console.log('Connected to server successfully'); return response; } catch (error) { clearTimeout(timeoutId); @@ -63,7 +66,19 @@ const authLink = setContext((_, { headers }) => { }; }); +const errorLink = onError(({ graphQLErrors, networkError }) => { + if (graphQLErrors) { + graphQLErrors.forEach(({ message, locations, path }) => + console.error(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`), + ); + } + + if (networkError) { + console.error(`[Network error]: ${networkError}`); + } +}); + export const client = new ApolloClient({ - link: authLink.concat(httpLink), + link: from([errorLink, authLink.concat(httpLink)]), cache: new InMemoryCache(), });