feat(join): add public recruitment page, Google Form embed, and navigation entry points (PR B of 3) - #204
Conversation
…ation entry points
|
@aakash-agarwal-cs is attempting to deploy a commit to the barunaniket-9400's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Careful work — the engineering side is right, and a couple of the fiddly bits are exactly right in a way that's easy to get wrong. Blocking only on content: the domain list is out of sync with the actual form, and that's on us, not you.
What's correct
- CSP — one token added to
frame-src, withframe-ancestorsandX-Frame-Optionsleft alone. That's the right call and the easy thing to over-edit. GoogleFormEmbed— server component, nosandbox(which would break Forms), has atitlefor screen readers, and the new-tab fallback is there.- Gates on
settings.canEmbedrather than re-derivingisOpen && formUrl && valid. That's exactly what the flag is for. force-dynamic,AppLinkovernext/link, closed state and fresh-DB state both handled without crashing.
Blocking
1. The page lists 9 domains; there are 6
The live form offers exactly these, verbatim:
Competitive Programming
Design
Events
Technical
Sponsorship
Social Media & Marketing
The domains array in src/app/join/page.tsx has nine, and Design is missing entirely while Problem Setting, Content & Editorial, and Operations & Logistics don't exist as domains. As it stands someone reads "Problem Setting" on /join, opens the form, and there's no such option.
This isn't your fault — the six were finalised after you'd started and nobody sent them over. The mapping:
- Frontend Development + Backend & Systems → Technical
- Social Media & Outreach + Content & Editorial → Social Media & Marketing
- Problem Setting → drop (it's now a yes/no question inside the CP section of the form)
- Operations & Logistics → drop, or fold into Events
- Add Design
The tag values will need a pass too.
2. "You can apply to more than one domain in your submission"
The form is single-select with section branching — one domain, one section. This line sets an expectation the form doesn't meet, so it needs to go.
Please confirm before merge
<h1>: "Join the Core Team" — the roster distinguishes coordinator / core / members, and recruits presumably join as members. Reads as overpromising unless it's deliberate.- The 4-step timeline (Application → Review & Shortlist → Interaction / Task → Onboarding) is plausible but invented. Worth confirming it matches the real process before it's on a public page.
Minor, your call
settings.cycle || "2026–27"hardcodes a fallback — if an admin leaves the cycle blank the page shows 2026–27 indefinitely.- The closed state says it twice: "Recruitment is Closed" in the hero and "Recruitment is currently closed" in the panel.
Once the domain list matches the form, this is good to go.
barunaniket
left a comment
There was a problem hiding this comment.
Verified against the file at head, not just the diff. Both blockers are resolved:
- Six domains, matching the live form verbatim — Competitive Programming, Technical, Design, Events, Sponsorship, Social Media & Marketing. Design is in; Problem Setting, Content & Editorial and Operations & Logistics are gone.
- "You can apply to more than one domain" is gone, replaced with singular phrasing that matches how the form actually behaves.
- "Core Team" removed from the heading, the metadata and the onboarding step.
The cycle-label fix is better than what I asked for — making it conditional throughout, so a blank cycle drops the label instead of rendering a stale year, is the right call and covers the fresh-database case too.
CI verify passes, and there's no overlap with the admin work that landed in #205/#206.
Merging. One copy change is coming in a follow-up rather than another round trip on your branch: the four-step timeline describes a shortlist-then-task-then-onboarding process that hasn't actually been decided — everything after submission is being handled from the response sheet for now. That's on us for not telling you; the section reads well, it just promises applicants a round that may not happen. I'll trim it to what we can stand behind.
Summary
Companion to
docs/recruitment.mdanddocs/recruitment-workplan.md. This is PR B of 3 (the public recruitment surface and form embed)./join(src/app/join/page.tsx) with server-side rendering (force-dynamic), reading recruitment drive state fromgetRecruitmentSettings().GoogleFormEmbedserver component (src/components/join/GoogleFormEmbed.tsx) with a theme-aware card wrapper (dark mode deliberate white card styling), responsive min-height, nosandboxrestrictions, and an external new-tab fallback link.next.config.ts: addshttps://docs.google.comtoframe-srcwhile leavingframe-ancestorsandX-Frame-Optionsstrictly intact.Joinlink toNavbar.tsxandFooter.tsx.Apply now →CTA button on the homepage (/) under the member benefits section using@/components/AppLink.isOpen: falseorformUrl: null, renders a clean closed notice with links to Instagram rather than an empty frame or crash.Type of change
How was this tested?
npm run test: 90/90 tests passed.npx tsc --noEmit: 0 TypeScript errors.npm run lint: 0 ESLint errors.npm run build: Production build succeeded cleanly (ƒ /joinserver-rendered).HTTP 200 OK, CSPframe-srcheaders, and HTML rendering for/joinand/.Checklist
npx tsc --noEmit,npm run lint,npm run test,npm run buildpackage-lock.jsonchanges