Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: GraphQL integration for user Registration #224

Merged
merged 7 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=""
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET=""


NEXT_PUBLIC_FIREBASE_API_KEY=""
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=""
NEXT_PUBLIC_FIREBASE_PROJECT_ID= ""
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET= ""
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= ""
NEXT_PUBLIC_FIREBASE_APP_ID= ""
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID= ""

NEXT_PUBLIC_APOLLO_URI=""
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"prettier:fix": "prettier --write \"./**/*.{ts,tsx,js,jsx,css,scss,md}\" --ignore-pattern node_modules/"
},
"dependencies": {
"@apollo/client": "^3.11.8",
"@babel/core": "^7.25.2",
"@nextui-org/react": "^2.4.8",
"@react-three/drei": "^9.112.1",
Expand All @@ -42,6 +43,7 @@
"firebase": "^10.14.1",
"flowbite-react": "^0.10.2",
"framer-motion": "^11.5.6",
"graphql": "^16.9.0",
"hamburger-react": "^2.5.1",
"js-cookie": "^3.0.5",
"lucide-react": "^0.452.0",
Expand All @@ -53,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": {
Expand Down
171 changes: 118 additions & 53 deletions src/app/register/page.jsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,47 @@
'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({
name: '',
email: '',
phone: '',
institute: '',
instituteId: '',
university: '',
rollNumber: '',
idCard: '',
Expand All @@ -43,27 +51,33 @@ function Page() {
payment: '',
undertaking: false,
campusAmbassador: false,
payment: '',
transactionID: '',
});
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) {
Expand All @@ -83,12 +97,6 @@ function Page() {
}));
}

function handleSubmit() {
const isFormValid = validateForm();
if (!isFormValid) return;
console.log(userDetails);
}

function validateForm() {
const validationResult = userSchema.safeParse(userDetails);
if (!validationResult.success) {
Expand Down Expand Up @@ -151,13 +159,7 @@ function Page() {
error={errors[field.id]}
/>
);
case 'button':
return (
<>
<PaymentHeading>Payment Section </PaymentHeading>
<QrButton label={field.label} />
</>
);

case 'checkbox':
return (
<CheckBox
Expand All @@ -174,20 +176,85 @@ function Page() {
}
}

const [isModalOpen, setModalOpen] = useState(true);

function handleSubmit() {
async function handleSubmit() {
const isFormValid = validateForm();
if (!isFormValid) return;
setModalOpen(true);
console.log(userDetails);

setLoading(true);
try {
let collegeID;
if (!userDetails.instituteId) {
const newCollgeDetails = await registerCollege({
variables: {
orgs: [
{
logo: userDetails.institute + userDetails.email + v4().slice(0, 8),
name: userDetails.institute,
orgType: 'MESS',
registrations: 0,
},
],
},
});

collegeID = newCollgeDetails.data.createMultipleOrgs[0].id;
}

const res = await registerUser({
variables: {
user: {
uid: storedUserId,
name: userDetails.name,
email: userDetails.email,
mobile: userDetails.phone,
college: userDetails.instituteId ? userDetails.instituteId : collegeID,
rollNumber: userDetails.rollNumber,
idCard: userDetails.idCard,
referredBy: userDetails.referralCode,
gender: userDetails.gender,
receipt: userDetails.payment,
transactionID: userDetails.transactionID,
hasPaid: false,
},
},
});
Cookies.set('userDataDB', res.data.createUser.id, {
expires: 7,
sameSite: 'strict',
});

console.log(res);
toast.success(
'Registration successful! You will recieve confirmation email within 4-5 days!',
{
duration: 5000,
},
);
setTimeout(() => {
router.push('/');
}, 1000);
} catch (error) {
console.error(error);
toast.error('Registration failed! Please try again');
} finally {
setLoading(false);
}
}

useEffect(() => {
if (Cookies.get('userDataDB')) {
router.push('/');
toast.success('You have been already registered!', {
duration: 5000,
});
}
}, []);

return (
<RegisterContainer>
<Moon />

{!isLoggedIn ? (
{isLoggedIn ? (
<RegisterInnerContainer>
<RegisterHeading>Register</RegisterHeading>
<RegisterForm>
Expand All @@ -209,16 +276,14 @@ function Page() {
isCampusAmbassador={userDetails.campusAmbassador}
/>
<RegsiterButton onClick={handleSubmit} disabled={loading}>
Submit
{loading ? 'Loading...' : 'Register'}
</RegsiterButton>
</RegisterInnerContainer>
) : (
<PrimaryButton onClick={handleGoogleSignIn} disabled={authLoading}>
{authLoading ? 'Loading...' : 'Sign In with Google'}
</PrimaryButton>
)}

<RegistrationModal isOpen={isModalOpen} onClose={() => setModalOpen(false)} />
</RegisterContainer>
);
}
Expand Down
5 changes: 3 additions & 2 deletions src/app/register/register.styles.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import styled from 'styled-components';
import tw from 'twin.macro';
import { Heading1, Heading2 } from '@/components/shared/Typography/Headings';

import { PrimaryButton } from '@/components/shared/Typography/Buttons';
import { Heading1, Heading2 } from '@/components/shared/Typography/Headings';

export const RegisterHeading = styled(Heading1)`
${tw`text-center text-2xl xxs:text-3xl ssm:text-4xl md:text-5xl lg:text-6xl my-0 py-0 font-spaceX text-white`}
Expand Down Expand Up @@ -57,7 +58,7 @@ export const Moon = styled.div`
`;

export const UndertakingLink = styled.a`
${tw`text-base font-prompt font-semibold hover:underline transition-all duration-200 ease-in-out`}
${tw`text-base font-prompt font-semibold text-blue-400 hover:underline transition-all duration-200 ease-in-out`}
`;

export const PaymentPolicyInfo = styled.div`
Expand Down
9 changes: 8 additions & 1 deletion src/components/EventsPage/CardComponents/PreviewCard.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import toast from 'react-hot-toast';

import {
PreviewButtonContainer,
PreviewCardContainer,
Expand All @@ -12,13 +14,18 @@ function PreviewCard({ ImageURL, PreviewDescription = '' }) {
const truncatedDescription =
words.length > 30 ? words.slice(0, 50).join(' ') + '...' : PreviewDescription;

function handleToast() {
toast('You can register after you are verified!', {
icon: '🚀',
});
}
return (
<PreviewCardContainer>
<PreviewCardImage src={ImageURL} alt='image' width={500} height={500} />
<PreviewCardContent>{truncatedDescription}</PreviewCardContent>
<PreviewButtonContainer>
<PreviewMoreInfoButton2>Rulebook</PreviewMoreInfoButton2>
<PreviewMoreInfoButton>Register</PreviewMoreInfoButton>
<PreviewMoreInfoButton onClick={handleToast}>Register</PreviewMoreInfoButton>
</PreviewButtonContainer>
</PreviewCardContainer>
);
Expand Down
Loading
Loading