From 2246bd61a6d5daae3e999d8b6cfdcbc3f35cebaf Mon Sep 17 00:00:00 2001 From: austinchan3678 Date: Thu, 20 Aug 2026 01:11:58 -0600 Subject: [PATCH] feat(onboarding): accept pipeline.sbcc.edu emails --- discord/api/onboarding_token.go | 23 +++++++++++----- web/src/pages/onboarding/OnboardingPage.tsx | 27 ++++++++++--------- .../onboarding/steps/CredentialsStep.tsx | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/discord/api/onboarding_token.go b/discord/api/onboarding_token.go index 96152e9..f8fc710 100644 --- a/discord/api/onboarding_token.go +++ b/discord/api/onboarding_token.go @@ -69,10 +69,19 @@ var validInitialRoles = map[string]bool{ "guest": true, } -// isUCSBEmail reports whether the email's domain is ucsb.edu (case-insensitive). -func isUCSBEmail(email string) bool { +var studentEmailDomains = map[string]bool{ + "ucsb.edu": true, + "pipeline.sbcc.edu": true, +} + +// isStudentEmail reports whether the email's domain is a recognized student +// domain (ucsb.edu or pipeline.sbcc.edu), case-insensitive. +func isStudentEmail(email string) bool { parts := strings.SplitN(email, "@", 2) - return len(parts) == 2 && strings.EqualFold(parts[1], "ucsb.edu") + if len(parts) != 2 { + return false + } + return studentEmailDomains[strings.ToLower(parts[1])] } func ConsumeOnboardingToken(c *gin.Context) { @@ -92,9 +101,9 @@ func ConsumeOnboardingToken(c *gin.Context) { switch req.InitialRole { case "member": - if !isUCSBEmail(req.Email) { + if !isStudentEmail(req.Email) { c.JSON(http.StatusBadRequest, gin.H{ - "error": "current members must sign up with their @ucsb.edu email", + "error": "current members must sign up with their @ucsb.edu or @pipeline.sbcc.edu email", }) return } @@ -105,9 +114,9 @@ func ConsumeOnboardingToken(c *gin.Context) { return } case "alumni": - if isUCSBEmail(req.Email) { + if isStudentEmail(req.Email) { c.JSON(http.StatusBadRequest, gin.H{ - "error": "alumni must sign up with a personal email since @ucsb.edu addresses expire after graduation", + "error": "alumni must sign up with a personal email since @ucsb.edu and @pipeline.sbcc.edu addresses expire after graduation", }) return } diff --git a/web/src/pages/onboarding/OnboardingPage.tsx b/web/src/pages/onboarding/OnboardingPage.tsx index 01f7bd8..148ee38 100644 --- a/web/src/pages/onboarding/OnboardingPage.tsx +++ b/web/src/pages/onboarding/OnboardingPage.tsx @@ -38,7 +38,7 @@ const HOLD_MS = 250 const STEP_SLIDE_PX = 24 -const STUDENT_DOMAIN = "ucsb.edu" +const STUDENT_DOMAINS = new Set(["ucsb.edu", "pipeline.sbcc.edu"]) const stepVariants: Variants = { enter: (dir: "forward" | "back") => ({ @@ -172,12 +172,13 @@ export default function OnboardingPage() { const emailDomain = data.email.split("@")[1]?.toLowerCase() ?? "" const hasFullDomain = emailDomain.includes(".") - const memberNeedsUcsbEmail = - data.role === "member" && hasFullDomain && emailDomain !== STUDENT_DOMAIN - const alumniRejectsUcsbEmail = - data.role === "alumni" && emailDomain === STUDENT_DOMAIN + const isStudentEmail = STUDENT_DOMAINS.has(emailDomain) + const memberNeedsStudentEmail = + data.role === "member" && hasFullDomain && !isStudentEmail + const alumniRejectsStudentEmail = + data.role === "alumni" && isStudentEmail const emailRoleMismatch = - currentStep === "credentials" && (memberNeedsUcsbEmail || alumniRejectsUcsbEmail) + currentStep === "credentials" && (memberNeedsStudentEmail || alumniRejectsStudentEmail) function update(patch: Partial) { setData((prev) => ({ ...prev, ...patch })) @@ -399,19 +400,21 @@ export default function OnboardingPage() { <> Use a personal email - UCSB emails expire after graduation. Sign up with a personal email + School emails expire after graduation. Sign up with a personal email so you keep access after your{" "} - @ucsb.edu{" "} + @ucsb.edu or{" "} + @pipeline.sbcc.edu{" "} account is deactivated. ) : ( <> - UCSB email required + Student email required Current members must sign up with their{" "} - @ucsb.edu email - so we can verify enrollment. You're using{" "} + @ucsb.edu or{" "} + @pipeline.sbcc.edu{" "} + email so we can verify enrollment. You're using{" "} @{emailDomain}. @@ -423,7 +426,7 @@ export default function OnboardingPage() { innerClassName="bg-popover" onClick={() => setEmailRoleDialogOpen(false)} > - {data.role === "alumni" ? "Use a different email" : "Use my UCSB email"} + {data.role === "alumni" ? "Use a different email" : "Use my student email"} diff --git a/web/src/pages/onboarding/steps/CredentialsStep.tsx b/web/src/pages/onboarding/steps/CredentialsStep.tsx index 61b92ec..4e91b79 100644 --- a/web/src/pages/onboarding/steps/CredentialsStep.tsx +++ b/web/src/pages/onboarding/steps/CredentialsStep.tsx @@ -19,7 +19,7 @@ export function CredentialsStep({ data, update }: StepProps) { id="email" type="email" autoComplete="email" - placeholder="you@ucsb.edu" + placeholder="you@ucsb.edu or you@pipeline.sbcc.edu" value={data.email} onChange={(e) => update({ email: e.target.value })} required