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} +

+
+ ))} +
- ))} -
-
-
- ); + + ); } diff --git a/src/app/(legal)/refund/page.tsx b/src/app/(legal)/refund/page.tsx index 424c509..57db428 100644 --- a/src/app/(legal)/refund/page.tsx +++ b/src/app/(legal)/refund/page.tsx @@ -1,69 +1,48 @@ "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 Link from "next/link"; // To create a back link -import { useRouter } from "next/navigation"; export default function Refund() { - const router = useRouter(); - return ( - -
-
- -
+ return ( + +
+ - {/* Title Section */} -
- - Refund Policy - -
+ {/* Title Section */} +
+ + Refund Policy + +
- {/* Policy Sections */} -
- {legalInfo.Refund.map((refund, index) => ( -
- {/* Section Title */} - - {refund.title} - + {/* Policy Sections */} +
+ {legalInfo.Refund.map((refund, index) => ( +
+ {/* Section Title */} + + {refund.title} + - {/* Section Description */} -

+ {/* Section Description */} +

+
+ ))} +
- ))} -
-
-
- ); + + ); } diff --git a/src/app/(legal)/terms/page.tsx b/src/app/(legal)/terms/page.tsx index d1dd148..5d4f8ca 100644 --- a/src/app/(legal)/terms/page.tsx +++ b/src/app/(legal)/terms/page.tsx @@ -1,67 +1,40 @@ "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"; import { legalInfo } from "@/data/legal-info"; import { cn } from "@/lib/utils"; -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} -

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

+ {terms.description} +

+
+ ))} +
- ))} -
-
- - ); + + ); } 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...

- )} -
- ); + ); } diff --git a/src/app/team/page.tsx b/src/app/team/page.tsx new file mode 100644 index 0000000..bf42360 --- /dev/null +++ b/src/app/team/page.tsx @@ -0,0 +1,103 @@ +"use client"; + +import { tedxsjecAssetsPrefix } from "@/lib/utils"; +import TeamCard from "@/components/common/team-card"; + +import BackButton from "@/components/shared/back-button"; +const webAndDesignTeam = [ + { + url: `${tedxsjecAssetsPrefix}/team/joywin.avif`, + title: "Web Lead", + id: 1, + name: "Joywin Bennis", + }, + { + url: `${tedxsjecAssetsPrefix}/team/vyshnav.avif`, + title: "Full Stack ", + id: 2, + name: "Vyshnav K", + }, + { + url: `${tedxsjecAssetsPrefix}/team/charis.avif`, + title: "Frontend ", + id: 3, + name: "Charis Pinto", + }, + { + url: `${tedxsjecAssetsPrefix}/team/pranav.avif`, + title: "Frontend ", + id: 4, + name: "Pranavv", + }, + { + url: `${tedxsjecAssetsPrefix}/team/santhishm.avif`, + title: "Frontend ", + id: 5, + name: "Santhishm", + }, + { + url: `${tedxsjecAssetsPrefix}/team/naveen.avif`, + title: "UI/UX Designer", + id: 6, + name: "Naveen", + }, + { + url: `${tedxsjecAssetsPrefix}/team/joshua.avif`, + title: "App Developer", + id: 7, + name: "Joshua", + }, + { + url: `${tedxsjecAssetsPrefix}/team/rachan.avif`, + title: "Design", + id: 8, + name: "Rachan Karkera", + }, + { + url: `${tedxsjecAssetsPrefix}/team/nihaal.avif`, + title: "Design", + id: 9, + name: "Nihaal Y K", + }, + { + url: `${tedxsjecAssetsPrefix}/team/uthpal.avif`, + title: "Design", + id: 10, + name: "Uthpal", + }, + { + url: `${tedxsjecAssetsPrefix}/team/deric.avif`, + title: "Design", + id: 11, + name: "Deric Jojo", + }, + { + url: `${tedxsjecAssetsPrefix}/team/alston.avif`, + title: "Design", + id: 12, + name: "Alston Peter", + }, + { + url: `${tedxsjecAssetsPrefix}/team/dhanush.avif`, + title: "Design", + id: 13, + name: "Dhanush D", + }, + +]; + +export default function Teams() { + return ( +
+
+ +

+ The Web Team and Design Team +

+
+ +
+
+
+ ); +} diff --git a/src/components/common/registration-form.tsx b/src/components/common/registration-form.tsx index c206dc7..8708fd5 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,479 @@ 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, }); - 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 { 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 === 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 (couponCode) { - const result = await invalidateCouponCode(couponCode, session!); - if (!result.success) { - toast.error( - result.message || - "An error occurred while invalidating the coupon" - ); + 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); } - } - 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 inform us at support.tedx@sjec.ac.in or click the contact us button at buttom right corner."); }, - 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) { + 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!); + 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 ( -
- -
- ); - } + +