From 4a428e6eef249577e9afb468252ee264b24211f9 Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:06:39 +0530 Subject: [PATCH 1/9] feat: integrate UploadDropzone for ID card and photo uploads in registration form --- src/components/common/registration-form.tsx | 59 ++++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index 8708fd5..e82ac75 100644 --- a/src/components/common/registration-form.tsx +++ b/src/components/common/registration-form.tsx @@ -36,6 +36,8 @@ import { FileUpload } from "../ui/file-upload"; import { RadioGroup, RadioGroupItem } from "../ui/radio-group"; import InfoButton from "../ui/info-button"; import { redirect } from "next/navigation"; +import { UploadDropzone } from "@uploadthing/react"; +import { OurFileRouter } from "@/app/api/uploadthing/core"; declare global { interface Window { @@ -91,6 +93,8 @@ export default function RegistrationForm() { entityName: "", couponCode: "", foodPreference: "veg", + photo: "", + idCard: "", }, }); @@ -530,12 +534,27 @@ export default function RegistrationForm() { ID Card - - handleFileUpload("idCard", files) - } - /> + + disabled={field.value !== ""} + endpoint="imageUploader" + onClientUploadComplete={(res) => { + console.log("Files: ", res); + if (!res || res.length === 0) { + toast.error("No files uploaded. Please try again."); + return; + } + form.setValue("idCard", res[0].url); + toast.dismiss(); + toast.success("✅ Id card uploaded successfully!"); + }} + onUploadError={(error) => { + console.error("Upload error:", error); + toast.error("ID upload failed. Please inform us at support.tedx@sjec.ac.in or click the contact us button at buttom right corner."); + }} + onUploadBegin={() => { + toast.loading("Uploading ID card..., dont close the window"); + }} + /> Upload your College ID card image @@ -553,14 +572,26 @@ export default function RegistrationForm() { Photo - file.id === "idCard") - } - key={"photo"} - onChange={(files) => handleFileUpload("photo", files)} + + disabled={field.value !== ""} + endpoint="imageUploader" + onClientUploadComplete={(res) => { + console.log("Files: ", res); + if (!res || res.length === 0) { + toast.error("No files uploaded. Please try again."); + return; + } + form.setValue("photo", res[0].url); + toast.dismiss(); + toast.success("✅ Photo uploaded successfully!"); + }} + onUploadError={(error) => { + console.error("Upload error:", error); + toast.error("Image upload failed. Please inform us at support.tedx@sjec.ac.in or click the contact us button at buttom right corner."); + }} + onUploadBegin={() => { + toast.loading("Uploading images..., dont close the window"); + }} /> From 1316ca324636f8d0dfcbe3437692a65136d74f04 Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:31:14 +0530 Subject: [PATCH 2/9] refactored: removed custom UT uploading functions --- src/components/common/registration-form.tsx | 53 --------------------- 1 file changed, 53 deletions(-) diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index e82ac75..000c1ac 100644 --- a/src/components/common/registration-form.tsx +++ b/src/components/common/registration-form.tsx @@ -98,44 +98,6 @@ export default function RegistrationForm() { }, }); - const { startUpload, routeConfig } = useUploadThing("imageUploader", { - onClientUploadComplete: (res) => { - if (!res || res.length === 0) { - toast.error("No files uploaded. Please try again."); - return; - } - try { - if (res.length === 2) { - form.setValue("idCard", res[0].url); - form.setValue("photo", res[1].url); - } else if (res.length === 1) { - form.setValue("photo", res[0].url); - } - toast.success("✅ Images uploaded successfully!"); - } catch (error) { - console.error("Error processing upload response:", error); - toast.error("Error processing uploaded files."); - } - }, - onUploadError: (error) => { - console.error("Upload error:", error); - toast.error("Image upload failed. Please inform us at support.tedx@sjec.ac.in or click the contact us button at buttom right corner."); - }, - }); - - const handleFileUpload = (id: "idCard" | "photo", files: File[]) => { - setUploadedFiles((prevFiles) => { - const existing = prevFiles.find((file) => file.id === id); - if (existing) { - return prevFiles.map((file) => (file.id === id ? { ...file, files } : file)); - } else { - return [...prevFiles, { id, files }]; - } - }); - - form.setValue(id, files.map((file) => file.name).join(", ")); - }; - const handlePayment = async () => { setIsProcessing(true); const couponCode = form.getValues("couponCode"); @@ -184,21 +146,6 @@ export default function RegistrationForm() { if (verificationData.isOk) { // Process after successful payment verification try { - if (uploadedFiles.length > 0) { - const allFiles = uploadedFiles.flatMap((file) => file.files); - - if (allFiles.length > 0) { - const uploadResult = await startUpload(allFiles); - if (!uploadResult) { - toast.error("Error uploading files. Please contact support from the contact us button at buttom right corner."); - }else{ - toast.success("✅ Files uploaded successfully!"); - } - } else { - toast.warning("⚠️ No files to upload."); - } - } - // Invalidate coupon if present if (couponCode) { const couponResult = await invalidateCouponCode(couponCode, session!); From 1b6b491c50c56cf26c8bb2474c96301d574ad086 Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:48:59 +0530 Subject: [PATCH 3/9] feat: added registration form details to razorpay notes --- src/components/common/registration-form.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index 000c1ac..a2110f7 100644 --- a/src/components/common/registration-form.tsx +++ b/src/components/common/registration-form.tsx @@ -21,7 +21,6 @@ import { basePrice, initialdiscount, sjecFacultyPrice, sjecStudentPrice } from " import { getSjecMemberType } from "@/lib/helper"; import { FormDataInterface } from "@/types"; import getErrorMessage from "@/utils/getErrorMessage"; -import { useUploadThing } from "@/utils/uploadthing"; import { baseSchema, studentFormSchema, studentSchema } from "@/utils/zod-schemas"; import { zodResolver } from "@hookform/resolvers/zod"; import { signIn, signOut, useSession } from "next-auth/react"; @@ -182,9 +181,19 @@ export default function RegistrationForm() { } }, notes: { - customerName: form.getValues("name"), - customerEmail: session?.user?.email, - customerContact: form.getValues("phone"), + name: form.getValues("name"), + email: session?.user?.email, + contact: form.getValues("phone"), + designation: form.getValues("designation"), + foodPreference: form.getValues("foodPreference"), + couponCode: couponCode, + entityName: form.getValues("entityName"), + memberType: memberType, + photo: form.getValues("photo"), + idCard: form.getValues("idCard"), + createdBy: session?.user?.id, + createdAt: new Date().toISOString(), + amount: pricing.finalPrice, }, prefill: { name: form.getValues("name"), From 30923b313f3b554fa9429f36a69e4fd1b2bf3ebd Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:39:04 +0530 Subject: [PATCH 4/9] feat: added UT button with custom structrure --- src/components/common/registration-form.tsx | 90 ++++++++++++++++----- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index a2110f7..c126b48 100644 --- a/src/components/common/registration-form.tsx +++ b/src/components/common/registration-form.tsx @@ -491,26 +491,76 @@ export default function RegistrationForm() { ID Card - disabled={field.value !== ""} - endpoint="imageUploader" - onClientUploadComplete={(res) => { - console.log("Files: ", res); - if (!res || res.length === 0) { - toast.error("No files uploaded. Please try again."); - return; - } - form.setValue("idCard", res[0].url); - toast.dismiss(); - toast.success("✅ Id card uploaded successfully!"); - }} - onUploadError={(error) => { - console.error("Upload error:", error); - toast.error("ID upload failed. Please inform us at support.tedx@sjec.ac.in or click the contact us button at buttom right corner."); - }} - onUploadBegin={() => { - toast.loading("Uploading ID card..., dont close the window"); - }} - /> + appearance={{ + button: ` + bg-red-500 + text-white + hover:bg-red-600 + disabled:bg-red-400 + disabled:cursor-not-allowed + focus:ring-4 + focus:ring-red-300 + dark:focus:ring-red-700 + rounded-md + px-4 + py-2 + transition-all + ease-in-out + `, + allowedContent: ` + text-gray-400 + text-sm + italic + dark:text-gray-500 + `, + }} + content={{ + button({ ready, isUploading }) { + if(field.value !== ""){ + return Uploaded; + } + if (isUploading) { + return Uploading your file...; + } + if (ready) { + return Click to upload; + } + + return Preparing to upload...; + }, + allowedContent({ ready, fileTypes, isUploading }) { + if (isUploading) { + return Uploading supported file types...; + } + if (ready) { + return Select a image then click on upload below; + } + return Checking allowed file types...; + }, + label({ }) { + return
Choose image or drag and drop
; + }, + }} + disabled={field.value !== ""} + endpoint="imageUploader" + onClientUploadComplete={(res) => { + console.log("Files: ", res); + if (!res || res.length === 0) { + toast.error("No files uploaded. Please try again."); + return; + } + form.setValue("idCard", res[0].url); + toast.dismiss(); + toast.success("✅ Id card uploaded successfully!"); + }} + onUploadError={(error) => { + console.error("Upload error:", error); + toast.error("ID upload failed. Please inform us at support.tedx@sjec.ac.in or click the contact us button at buttom right corner."); + }} + onUploadBegin={() => { + toast.loading("Uploading ID card..., dont close the window"); + }} + />
Upload your College ID card image From 55b474d646998a2cb741ba82aa7fa631e0671cb5 Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:44:12 +0530 Subject: [PATCH 5/9] feat: enhance UploadDropzone appearance and upload status messages in registration form --- src/components/common/registration-form.tsx | 87 +++++++++++++++++---- 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index c126b48..59fda11 100644 --- a/src/components/common/registration-form.tsx +++ b/src/components/common/registration-form.tsx @@ -493,20 +493,20 @@ export default function RegistrationForm() { appearance={{ button: ` - bg-red-500 - text-white - hover:bg-red-600 - disabled:bg-red-400 - disabled:cursor-not-allowed - focus:ring-4 - focus:ring-red-300 - dark:focus:ring-red-700 - rounded-md - px-4 - py-2 - transition-all - ease-in-out - `, + bg-red-500 + text-white + hover:bg-red-600 + disabled:bg-[#e62b1e]/80 + disabled:cursor-not-allowed + focus:ring-4 + focus:ring-red-300 + dark:focus:ring-[#e62b1e] + rounded-md + px-4 + py-2 + transition-all + ease-in-out + `, allowedContent: ` text-gray-400 text-sm @@ -529,6 +529,9 @@ export default function RegistrationForm() { return Preparing to upload...; }, allowedContent({ ready, fileTypes, isUploading }) { + if(field.value !== ""){ + return Image was uploaded successfully; + } if (isUploading) { return Uploading supported file types...; } @@ -557,9 +560,6 @@ export default function RegistrationForm() { console.error("Upload error:", error); toast.error("ID upload failed. Please inform us at support.tedx@sjec.ac.in or click the contact us button at buttom right corner."); }} - onUploadBegin={() => { - toast.loading("Uploading ID card..., dont close the window"); - }} /> @@ -579,6 +579,59 @@ export default function RegistrationForm() { Photo + appearance={{ + button: ` + bg-red-500 + text-white + hover:bg-red-600 + disabled:bg-[#e62b1e]/80 + disabled:cursor-not-allowed + focus:ring-4 + focus:ring-red-300 + dark:focus:ring-[#e62b1e] + rounded-md + px-4 + py-2 + transition-all + ease-in-out + `, + allowedContent: ` + text-gray-400 + text-sm + italic + dark:text-gray-500 + `, + }} + content={{ + button({ ready, isUploading }) { + if(field.value !== ""){ + return Uploaded; + } + if (isUploading) { + return Uploading your file...; + } + if (ready) { + return Click to upload; + } + + return Preparing to upload...; + }, + allowedContent({ ready, fileTypes, isUploading }) { + if(field.value !== ""){ + return Image was uploaded successfully; + } + if (isUploading) { + return Uploading supported file types...; + } + if (ready) { + return Select a image then click on upload below; + } + return Checking allowed file types...; + }, + label({ }) { + return
Choose image or drag and drop
; + }, + }} disabled={field.value !== ""} endpoint="imageUploader" onClientUploadComplete={(res) => { From bc275db1e7df592c024f57f34f9f57c1b5f210cc Mon Sep 17 00:00:00 2001 From: Joywin Bennis <107112207+joywin2003@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:50:13 +0530 Subject: [PATCH 6/9] code clean up --- src/components/common/registration-form.tsx | 1402 ++++++++++--------- 1 file changed, 746 insertions(+), 656 deletions(-) diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index 59fda11..e46cdb7 100644 --- a/src/components/common/registration-form.tsx +++ b/src/components/common/registration-form.tsx @@ -4,24 +4,46 @@ import { getPrice } from "@/app/actions/get-price"; import { invalidateCouponCode } from "@/app/actions/invalidate-coupon"; import { submitForm } from "@/app/actions/submit-form"; import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { basePrice, initialdiscount, sjecFacultyPrice, sjecStudentPrice } from "@/constants"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + basePrice, + initialdiscount, + sjecFacultyPrice, + sjecStudentPrice, +} from "@/constants"; import { getSjecMemberType } from "@/lib/helper"; import { FormDataInterface } from "@/types"; import getErrorMessage from "@/utils/getErrorMessage"; -import { baseSchema, studentFormSchema, studentSchema } from "@/utils/zod-schemas"; +import { + baseSchema, + studentFormSchema, + studentSchema, +} from "@/utils/zod-schemas"; import { zodResolver } from "@hookform/resolvers/zod"; import { signIn, signOut, useSession } from "next-auth/react"; import Script from "next/script"; @@ -31,7 +53,6 @@ import { toast } from "sonner"; import * as z from "zod"; import { PaymentLoading } from "../payment/payment-loading"; import { PaymentSuccessfulComponent } from "../payment/payment-successful"; -import { FileUpload } from "../ui/file-upload"; import { RadioGroup, RadioGroupItem } from "../ui/radio-group"; import InfoButton from "../ui/info-button"; import { redirect } from "next/navigation"; @@ -39,686 +60,755 @@ import { UploadDropzone } from "@uploadthing/react"; import { OurFileRouter } from "@/app/api/uploadthing/core"; declare global { - interface Window { - Razorpay: any; - } + interface Window { + Razorpay: any; + } } type FormSchema = z.infer; type UploadedFile = { - id: string; - files: File[]; + id: string; + files: File[]; }; export default function RegistrationForm() { - const [step, setStep] = useState(1); - const [uploadedFiles, setUploadedFiles] = useState([]); - const [isProcessing, setIsProcessing] = useState(false); - const [success, setSuccess] = useState(false); - const [memberType, setMemberType] = useState<"student" | "faculty" | "external">("external"); - const [pricing, setPricing] = useState({ - basePrice: basePrice, - discountAmount: initialdiscount, - finalPrice: basePrice, - }); + const [step, setStep] = useState(1); + const [isProcessing, setIsProcessing] = useState(false); + const [success, setSuccess] = useState(false); + const [memberType, setMemberType] = useState< + "student" | "faculty" | "external" + >("external"); + const [pricing, setPricing] = useState({ + basePrice: basePrice, + discountAmount: initialdiscount, + finalPrice: basePrice, + }); - const { data: session } = useSession(); + const { data: session } = useSession(); - if (!session) { - redirect("/auth/signin/?callbackUrl=/register"); - } + if (!session) { + redirect("/auth/signin/?callbackUrl=/register"); + } - useEffect(() => { - setMemberType(getSjecMemberType(session?.user.email!)); - setPricing((prevPricing) => ({ - ...prevPricing, - finalPrice: - memberType === "student" - ? sjecStudentPrice - : memberType === "faculty" - ? sjecFacultyPrice - : basePrice, - })); - }, [session?.user.email, memberType]); + useEffect(() => { + setMemberType(getSjecMemberType(session?.user.email!)); + setPricing((prevPricing) => ({ + ...prevPricing, + finalPrice: + memberType === "student" + ? sjecStudentPrice + : memberType === "faculty" + ? sjecFacultyPrice + : basePrice, + })); + }, [session?.user.email, memberType]); - const form = useForm({ - resolver: zodResolver(baseSchema), - defaultValues: { - designation: getSjecMemberType(session?.user.email!), - name: session?.user.name!, - email: session?.user.email!, - phone: "", - entityName: "", - couponCode: "", - foodPreference: "veg", - photo: "", - idCard: "", - }, - }); + const form = useForm({ + resolver: zodResolver(baseSchema), + defaultValues: { + designation: getSjecMemberType(session?.user.email!), + name: session?.user.name!, + email: session?.user.email!, + phone: "", + entityName: "", + couponCode: "", + foodPreference: "veg", + photo: "", + idCard: "", + }, + }); - const handlePayment = async () => { - setIsProcessing(true); - const couponCode = form.getValues("couponCode"); + const handlePayment = async () => { + setIsProcessing(true); + const couponCode = form.getValues("couponCode"); - try { - // Create the order on the backend - const response = await fetch("/api/create-order", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ amount: pricing.finalPrice }), - }); + try { + // Create the order on the backend + const response = await fetch("/api/create-order", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ amount: pricing.finalPrice }), + }); - if (!response.ok) { - throw new Error("Failed to create the order. Please try again."); - } + if (!response.ok) { + throw new Error("Failed to create the order. Please try again."); + } - const data = await response.json(); + const data = await response.json(); - // Razorpay options - const options = { - key: process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID, - amount: pricing.finalPrice * 100, - currency: "INR", - name: "TEDxSJEC", - description: "Registration Fee", - order_id: data.orderId, - handler: async (response: any) => { - try { - const verifyResponse = await fetch("/api/verify-order", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - orderId: response.razorpay_order_id, - razorpayPaymentId: response.razorpay_payment_id, - razorpaySignature: response.razorpay_signature, - amount: pricing.finalPrice, - }), - }); + // Razorpay options + const options = { + key: process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID, + amount: pricing.finalPrice * 100, + currency: "INR", + name: "TEDxSJEC", + description: "Registration Fee", + order_id: data.orderId, + handler: async (response: any) => { + try { + const verifyResponse = await fetch("/api/verify-order", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + orderId: response.razorpay_order_id, + razorpayPaymentId: response.razorpay_payment_id, + razorpaySignature: response.razorpay_signature, + amount: pricing.finalPrice, + }), + }); - if (!verifyResponse.ok) { - throw new Error("Payment verification failed. Please try again."); - } + if (!verifyResponse.ok) { + throw new Error("Payment verification failed. Please try again."); + } - const verificationData = await verifyResponse.json(); + const verificationData = await verifyResponse.json(); - if (verificationData.isOk) { - // Process after successful payment verification - try { - // Invalidate coupon if present - if (couponCode) { - const couponResult = await invalidateCouponCode(couponCode, session!); - if (!couponResult.success) { - toast.error(couponResult.message || "Error invalidating coupon."); - throw new Error("Coupon invalidation failed."); - } - } - - // Submit the form - const formResponse = form.getValues(); - await submitForm(formResponse as FormDataInterface, pricing.finalPrice); - toast.success("✅ Form submitted successfully!"); + if (verificationData.isOk) { + // Process after successful payment verification + try { + // Invalidate coupon if present + if (couponCode) { + const couponResult = await invalidateCouponCode( + couponCode, + session! + ); + if (!couponResult.success) { + toast.error( + couponResult.message || "Error invalidating coupon." + ); + throw new Error("Coupon invalidation failed."); + } + } - // Mark success - setSuccess(true); - } catch (processError) { - console.error("Post-payment processing failed:", processError); - toast.error("An error occurred during post-payment processing."); - } - } else { - throw new Error( - "Payment verification failed: " + getErrorMessage(verificationData.error) - ); - } - } catch (handlerError:any) { - console.error( - "Payment verification or post-payment processing failed:", - handlerError - ); - toast.error(handlerError.message || "An error occurred during payment verification."); - } finally { - setIsProcessing(false); - } - }, - notes: { - name: form.getValues("name"), - email: session?.user?.email, - contact: form.getValues("phone"), - designation: form.getValues("designation"), - foodPreference: form.getValues("foodPreference"), - couponCode: couponCode, - entityName: form.getValues("entityName"), - memberType: memberType, - photo: form.getValues("photo"), - idCard: form.getValues("idCard"), - createdBy: session?.user?.id, - createdAt: new Date().toISOString(), - amount: pricing.finalPrice, - }, - prefill: { - name: form.getValues("name"), - email: session?.user?.email, - contact: form.getValues("phone"), - }, - theme: { - color: "#3399cc", - }, - modal: { - ondismiss: () => { - setIsProcessing(false); - toast.info("Payment process dismissed."); - }, - }, - }; + // Submit the form + const formResponse = form.getValues(); + await submitForm( + formResponse as FormDataInterface, + pricing.finalPrice + ); + toast.success("✅ Form submitted successfully!"); - if (!process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID) { - throw new Error("Razorpay key is missing. Please configure it in your environment."); + // Mark success + setSuccess(true); + } catch (processError) { + console.error("Post-payment processing failed:", processError); + toast.error( + "An error occurred during post-payment processing." + ); + } + } else { + throw new Error( + "Payment verification failed: " + + getErrorMessage(verificationData.error) + ); } - - const rzp1 = new window.Razorpay(options); - rzp1.open(); - } catch (error: any) { - console.error("Payment initiation error:", error); - toast.error(`Payment error: ${getErrorMessage(error)}`); + } catch (handlerError: any) { + console.error( + "Payment verification or post-payment processing failed:", + handlerError + ); + toast.error( + handlerError.message || + "An error occurred during payment verification." + ); + } finally { setIsProcessing(false); - } - }; - - - const onSubmit = async (values: FormSchema) => { - await handlePayment(); - }; + } + }, + notes: { + name: form.getValues("name"), + email: session?.user?.email, + contact: form.getValues("phone"), + designation: form.getValues("designation"), + foodPreference: form.getValues("foodPreference"), + couponCode: couponCode, + entityName: form.getValues("entityName"), + memberType: memberType, + photo: form.getValues("photo"), + idCard: form.getValues("idCard"), + createdBy: session?.user?.id, + createdAt: new Date().toISOString(), + amount: pricing.finalPrice, + }, + prefill: { + name: form.getValues("name"), + email: session?.user?.email, + contact: form.getValues("phone"), + }, + theme: { + color: "#3399cc", + }, + modal: { + ondismiss: () => { + setIsProcessing(false); + toast.info("Payment process dismissed."); + }, + }, + }; - const verifyCoupon = async () => { - const couponCode = form.getValues("couponCode"); - if (!couponCode) { - return; - } - if (couponCode.length !== 10) { - toast.error("Invalid Coupon Code"); - return; - } - try { - const result = await getPrice(couponCode); - if (!result.success) { - toast.error(result.message || "An error occurred while applying the coupon"); - return; - } - const { basePrice, discountAmount, finalPrice } = result; - setPricing({ - basePrice: basePrice ?? pricing.basePrice, - discountAmount: discountAmount ?? pricing.discountAmount, - finalPrice: finalPrice ?? pricing.finalPrice, - }); - toast.success("Coupon applied successfully"); - } catch (e) { - console.error(e); - toast.error(getErrorMessage(e)); - } - }; + if (!process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID) { + throw new Error( + "Razorpay key is missing. Please configure it in your environment." + ); + } - const handleNext = async () => { - let isValid = false; - if (step === 1) { - isValid = await form.trigger(["designation", "foodPreference", "name"]); - } else if (step === 2) { - const designation = form.getValues("designation"); - if (designation === "student") { - form.clearErrors(); - const validationResult = await studentFormSchema.safeParseAsync(form.getValues()); - isValid = validationResult.success; - if (!isValid) { - if (validationResult.error) { - validationResult.error.issues.forEach((issue) => { - form.setError(issue.path[0] as keyof FormSchema, { - type: "manual", - message: issue.message, - }); - }); - } - } - } else { - isValid = await form.trigger(["name", "email", "phone", "photo"]); - } - } + const rzp1 = new window.Razorpay(options); + rzp1.open(); + } catch (error: any) { + console.error("Payment initiation error:", error); + toast.error(`Payment error: ${getErrorMessage(error)}`); + setIsProcessing(false); + } + }; - if (isValid) { - setStep(step + 1); - } - }; + const onSubmit = async (values: FormSchema) => { + await handlePayment(); + }; - if (isProcessing) { - return ( -
- -
+ const verifyCoupon = async () => { + const couponCode = form.getValues("couponCode"); + if (!couponCode) { + return; + } + if (couponCode.length !== 10) { + toast.error("Invalid Coupon Code"); + return; + } + try { + const result = await getPrice(couponCode); + if (!result.success) { + toast.error( + result.message || "An error occurred while applying the coupon" ); + return; + } + const { basePrice, discountAmount, finalPrice } = result; + setPricing({ + basePrice: basePrice ?? pricing.basePrice, + discountAmount: discountAmount ?? pricing.discountAmount, + finalPrice: finalPrice ?? pricing.finalPrice, + }); + toast.success("Coupon applied successfully"); + } catch (e) { + console.error(e); + toast.error(getErrorMessage(e)); } + }; - if (success) { - return ( -
- -
+ const handleNext = async () => { + let isValid = false; + if (step === 1) { + isValid = await form.trigger(["designation", "foodPreference", "name"]); + } else if (step === 2) { + const designation = form.getValues("designation"); + if (designation === "student") { + form.clearErrors(); + const validationResult = await studentFormSchema.safeParseAsync( + form.getValues() ); + isValid = validationResult.success; + if (!isValid) { + if (validationResult.error) { + validationResult.error.issues.forEach((issue) => { + form.setError(issue.path[0] as keyof FormSchema, { + type: "manual", + message: issue.message, + }); + }); + } + } + } else { + isValid = await form.trigger(["name", "email", "phone", "photo"]); + } + } + + if (isValid) { + setStep(step + 1); } + }; + if (isProcessing) { return ( - -