Skip to content

Commit

Permalink
Razorpay payment gateway (#827)
Browse files Browse the repository at this point in the history
* razorpay: Add feature of payment order through razorpay.

Signed-off-by: sayyedarib <sayyedaribhussain4321@gmail.com>

* razorpay: Add verification logic of payment.

Signed-off-by: sayyedarib <sayyedaribhussain4321@gmail.com>

* razorpay: remove unecessary comments and consoles,
	  add comments wherever needed

Signed-off-by: sayyedarib <sayyedaribhussain4321@gmail.com>

* razorpay_and_index: Add toast for verification messsage.

Signed-off-by: sayyedarib <sayyedaribhussain4321@gmail.com>

---------

Signed-off-by: sayyedarib <sayyedaribhussain4321@gmail.com>
  • Loading branch information
sayyedarib authored Dec 30, 2023
1 parent 954069b commit c558993
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 49 deletions.
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ NEXT_PUBLIC_ENCRYPTION_SECRET_KEY = "encryptionSecretKey"
NEXT_PUBLIC_GOOGLE_CLIENT_ID="secured h"

## If you backend server running on localhost you can this one.
# NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
NEXT_PUBLIC_BACKEND_URL=https://demoapi.grabtern.com
NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
# NEXT_PUBLIC_BACKEND_URL=https://demoapi.grabtern.com
#up is the prod. link

## To use production one please uncomment this one( this is for OSS community)
Expand Down
173 changes: 173 additions & 0 deletions hook/razorpay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import axios from "axios";

const loadRazorpayScript = () => {
return new Promise((resolve) => {
const script = document.createElement("script");
script.src = "https://checkout.razorpay.com/v1/checkout.js";
script.async = true;
script.onload = resolve;
document.body.appendChild(script);
});
};

const createCustomEvent = (message, number) => {
return document.dispatchEvent(
new CustomEvent("razorpay", {
detail: {
status: number,
message: message,
},
}),
);
};

const bookedSession = async (
paymentProof,
sessionDetails,
mentorDetail,
selectedDay,
selectedTime,
) => {
console.log("payment proof", paymentProof);
try {
const requestData = {
mentorUsername: mentorDetail.username,
sessionID: sessionDetails._id,
sessionDate: new Date(selectedDay).toDateString(),
sessionTime: selectedTime,
paymentProof: paymentProof,
};

const response = await axios.post(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/api/mentors/bookSessionMail`,
requestData,
{ withCredentials: true },
);

console.log("response", response);

if (response.data) {
console.log("You have successfully booked a session!");
// window.location.href = "/";
} else {
console.error(
"Error booking session: Unexpected response from the server.",
);
}
} catch (error) {
if (error.response?.data?.message) {
// toast.error(error.response.data.message);
console.error("Error booking session:", error.response.data.message);
} else {
// toast.error("Error booking session: An unexpected error occurred.");
console.error("Error booking session:", error);
}
}
};

// const verifyOrder = async (orderDetails, sessionDetails, mentorDetail, selectedDay, selectedTime) => {
// try {
// const response = await axios.post(
// `${process.env.NEXT_PUBLIC_BACKEND_URL}/api/users/payment/verifyOrder`,
// orderDetails,
// );
// if (response.status == 200) {
// // createCustomEvent('Payment has been verified', 0);
// bookedSession(sessionDetails, mentorDetail, selectedDay, selectedTime, orderDetails)
// } else {
// createCustomEvent('Payment could not be verified', 1);
// }
// } catch (err) {
// createCustomEvent('Payment could not be verified', 1);
// }
// };

const createRazorpayObject = async (
sessionDetails,
mentorDetail,
selectedDay,
selectedTime,
) => {
const response = await axios.post(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/api/users/payment/createOrder`,
sessionDetails,
);
const { id, amount, currency, notes } = response.data;
const options = {
key: "rzp_test_T6Il7sPWsuqEPB",
amount: amount,
currency: "INR",
name: "Grabtern",
description: notes?.description,
image:
"https://th.bing.com/th/id/OIP.cs4xLIcOvEpEa8xYyPjzfwAAAA?rs=1&pid=ImgDetMain",
order_id: id,
handler: function (paymentProof) {
bookedSession(
paymentProof,
sessionDetails,
mentorDetail,
selectedDay,
selectedTime,
);
},
prefill: {
//user information need to be added here using login info of user
contact: "8604078497",
name: "Sayyed Arib",
email: "sayyedaribhussain4321@gmail.com",
},
notes: notes,
theme: {
color: "#2300a3",
},
};
const razorpayObject = new Razorpay(options);

razorpayObject.on("payment.failed", function (response) {
// createCustomEvent('Payment failed', 1);
alert("Payment failed");
});

return razorpayObject;
};

let razorpayObjectPromise;

export const getRazorpayObject = async (
sessionDetails,
mentorDetail,
selectedDay,
selectedTime,
) => {
if (!razorpayObjectPromise) {
// Load the script and create the Razorpay object only once
razorpayObjectPromise = loadRazorpayScript().then(() =>
createRazorpayObject(
sessionDetails,
mentorDetail,
selectedDay,
selectedTime,
),
);
}

return razorpayObjectPromise;
};

export const razorpay_object = async (
e,
sessionDetails,
mentorDetail,
selectedDay,
selectedTime,
) => {
e.preventDefault();
const razorpayObject = await getRazorpayObject(
sessionDetails,
mentorDetail,
selectedDay,
selectedTime,
);
razorpayObject.open();
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^14.0.0",
"autoprefixer": "^10.4.14",
"axios": "^1.4.0",
"axios": "^1.6.2",
"eslint": "^8.7.0",
"eslint-config-next": "13.1.1",
"eslint-config-prettier": "^8.8.0",
Expand Down
111 changes: 65 additions & 46 deletions pages/[mentorUsername]/bookSession/index.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import dynamic from "next/dynamic";
import axios from "axios";
import ButtonUI from "../../../components/UI/Button/Button";
import { useRouter } from "next/router";
import { razorpay_object } from "../../../hook/razorpay";

const Header = dynamic(() => import("../../../components/layout/Header"));

Expand All @@ -18,7 +19,6 @@ function Index({ mentorDetail, bookSession, sessionID }) {
const [listDates, setListDates] = useState([]);
const [availableDays, setAvailableDays] = useState([]);
const [loading, setLoading] = useState(false);

//User Info
const user = JSON.parse(localStorage.getItem("userData"));
const userName = user?.user_name;
Expand Down Expand Up @@ -86,11 +86,33 @@ function Index({ mentorDetail, bookSession, sessionID }) {
});
};

useEffect(() => {
if (localStorage.getItem("paymentIssuePopup") === "0") {
setPaymentIssuePopup(false);
const showToast = (status, message) => {
if (status === 2) {
toast.success(message);
} else if (status === 1) {
toast.error(message);
}
};
const [paymentStatus, setPaymentStatus] = useState({
status: 0,
message: "",
});
const updatePaymentStatus = (e) => {
setPaymentStatus({ status: e.detail.status, status: e.detail.message });
};
const status = document.addEventListener("razorpay", updatePaymentStatus);
useEffect(() => {
const handleRazorpay = (e) => {
showToast(e.detail.status, e.detail.message);
};
document.addEventListener("razorpay", handleRazorpay);
}, []);

// useEffect(() => {
// if (localStorage.getItem("paymentIssuePopup") === "0") {
// setPaymentIssuePopup(false);
// }
// });

// TODO: MOve this to utils/image file
const uploadToCloudinary = async (imageSrc) => {
Expand Down Expand Up @@ -118,32 +140,32 @@ function Index({ mentorDetail, bookSession, sessionID }) {
};

// TODO: MOve this to utils/image file
const handleImageChange = async (e) => {
setLoading(true);
const file = e.target.files[0];
if (!file) {
setLoading(false);
return;
}

try {
const base64 = await convertBase64(file);
const imageCloudinaryUrl = await uploadToCloudinary(base64);

if (!imageCloudinaryUrl) {
setLoading(false);
toast.error("Failed to upload the image to our server");
return;
}

bookedSession(imageCloudinaryUrl);
} catch (error) {
setLoading(false);
toast.error("An error occurred while processing the image.");
}
};

const bookSessionPaymentStep = () => {
// const handleImageChange = async (e) => {
// setLoading(true);
// const file = e.target.files[0];
// if (!file) {
// setLoading(false);
// return;
// }

// try {
// const base64 = await convertBase64(file);
// const imageCloudinaryUrl = await uploadToCloudinary(base64);

// if (!imageCloudinaryUrl) {
// setLoading(false);
// toast.error("Failed to upload the image to our server");
// return;
// }

// bookedSession(imageCloudinaryUrl);
// } catch (error) {
// setLoading(false);
// toast.error("An error occurred while processing the image.");
// }
// };

const bookSessionPaymentStep = (e) => {
if (!userName) {
toast.error("Please log in as a user before booking a session.");
setTimeout(() => {
Expand All @@ -159,23 +181,18 @@ function Index({ mentorDetail, bookSession, sessionID }) {
return;
}

setQrPopup(true);
// setQrPopup(true);
razorpay_object(e, bookSession, mentorDetail, selectedDay, selectedTime);
};

const handleCopy = () => {
const paymentDetails = "9368086395@paytm";
navigator.clipboard.writeText(paymentDetails);
alert("Successfully copied!");
};
// const handleCopy = () => {
// const paymentDetails = "9368086395@paytm";
// navigator.clipboard.writeText(paymentDetails);
// alert("Successfully copied!");
// };

const bookedSession = async (imageCloudinaryUrl) => {
const bookedSession = async () => {
try {
if (imageCloudinaryUrl === null) {
setLoading(false);
toast.error("Upload transaction proof first to book a session.");
return;
}

const requestData = {
mentorUsername: mentorDetail.username,
sessionID: bookSession._id,
Expand Down Expand Up @@ -251,6 +268,7 @@ function Index({ mentorDetail, bookSession, sessionID }) {
className="container sessionContainer"
style={{ marginTop: "100px" }}
>
{/* Keep this method in case razorpay faces some issue
{paymentIssuePopup && (
<div className="modal-overlay">
<div className="modal-content">
Expand All @@ -272,7 +290,7 @@ function Index({ mentorDetail, bookSession, sessionID }) {
</span>
</div>
</div>
)}
)}
{qrPopup && (
<div className="modal-overlay">
<div className="modal-content">
Expand All @@ -293,7 +311,8 @@ function Index({ mentorDetail, bookSession, sessionID }) {
</div>
</div>
</div>
)}
)}
*/}
<h1>Let's book a session</h1>

<div className="session">
Expand Down Expand Up @@ -374,7 +393,7 @@ function Index({ mentorDetail, bookSession, sessionID }) {
<div className="price">
<b>Book Session Price:</b> {bookSession.price}
</div>
<div className="button">
<div id="pay-button" className="button">
<ButtonUI
text="Book Session Now"
onClick={bookSessionPaymentStep}
Expand Down
1 change: 1 addition & 0 deletions pages/_app.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ function MyApp({ Component, pageProps }) {
nomodule
src="https://cdn.jsdelivr.net/npm/ionicons/dist/ionicons/ionicons.js"
></script>
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
{/* <script src="https://accounts.google.com/gsi/client" async defer ></script> */}
</Head>

Expand Down
4 changes: 4 additions & 0 deletions pages/_document.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export default function Document() {
src="https://accounts.google.com/gsi/client"
strategy="beforeInteractive"
></Script>
<Script
src="https://checkout.razorpay.com/v1/checkout.js"
strategy="beforeInteractive"
></Script>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />

Expand Down

0 comments on commit c558993

Please sign in to comment.