diff --git a/apps/dashboard/src/routes/(org-site)/+layout.server.ts b/apps/dashboard/src/routes/(org-site)/+layout.server.ts index d634b1ae..d1079dcf 100644 --- a/apps/dashboard/src/routes/(org-site)/+layout.server.ts +++ b/apps/dashboard/src/routes/(org-site)/+layout.server.ts @@ -1,18 +1,11 @@ -import { PUBLIC_ORG_SITE_LIGHT_MODE_ROUTES } from '$lib/utils/constants/routes'; import { error } from '@sveltejs/kit'; -function canResolveOrgFromCoursePath(pathname: string): boolean { - return PUBLIC_ORG_SITE_LIGHT_MODE_ROUTES.some((pattern) => new RegExp(pattern).test(pathname)); -} - -export const load = async ({ parent, url }) => { +export const load = async ({ parent }) => { const { org, isOrgSite } = await parent(); // An org-site subdomain that doesn't resolve to a real org must 404 rather // than fall back to whatever org a requested course happens to belong to. - // Course landing/enroll pages can still resolve org context from the course - // slug when the host lookup fails (e.g. custom domain with a backend port). - if (isOrgSite && !org && !canResolveOrgFromCoursePath(url.pathname)) { + if (isOrgSite && !org) { throw error(404, 'Organization not found'); } diff --git a/apps/dashboard/src/routes/(org-site)/course/[slug]/enroll/+page.svelte b/apps/dashboard/src/routes/(org-site)/course/[slug]/enroll/+page.svelte index 8be53027..29b83edf 100644 --- a/apps/dashboard/src/routes/(org-site)/course/[slug]/enroll/+page.svelte +++ b/apps/dashboard/src/routes/(org-site)/course/[slug]/enroll/+page.svelte @@ -28,8 +28,6 @@ const isEmailVerified = $derived(Boolean($profile.isEmailVerified || sessionUser?.emailVerified)); function resolvePostEnrollRedirect(): string { - // Org-site enrollments are always students — the API's `/courses/:id/lessons` - // target is the admin course editor and 404s or blocks students on custom domains. return '/lms'; } diff --git a/packages/db/src/auth/email-verification.ts b/packages/db/src/auth/email-verification.ts index 9e2fb595..309ba51c 100644 --- a/packages/db/src/auth/email-verification.ts +++ b/packages/db/src/auth/email-verification.ts @@ -11,10 +11,28 @@ type ChangeEmailConfirmationOptions = Parameters< NonNullable['changeEmail']>['sendChangeEmailConfirmation']> >[0]; +/** + * Email verification flow. + * + * 1. user says I want to change my email from email@old.com to email@new.com + * 2. we send an email to email@old.com asking user to verify if they really want to change their email to email@new.com `sendChangeEmailConfirmation()`. [better-auth]. + * 3. user clicks the link in the email + * 4. we update the email in the database. [better-auth]. + * 5. we send a confirmation email to email@new.com `sendVerificationEmail()`. [dashboard]. + * 6. user clicks the link in the email + * 7. we mark email@new.com as verified. [better-auth]. + */ + function stripTriggerParam(url: string): string { return url.replace('trigger=app', '').replace('trigger%3Dapp', ''); } +/** + * Brands verification mail with the org from `resolveVerificationOrg` (callback URL + * host/?org=, self-hosted first org, then the user's first membership). When no + * org applies — e.g. dashboard signup before onboarding creates an org — copy + * and masthead fall back to ClassroomIO defaults. + */ async function sendOrgAwareVerifyEmail(options: { to: string; verificationUrl: string; diff --git a/packages/email/src/emails/verify-email.ts b/packages/email/src/emails/verify-email.ts index 29a06e81..fa358756 100644 --- a/packages/email/src/emails/verify-email.ts +++ b/packages/email/src/emails/verify-email.ts @@ -17,7 +17,10 @@ export const verifyEmailEmail = defineEmail({ render: (fields) => { const isEmailChange = !!fields.newEmail; const userName = fields.userName || 'there'; - const orgName = fields.orgName; + const hasOrgBranding = Boolean(fields.branding?.orgName); + const welcomeLine = hasOrgBranding + ? `Welcome to ${fields.orgName}! In order to get your account ready for usage, we need to verify your email.` + : 'Welcome! In order to get your account ready for usage, we need to verify your email.'; const content = isEmailChange ? ` @@ -31,7 +34,7 @@ export const verifyEmailEmail = defineEmail({ ` : `

Hey ${userName} 👋

-

Welcome to ${orgName}! In order to get your account ready for usage, we need to verify your email.

+

${welcomeLine}

We do this to make sure we don't get fake user emails in our signup. To get the best out of our product, we'll need you to verify your email by clicking the Verify button below.

Verify