Skip to content

Commit

Permalink
pbctf-registration-page added
Browse files Browse the repository at this point in the history
  • Loading branch information
alfiyafatima09 committed Sep 21, 2024
1 parent c603989 commit 787df06
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 6 deletions.
41 changes: 41 additions & 0 deletions app/(default)/pbctf/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client";
import PBCTFForm from "@/components/forms/pbctfForm";
import DotPattern from "@/components/magicui/dot-pattern";
import { cn } from "@/lib/utils";
import { onAuthStateChanged } from "firebase/auth";
import { auth } from "@/Firebase";
import { useEffect } from "react";
import { useRouter } from "next/navigation";

const PBCTFRegisterPage = () => {
const router = useRouter();

useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (!user) {
router.push("/login");
}
});
}, [router]);

return (
<div className="min-h-screen flex items-center justify-center py-6 px-4 sm:px-6 lg:px-8 relative overflow-hidden">
<div className="w-full max-w-2xl space-y-8 relative z-10">
<PBCTFForm />
</div>
<DotPattern
width={20}
height={20}
cx={1}
cy={1}
cr={1}
className={cn(
"absolute inset-0 scale-150 opacity-50 [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]"
)}
/>
</div>
);
};

export default PBCTFRegisterPage;

5 changes: 4 additions & 1 deletion app/css/additional-styles/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,7 @@ html {
-webkit-transform: translate3d(10px, 0, 0) scale(1.2);
transform: translate3d(10px, 0, 0) scale(1.2);
}
}
}



314 changes: 314 additions & 0 deletions components/forms/pbctfForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
"use client";
import "../../app/css/additional-styles/utility-patterns.css";
import "../../app/css/additional-styles/theme.css";
import { useEffect, useState } from "react";
import { useForm, SubmitHandler } from "react-hook-form";
import { collection, addDoc } from "firebase/firestore";
import { db } from "@/Firebase";
import { branches } from "@/lib/constants/dropdownOptions";
import { Press_Start_2P } from "next/font/google";

const pressStart2P = Press_Start_2P({
weight: "400",
subsets: ["latin"],
});

type ParticipantData = {
name: string;
year: string;
branch: string;
usn: string;
email: string;
phone: string;
};

type FormData = {
participationType: "solo" | "duo";
participant1: ParticipantData;
participant2?: ParticipantData;
};

const PBCTFForm: React.FC = () => {
const [isSuccess, setSuccess] = useState<boolean>(false);
const [participationType, setParticipationType] = useState<"solo" | "duo">(
"solo"
);
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);

const [headingText, setHeadingText] = useState("");
const heading = "Be a Part of PBCTF Register Now!";

useEffect(() => {
let currentIndex = 0;
let timeoutId: NodeJS.Timeout;

const typeEffect = () => {
if (currentIndex <= heading.length) {
setHeadingText(heading.substring(0, currentIndex));
currentIndex++;
timeoutId = setTimeout(typeEffect, 200); // Typing speed
}
};

typeEffect();

return () => clearTimeout(timeoutId);
}, []);

const {
register,
handleSubmit,
formState: { errors },
watch,
} = useForm<FormData>();

const watchYear1 = watch("participant1.year");
const watchYear2 = watch("participant2.year");

const onSubmit: SubmitHandler<FormData> = async (data) => {
if (isSubmitting) return;
setIsSubmitting(true);
try {
await addDoc(collection(db, "pbctf_registrations"), data);
setSuccess(true);
} catch (error) {
console.error("Error submitting form:", error);
} finally {
setIsSubmitting(false);
}
};
if (isSuccess) {
return (
<div className="w-full max-w-md mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex flex-col p-6 sm:p-8 rounded-lg shadow-lg bg-black bg-opacity-30 backdrop-blur-lg border border-green-500">
<div className="flex flex-col items-center text-center">
<div className="inline-block p-4 bg-green-500 rounded-full animate-bounce">
<svg
className="w-8 h-8 text-white"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 13l4 4L19 7"
/>
</svg>
</div>
<h2 className="mt-4 text-2xl sm:text-3xl font-bold text-green-500">
Registration Successful!
</h2>
<p className="mt-4 text-lg text-gray-300 leading-relaxed">
You have successfully registered for the PBCTF!
</p>
<p className="mt-2 text-md text-gray-400 leading-relaxed">
Join the WhatsApp Group for further updates immediately.
</p>
</div>
<div className="flex mx-auto items-center mt-6">
<a
href="https://chat.whatsapp.com/GmI6EGCxLInHJ8gclb1ZlS"
className="w-full"
>
<button className="w-full px-6 py-3 bg-green-500 hover:bg-green-600 text-white text-lg font-semibold rounded-full transition duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opacity-50">
Join WhatsApp Group!
</button>
</a>
</div>
</div>
</div>
);
}

