diff --git a/app/(default)/api/membersData/route.ts b/app/(default)/api/membersData/route.ts index 42b0a05..1a676b5 100644 --- a/app/(default)/api/membersData/route.ts +++ b/app/(default)/api/membersData/route.ts @@ -1,209 +1,279 @@ import { NextResponse } from "next/server"; import { db, storage } from "@/Firebase"; import { - collection, addDoc, getDocs, DocumentData, - DocumentSnapshot, - doc, - updateDoc, - deleteDoc, - getDoc -} from 'firebase/firestore'; -import { ref, uploadBytes, getDownloadURL, deleteObject } from 'firebase/storage'; + collection, + addDoc, + getDocs, + DocumentData, + DocumentSnapshot, + doc, + updateDoc, + deleteDoc, + getDoc, +} from "firebase/firestore"; +import { + ref, + uploadBytes, + getDownloadURL, + deleteObject, +} from "firebase/storage"; export async function GET() { - try { - const querySnapshot = await getDocs(collection(db, "pbMembers")); - - const membersRaw = querySnapshot.docs.map( - (doc: DocumentSnapshot) => ({ - id: doc.id, - ...doc.data(), - }) + try { + const querySnapshot = await getDocs(collection(db, "pbMembers")); + + const membersRaw = querySnapshot.docs.map( + (doc: DocumentSnapshot) => ({ + id: doc.id, + ...doc.data(), + }) + ); + + const members = membersRaw.map((member: any) => ({ + id: member.id, + name: member.name, + role: member.role, + company: member.company || "", + year: member.year, + linkedInUrl: member.linkedInUrl || "", + imageUrl: member.imageUrl || "", + })); + + return NextResponse.json(members); + } catch (error: any) { + console.error("Error fetching members:", error); + return NextResponse.json( + { + error: "An error occurred while fetching members", + details: error.message, + }, + { status: 500 } + ); + } +} + +// POST handler to add a new member +export async function POST(request: Request) { + try { + const data = await request.json(); + const { name, year, role, company, imageUrl, linkedInUrl } = data; + + // Validation + if (!name) { + return NextResponse.json( + { message: "Missing Name.", error: true }, + { status: 400 } + ); + } + if (!year) { + return NextResponse.json( + { message: "Missing Year.", error: true }, + { status: 400 } + ); + } + if (!role) { + return NextResponse.json( + { message: "Missing Role.", error: true }, + { status: 400 } + ); + } + + let downloadURL = ""; + if (imageUrl) { + const response = await fetch(imageUrl); + if (!response.ok) { + return NextResponse.json( + { message: "Failed to fetch image from the URL.", error: true }, + { status: 400 } ); + } - const members = membersRaw.map((member: any) => ({ - id: member.id, - name: member.name, - role: member.role, - company: member.company || '', - year: member.year, - linkedInUrl: member.linkedInUrl || '', - imageUrl: member.imageUrl || '' - })); - - return NextResponse.json(members); - } catch (error:any) { - console.error("Error fetching members:", error); + const contentType = response.headers.get("content-type"); + if (!contentType || !contentType.startsWith("image/")) { return NextResponse.json( - { error: "An error occurred while fetching members", details: error.message }, - { status: 500 } + { message: "The provided URL is not a valid image.", error: true }, + { status: 400 } ); + } + + const blob = await response.blob(); + const extension = contentType.split("/")[1]; + const imageRef = ref(storage, `members/${name}.${extension}`); + await uploadBytes(imageRef, blob, { contentType }); + downloadURL = await getDownloadURL(imageRef); } + + const docRef = await addDoc(collection(db, "pbMembers"), { + name, + year, + role, + company, + linkedInUrl, + imageUrl: downloadURL, + }); + + return NextResponse.json( + { message: "Member added successfully", id: docRef.id }, + { status: 201 } + ); + } catch (error: any) { + console.error("Error adding member:", error); + return NextResponse.json( + { message: `Failed to add member: ${error.message}`, error: true }, + { status: 500 } + ); } } -// POST handler to add a new member -export async function POST(request: Request) { - try { - const data = await request.json(); - const { name, year, role, company, imageUrl, linkedInUrl } = data; - - // Validation - if (!name) { - return NextResponse.json({ message: 'Missing Name.', error: true }, { status: 400 }); - } - if (!year) { - return NextResponse.json({ message: 'Missing Year.', error: true }, { status: 400 }); - } - if (!role) { - return NextResponse.json({ message: 'Missing Role.', error: true }, { status: 400 }); - } - - let downloadURL = ''; - if (imageUrl) { - const response = await fetch(imageUrl); - if (!response.ok) { - return NextResponse.json({ message: 'Failed to fetch image from the URL.', error: true }, { status: 400 }); - } - - const contentType = response.headers.get('content-type'); - if (!contentType || !contentType.startsWith('image/')) { - return NextResponse.json({ message: 'The provided URL is not a valid image.', error: true }, { status: 400 }); - } - - const blob = await response.blob(); - const extension = contentType.split('/')[1]; - const imageRef = ref(storage, `members/${name}.${extension}`); - await uploadBytes(imageRef, blob, { contentType }); - downloadURL = await getDownloadURL(imageRef); - } - - const docRef = await addDoc(collection(db, 'pbMembers'), { - name, - year, - role, - company, - linkedInUrl, - imageUrl: downloadURL, - }); +export async function PUT(request: Request) { + try { + const data = await request.json(); + const { id, name, year, role, company, imageUrl, linkedInUrl } = data; - return NextResponse.json({ message: 'Member added successfully', id: docRef.id }, { status: 201 }); - } catch (error:any) { - console.error('Error adding member:', error); - return NextResponse.json({ message: `Failed to add member: ${error.message}`, error: true }, { status: 500 }); + // Validation + if (!id) { + return NextResponse.json( + { message: "Missing Member ID", error: true }, + { status: 400 } + ); + } + if (!name) { + return NextResponse.json( + { message: "Missing Name.", error: true }, + { status: 400 } + ); + } + if (!year) { + return NextResponse.json( + { message: "Missing Year.", error: true }, + { status: 400 } + ); + } + if (!role) { + return NextResponse.json( + { message: "Missing Role.", error: true }, + { status: 400 } + ); } - export async function PUT(request: Request) { - try { - const data = await request.json(); - const { id, name, year, role, company, imageUrl, linkedInUrl } = data; - - // Validation - if (!id) { - return NextResponse.json({ message: 'Missing Member ID', error: true }, { status: 400 }); - } - if (!name) { - return NextResponse.json({ message: 'Missing Name.', error: true }, { status: 400 }); - } - if (!year) { - return NextResponse.json({ message: 'Missing Year.', error: true }, { status: 400 }); - } - if (!role) { - return NextResponse.json({ message: 'Missing Role.', error: true }, { status: 400 }); - } - - const memberRef = doc(db, "pbMembers", id); - const memberSnapshot = await getDoc(memberRef); - if (!memberSnapshot.exists()) { - return NextResponse.json({ message: 'Member not found', error: true }, { status: 404 }); - } - - const memberData = memberSnapshot.data(); - let downloadURL = memberData.imageUrl; - - if (imageUrl && imageUrl !== memberData.imageUrl) { - const response = await fetch(imageUrl); - if (!response.ok) { - return NextResponse.json({ message: 'Failed to fetch image from the URL.', error: true }, { status: 400 }); - } - - const contentType = response.headers.get('content-type'); - if (!contentType || !contentType.startsWith('image/')) { - return NextResponse.json({ message: 'The provided URL is not a valid image.', error: true }, { status: 400 }); - } - - const blob = await response.blob(); - const extension = contentType.split('/')[1]; - const timestamp = Date.now(); - const imageRef = ref(storage, `members/${name}_${timestamp}.${extension}`); - await uploadBytes(imageRef, blob, { contentType }); - downloadURL = await getDownloadURL(imageRef); - - if (memberData.imageUrl) { - const oldImageRef = ref(storage, memberData.imageUrl); - await deleteObject(oldImageRef).catch(error => { - console.error('Error deleting old image:', error); - }); - } - } - - const updatedData = { - name, - year, - role, - company, - linkedInUrl, - imageUrl: downloadURL, - }; - - await updateDoc(memberRef, updatedData); - - return NextResponse.json({ message: 'Member updated successfully', data: updatedData }, { status: 200 }); - } catch (error:any) { - console.error('Error updating member:', error); - return NextResponse.json({ message: `Failed to update member: ${error.message}`, error: true }, { status: 500 }); + const memberRef = doc(db, "pbMembers", id); + const memberSnapshot = await getDoc(memberRef); + if (!memberSnapshot.exists()) { + return NextResponse.json( + { message: "Member not found", error: true }, + { status: 404 } + ); } - export async function DELETE(request: Request) { - try { - const { id } = await request.json(); + const memberData = memberSnapshot.data(); + let downloadURL = memberData.imageUrl; - // Validation - if (!id) { - return NextResponse.json({ message: 'Missing member ID', error: true }, { status: 400 }); - } + if (imageUrl && imageUrl !== memberData.imageUrl) { + const response = await fetch(imageUrl); + if (!response.ok) { + return NextResponse.json( + { message: "Failed to fetch image from the URL.", error: true }, + { status: 400 } + ); + } - const memberRef = doc(db, 'pbMembers', id); - const memberSnapshot = await getDoc(memberRef); + const contentType = response.headers.get("content-type"); + if (!contentType || !contentType.startsWith("image/")) { + return NextResponse.json( + { message: "The provided URL is not a valid image.", error: true }, + { status: 400 } + ); + } - if (!memberSnapshot.exists()) { - return NextResponse.json({ message: 'Member not found', error: true }, { status: 404 }); - } + const blob = await response.blob(); + const extension = contentType.split("/")[1]; + const timestamp = Date.now(); + const imageRef = ref( + storage, + `members/${name}_${timestamp}.${extension}` + ); + await uploadBytes(imageRef, blob, { contentType }); + downloadURL = await getDownloadURL(imageRef); + + if (memberData.imageUrl) { + const oldImageRef = ref(storage, memberData.imageUrl); + await deleteObject(oldImageRef).catch((error) => { + console.error("Error deleting old image:", error); + }); + } + } + + const updatedData = { + name, + year, + role, + company, + linkedInUrl, + imageUrl: downloadURL, + }; + + await updateDoc(memberRef, updatedData); + + return NextResponse.json( + { message: "Member updated successfully", data: updatedData }, + { status: 200 } + ); + } catch (error: any) { + console.error("Error updating member:", error); + return NextResponse.json( + { message: `Failed to update member: ${error.message}`, error: true }, + { status: 500 } + ); + } +} +export async function DELETE(request: Request) { + try { + const { id } = await request.json(); + + // Validation + if (!id) { + return NextResponse.json( + { message: "Missing member ID", error: true }, + { status: 400 } + ); + } // Fetch the member document from Firestore const memberRef = doc(db, "pbMembers", id); const memberSnapshot = await getDoc(memberRef); - if (!memberSnapshot.exists()) { + if (!memberSnapshot.exists()) { return NextResponse.json( { message: "Member not found", error: true }, { status: 404 } ); } - - if (imageUrl) { - const imageRef = ref(storage, imageUrl); - await deleteObject(imageRef).catch((error) => { - console.error('Error deleting image from Firebase Storage:', error); - return NextResponse.json({ message: 'Failed to delete image from storage', error: true }, { status: 500 }); - }); - } - - await deleteDoc(memberRef); - - return NextResponse.json({ message: 'Member and associated image deleted successfully' }, { status: 200 }); - } catch (error:any) { - console.error('Error deleting member:', error); - return NextResponse.json({ message: `Failed to delete member: ${error.message}`, error: true }, { status: 500 }); + // Extract member data and image URL + const memberData = memberSnapshot.data(); + const imageUrl = memberData.imageUrl; + + if (imageUrl) { + const imageRef = ref(storage, imageUrl); + await deleteObject(imageRef).catch((error) => { + console.error("Error deleting image from Firebase Storage:", error); + return NextResponse.json( + { message: "Failed to delete image from storage", error: true }, + { status: 500 } + ); + }); } + + await deleteDoc(memberRef); + + return NextResponse.json( + { message: "Member and associated image deleted successfully" }, + { status: 200 } + ); + } catch (error: any) { + console.error("Error deleting member:", error); + return NextResponse.json( + { message: `Failed to delete member: ${error.message}`, error: true }, + { status: 500 } + ); + } } diff --git a/app/(default)/api/registration/pbctf/route.ts b/app/(default)/api/registration/pbctf/route.ts index b53ba99..de6f3c8 100644 --- a/app/(default)/api/registration/pbctf/route.ts +++ b/app/(default)/api/registration/pbctf/route.ts @@ -65,7 +65,6 @@ export async function GET(request: Request) { } } - export async function POST(request: Request) { try { const { searchParams } = new URL(request.url); // Extract query parameters @@ -93,8 +92,7 @@ export async function POST(request: Request) { // Add a new registration async function validateRecaptcha(request: Request) { const formData = await request.json(); - const { recaptcha_token, ...data } = formData; - + const { recaptcha_token } = formData; const recaptchaToken = recaptcha_token; @@ -135,156 +133,8 @@ async function validateRecaptcha(request: Request) { }); } - // Validate registration data - - //Paticipant type - if (!data.participationType || !["solo", "duo"].includes(data.participationType)) { - return NextResponse.json({ - message: "Invalid participation type!", - error: "Invalid participation type!", - }, { status: 400 }); - } - - //Participant 1 - if (!data.participant1 || !data.participant1.name) { - return NextResponse.json({ - message: "Participant 1's name is required.", - error: "Participant 1's name is required.", - }, { status: 400 }); - } - - if (!data.participant1.year || !["1", "2", "3", "4"].includes(data.participant1.year)) { - return NextResponse.json({ - message: "Participant 1's year is required.", - error: "Participant 1's year is required.", - }, { status: 400 }); - } - - if (!data.participant1.branch) { - return NextResponse.json({ - message: "Participant 1's branch is required.", - error: "Participant 1's branch is required.", - }, { status: 400 }); - } - - const usnPattern1 = data.participant1.year === "1" - ? /^[1-9][0-9][A-Z]{4}[0-9]{4}$/ - : /^1DS[1-3][0-9][A-Z]{2}[0-9]{3}$/; - - if (!data.participant1.usn || !usnPattern1.test(data.participant1.usn)) { - return NextResponse.json({ - message: "Participant 1's USN is invalid.", - error: "Invalid USN for Participant 1.", - }, { status: 400 }); - } - - const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; - if (!data.participant1.email || !emailPattern.test(data.participant1.email)) { - return NextResponse.json({ - message: "Participant 1's email is invalid.", - error: "Invalid email for Participant 1.", - }, { status: 400 }); - } - - const phonePattern = /^[6-9]\d{9}$/; - if (!data.participant1.phone || !phonePattern.test(data.participant1.phone)) { - return NextResponse.json({ - message: "Participant 1's phone number is invalid.", - error: "Invalid phone number for Participant 1.", - }, { status: 400 }); - } - - //Participant 2 If Duo - if (data.participationType === "duo") { - if (!data.participant2 || !data.participant2.name) { - return NextResponse.json({ - message: "Participant 2's name is required.", - error: "Participant 2's name is required.", - }, { status: 400 }); - } - - if (!data.participant2.year || !["1", "2", "3", "4"].includes(data.participant2.year)) { - return NextResponse.json({ - message: "Participant 2's year is required.", - error: "Participant 2's year is required.", - }, { status: 400 }); - } - - if (!data.participant2.branch) { - return NextResponse.json({ - message: "Participant 2's branch is required.", - error: "Participant 2's branch is required.", - }, { status: 400 }); - } - - const usnPattern2 = data.participant2.year === "1" - ? /^[1-9][0-9][A-Z]{4}[0-9]{4}$/ - : /^1DS[1-3][0-9][A-Z]{2}[0-9]{3}$/; - - if (!data.participant2.usn || !usnPattern2.test(data.participant2.usn)) { - return NextResponse.json({ - message: "Participant 2's USN is invalid.", - error: "Invalid USN for Participant 2.", - }, { status: 400 }); - } - - if (!data.participant2.email || !emailPattern.test(data.participant2.email)) { - return NextResponse.json({ - message: "Participant 2's email is invalid.", - error: "Invalid email for Participant 2.", - }, { status: 400 }); - } - - if (!data.participant2.phone || !phonePattern.test(data.participant2.phone)) { - return NextResponse.json({ - message: "Participant 2's phone number is invalid.", - error: "Invalid phone number for Participant 2.", - }, { status: 400 }); - } - } - - // Check if USNs are the same for duo participation - if ( - data.participationType === "duo" && - data.participant2 && - data.participant1.usn === data.participant2.usn - ) { - return NextResponse.json({ - message: "USNs for Participant 1 and Participant 2 cannot be the same", - error: "USNs for Participant 1 and Participant 2 cannot be the same", - }, { status: 400 }); - } - - // Check USN uniqueness for participant1 - const isUnique1 = await checkUsnUniqueness(data.participant1.usn); - if (!isUnique1) { - return NextResponse.json({ - message: "Participant 1's USN already exists.", - error: "Participant 1's USN already exists.", - }, { status: 400 }); - } - - // Check USN uniqueness for participant2 if it exists - if (data.participationType === "duo" && data.participant2) { - const isUnique2 = await checkUsnUniqueness(data.participant2.usn); - if (!isUnique2) { - return NextResponse.json({ - message: "Participant 2's USN already exists.", - error: "Participant 2's USN already exists.", - }, { status: 400 }); - } - } - try { - // Save to Firebase - await addDoc(collection(db, "pbctf_registrations"), data); - return NextResponse.json({ message: "Registration successful"}); - } catch (error) { - console.error(error); - return NextResponse.json( - { message: "An error occurred", error }, - { status: 500 } - ); - } + // Return a response + return NextResponse.json({ message: "Recaptcha validated!" }); } async function addRegistration(request: Request) { @@ -309,4 +159,4 @@ async function addRegistration(request: Request) { { status: 500 } ); } -} +} \ No newline at end of file diff --git a/components/Members.tsx b/components/Members.tsx index a08f937..31c17ca 100644 --- a/components/Members.tsx +++ b/components/Members.tsx @@ -134,15 +134,8 @@ export default function Members() { memberData = { ...newMember, imageUrl }; - setNewMember((prev) => ({ ...prev, imageUrl: downloadURL })); - } catch (error) { - console.error('Error uploading file:', error); - } - } else { - console.warn('No file selected.'); - } - }; - const handleAddOrEditMember = async () => { + if (newMember.id) { + // Update member in Firestore try { const response = await fetch(`/api/membersData`, { method: "PUT", @@ -280,40 +273,60 @@ export default function Members() { if (!uniqueMembersMap.has(key)) { uniqueMembersMap.set(key, member); } + }); - }; - - return ( -
-

- Point Blank's Team -

-
- {loading ? ( -
- -
- ) : ( -
- {headings.map((heading, index) => ( - - {heading === "First Year" && ( -
-

- Recruitment Incoming Soon! -

- -