From 0c7263e544bfce72738f4a1a24208364d5169573 Mon Sep 17 00:00:00 2001
From: Srishty Mangutte <68679980+Srish-ty@users.noreply.github.com>
Date: Sun, 3 Nov 2024 12:11:00 +0530
Subject: [PATCH 1/3] chore: payment gateway integration (#242)
* fix:remove playground and unnecessary files
* feat: added payment
* fix: env vars
* fix: env vars
---
.env.sample | 5 +++
package.json | 3 +-
src/app/callback/page.jsx | 31 +++++++++++++++++++
src/app/payment/page.jsx | 44 +++++++++++++++++++++++++++
src/app/payment/payButton.jsx | 29 ++++++++++++++++++
src/app/payment/payment.styles.jsx | 7 +++++
src/app/playground/page.js | 21 -------------
src/config/content/NavData.js | 10 ------
src/pages/api/phonepePayment.js | 42 +++++++++++++++++++++++++
src/pages/api/phonepePaymentStatus.js | 31 +++++++++++++++++++
10 files changed, 191 insertions(+), 32 deletions(-)
create mode 100644 src/app/callback/page.jsx
create mode 100644 src/app/payment/page.jsx
create mode 100644 src/app/payment/payButton.jsx
create mode 100644 src/app/payment/payment.styles.jsx
delete mode 100644 src/app/playground/page.js
delete mode 100644 src/config/content/NavData.js
create mode 100644 src/pages/api/phonepePayment.js
create mode 100644 src/pages/api/phonepePaymentStatus.js
diff --git a/.env.sample b/.env.sample
index f2817e41..ceda341a 100644
--- a/.env.sample
+++ b/.env.sample
@@ -11,3 +11,8 @@ NEXT_PUBLIC_FIREBASE_APP_ID= ""
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID= ""
NEXT_PUBLIC_APOLLO_URI=""
+
+NEXT_PUBLIC_PHONEPE_MERCHANT_ID=your_merchant_id
+NEXT_PUBLIC_PHONEPE_API_KEY=""
+NEXT_PUBLIC_PHONEPE_API_KEY_INDEX=""
+NEXT_PUBLIC_PHONEPE_API_URL=""
diff --git a/package.json b/package.json
index 128dfb53..354aae69 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"@react-three/fiber": "^8.17.7",
"ajv": "^8.17.1",
"axios": "^1.7.7",
+ "crypto": "^1.0.1",
"firebase": "^10.14.1",
"flowbite-react": "^0.10.2",
"framer-motion": "^11.5.6",
@@ -55,8 +56,8 @@
"swiper": "^11.1.14",
"three": "^0.168.0",
"twin.macro": "^3.4.1",
- "yarn": "^1.22.22",
"uuidv4": "^6.2.13",
+ "yarn": "^1.22.22",
"zod": "^3.23.8"
},
"devDependencies": {
diff --git a/src/app/callback/page.jsx b/src/app/callback/page.jsx
new file mode 100644
index 00000000..1bbd7d94
--- /dev/null
+++ b/src/app/callback/page.jsx
@@ -0,0 +1,31 @@
+'use client';
+import { useEffect } from 'react';
+import { useRouter } from 'next/router';
+
+const CallbackPage = () => {
+ const router = useRouter();
+ const { transactionId } = router.query;
+
+ useEffect(() => {
+ const checkPaymentStatus = async () => {
+ if (transactionId) {
+ const response = await fetch('/api/phonepePaymentStatus', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ transactionId }),
+ });
+ const data = await response.json();
+ if (data.status === 'SUCCESS') {
+ alert('Payment successful!');
+ } else {
+ alert('Payment failed. Please try again.');
+ }
+ }
+ };
+ checkPaymentStatus();
+ }, [transactionId]);
+
+ return
Processing your payment...
;
+};
+
+export default CallbackPage;
diff --git a/src/app/payment/page.jsx b/src/app/payment/page.jsx
new file mode 100644
index 00000000..2c67a6a0
--- /dev/null
+++ b/src/app/payment/page.jsx
@@ -0,0 +1,44 @@
+'use client';
+import React, { useEffect, useState } from 'react';
+import PayButton from './payButton';
+import { PayContainer } from './payment.styles';
+import Cookies from 'js-cookie';
+
+const PaymentPage = () => {
+ const [isClient, setIsClient] = useState(false);
+ const [userEmail, setUserEmail] = useState('');
+
+ useEffect(() => {
+ setIsClient(true);
+ const userData = Cookies.get('userData');
+ const email = (userData && JSON.parse(userData).email) || '';
+ setUserEmail(email);
+ }, []);
+
+ const validEmails = [
+ 'innovision2024.nitr@gmail.com',
+ 'srishtymangutte@gmail.com',
+ 'jaiswal2nikhil@gmail.com',
+ ];
+
+ if (!isClient) {
+ return null;
+ }
+
+ return (
+
+
+ {validEmails.includes(userEmail) ? (
+ <>
+ Payment Page
+
+ >
+ ) : (
+ 404 page not found
+ )}
+
+
+ );
+};
+
+export default PaymentPage;
diff --git a/src/app/payment/payButton.jsx b/src/app/payment/payButton.jsx
new file mode 100644
index 00000000..b5ef1f89
--- /dev/null
+++ b/src/app/payment/payButton.jsx
@@ -0,0 +1,29 @@
+'use client';
+import { useState } from 'react';
+import { SecondaryButton } from '@/components/shared/Typography/Buttons';
+
+const PayButton = () => {
+ const handlePayment = async () => {
+ const response = await fetch('/api/phonepePayment', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ amount: 100,
+ orderId: 'unique_order_id_12345',
+ callbackUrl: `${window.location.origin}/callback`,
+ }),
+ });
+
+ const data = await response.json();
+
+ if (data.success) {
+ window.location.href = data.paymentUrl;
+ } else {
+ alert('Payment failed. Please try again.');
+ }
+ };
+
+ return ;
+};
+
+export default PayButton;
diff --git a/src/app/payment/payment.styles.jsx b/src/app/payment/payment.styles.jsx
new file mode 100644
index 00000000..f4a4225a
--- /dev/null
+++ b/src/app/payment/payment.styles.jsx
@@ -0,0 +1,7 @@
+import tw from 'twin.macro';
+import styled from 'styled-components';
+
+export const PayContainer = styled.div`
+ background-image: url('https://res.cloudinary.com/dhv234qct/image/upload/v1728888341/Inno2k24/yupqoznoucyhxwchhbv7.png');
+ ${tw`w-full flex flex-col items-center justify-center bg-cover pt-36 `}
+`;
diff --git a/src/app/playground/page.js b/src/app/playground/page.js
deleted file mode 100644
index 7a5517df..00000000
--- a/src/app/playground/page.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use client';
-
-import { Hero } from '@/components/HeroSection/Hero';
-import { AboutUsMain } from '@/components/AboutUs/Main';
-import { EventSectionMain } from '@/components/EventsSection/wrapperComponents/Main';
-import { StatisticsMain } from '@/components/Statistics/wrapper/Main';
-import { SponsorSection } from '@/components/Sponsors/sponsors';
-
-const Page = () => {
- return (
- <>
-
-
-
-
-
- >
- );
-};
-
-export default Page;
diff --git a/src/config/content/NavData.js b/src/config/content/NavData.js
deleted file mode 100644
index 27c8f755..00000000
--- a/src/config/content/NavData.js
+++ /dev/null
@@ -1,10 +0,0 @@
-export const NavData = [
- {
- text: 'Home',
- path: '/',
- },
- {
- text: 'Playground',
- path: '/playground',
- },
-];
diff --git a/src/pages/api/phonepePayment.js b/src/pages/api/phonepePayment.js
new file mode 100644
index 00000000..284996ee
--- /dev/null
+++ b/src/pages/api/phonepePayment.js
@@ -0,0 +1,42 @@
+import crypto from 'crypto';
+
+export default async function handler(req, res) {
+ if (req.method === 'POST') {
+ const { amount, orderId, callbackUrl } = req.body;
+
+ const payload = {
+ merchantId: process.env.NEXT_PUBLIC_PHONEPE_MERCHANT_ID,
+ transactionId: orderId,
+ amount: amount,
+ merchantTransactionId: orderId,
+ redirectUrl: callbackUrl,
+ };
+
+ const payloadString = JSON.stringify(payload);
+ const base64Payload = Buffer.from(payloadString).toString('base64');
+
+ const checksum = crypto
+ .createHmac('sha256', process.env.NEXT_PUBLIC_PHONEPE_API_KEY)
+ .update(base64Payload + '/pg/v1/pay' + process.env.NEXT_PUBLIC_PHONEPE_API_KEY)
+ .digest('base64');
+
+ try {
+ const response = await fetch(`${process.env.NEXT_PUBLIC_PHONEPE_API_URL}/pg/v1/pay`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-VERIFY': `${checksum}###${process.env.NEXT_PUBLIC_PHONEPE_API_KEY_INDEX}`,
+ },
+ body: payloadString,
+ });
+
+ const data = await response.json();
+ res.status(200).json(data);
+ } catch (error) {
+ console.error(error);
+ res.status(500).json({ error: 'Payment initiation failed' });
+ }
+ } else {
+ res.status(405).json({ error: 'Method not allowed' });
+ }
+}
diff --git a/src/pages/api/phonepePaymentStatus.js b/src/pages/api/phonepePaymentStatus.js
new file mode 100644
index 00000000..119042d2
--- /dev/null
+++ b/src/pages/api/phonepePaymentStatus.js
@@ -0,0 +1,31 @@
+import crypto from 'crypto';
+
+export default async function handler(req, res) {
+ if (req.method === 'POST') {
+ const { transactionId } = req.body;
+
+ const url = `${process.env.NEXT_PUBLIC_PHONEPE_API_URL}/status/${process.env.NEXT_PUBLIC_PHONEPE_MERCHANT_ID}/${transactionId}`;
+ const checksum = crypto
+ .createHmac('sha256', process.env.NEXT_PUBLIC_PHONEPE_API_KEY)
+ .update(`${url}${process.env.NEXT_PUBLIC_PHONEPE_API_KEY_INDEX}`)
+ .digest('base64');
+
+ try {
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-VERIFY': `${checksum}###${process.env.NEXT_PUBLIC_PHONEPE_API_KEY_INDEX}`,
+ },
+ });
+
+ const data = await response.json();
+ res.status(200).json(data);
+ } catch (error) {
+ console.error(error);
+ res.status(500).json({ error: 'Failed to verify payment status' });
+ }
+ } else {
+ res.status(405).json({ error: 'Method not allowed' });
+ }
+}
From 7a58807a57e35a6db7ea94c4ba9f6d196110ac92 Mon Sep 17 00:00:00 2001
From: Ayan
Date: Sun, 3 Nov 2024 12:12:32 +0530
Subject: [PATCH 2/3] fix:Registration of nitr student (#241)
* Feat: improved Upper Slider,lower Slider,fix Responsiveness of EventPage
* Feat:fix minor changes
* feat:add payment Section in Register Form
* feat:update payment section in register page
* feat:update payment section in registration page
* feat: fix prettier issue
* fix: prettier fix
* feat: update Payment Section
* fix:prettier issue
* faet: fix event section rendering, update eventdata.
* fix:registration nitr student
* fix:minor changes
---
src/components/EventsPage/Event/Event.jsx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/components/EventsPage/Event/Event.jsx b/src/components/EventsPage/Event/Event.jsx
index 101927d4..44078d28 100644
--- a/src/components/EventsPage/Event/Event.jsx
+++ b/src/components/EventsPage/Event/Event.jsx
@@ -19,6 +19,7 @@ const initialState = {
uid: null,
registered: false,
hasPaid: false,
+ isNitR: false,
isCurrentSlideId: 0,
};
@@ -49,9 +50,9 @@ export const Events = ({ EventItem }) => {
const userData = Cookies.get('userDataDB');
if (userData) {
- const { id, hasPaid } = JSON.parse(userData);
+ const { id, hasPaid, isNitR } = JSON.parse(userData);
- setState((prev) => ({ ...prev, uid: id, hasPaid }));
+ setState((prev) => ({ ...prev, uid: id, hasPaid, isNitR }));
}
} catch (error) {
console.error('Error parsing user data cookie:', error);
@@ -115,7 +116,7 @@ export const Events = ({ EventItem }) => {
}));
try {
- if (state.hasPaid) {
+ if (state.hasPaid || state.isNitR) {
const response = await handleLoadingAndToast(
registerForEvent({
variables: {
From c55adf3cdd9505a99585cb69e6c557d13bf64787 Mon Sep 17 00:00:00 2001
From: Ayush <135319056+ayussh-2@users.noreply.github.com>
Date: Sun, 3 Nov 2024 12:13:16 +0530
Subject: [PATCH 3/3] fix: add prefilled details from firebase data (#240)
fix: add prefilled details from firebase
---
src/app/register/page.jsx | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/app/register/page.jsx b/src/app/register/page.jsx
index 7df0a557..b1b254ad 100644
--- a/src/app/register/page.jsx
+++ b/src/app/register/page.jsx
@@ -25,12 +25,12 @@ 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 { GET_USER_BY_UID } from '@/graphql/queries/userQueries';
import { useIsLoggedIn } from '@/hooks/useIsLoggedIn';
import { useUserDetails } from '@/hooks/useUserDetails';
import handleLoadingAndToast from '@/utils/handleLoadingToast';
import { uploadToCloudinary } from '@/utils/uploadToCloudinary';
import { useMutation, useSuspenseQuery } from '@apollo/client';
-import { GET_USER_BY_UID } from '@/graphql/queries/userQueries';
import {
DisclaimerPara,
@@ -301,6 +301,16 @@ function Page() {
}
const userCookie = Cookies.get('userDataDB');
+ const userGoogleData = Cookies.get('userData');
+
+ if (userGoogleData) {
+ const googleData = JSON.parse(userGoogleData);
+ setUserDetails((prev) => ({
+ ...prev,
+ name: googleData.name.toUpperCase(),
+ email: googleData.email,
+ }));
+ }
const hasUserData = userDataDB?.user?.data?.length > 0;
const userData = hasUserData ? userDataDB.user.data[0] : null;
const isNitR = userData?.college === nitrID;