Skip to content

Commit

Permalink
Merge pull request #74 from kamini08/main
Browse files Browse the repository at this point in the history
  • Loading branch information
SkySingh04 authored Sep 22, 2024
2 parents e2a334a + 6e0d1c3 commit 9dcb568
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 71 deletions.
64 changes: 64 additions & 0 deletions app/(default)/api/registration/pbctf/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { db } from "@/Firebase";

import { recruitValidate } from "@/lib/server/utils";

import {
addDoc,
collection,
getDocs,
limit,
query,
where,
} from "firebase/firestore";
import { NextResponse } from "next/server";

// Add a new registration
export async function POST(request: Request) {
const formData = await request.json();
const { recaptcha_token } = formData;


const recaptchaToken = recaptcha_token;

const details = {
event: {
token: recaptchaToken,
siteKey: process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY,
},
};


if (!recaptchaToken) {
return NextResponse.json(
{
message: "reCAPTCHA token not found! Try again",
error: "reCAPTCHA token not found!",
},
{
status: 500,
}
);
}

// Verify the reCATPTCHA token

const recaptchaResponse = await fetch(
`https://recaptchaenterprise.googleapis.com/v1/projects/${process.env.RECAPTCHA_PROJECT}/assessments?key=${process.env.RECAPTCHA_API_KEY}`,
{
method: "POST",
body: JSON.stringify(details),
}
);

const recaptchaResult = await recaptchaResponse.json();
console.log(recaptchaResult.riskAnalysis.score);
if (recaptchaResult.riskAnalysis.score < 0.7) {
return NextResponse.json({
message: "reCAPTCHA validation failed",
error: recaptchaResult["error-codes"],
});
}

// Return a response
return NextResponse.json({ message: "Recaptcha validated!" });
}
14 changes: 7 additions & 7 deletions app/(default)/pbctf/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import { useRouter } from "next/navigation";
const PBCTFRegisterPage = () => {
const router = useRouter();

useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (!user) {
router.push("/login");
}
});
}, [router]);
// 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">
Expand Down
20 changes: 10 additions & 10 deletions app/(default)/recruitment/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ import { useRouter } from "next/navigation";
const RegisterPage = () => {
const router = useRouter();

// useEffect(() => {
// onAuthStateChanged(auth, (user) => {
// if (!user) {
// router.push("/login");
// }
// });
// });\
// useEffect(() => {
// router.push("/");
// })
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (!user) {
router.push("/login");
}
});
});
useEffect(() => {
router.push("/");
})
return (
<div className="w-50 mt-16 mx-auto flex flex-col items-center justify-center">
<div className="form-container my-2">
Expand Down
2 changes: 1 addition & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function RootLayout({
<head>
<Script
src={`https://www.google.com/recaptcha/enterprise.js?render=${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`}
strategy="lazyOnload" // Set reCAPTCHA ready state when the script is loaded
strategy="beforeInteractive"
/>
</head>
<body
Expand Down
27 changes: 27 additions & 0 deletions components/forms/pbctfForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { collection, addDoc, query, where, getDocs } from "firebase/firestore";
import { db } from "@/Firebase";
import { branches } from "@/lib/constants/dropdownOptions";
import { Press_Start_2P } from "next/font/google";
import toast from "react-hot-toast";

const pressStart2P = Press_Start_2P({
weight: "400",
Expand All @@ -33,6 +34,7 @@ const PBCTFForm: React.FC = () => {
const [participationType, setParticipationType] = useState<"solo" | "duo">("solo");
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const [usnError, setUsnError] = useState<string | null>(null);
const [token, setToken] = useState<string | null>();

const [headingText, setHeadingText] = useState("");
const heading = "Be a Part of PBCTF Register Now!";
Expand Down Expand Up @@ -66,6 +68,10 @@ const PBCTFForm: React.FC = () => {
const watchUsn1 = watch("participant1.usn");
const watchUsn2 = watch("participant2.usn");

const setTokenFunc = (getToken: string) => {
setToken(getToken);
};

const checkUsnUniqueness = async (usn: string): Promise<boolean> => {
const q = query(collection(db, "pbctf_registrations"),
where("participant1.usn", "==", usn));
Expand All @@ -88,6 +94,27 @@ const PBCTFForm: React.FC = () => {
setUsnError(null);

try {

grecaptcha.enterprise.ready(async () => {
const token = await grecaptcha.enterprise.execute(
process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY
);
setTokenFunc(token);
});

const recaptcha_token = token;
const response = await fetch("/api/registration/pbctf", {
method: "POST",
body: JSON.stringify({recaptcha_token}),
});

const res = await response.json();

if (!response.ok || res.error) {
toast.error(res.message);
return;
}

// Check if USNs are the same for duo participation
if (data.participationType === "duo" && data.participant2 && data.participant1.usn === data.participant2.usn) {
setUsnError("USNs for Participant 1 and Participant 2 cannot be the same");
Expand Down
22 changes: 15 additions & 7 deletions components/forms/recruitmentForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { useForm, SubmitHandler } from "react-hook-form";
import { years, branches } from "@/lib/constants/dropdownOptions";
import Success from "./success";
import toast from "react-hot-toast";
import { getErrorMessage, fetchCsrfToken } from "@/lib/client/clientUtils";
import { getErrorMessage } from "@/lib/client/clientUtils";

const RecruitmentForm: React.FC = () => {
const [isSuccess, setSuccess] = useState<boolean>(false);
const [mode, setMode] = useState<boolean>(false);
const [display, setDisplay] = useState<boolean>(false);
const [token, setToken] = useState("");

const [token, setToken] = useState<string | null>();
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);

const {
register,
Expand Down Expand Up @@ -41,6 +41,9 @@ const RecruitmentForm: React.FC = () => {
};

const onSubmit: SubmitHandler<any> = async (data: any) => {

if (isSubmitting) return;
setIsSubmitting(true);
try {
grecaptcha.enterprise.ready(async () => {
const token = await grecaptcha.enterprise.execute(
Expand Down Expand Up @@ -68,6 +71,8 @@ const RecruitmentForm: React.FC = () => {
} catch (error) {
console.error("Error submitting form:", error);
toast.error(getErrorMessage(error));
} finally {
setIsSubmitting(false);
}
};

Expand Down Expand Up @@ -232,10 +237,13 @@ const RecruitmentForm: React.FC = () => {
<input
{...register("whatsapp_number", {
required: "Whatsapp Number is required",
pattern: {
value: /^[6-9]\d{9}$/,
message: "Invalid phone number (10 digits starting with 6-9)",
},
})}
maxLength={10}
name="whatsapp_number"
type="tel"
pattern="[1-9]{1}[0-9]{9}"
placeholder="Enter your whatsapp number"
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"
/>
Expand Down Expand Up @@ -266,10 +274,10 @@ const RecruitmentForm: React.FC = () => {

<button
type="submit"
disabled={isSuccess}
disabled={isSubmitting}
className="bg-green-500 text-white rounded-lg py-2 px-4 hover:bg-green-600 "
>
Submit
{isSubmitting ? "Submitting..." : "Submit"}
</button>
</div>
</form>
Expand Down
76 changes: 30 additions & 46 deletions components/forms/success.tsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,50 @@


export default function Success(props: any) {
return (
<div className="w-full mx-auto">
<div className="flex flex-col p-5 rounded-lg shadow">

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-300 rounded-full">
<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"
x="0px"
y="0px"
width="100"
height="100"
viewBox="0 0 64 64"
>
<circle cx="32" cy="32" r="23" fill="#98c900"></circle>
<path
fill="#fff"
d="M31.921,13.966c2.577,0,4.674-1.957,4.946-4.461c-1.594-0.349-3.247-0.539-4.946-0.539 c-12.703,0-23,10.297-23,23c0,1.699,0.19,3.352,0.539,4.946c2.505-0.272,4.461-2.369,4.461-4.946 C13.921,22.041,21.997,13.966,31.921,13.966z"
opacity=".3"
></path>
<path
d="M54.382,27.021c-2.505,0.272-4.461,2.369-4.461,4.946c0,9.925-8.075,18-18,18 c-2.577,0-4.674,1.957-4.946,4.461c1.594,0.349,3.247,0.539,4.946,0.539c12.703,0,23-10.297,23-23 C54.921,30.268,54.732,28.614,54.382,27.021z"
opacity=".15"
></path>
<path
fill="none"
stroke="#fff"
stroke-linecap="round"
stroke-linejoin="round"
stroke-miterlimit="10"
stroke-width="3"
d="M14.968,23.393c1.878-3.699,4.932-6.705,8.666-8.522"
></path>
<ellipse cx="32" cy="61" opacity=".3" rx="19" ry="3"></ellipse>
<g>
<path
fill="#edff9c"
d="M29,42c-0.512,0-1.023-0.195-1.414-0.586l-7-7c-0.781-0.781-0.781-2.047,0-2.828 c0.781-0.781,2.047-0.781,2.828,0L29,37.171l12.586-12.585c0.781-0.781,2.047-0.781,2.828,0c0.781,0.781,0.781,2.047,0,2.828 l-14,14C30.023,41.805,29.512,42,29,42z"
></path>
</g>
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 13l4 4L19 7"
/>
</svg>
</div>
<h2 className="mt-2 font-semibold text-gray-100">
Registration Successfull!
<h2 className="mt-4 text-2xl sm:text-3xl font-bold text-green-500">
Registration Successful!
</h2>
<p className="mt-2 text-sm text-gray-500 leading-relaxed">
{props.message}
<p className="mt-4 text-lg text-gray-300 leading-relaxed">
{props.message}
</p>
<p className="mt-2 text-sm text-gray-400 leading-relaxed">
Join the Whatsapp Group for further updates immediately.
<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-3">
<a href={props.joinLink}>
<button className="flex-1 px-4 py-2 mx-auto bg-green-500 hover:bg-green-600 text-white text-sm rounded-md">
Join the Whatsapp Group!
<div className="flex mx-auto items-center mt-6">
<a
href={props.joinLink}
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>
);
);

}

0 comments on commit 9dcb568

Please sign in to comment.