const renderParticipantFields = (participantNumber: 1 | 2) => (
<div className="mb-4">
<h3 className="h3 mb-2">Participant {participantNumber}</h3>
<div className="space-y-3">
<div>
<input
{...register(`participant${participantNumber}.name` as const, {
required: "Name required",
})}
placeholder="Name"
className="w-full px-4 py-2 border rounded-md bg-transparent form-input focus:border-0 focus:outline-offset-0 focus:outline-green-500"
/>
{errors[`participant${participantNumber}`]?.name && (
<p className="mt-1 text-xs text-red-500">
{errors[`participant${participantNumber}`]?.name?.message}
</p>
)}
</div>
<div className="grid grid-cols-2 gap-3">
<div>
<select
{...register(`participant${participantNumber}.year` as const, {
required: "Year required",
})}
className="w-full px-4 py-2 border rounded-md bg-transparent form-input focus:border-0 focus:outline-offset-0 focus:outline-green-500"
>
<option value="" className="bg-black">
Select Year
</option>
<option value="1" className="bg-black">
1st Year
</option>
<option value="2" className="bg-black">
2nd Year
</option>
<option value="3" className="bg-black">
3rd Year
</option>
<option value="4" className="bg-black">
4th Year
</option>
</select>
{errors[`participant${participantNumber}`]?.year && (
<p className="mt-1 text-xs text-red-500">
{errors[`participant${participantNumber}`]?.year?.message}
</p>
)}
</div>
<div>
<select
{...register(`participant${participantNumber}.branch` as const, {
required: "Branch required",
})}
className="w-full px-4 py-2 border rounded-md bg-transparent form-input focus:border-0 focus:outline-offset-0 focus:outline-green-500"
>
<option value="" className="bg-black">
Select Branch
</option>
{branches.map((branch, index) => (
<option key={index} value={branch} className="bg-black">
{branch}
</option>
))}
</select>
{errors[`participant${participantNumber}`]?.branch && (
<p className="mt-1 text-xs text-red-500">
{errors[`participant${participantNumber}`]?.branch?.message}
</p>
)}
</div>
</div>
<div>
<input
{...register(`participant${participantNumber}.usn` as const, {
required: "USN required",
pattern: {
value:
(participantNumber === 1 && watchYear1 === "1") ||
(participantNumber === 2 && watchYear2 === "1")
? /^[1-9][0-9][A-Z]{4}[0-9]{4}$/
: /^1DS[1-3][0-9][A-Z]{2}[0-9]{3}$/,
message: "Invalid USN",
},
})}
placeholder="USN"
className="w-full px-4 py-2 border rounded-md bg-transparent form-input focus:border-0 focus:outline-offset-0 focus:outline-green-500"
/>
{errors[`participant${participantNumber}`]?.usn && (
<p className="mt-1 text-xs text-red-500">
{errors[`participant${participantNumber}`]?.usn?.message}
</p>
)}
</div>
<div>
<input
{...register(`participant${participantNumber}.email` as const, {
required: "Email required",
pattern: {
value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message: "Invalid email address",
},
})}
placeholder="Email"
className="w-full px-4 py-2 border rounded-md bg-transparent form-input focus:border-0 focus:outline-offset-0 focus:outline-green-500"
/>
{errors[`participant${participantNumber}`]?.email && (
<p className="mt-1 text-xs text-red-500">
{errors[`participant${participantNumber}`]?.email?.message}
</p>
)}
</div>
<div>
<input
{...register(`participant${participantNumber}.phone` as const, {
required: "Phone required",
pattern: {
value: /^[6-9]\d{9}$/,
message: "Invalid phone number (10 digits starting with 6-9)",
},
})}
placeholder="Phone Number"
maxLength={10} // Restrict to 10 digits
type="tel" // Show numeric keyboard on mobile
className="w-full px-4 py-2 border rounded-md bg-transparent form-input focus:border-0 focus:outline-offset-0 focus:outline-green-500"
/>
{errors[`participant${participantNumber}`]?.phone && (
<p className="mt-1 text-xs text-red-500">
{errors[`participant${participantNumber}`]?.phone?.message}
</p>
)}
</div>
</div>
</div>
);

return (
<div className="max-w-3xl mx-auto p-4 sm:p-6 rounded-lg mt-10">
<h1
className={`${pressStart2P.className} md:text-2xl sm:text-sm font-bold mb-6 text-center text-green-500`}
style={{
textShadow: "2px 2px 0px #000",
letterSpacing: "2px",
minHeight: "3rem",
}}
>
{headingText}
</h1>
<form
onSubmit={handleSubmit(onSubmit)}
className="space-y-6 sm:mx-auto md:mx-20"
>
<div>
<label className="block mb-2">
Participation Type<span className="text-red-600"> * </span>
</label>
<select
{...register("participationType", { required: true })}
onChange={(e) =>
setParticipationType(e.target.value as "solo" | "duo")
}
className="w-full px-4 py-2 border rounded-md bg-transparent form-input focus:border-0 focus:outline-offset-0 focus:outline-green-500"
>
<option value="solo" className="bg-black">
Solo
</option>
<option value="duo" className="bg-black">
Duo
</option>
</select>
</div>

{renderParticipantFields(1)}
{participationType === "duo" && renderParticipantFields(2)}

<div className="flex justify-center w-full">
<button
type="submit"
disabled={isSubmitting}
className="w-1/2 bg-green-500 text-white rounded-full py-2 px-4 text-base font-semibold hover:bg-green-600 transition duration-300 transform hover:scale-105 disabled:bg-gray-500 disabled:cursor-not-allowed disabled:hover:scale-100 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opacity-50 mx-auto"
>
{isSubmitting ? "Submitting..." : "Submit"}
</button>
</div>
</form>
</div>
);
};

export default PBCTFForm;
Loading

0 comments on commit 787df06

Please sign in to comment.