diff --git a/src/app/(default)/organizer-application/page.tsx b/src/app/(default)/organizer-application/page.tsx new file mode 100644 index 00000000..e66c692b --- /dev/null +++ b/src/app/(default)/organizer-application/page.tsx @@ -0,0 +1,619 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { Toaster, toast } from "sonner"; +import { Fireworks } from "@fireworks-js/react"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Textarea } from "@/components/ui/textarea"; +import { CheckCircle, Mail, Home } from "lucide-react"; +import { + YearStanding, + OrganizerTeam, + type OrganizerApplicationCreateEntity, +} from "@/lib/api/organizer-application/entity"; +import { useSubmitOrganizerApplication } from "@/lib/api/organizer-application/hook"; + +interface FormData { + name: string; + email: string; + yearStanding: YearStanding | ""; + major: string; + firstChoiceTeam: OrganizerTeam | ""; + secondChoiceTeam: OrganizerTeam | ""; + whyHackpsu: string; + newIdea: string; + whatExcitesYou: string; + resume: File | null; +} + +export default function OrganizerApplicationPage() { + const router = useRouter(); + const submitApplicationMutation = useSubmitOrganizerApplication(); + const [isSubmitted, setIsSubmitted] = useState(false); + + const [formData, setFormData] = useState({ + name: "", + email: "", + yearStanding: "", + major: "", + firstChoiceTeam: "", + secondChoiceTeam: "", + whyHackpsu: "", + newIdea: "", + whatExcitesYou: "", + resume: null, + }); + + const handleChange = ( + e: React.ChangeEvent + ) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const handleSelectChange = (name: string, value: string) => { + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const handleFileChange = (e: React.ChangeEvent) => { + if (e.target.files && e.target.files[0]) { + const file = e.target.files[0]; + + // Validate file type + const validTypes = [ + "application/pdf", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ]; + if (!validTypes.includes(file.type)) { + toast.error("Please upload a PDF, DOC, or DOCX file"); + e.target.value = ""; + return; + } + + // Validate file size (10MB) + const maxSize = 10 * 1024 * 1024; + if (file.size > maxSize) { + toast.error("File size must be less than 10MB"); + e.target.value = ""; + return; + } + + setFormData((prev) => ({ ...prev, resume: file })); + } + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + // Validation + if ( + !formData.name || + !formData.email || + !formData.yearStanding || + !formData.major || + !formData.firstChoiceTeam || + !formData.secondChoiceTeam || + !formData.whyHackpsu || + !formData.newIdea || + !formData.whatExcitesYou || + !formData.resume + ) { + toast.error("Please fill in all required fields"); + return; + } + + if (formData.firstChoiceTeam === formData.secondChoiceTeam) { + toast.error("First and second choice teams must be different"); + return; + } + + const applicationData: OrganizerApplicationCreateEntity = { + name: formData.name, + email: formData.email, + yearStanding: formData.yearStanding as YearStanding, + major: formData.major, + firstChoiceTeam: formData.firstChoiceTeam as OrganizerTeam, + secondChoiceTeam: formData.secondChoiceTeam as OrganizerTeam, + whyHackpsu: formData.whyHackpsu, + newIdea: formData.newIdea, + whatExcitesYou: formData.whatExcitesYou, + resume: formData.resume, + }; + + toast.promise(submitApplicationMutation.mutateAsync(applicationData), { + loading: "Submitting your application...", + success: () => { + setIsSubmitted(true); + window.scrollTo({ top: 0, behavior: "smooth" }); + return "Application submitted successfully!"; + }, + error: (err: any) => + err?.message || "An error occurred while submitting your application.", + }); + }; + + const yearStandingOptions = Object.values(YearStanding); + const teamOptions = Object.values(OrganizerTeam); + + // Success View + if (isSubmitted) { + return ( +
+ {/* Confetti Effect */} + + + {/* Success Content */} +
+ + +
+
+ +
+
+ + Application Submitted! + +
+ + +
+

+ Thank you for applying to join the HackPSU organizing team! +

+ +
+
+ +
+

+ What happens next? +

+
    +
  • + We've received your application and our team will + review it carefully +
  • +
  • You'll hear back from us via email
  • +
  • + If selected for an interview, we'll reach out + with more details +
  • +
  • + Keep an eye on your inbox (and spam folder, just in + case!) +
  • +
+
+
+
+ +
+

+ We're excited to learn more about you! +

+

+ Being part of HackPSU means joining a community of + passionate individuals who love creating amazing + experiences. Whether you're accepted to your first + choice team or second choice team, you'll make a real + impact! +

+
+ +
+

+ Have questions? Reach out to us at{" "} + + team@hackpsu.org + +

+
+
+
+ + + + +
+
+
+ ); + } + + // Form View + return ( + <> + +
+
+
+
+

+ HackPSU Organizer Team Application +

+ + + + About HackPSU + + +

+ HackPSU is the largest 24-hour student-run hackathon and + technology event at Penn State. We're all about + celebrating innovation, creativity, and the thrill of + learning. Imagine being part of a team that brings + mind-blowing ideas to life and creates an unforgettable + experience for everyone involved. That's what HackPSU + is all about! +

+ +
+

+ Experience Level +

+

+ Here's the exciting news: you do NOT need a tech + background to join the HackPSU organizing team. We're + all about embracing diverse perspectives and talents. + Whether you're a coding expert or have never written + a line of code, as long as you are curious and have a + can-do attitude, we would like to hear from you. +

+

+ We have teams like Entertainment, Logistics, + Communications, Design, and Marketing that are open to + everyone from all majors and backgrounds! +

+
+ +
+

+ Important: The application for the tech + team is extremely competitive with limited openings, so + ensure you choose a desired second choice team. Make sure + to carefully select your second choice. If rejected from + the first choice, you will be considered for your second + choice team. +

+
+ +
+

+ Note: Applications are considered on a + rolling basis and may take up to 3 weeks into the fall + semester to process. Team roles will close once the + positions are filled. +

+
+ +

+ Still got questions? Reach out at{" "} + + team@hackpsu.org + +

+ +

+ Find a detailed list of team descriptions{" "} + + here + + . +

+
+
+
+ +
+ + + Personal Information + Tell us about yourself + + +
+ + +

+ First and last name +

+
+ +
+ + +

+ Please provide an email that you check regularly! We will + be using this email to contact you for interviews. +

+
+ +
+ + +
+ +
+ + +
+
+
+ + + + Team Preferences + + Select your first and second choice teams + + + +
+ + +
+ +
+ + +
+
+
+ + + + Resume + + Upload your resume (PDF, DOC, or DOCX, max 10MB) + + + +
+ + + {formData.resume && ( +

+ Selected: {formData.resume.name} +

+ )} +
+
+
+ + + + Application Questions + + Help us get to know you better + + + +
+ +