From 09f445384a53973fb23b55c8d6086e82d6a8f2cd Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Sep 2026 13:48:22 -0700 Subject: [PATCH 1/6] feat: add individual github, linkedin, portfolio website, and resume question types --- src/components/features/hackerapp/hacker-app-question.tsx | 8 ++++++++ src/lib/firebase/types.ts | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/features/hackerapp/hacker-app-question.tsx b/src/components/features/hackerapp/hacker-app-question.tsx index 62c5295..b0f0c2b 100644 --- a/src/components/features/hackerapp/hacker-app-question.tsx +++ b/src/components/features/hackerapp/hacker-app-question.tsx @@ -44,6 +44,10 @@ const QUESTION_TYPES: HackerApplicationQuestionType[] = [ "School", "Major", "Country", + "Github", + "LinkedIn", + "Portfolio Website", + "Resume", ]; // Question types that if selected, bricks the select field and locks in the value @@ -53,6 +57,10 @@ const QUESTION_TYPES_UNIQUE: HackerApplicationQuestionType[] = [ "School", "Major", "Country", + "Github", + "LinkedIn", + "Portfolio Website", + "Resume", ]; export const SHOW_FORM_INPUT: HackerApplicationQuestionType[] = [ diff --git a/src/lib/firebase/types.ts b/src/lib/firebase/types.ts index a3a81ae..afdca89 100644 --- a/src/lib/firebase/types.ts +++ b/src/lib/firebase/types.ts @@ -350,7 +350,11 @@ export type HackerApplicationQuestionType = | "Dropdown" | "School" | "Major" - | "Country"; + | "Country" + | "Github" + | "LinkedIn" + | "Portfolio Website" + | "Resume"; // keep in sync with portal-v2 src/lib/firebase/types/hacker-app-questions.ts, which renders these export const FORM_INPUT_FIELDS = [ "academicYear", From afc46f49b1a5057c9a530b1a12f77c0da0d9d22b Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Sep 2026 17:03:59 -0700 Subject: [PATCH 2/6] feat(hackerapp): pin fixed question types to their section --- .../hackerapp/hacker-app-question.tsx | 7 +++++- .../features/hackerapp/hacker-app-sections.ts | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/components/features/hackerapp/hacker-app-question.tsx b/src/components/features/hackerapp/hacker-app-question.tsx index b0f0c2b..fbe1dd5 100644 --- a/src/components/features/hackerapp/hacker-app-question.tsx +++ b/src/components/features/hackerapp/hacker-app-question.tsx @@ -31,7 +31,11 @@ import { getEligibleSources, } from "./hacker-app-conditions"; import type { UsedFieldsRegistry } from "./hacker-app-main"; -import { LEGAL_NAME_FORM_INPUTS, isFormInputAllowedInSection } from "./hacker-app-sections"; +import { + LEGAL_NAME_FORM_INPUTS, + isFormInputAllowedInSection, + isQuestionTypeAllowedInSection, +} from "./hacker-app-sections"; const QUESTION_TYPES: HackerApplicationQuestionType[] = [ "Long Answer", @@ -140,6 +144,7 @@ export const HackerAppQuestion = memo(function HackerAppQuestion({ ); const usableQuestionTypes = QUESTION_TYPES?.filter( (qt) => + isQuestionTypeAllowedInSection(qt, section) && (qt !== "Full Legal Name" || !hasSplitLegalName) && (!QUESTION_TYPES_UNIQUE.includes(qt) || !usedFieldsRegistry.questionType.has(qt)), ); diff --git a/src/components/features/hackerapp/hacker-app-sections.ts b/src/components/features/hackerapp/hacker-app-sections.ts index c1e9ab4..575c4eb 100644 --- a/src/components/features/hackerapp/hacker-app-sections.ts +++ b/src/components/features/hackerapp/hacker-app-sections.ts @@ -1,5 +1,6 @@ import type { HackerApplicationQuestionFormInputField, + HackerApplicationQuestionType, HackerApplicationSections, } from "@/lib/firebase/types"; @@ -69,3 +70,25 @@ export const isFormInputAllowedInSection = ( const pinned = SECTION_BY_FORM_INPUT[formInput]; return pinned === undefined || pinned === section; }; + +export const QUESTION_TYPE_SECTION: Partial< + Record +> = { + "Full Legal Name": "BasicInfo", + School: "BasicInfo", + Major: "BasicInfo", + Country: "BasicInfo", + Portfolio: "Skills", + Github: "Skills", + LinkedIn: "Skills", + "Portfolio Website": "Skills", + Resume: "Skills", +}; + +export const isQuestionTypeAllowedInSection = ( + questionType: HackerApplicationQuestionType, + section: HackerApplicationSections, +): boolean => { + const pinned = QUESTION_TYPE_SECTION[questionType]; + return pinned === undefined || pinned === section; +}; From aee8af2b77d0c97c213f3d646b9549381497d909 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Sep 2026 17:07:30 -0700 Subject: [PATCH 3/6] fix(hackerapp): limit section gating to skills types --- src/components/features/hackerapp/hacker-app-sections.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/features/hackerapp/hacker-app-sections.ts b/src/components/features/hackerapp/hacker-app-sections.ts index 575c4eb..dfa5f9b 100644 --- a/src/components/features/hackerapp/hacker-app-sections.ts +++ b/src/components/features/hackerapp/hacker-app-sections.ts @@ -74,10 +74,6 @@ export const isFormInputAllowedInSection = ( export const QUESTION_TYPE_SECTION: Partial< Record > = { - "Full Legal Name": "BasicInfo", - School: "BasicInfo", - Major: "BasicInfo", - Country: "BasicInfo", Portfolio: "Skills", Github: "Skills", LinkedIn: "Skills", From 86b6f9fc2f42348265975a46a3673ed3c5ff2424 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Sep 2026 17:18:02 -0700 Subject: [PATCH 4/6] fix(evaluator): don't linkify non-url answers --- .../features/evaluator/response.tsx | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/features/evaluator/response.tsx b/src/components/features/evaluator/response.tsx index 110d2d0..0433c35 100644 --- a/src/components/features/evaluator/response.tsx +++ b/src/components/features/evaluator/response.tsx @@ -65,30 +65,29 @@ const BooleanMap = ({ value }: { value?: Record }) => { }; const LinkField = ({ href }: { href?: string }) => { + const value = href ?? ""; + const isUrl = /^https?:\/\//i.test(value.trim()); + const handleClipboard = () => { - if (!href) return; - navigator.clipboard.writeText(href); + if (!value) return; + navigator.clipboard.writeText(value); toast("Copied link to clipboard!"); }; - const hasLink = Boolean(href); + if (!isUrl) { + return ; + } return ( From 43de2162bc841ee0060c3a10e39db035aa6bfa30 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Sep 2026 17:31:24 -0700 Subject: [PATCH 5/6] fix(evaluator): show uploaded state for resumes --- .../features/evaluator/response.tsx | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/components/features/evaluator/response.tsx b/src/components/features/evaluator/response.tsx index 0433c35..5707bdb 100644 --- a/src/components/features/evaluator/response.tsx +++ b/src/components/features/evaluator/response.tsx @@ -44,10 +44,12 @@ export function Response({ label, type, response, userId }: ResponseProps) { ) : type === "booleanMap" ? ( } /> + ) : type === "resume" ? ( + ) : loading ? ( ) : ( - + )} ); @@ -64,6 +66,38 @@ const BooleanMap = ({ value }: { value?: Record }) => { ); }; +const ResumeField = ({ href, loading }: { href?: string; loading: boolean }) => { + if (loading) return ; + + const value = href ?? ""; + if (!value.trim()) { + return ; + } + + const handleClipboard = () => { + navigator.clipboard.writeText(value); + toast("Copied link to clipboard!"); + }; + + return ( +
+ Uploaded + + View resume + + + +
+ ); +}; + const LinkField = ({ href }: { href?: string }) => { const value = href ?? ""; const isUrl = /^https?:\/\//i.test(value.trim()); From b40609896980255b903fdc43af1bfbca83ed33cb Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Sep 2026 17:42:39 -0700 Subject: [PATCH 6/6] style(evaluator): format link field --- src/components/features/evaluator/response.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/features/evaluator/response.tsx b/src/components/features/evaluator/response.tsx index 5707bdb..b1ca670 100644 --- a/src/components/features/evaluator/response.tsx +++ b/src/components/features/evaluator/response.tsx @@ -114,10 +114,12 @@ const LinkField = ({ href }: { href?: string }) => { return (