Skip to content

Commit

Permalink
Added resume field in Application Page (#103)
Browse files Browse the repository at this point in the history
* Created button and label

* Minor style changes

* Changed to correct html input element

* Added error checking for file upload

* Drag and drop works

* Added visual indication for drag and drop

* Moved output feedback to its own component

* Made resume required

* Removed drag and drop

* Style changes

* Form actually sends file with multipart

* File is reset on page load

* Removed unnecessary import from layout

* Added to upload feedback

* Update apps/site/src/app/apply/sections/Form/ResumeOutputFeedback.tsx

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Style changes to ResumeOutputFeedback

* Added back action endpoint for form
  • Loading branch information
IanWearsHat authored Dec 17, 2023
1 parent 44ff58a commit 34534c2
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 10 deletions.
2 changes: 1 addition & 1 deletion apps/site/src/app/apply/sections/Form/AgeInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function AgeInformation() {
</div>

<SimpleRadio
name="minor-check"
name="minor_check"
values={yesNoOptions}
title="Will you be 18 years or older by January 26th, 2024?"
titleClass="text-xl font-bold m-0 text-center"
Expand Down
8 changes: 4 additions & 4 deletions apps/site/src/app/apply/sections/Form/BasicInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function BasicInformation() {

<div className="flex gap-5 w-full max-[1000px]:flex-col max-[1000px]:items-center">
<TextInput
name="first-name"
name="first_name"
labelClass={styles.label}
labelText="First Name"
inputClass={styles.input}
Expand All @@ -40,7 +40,7 @@ export default function BasicInformation() {
placeholder=""
/>
<TextInput
name="last-name"
name="last_name"
labelClass={styles.label}
labelText="Last Name"
inputClass={styles.input}
Expand All @@ -53,14 +53,14 @@ export default function BasicInformation() {

<div className="flex gap-5 w-full max-[1000px]:flex-col max-[1000px]:items-center">
<RadioSelect
IdentifierId="pronouns-identifier"
IdentifierId="pronouns_identifier"
name="pronouns"
labelText="Pronouns"
values={pronouns}
containerClass="flex flex-col w-6/12 max-[1000px]:w-full"
/>
<RadioSelect
IdentifierId="ethnicity-identifier"
IdentifierId="ethnicity_identifier"
name="ethnicity"
labelText="Race / Ethnicity"
values={ethnicity}
Expand Down
10 changes: 10 additions & 0 deletions apps/site/src/app/apply/sections/Form/Form.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,13 @@
.image {
z-index: -1;
}

.upload {
& > * {
// prevents child elements from interfering with drag & drop
pointer-events: none;
}
background-color: #e1e1e1;
border-radius: 12px;
padding: 1rem 2rem;
}
3 changes: 3 additions & 0 deletions apps/site/src/app/apply/sections/Form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import BasicInformation from "./BasicInformation";
import AgeInformation from "./AgeInformation";
import SchoolInformation from "./SchoolInformation";
import ProfileInformation from "./ProfileInformation";
import ResumeInformation from "./ResumeInformation";
import Button from "@/lib/components/Button/Button";
import koiLeft from "@/assets/images/koi-swim-left.png";
import koiRight from "@/assets/images/koi-swim-right.png";
Expand Down Expand Up @@ -39,10 +40,12 @@ export default function Form() {
method="post"
className={`${styles.form} text-[#000000] w-8/12 flex flex-col items-center py-12 gap-10 z-1 max-[800px]:w-9/12 max-[400px]:w-11/12`}
action="/api/user/apply"
encType="multipart/form-data"
>
<BasicInformation />
<SchoolInformation />
<ProfileInformation />
<ResumeInformation />
<AgeInformation />
<Button text="Submit Application" />
</form>
Expand Down
4 changes: 2 additions & 2 deletions apps/site/src/app/apply/sections/Form/ProfileInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function ProfileInformation() {
</div>

<Textfield
name="collaboration-answer"
name="collaboration_answer"
labelClass={`${styles.label} mt-7`}
labelText="Why is collaboration important to being a programmer or technologist, and what does it mean to you? (150 words)"
inputClass={`bg-[#E1E1E1] p-3 h-48 resize-none rounded-xl`}
Expand All @@ -42,7 +42,7 @@ export default function ProfileInformation() {
/>

<Textfield
name="job-answer"
name="job_answer"
labelClass={`${styles.label} mt-7`}
labelText="If you could have any job in the world, what would it be? (ex. YouTuber, Body Builder, etc.) (100 words)"
inputClass={`bg-[#E1E1E1] p-3 h-48 resize-none rounded-xl`}
Expand Down
91 changes: 91 additions & 0 deletions apps/site/src/app/apply/sections/Form/ResumeInformation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"use client";

import { ChangeEvent, useEffect, useState, useRef } from "react";

import RequiredAsterisk from "@/app/apply/sections/Components/RequiredAsterisk";
import OutputFeedBack from "./ResumeOutputFeedback";

import uploadImage from "@/assets/icons/upload-resume-icon.svg";
import Image from "next/image";

import styles from "./Form.module.scss";

class InvalidFile extends Error {
constructor(message: string) {
super(message);
this.name = "InvalidFile";
}
}

export default function ResumeInformation() {
const inputRef = useRef<HTMLInputElement>(null);
const [resumePath, setResumePath] = useState("");
const [errorMessage, setErrorMessage] = useState("");

useEffect(() => {
if (inputRef.current) {
inputRef.current.value = "";
}
}, []);

const handleFileUpload = (event: ChangeEvent<HTMLInputElement>) => {
event.preventDefault();

setErrorMessage("");
setResumePath("");

let file = event.target.files ? event.target.files[0] : null;
try {
handleFile(file);
} catch (error) {
event.target.value = "";
}
};

const handleFile = (file: File | null) => {
if (!file) throw TypeError;

let path = file.name;

let extension = path.split(".").pop();
if (extension != "pdf") {
setErrorMessage("Invalid file format");
throw new InvalidFile("Invalid file format");
}

if (file.size > 500000) {
setErrorMessage("Invalid file size (file size exceeds 0.5 MB)");
throw new InvalidFile("Invalid file size");
}
setResumePath(path);
};

return (
<div className="flex flex-col items-start w-11/12">
<label className={styles.label}>
Resume (PDF, 0.5 MB max) <RequiredAsterisk />
</label>
<label
htmlFor="resume_upload"
className={`${styles.upload} cursor-pointer mb-3`}
>
<Image src={uploadImage} width="100" alt="Upload resume icon" />
<h2 className="text-center">Upload file</h2>
</label>
<input
ref={inputRef}
className="opacity-0 absolute"
name="resume_upload"
id="resume_upload"
type="file"
accept="application/pdf"
onChange={handleFileUpload}
required
></input>
<OutputFeedBack
errorMessage={errorMessage}
resumePath={resumePath}
/>
</div>
);
}
19 changes: 19 additions & 0 deletions apps/site/src/app/apply/sections/Form/ResumeOutputFeedback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
interface OutputFeedbackProps {
errorMessage: string;
resumePath: string;
}

export default function OutputFeedBack({
errorMessage,
resumePath,
}: OutputFeedbackProps) {
if (errorMessage) {
return <span className="text-[#FF2222] text-xl">{errorMessage}</span>;
}

return (
<span className="text-xl">
{resumePath ? "Successfully uploaded " + resumePath : ""}
</span>
);
}
6 changes: 3 additions & 3 deletions apps/site/src/app/apply/sections/Form/SchoolInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default function SchoolInformation() {
<DropdownSelect
labelStyle={styles.label}
inputStyle={styles.input}
name="education-level"
name="education_level"
labelText="Current Education Level"
values={educationLevels}
containerClass="flex flex-col w-6/12 max-[1000px]:w-full"
Expand All @@ -79,7 +79,7 @@ export default function SchoolInformation() {
<DropdownSelect
labelStyle={styles.label}
inputStyle={styles.input}
name="school-name"
name="school_name"
labelText="School Name"
values={universityOptions}
containerClass="flex flex-col w-6/12 max-[1000px]:w-full"
Expand All @@ -97,7 +97,7 @@ export default function SchoolInformation() {
/>

<SimpleRadio
name="hack-check"
name="hack_check"
values={yesNoOptions}
title="Is this your first Hackathon?"
titleClass="text-lg mb-0 p-0"
Expand Down
10 changes: 10 additions & 0 deletions apps/site/src/assets/icons/upload-resume-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 34534c2

Please sign in to comment.