From 9138d994c92b09f0800e6e7ad9ee3f60fab624d8 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Wed, 27 Nov 2024 16:28:24 +0530 Subject: [PATCH 1/9] Refactor sign-in page to handle access denied issue --- src/app/auth/signin/signin-page.tsx | 82 +++++++++++++++++------------ 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/src/app/auth/signin/signin-page.tsx b/src/app/auth/signin/signin-page.tsx index 6ac9886..0acb1bd 100644 --- a/src/app/auth/signin/signin-page.tsx +++ b/src/app/auth/signin/signin-page.tsx @@ -9,40 +9,52 @@ import { useState, useEffect } from "react"; import { tailChase } from "ldrs"; export default function SignIn() { - const router = useRouter(); - const { status } = useSession(); - const searchParams = useSearchParams(); - const [loading, setLoading] = useState(false); - const callbackUrl = searchParams.get("callbackUrl") || "/"; - - useEffect(() => { - if (typeof window !== "undefined") { - tailChase.register(); - } - if (status === "unauthenticated") { - setLoading(true); - signIn("google").catch((error) => { - console.error("Sign in failed:", error); - setLoading(false); - }); - } else if (status === "authenticated") { - router.push(callbackUrl); - } - }, [status, router, callbackUrl]); - - return ( -
- {loading ? ( -
- + const router = useRouter(); + const { status } = useSession(); + const searchParams = useSearchParams(); + const [loading, setLoading] = useState(false); + const callbackUrl = searchParams.get("callbackUrl") || "/"; + + useEffect(() => { + if (typeof window !== "undefined") { + tailChase.register(); + } + const userAgent = window.navigator.userAgent; + const url = window.location.href; + + // Check for LinkedIn and Instagram app on iPhone/iPad and redirect + if ( + userAgent.includes("Mobile") && + (userAgent.includes("iPhone") || userAgent.includes("iPad")) && + (userAgent.includes("LinkedInApp") || userAgent.includes("Instagram")) + ) { + window.location.href = "x-safari-" + url; + return; + } + + console.log("user-Agent " + userAgent); + console.log("url = " + url); + + if (status === "unauthenticated") { + setLoading(true); + signIn("google").catch((error) => { + console.error("Sign in failed:", error); + setLoading(false); + }); + } else if (status === "authenticated") { + router.push(callbackUrl); + } + }, [status, router, callbackUrl]); + + return ( +
+ {loading ? ( +
+ +
+ ) : ( +

Redirecting...

+ )}
- ) : ( -

Redirecting...

- )} -
- ); + ); } From 27c35c1d62b4a57828da38a139c3997575468730 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Wed, 27 Nov 2024 20:29:31 +0530 Subject: [PATCH 2/9] added backbutton component --- src/app/(legal)/privacy/page.tsx | 85 +++++++++++--------------------- 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/src/app/(legal)/privacy/page.tsx b/src/app/(legal)/privacy/page.tsx index d4afd27..68e3c89 100644 --- a/src/app/(legal)/privacy/page.tsx +++ b/src/app/(legal)/privacy/page.tsx @@ -1,68 +1,43 @@ "use client"; +import BackButton from "@/components/shared/back-button"; import Container from "@/components/shared/container"; import { Text } from "@/components/shared/text"; import { legalInfo } from "@/data/legal-info"; import { cn } from "@/lib/utils"; -import { useRouter } from "next/navigation"; + export default function PrivacyPolicy() { - const router = useRouter(); - return ( - -
-
- -
+ + return ( + +
+ - - Privacy Policy - + + Privacy Policy + -
- {legalInfo.Privacy.map((privacy, index) => ( -
- - {privacy.title} - +
+ {legalInfo.Privacy.map((privacy, index) => ( +
+ + {privacy.title} + -

- {privacy.description} -

+

+ {privacy.description} +

+
+ ))} +
- ))} -
-
-
- ); + + ); } From 13f70fbe5d68f1ab79d8a7540472898a04de66e3 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Wed, 27 Nov 2024 20:30:24 +0530 Subject: [PATCH 3/9] add : backbutton component for refund page and terms --- src/app/(legal)/refund/page.tsx | 22 +-------- src/app/(legal)/terms/page.tsx | 83 ++++++++++++--------------------- 2 files changed, 31 insertions(+), 74 deletions(-) diff --git a/src/app/(legal)/refund/page.tsx b/src/app/(legal)/refund/page.tsx index 424c509..e9d1d52 100644 --- a/src/app/(legal)/refund/page.tsx +++ b/src/app/(legal)/refund/page.tsx @@ -1,5 +1,6 @@ "use client"; +import BackButton from "@/components/shared/back-button"; import Container from "@/components/shared/container"; import { Text } from "@/components/shared/text"; import { legalInfo } from "@/data/legal-info"; @@ -12,26 +13,7 @@ export default function Refund() { return (
-
- -
+ {/* Title Section */}
diff --git a/src/app/(legal)/terms/page.tsx b/src/app/(legal)/terms/page.tsx index d1dd148..42a725d 100644 --- a/src/app/(legal)/terms/page.tsx +++ b/src/app/(legal)/terms/page.tsx @@ -1,5 +1,6 @@ "use client"; +import BackButton from "@/components/shared/back-button"; import Container from "@/components/shared/container"; import { Text } from "@/components/shared/text"; import { Button } from "@/components/ui/button"; @@ -9,59 +10,33 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; export default function TermsAndConditions() { - const router = useRouter(); - return ( - -
-
- -
- - Terms and Conditions - -
- {legalInfo.Terms.map((terms, index) => ( -
- - {terms.title} - -

- {terms.description} -

+ const router = useRouter(); + return ( + +
+ + + Terms and Conditions + +
+ {legalInfo.Terms.map((terms, index) => ( +
+ + {terms.title} + +

+ {terms.description} +

+
+ ))} +
- ))} -
-
- - ); + + ); } From bfd3560e445b7ec6e98657cd075cf4ff4209efa5 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Wed, 27 Nov 2024 20:30:46 +0530 Subject: [PATCH 4/9] Backbutton component --- src/components/shared/back-button.tsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/components/shared/back-button.tsx diff --git a/src/components/shared/back-button.tsx b/src/components/shared/back-button.tsx new file mode 100644 index 0000000..bc11ed7 --- /dev/null +++ b/src/components/shared/back-button.tsx @@ -0,0 +1,26 @@ +"use client"; +import { cn } from "@/lib/utils"; +import { useRouter } from "next/navigation"; +export default function BackButton({ className }: { className?: string }) { + const router = useRouter(); + return ( +
+ +
+ ); + +} \ No newline at end of file From dfc7e39461ffc3d4bd9d4c37f9017730e4ff749a Mon Sep 17 00:00:00 2001 From: vyshnav Date: Wed, 27 Nov 2024 23:20:53 +0530 Subject: [PATCH 5/9] Refactor team-section component and add show more button --- src/components/common/team-section.tsx | 132 +++++++++++++------------ 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/src/components/common/team-section.tsx b/src/components/common/team-section.tsx index 3a02b69..442f4ba 100644 --- a/src/components/common/team-section.tsx +++ b/src/components/common/team-section.tsx @@ -1,69 +1,79 @@ +"use client"; + +import { useState } from "react"; import { tedxsjecAssetsPrefix } from "@/lib/utils"; import TeamCard from "./team-card"; +import { Button } from "../ui/button"; +import Link from "next/link"; -const team = [ - { - url: `${tedxsjecAssetsPrefix}/team/sharon.avif`, - title: "Organizer & Licensee", - id: 1, - name: "Sharon Tyana Menezes", - }, - { - url: `${tedxsjecAssetsPrefix}/team/sasha.avif`, - title: "Co-Organizer", - id: 2, - name: "Sasha Sajith", - }, - { - url: `${tedxsjecAssetsPrefix}/team/hanniele.avif`, - title: "Technical Head", - id: 3, - name: "Hanniel Andrade", - }, - { - url: `${tedxsjecAssetsPrefix}/team/vyasa.avif`, - title: "Curation Head", - id: 4, - name: "Vyasa M Nayak", - }, - { - url: `${tedxsjecAssetsPrefix}/team/kaneeksha.avif`, - title: "Publicity & Promotions Head", - id: 5, - name: "Kaneeksha Kiran", - }, - { - url: `${tedxsjecAssetsPrefix}/team/lawrence.avif`, - title: "Design Head", - id: 6, - name: "Lawrence Robert D'Souza", - }, - - { - url: `${tedxsjecAssetsPrefix}/team/larsen.avif`, - title: "Creative Head", - id: 8, - name: "Larsen Lionel Dsouza", - }, - { - url: `${tedxsjecAssetsPrefix}/team/ritesh.avif`, - title: "Creative Head", - id: 9, - name: "Ritesh", - }, - { - url: `${tedxsjecAssetsPrefix}/team/anupam.avif`, - title: "Logistics Head", - id: 9, - name: "Anupam B Shetty", - }, +const coreTeam = [ + { + url: `${tedxsjecAssetsPrefix}/team/sharon.avif`, + title: "Organizer & Licensee", + id: 1, + name: "Sharon Tyana Menezes", + }, + { + url: `${tedxsjecAssetsPrefix}/team/sasha.avif`, + title: "Co-Organizer", + id: 2, + name: "Sasha Sajith", + }, + { + url: `${tedxsjecAssetsPrefix}/team/hanniele.avif`, + title: "Technical Head", + id: 3, + name: "Hanniel Andrade", + }, + { + url: `${tedxsjecAssetsPrefix}/team/vyasa.avif`, + title: "Curation Head", + id: 4, + name: "Vyasa M Nayak", + }, + { + url: `${tedxsjecAssetsPrefix}/team/kaneeksha.avif`, + title: "Publicity & Promotions Head", + id: 5, + name: "Kaneeksha Kiran", + }, + { + url: `${tedxsjecAssetsPrefix}/team/lawrence.avif`, + title: "Design Head", + id: 6, + name: "Lawrence Robert D'Souza", + }, + { + url: `${tedxsjecAssetsPrefix}/team/larsen.avif`, + title: "Creative Head", + id: 7, + name: "Larsen Lionel Dsouza", + }, + { + url: `${tedxsjecAssetsPrefix}/team/ritesh.avif`, + title: "Creative Head", + id: 8, + name: "Ritesh", + }, + { + url: `${tedxsjecAssetsPrefix}/team/anupam.avif`, + title: "Logistics Head", + id: 9, + name: "Anupam B Shetty", + }, ]; const Team = () => { - return ( -
- -
- ); + return ( +
+ + + + +
+ ); }; + export default Team; From e983303279f11397b75b2ba503345c6c1a8508fe Mon Sep 17 00:00:00 2001 From: vyshnav Date: Wed, 27 Nov 2024 23:21:26 +0530 Subject: [PATCH 6/9] refactor reg form for better error handling --- src/components/common/registration-form.tsx | 1115 ++++++++++--------- 1 file changed, 561 insertions(+), 554 deletions(-) diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index c206dc7..a0d9dd5 100644 --- a/src/components/common/registration-form.tsx +++ b/src/components/common/registration-form.tsx @@ -4,47 +4,25 @@ 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 { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, + 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 { useUploadThing } from "@/utils/uploadthing"; -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"; @@ -60,444 +38,476 @@ import InfoButton from "../ui/info-button"; import { redirect } from "next/navigation"; 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 { data: session } = useSession(); - - 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]); - - 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", - }, - }); - - const { startUpload, routeConfig } = useUploadThing("imageUploader", { - onClientUploadComplete: (res) => { - if (res && res.length == 2) { - form.setValue("idCard", res[0].url); - form.setValue("photo", res[1].url); - } - if (res && res.length == 1) { - form.setValue("photo", res[0].url); - } - toast.success("✅ Images uploaded successfully!"); - }, - onUploadError: () => { - toast.error("error occurred while uploading"); - }, - // onUploadBegin: (file) => { - // toast.info(" upload has begun "); - // }, - }); - - 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 }]; - } + 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 { data: session } = useSession(); + + 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]); + + 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", + }, }); - form.setValue(id, files.map((file) => file.name).join(", ")); - }; - - const handlePayment = async () => { - setIsProcessing(true); - const couponCode = form.getValues("couponCode"); - try { - const response = await fetch("/api/create-order", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ amount: pricing.finalPrice }), - }); - const data = await response.json(); - - 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) => { - const resp = 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, - }), - }); - - const data = await resp.json(); - if (data.isOk) { + const { startUpload, routeConfig } = useUploadThing("imageUploader", { + onClientUploadComplete: (res) => { + if (!res || res.length === 0) { + toast.error("No files uploaded. Please try again."); + return; + } + try { - if (uploadedFiles.length > 0) { - const allFiles = uploadedFiles.flatMap((file) => file.files); - if (allFiles.length > 0) { - await startUpload(allFiles); + 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); } - } - if (couponCode) { - const result = await invalidateCouponCode(couponCode, session!); - if (!result.success) { - toast.error( - result.message || - "An error occurred while invalidating the coupon" - ); - } - } - const formResponse = form.getValues(); - await submitForm( - formResponse as FormDataInterface, - pricing.finalPrice - ); - setIsProcessing(false); - setSuccess(true); + toast.success("✅ Images uploaded successfully!"); } catch (error) { - setIsProcessing(false); - toast.error(`Payment failed: ${getErrorMessage(data.error)}`); + console.error("Error processing upload response:", error); + toast.error("Error processing uploaded files."); } - } else { - setIsProcessing(false); - toast.error(`Payment failed: ${getErrorMessage(data.error)}`); - } - }, - notes: { - customerName: form.getValues("name"), - customerEmail: session?.user?.email, - customerContact: form.getValues("phone"), }, - prefill: { - name: form.getValues("name"), - email: session?.user?.email, - contact: form.getValues("phone"), + onUploadError: (error) => { + console.error("Upload error:", error); + toast.error("Image upload failed. Please try again later."); }, - theme: { - color: "#3399cc", - }, - modal: { - ondismiss: () => { + }); + + 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"); + + 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."); + } + + 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, + }), + }); + + if (!verifyResponse.ok) { + throw new Error("Payment verification failed. Please try again."); + } + + const verificationData = await verifyResponse.json(); + + if (verificationData.isOk) { + // Process after successful payment verification + try { + if (uploadedFiles.length > 0) { + const allFiles = uploadedFiles.flatMap((file) => file.files); + + if (allFiles.length > 0) { + await startUpload(allFiles); + toast.success("✅ Files uploaded successfully!"); + } else { + toast.warning("⚠️ No files to upload."); + } + } + + // 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!"); + + // 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: { + customerName: form.getValues("name"), + customerEmail: session?.user?.email, + customerContact: form.getValues("phone"), + }, + 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."); + }, + }, + }; + + if (!process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID) { + throw new Error("Razorpay key is missing. Please configure it in your environment."); + } + + 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); - }, - }, - }; - const rzp1 = new window.Razorpay(options); - rzp1.open(); - } catch (error) { - toast.error(`Payment error: ${getErrorMessage(error)}`); - setIsProcessing(false); - } - }; + } + }; - const onSubmit = async (values: FormSchema) => { - await handlePayment(); - }; - 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)); - } - }; - - 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, - }); + const onSubmit = async (values: FormSchema) => { + await handlePayment(); + }; + + 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)); + } + }; + + 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); } - } else { - isValid = await form.trigger(["name", "email", "phone", "photo"]); - } + }; + + if (isProcessing) { + return ( +
+ +
+ ); } - if (isValid) { - setStep(step + 1); + if (success) { + return ( +
+ +
+ ); } - }; - if (isProcessing) { return ( -
- -
- ); - } + +