diff --git a/.env b/.env index fa5493c2..80f3734e 100644 --- a/.env +++ b/.env @@ -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) diff --git a/hook/razorpay.js b/hook/razorpay.js new file mode 100644 index 00000000..b29a647c --- /dev/null +++ b/hook/razorpay.js @@ -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(); +}; diff --git a/package.json b/package.json index 59e7e8b5..fe70e936 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pages/[mentorUsername]/bookSession/index.page.js b/pages/[mentorUsername]/bookSession/index.page.js index 28cab892..cf879ad0 100644 --- a/pages/[mentorUsername]/bookSession/index.page.js +++ b/pages/[mentorUsername]/bookSession/index.page.js @@ -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")); @@ -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; @@ -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) => { @@ -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(() => { @@ -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, @@ -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 && (
@@ -272,7 +290,7 @@ function Index({ mentorDetail, bookSession, sessionID }) {
- )} + )} {qrPopup && (
@@ -293,7 +311,8 @@ function Index({ mentorDetail, bookSession, sessionID }) {
- )} + )} + */}

Let's book a session

@@ -374,7 +393,7 @@ function Index({ mentorDetail, bookSession, sessionID }) {
Book Session Price: {bookSession.price}
-
+
+ {/* */} diff --git a/pages/_document.page.js b/pages/_document.page.js index cce1aaac..f0d66850 100644 --- a/pages/_document.page.js +++ b/pages/_document.page.js @@ -11,6 +11,10 @@ export default function Document() { src="https://accounts.google.com/gsi/client" strategy="beforeInteractive" > +