Skip to content

Commit

Permalink
Resume upload field improvements (#116)
Browse files Browse the repository at this point in the history
* Resume upload field improvements:

- Made resume field optional
- More accurate validation text ("selected" instead of "uploaded"
- Changed icon to file icon instead of download icon

* feat: show green file uploaded icon on upload

* Handle empty resume on API by checking zero size

- The browser will still provided an empty octet stream even when a file
  has not been selected
- If resume is provided but has no size, ignore file

* feat: more styling for resume upload feedback

* feat: third icon for invalid uploads

* fix: remove required asterisk

---------

Co-authored-by: Taesung Hwang <[email protected]>
  • Loading branch information
samderanova and taesungh authored Dec 18, 2023
1 parent 4b94251 commit 65ee82e
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 30 deletions.
2 changes: 1 addition & 1 deletion apps/api/src/routers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ async def apply(
"Please enable JavaScript on your browser.",
)

if resume is not None:
if resume is not None and resume.size and resume.size > 0:
try:
resume_url = await resume_handler.upload_resume(
raw_application_data, resume
Expand Down
3 changes: 2 additions & 1 deletion apps/api/tests/test_user_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
SAMPLE_FILES = {"resume": SAMPLE_RESUME}
BAD_RESUME = ("bad-resume.doc", b"resume", "application/msword")
LARGE_RESUME = ("large-resume.pdf", b"resume" * 100_000, "application/pdf")
EMPTY_RESUME = ("", b"", "application/octet-stream")

EXPECTED_RESUME_UPLOAD = ("pk-fire-69f2afc2.pdf", b"resume", "application/pdf")
SAMPLE_RESUME_URL = HttpUrl("https://drive.google.com/file/d/...")
Expand Down Expand Up @@ -240,7 +241,7 @@ def test_apply_successfully_without_resume(
"""Test that a valid application is submitted properly without a resume."""
mock_mongodb_handler_retrieve_one.return_value = None
mock_datetime.now.return_value = SAMPLE_SUBMISSION_TIME
res = client.post("/apply", data=SAMPLE_APPLICATION, files=None)
res = client.post("/apply", data=SAMPLE_APPLICATION, files={"resume": EMPTY_RESUME})

mock_gdrive_handler_upload_file.assert_not_called()
mock_mongodb_handler_update_one.assert_awaited_once_with(
Expand Down
3 changes: 0 additions & 3 deletions apps/site/src/app/apply/sections/Form/Form.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,4 @@
// prevents child elements from interfering with drag & drop
pointer-events: none;
}
background-color: #e1e1e1;
border-radius: 12px;
padding: 1rem 2rem;
}
37 changes: 25 additions & 12 deletions apps/site/src/app/apply/sections/Form/ResumeInformation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

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

import RequiredAsterisk from "@/app/apply/sections/Components/RequiredAsterisk";
import OutputFeedBack from "./ResumeOutputFeedback";
import { FileCheck, FileText, FileWarning } from "lucide-react";

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

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

Expand All @@ -19,8 +17,9 @@ class InvalidFile extends Error {

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

useEffect(() => {
if (inputRef.current) {
Expand All @@ -40,6 +39,7 @@ export default function ResumeInformation() {
} catch (error) {
event.target.value = "";
}
setHasUploaded(true);
};

const handleFile = (file: File | null) => {
Expand All @@ -62,14 +62,28 @@ export default function ResumeInformation() {

return (
<div className="flex flex-col items-start w-11/12">
<label className={styles.label}>
Resume (PDF, 0.5 MB max) <RequiredAsterisk />
</label>
<label className={styles.label}>Resume (PDF, 0.5 MB max)</label>
<label
htmlFor="resume_upload"
className={`${styles.upload} cursor-pointer mb-3`}
className={`${styles.upload} cursor-pointer mb-3 p-5 rounded-xl bg-[#e1e1e1]`}
>
<Image src={uploadImage} width="100" alt="Upload resume icon" />
{!hasUploaded ? (
<FileText className="m-auto" width={50} height={50} />
) : errorMessage === "" ? (
<FileCheck
className="m-auto"
width={50}
height={50}
color="green"
/>
) : (
<FileWarning
className="m-auto"
width={50}
height={50}
color="red"
/>
)}
<h2 className="text-center">Upload file</h2>
</label>
<input
Expand All @@ -80,7 +94,6 @@ export default function ResumeInformation() {
type="file"
accept="application/pdf"
onChange={handleFileUpload}
required
></input>
<OutputFeedBack
errorMessage={errorMessage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ export default function OutputFeedBack({
resumePath,
}: OutputFeedbackProps) {
if (errorMessage) {
return <span className="text-[#FF2222] text-xl">{errorMessage}</span>;
return <span className="text-[red] italic">{errorMessage}</span>;
}

return (
<span className="text-xl">
{resumePath ? "Successfully uploaded " + resumePath : ""}
<span className="italic">
{resumePath ? "Selected " + resumePath : ""}
</span>
);
}
10 changes: 0 additions & 10 deletions apps/site/src/assets/icons/upload-resume-icon.svg

This file was deleted.

0 comments on commit 65ee82e

Please sign in to comment.