fix(dashboard): use verified custom domain for view-as-student handoff (#677)

* fix(dashboard): use verified custom domain for view-as-student handoff

Prefer the org's verified custom domain over window.location.origin when
resolving the public tenant host. This prevents admin URLs like
app.example.com from being used for the student login-link handoff when
the org's public site is example.com.

Co-authored-by: Rotimi Best <[email protected]>

* fix(dashboard): keep self-hosted org origin on window.location

Self-hosted deployments serve admin and LMS from the same URL, so
getOrgPublicOrigin should always return window.location.origin there
rather than preferring a configured custom domain.

Co-authored-by: Rotimi Best <[email protected]>

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
Rotimi Best
2026-06-19 14:50:37 +01:00
committed by GitHub
co-authored by Rotimi Best Cursor Agent
parent 0a6db37566
commit 5320f1eb44
2 changed files with 30 additions and 13 deletions
@@ -1,7 +1,9 @@
import { get } from 'svelte/store';
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
import { snackbar } from '$features/ui/snackbar/store';
import { accountApi } from '$features/account/api/account.svelte';
import { currentOrg, getOrgPublicOrigin } from '$lib/utils/store/org';
interface OpenCoursePreviewOptions {
courseId: string;
@@ -21,7 +23,7 @@ export function getPublicCoursePageUrl(courseSlug: string, currentOrgDomain = ''
}
const trimmedDomain = currentOrgDomain?.trim();
const origin = trimmedDomain || window.location.origin;
const origin = trimmedDomain || getOrgPublicOrigin(get(currentOrg));
return new URL(resolve(`/course/${courseSlug}`, {}), origin).toString();
}
@@ -73,7 +75,7 @@ export async function viewAsStudent({ courseId, currentOrgDomain = '' }: ViewAsS
return false;
}
const origin = currentOrgDomain?.trim() || window.location.origin;
const origin = currentOrgDomain?.trim() || getOrgPublicOrigin(get(currentOrg));
const loginLinkUrl = new URL('/api/auth/login-link', origin);
loginLinkUrl.searchParams.set('token', token);
loginLinkUrl.searchParams.set('redirect', `/courses/${courseId}/lessons?next=true`);
+26 -11
View File
@@ -77,19 +77,34 @@ export const currentOrgPath = derived(currentOrg, ($currentOrg) =>
$currentOrg.siteName ? `/org/${$currentOrg.siteName}` : '#'
);
export const currentOrgDomain = derived(currentOrg, ($currentOrg) => {
if (PUBLIC_IS_SELFHOSTED === 'true') return window.location.origin;
type OrgPublicOrigin = Pick<AccountOrg, 'customDomain' | 'isCustomDomainVerified' | 'siteName'>;
const browserOrigin = dev && browser && window.location.origin;
/**
* Public origin for an org's tenant site (student LMS, public course pages, login-link handoff).
* Self-hosted uses the current deployment URL. On cloud, verified custom domains win over the
* admin host so `app.classroomio.com` still hands off to the org's `example.com` tenant site.
*/
export function getOrgPublicOrigin(org: OrgPublicOrigin): string {
if (PUBLIC_IS_SELFHOSTED === 'true') {
return browser ? window.location.origin : '';
}
return browserOrigin
? browserOrigin
: $currentOrg.customDomain && $currentOrg.isCustomDomainVerified
? `https://${$currentOrg.customDomain}`
: $currentOrg.siteName
? `https://${$currentOrg.siteName}.${TENANT_ROOT_DOMAIN}`
: '';
});
if (org.customDomain && org.isCustomDomainVerified) {
return `https://${org.customDomain}`;
}
if (dev && browser) {
return window.location.origin;
}
if (org.siteName) {
return `https://${org.siteName}.${TENANT_ROOT_DOMAIN}`;
}
return browser ? window.location.origin : '';
}
export const currentOrgDomain = derived(currentOrg, ($currentOrg) => getOrgPublicOrigin($currentOrg));
export const isFreePlan = derived(currentOrg, ($currentOrg) => {
if (!$currentOrg.id || PUBLIC_IS_SELFHOSTED === 'true') return false;