feat: centralize baseURL and app experience for cloud and self hosted
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
import ArrowLeftIcon from '@lucide/svelte/icons/arrow-left';
|
||||
|
||||
import { IconButton } from '@cio/ui/custom/icon-button';
|
||||
import { globalStore } from '$lib/utils/store/app';
|
||||
import { isStudentExperience } from '$lib/utils/store/app';
|
||||
import { currentOrgPath } from '$lib/utils/store/org';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
let { title = $bindable(''), navClass = '', isCoursePage = false }: Props = $props();
|
||||
|
||||
let coursesPath = $derived(
|
||||
$globalStore.isStudent ? '/lms/mylearning' : isCoursePage ? `${$currentOrgPath}/courses` : $currentOrgPath
|
||||
$isStudentExperience ? '/lms/mylearning' : isCoursePage ? `${$currentOrgPath}/courses` : $currentOrgPath
|
||||
);
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { resolve } from '$app/paths';
|
||||
import { ROLE } from '@cio/utils/constants';
|
||||
import { user } from '$lib/utils/store/user';
|
||||
import { currentOrg, currentOrgPath } from '$lib/utils/store/org';
|
||||
import { basePath } from '$lib/utils/store/app';
|
||||
import { isCoursePage } from '$lib/utils/functions/app';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import type { TCustomLinks } from './types';
|
||||
@@ -38,11 +37,10 @@
|
||||
let redirect = $derived(isCoursePage(page.url.pathname) ? `?redirect=${page.url.pathname}` : '');
|
||||
let showLinks = $derived(customLinks && customLinks.show && customLinks.links && customLinks.links.length > 0);
|
||||
|
||||
let isAdminOrTeacher = $derived($currentOrg.roleId === ROLE.ADMIN || $currentOrg.roleId === ROLE.TUTOR);
|
||||
let gotoHref = $derived(
|
||||
isAdminOrTeacher && $currentOrgPath !== '#' ? resolve($currentOrgPath, {}) : resolve('/lms', {})
|
||||
let gotoHref = $derived(resolve($basePath !== '#' ? $basePath : '/lms', {}));
|
||||
let gotoLabel = $derived(
|
||||
$basePath === '/lms' || $basePath === '#' ? 'navigation.goto_lms' : 'navigation.goto_dashboard'
|
||||
);
|
||||
let gotoLabel = $derived(isAdminOrTeacher ? 'navigation.goto_dashboard' : 'navigation.goto_lms');
|
||||
|
||||
function toggleMobileMenu() {
|
||||
mobileMenuOpen = !mobileMenuOpen;
|
||||
|
||||
@@ -122,35 +122,27 @@ class AppInitApi extends BaseApi {
|
||||
}
|
||||
|
||||
const isStudent = get(isOrgStudent);
|
||||
|
||||
const userHasOrganizations = this.data.organizations.length > 0;
|
||||
|
||||
const isCloud = PUBLIC_IS_SELFHOSTED !== 'true';
|
||||
|
||||
// CLOUD: when user has no orgs and isOrgSite is false, route to /onboarding
|
||||
// isOrgSite - means the user is on a multi tenant organization site, we don't want to redirect to /onboarding in this case
|
||||
if (isCloud) {
|
||||
const shouldRedirectToOnboarding = !userHasOrganizations && !isOrgSite;
|
||||
|
||||
if (shouldRedirectToOnboarding) {
|
||||
return goto(resolve(`/onboarding`, {}));
|
||||
}
|
||||
|
||||
if (!shouldRedirectOnAuth(page.url.pathname)) return;
|
||||
|
||||
return isOrgSite || isStudent ? this.goToLMS() : this.goToOrg();
|
||||
} else {
|
||||
// Self-hosted: when user has no orgs, route to /onboarding
|
||||
// This should only happen once cause Self hosted instance is single tenant
|
||||
//
|
||||
if (!userHasOrganizations) {
|
||||
return goto(resolve(`/onboarding`, {}));
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldRedirectOnAuth(page.url.pathname)) return;
|
||||
|
||||
return isStudent ? this.goToLMS() : this.goToOrg();
|
||||
}
|
||||
const shouldGoToLMS = isCloud ? isOrgSite || !!isStudent : !!isStudent;
|
||||
return shouldGoToLMS ? this.goToLMS() : this.goToOrg();
|
||||
}
|
||||
|
||||
goToLMS() {
|
||||
|
||||
@@ -104,10 +104,11 @@ function isURLCustomDomain(url: URL) {
|
||||
}
|
||||
|
||||
export function getSubdomain(url: URL) {
|
||||
const appHost = env.PRIVATE_APP_HOST;
|
||||
if (!appHost) return null;
|
||||
|
||||
const host = url.hostname.replace('www.', '');
|
||||
const parts = host.split('.');
|
||||
const appHost = env.PRIVATE_APP_HOST;
|
||||
|
||||
const appHostParts = appHost.split('.');
|
||||
const isAppHost = parts.slice(-appHostParts.length).join('.') === appHost;
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ import type {
|
||||
UpvotePostRequest
|
||||
} from '../utils/types';
|
||||
import { ZCommunityComment, ZCommunityQuestionUpdate, ZCreateCommunityQuestion } from '@cio/utils/validation/community';
|
||||
import { currentOrgPath, currentOrg as currentOrgStore } from '$lib/utils/store/org';
|
||||
import { currentOrg as currentOrgStore } from '$lib/utils/store/org';
|
||||
|
||||
import type { TCreateCommunityQuestion } from '@cio/utils/validation/community';
|
||||
import { coursesApi } from '$features/course/api/courses.svelte';
|
||||
import { currentCommunityQuestion } from '../utils/store';
|
||||
import generateSlug from '$lib/utils/functions/generateSlug';
|
||||
import { get } from 'svelte/store';
|
||||
import { globalStore } from '$lib/utils/store/app';
|
||||
import { basePath, isStudentExperience } from '$lib/utils/store/app';
|
||||
import { goto } from '$app/navigation';
|
||||
import { mapZodErrorsToTranslations } from '$lib/utils/validation';
|
||||
import { profile as profileStore } from '$lib/utils/store/user';
|
||||
@@ -70,9 +70,8 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
* Fetches community questions for an organization
|
||||
* Handles API call, success/error handling, and navigation
|
||||
* @param orgId Organization ID
|
||||
* @param isLMS Whether this is in LMS context (affects navigation path)
|
||||
*/
|
||||
async fetchCommunityQuestions({ orgId, isLMS = false }: { orgId: string; isLMS?: boolean }) {
|
||||
async fetchCommunityQuestions({ orgId }: { orgId: string }) {
|
||||
await this.execute<typeof classroomio.community.$get>({
|
||||
requestFn: () => classroomio.community.$get({ query: { orgId } }),
|
||||
logContext: 'fetching community questions',
|
||||
@@ -81,8 +80,7 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
},
|
||||
onError: (result) => {
|
||||
console.error('Error loading community questions:', result);
|
||||
const basePath = isLMS ? '/lms' : get(currentOrgPath);
|
||||
goto(resolve(basePath, {}));
|
||||
goto(resolve(get(basePath), {}));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -91,9 +89,8 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
* Fetches a single community question by slug
|
||||
* Handles API call, success/error handling, navigation, and store updates
|
||||
* @param slug Question slug
|
||||
* @param isLMS Whether this is in LMS context (affects navigation path and store updates)
|
||||
*/
|
||||
async fetchCommunityQuestion({ slug, isLMS = false }: { slug: string; isLMS?: boolean }) {
|
||||
async fetchCommunityQuestion({ slug }: { slug: string }) {
|
||||
await this.execute<(typeof classroomio.community)[':slug']['$get']>({
|
||||
requestFn: () => classroomio.community[':slug'].$get({ param: { slug } }),
|
||||
logContext: 'fetching community question',
|
||||
@@ -105,9 +102,9 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
}
|
||||
},
|
||||
onError: (result) => {
|
||||
console.error(`[${isLMS ? 'LMS' : 'ORG'}] Error loading community`, result);
|
||||
const basePath = isLMS ? '/lms' : get(currentOrgPath);
|
||||
goto(resolve(basePath, {}));
|
||||
const isStudent = get(isStudentExperience);
|
||||
console.error(`[${isStudent ? 'LMS' : 'ORG'}] Error loading community`, result);
|
||||
goto(resolve(get(basePath), {}));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -116,9 +113,8 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
* Creates a new community question
|
||||
* Handles validation, API call, success/error handling, and navigation
|
||||
* @param fields User-provided fields (title, body, courseId)
|
||||
* @param isLMS Whether this is in LMS context (affects navigation path)
|
||||
*/
|
||||
async createQuestion(fields: TCreateCommunityQuestion, isLMS: boolean = false) {
|
||||
async createQuestion(fields: TCreateCommunityQuestion) {
|
||||
const result = ZCreateCommunityQuestion.safeParse(fields);
|
||||
if (!result.success) {
|
||||
this.errors = mapZodErrorsToTranslations(result.error, 'community');
|
||||
@@ -156,8 +152,8 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
snackbar.success('snackbar.community.success.question_submitted');
|
||||
|
||||
// Navigate to the question based on context
|
||||
const basePath = isLMS ? '/lms' : get(currentOrgPath);
|
||||
goto(resolve(`${basePath}/community/${questionSlug}`, {}));
|
||||
const path = get(basePath);
|
||||
goto(resolve(`${path}/community/${questionSlug}`, {}));
|
||||
|
||||
// Mark as successful
|
||||
this.success = true;
|
||||
@@ -178,10 +174,9 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
* Handles validation, API call, and success/error handling
|
||||
* Uses this.comment state for the comment body
|
||||
* @param questionId Question ID
|
||||
* @param isLMS Whether this is in LMS context (affects store updates)
|
||||
* @param onSuccess Optional callback to execute on successful comment creation
|
||||
*/
|
||||
async createComment(questionId: number, isLMS: boolean = false, onSuccess?: () => void) {
|
||||
async createComment(questionId: number, onSuccess?: () => void) {
|
||||
const profile = get(profileStore);
|
||||
if (!profile?.id) {
|
||||
snackbar.error('snackbar.community.error.missing_context');
|
||||
@@ -220,7 +215,7 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
|
||||
// Refetch the question to get updated comments with proper structure
|
||||
if (this.question && this.question.slug) {
|
||||
this.fetchCommunityQuestion({ slug: this.question.slug, isLMS });
|
||||
this.fetchCommunityQuestion({ slug: this.question.slug });
|
||||
}
|
||||
|
||||
// Call the onSuccess callback if provided
|
||||
@@ -369,9 +364,8 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
* Deletes a question by its ID (including all comments)
|
||||
* Handles API call, success/error handling, and navigation
|
||||
* @param questionId Question ID
|
||||
* @param isLMS Whether this is in LMS context (affects navigation path)
|
||||
*/
|
||||
async deleteQuestion(questionId: string, isLMS: boolean = false) {
|
||||
async deleteQuestion(questionId: string) {
|
||||
await this.execute<(typeof classroomio.community)[':id']['$delete']>({
|
||||
requestFn: () => classroomio.community[':id'].$delete({ param: { id: questionId } }),
|
||||
logContext: 'deleting community question',
|
||||
@@ -380,8 +374,8 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
snackbar.success('snackbar.community.success.success_delete');
|
||||
|
||||
// Navigate back to community page based on context
|
||||
const basePath = isLMS ? '/lms' : get(currentOrgPath);
|
||||
goto(resolve(`${basePath}/community`, {}));
|
||||
const path = get(basePath);
|
||||
goto(resolve(`${path}/community`, {}));
|
||||
|
||||
// Mark as successful
|
||||
this.success = true;
|
||||
@@ -438,9 +432,9 @@ class CommunityApi extends BaseApiWithErrors {
|
||||
async fetchCoursesForOrg(userId: string | null, orgId: string) {
|
||||
if (this.courses.length || !userId || !orgId) return;
|
||||
|
||||
const isLMS = get(globalStore).isOrgSite;
|
||||
const isStudent = get(isStudentExperience);
|
||||
|
||||
if (isLMS) {
|
||||
if (isStudent) {
|
||||
const response = await coursesApi.getEnrolledCourses();
|
||||
|
||||
if (response?.success && response?.data) {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { goto } from '$app/navigation';
|
||||
import { currentOrgPath } from '$lib/utils/store/org';
|
||||
import { resolve } from '$app/paths';
|
||||
import { basePath } from '$lib/utils/store/app';
|
||||
import { Button } from '@cio/ui/base/button';
|
||||
import { isMobileStore } from '@cio/ui/hooks/is-mobile.svelte';
|
||||
import PlusIcon from '@lucide/svelte/icons/plus';
|
||||
|
||||
let { isLMS = false }: { isLMS?: boolean } = $props();
|
||||
|
||||
function askCommunity() {
|
||||
goto(`${isLMS ? '/lms/community/ask' : `${$currentOrgPath}/community/ask`}`);
|
||||
goto(resolve(`${$basePath}/community/ask`, {}));
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
import { currentOrg } from '$lib/utils/store/org';
|
||||
import { communityApi } from '$features/community/api/community.svelte';
|
||||
|
||||
interface Props {
|
||||
isLMS?: boolean;
|
||||
}
|
||||
|
||||
let { isLMS = false }: Props = $props();
|
||||
|
||||
let fields = $state({
|
||||
title: '',
|
||||
body: '',
|
||||
@@ -45,10 +39,8 @@
|
||||
</p>
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each communityApi.courses as course}
|
||||
{#if course.id}
|
||||
{#each communityApi.courses as course (course.id)}
|
||||
<Select.Item value={course.id}>{course.title}</Select.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
@@ -68,11 +60,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-end">
|
||||
<Button
|
||||
variant="default"
|
||||
onclick={() => communityApi.createQuestion(fields, isLMS)}
|
||||
disabled={communityApi.isLoading}
|
||||
>
|
||||
<Button variant="default" onclick={() => communityApi.createQuestion(fields)} disabled={communityApi.isLoading}>
|
||||
{$t('community.ask.publish')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -26,11 +26,10 @@
|
||||
|
||||
interface Props {
|
||||
slug: string;
|
||||
isLMS?: boolean;
|
||||
question?: CommunityQuestionSuccess['data'] | null;
|
||||
}
|
||||
|
||||
let { isLMS = false, question }: Props = $props();
|
||||
let { question }: Props = $props();
|
||||
|
||||
let commentEditor: TiptapEditor | undefined = $state();
|
||||
let isValidAnswer = false; // V2 allow admin mark an answer as accepted
|
||||
@@ -86,7 +85,7 @@
|
||||
}}
|
||||
onDelete={() => {
|
||||
if (communityApi.question) {
|
||||
communityApi.deleteQuestion(String(communityApi.question.id), isLMS);
|
||||
communityApi.deleteQuestion(String(communityApi.question.id));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -119,10 +118,8 @@
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each communityApi.courses as course}
|
||||
{#if course.id}
|
||||
{#each communityApi.courses as course (course.id)}
|
||||
<Select.Item value={course.id}>{course.title}</Select.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
@@ -224,7 +221,7 @@
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
{#each communityApi.question?.comments as commentItem}
|
||||
{#each communityApi.question?.comments as commentItem (commentItem.id)}
|
||||
<CommunityCommentItem
|
||||
comment={commentItem}
|
||||
isVoted={!!voted.comment[commentItem.id]}
|
||||
@@ -266,7 +263,7 @@
|
||||
console.log('comment', communityApi.comment);
|
||||
console.log('question', communityApi.question);
|
||||
if (communityApi.question) {
|
||||
communityApi.createComment(Number(communityApi.question.id), isLMS, () => {
|
||||
communityApi.createComment(Number(communityApi.question.id), () => {
|
||||
commentEditor?.commands?.clearContent?.();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,18 +11,18 @@
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { calDateDiff } from '$lib/utils/functions/date';
|
||||
import { currentOrg, currentOrgPath } from '$lib/utils/store/org';
|
||||
import { currentOrg } from '$lib/utils/store/org';
|
||||
import { basePath } from '$lib/utils/store/app';
|
||||
|
||||
import { CommunityListLoader, AskCommunityButton } from '../components';
|
||||
import { communityApi } from '../api/community.svelte';
|
||||
import type { CommunityQuestionData } from '../utils/types';
|
||||
|
||||
interface Props {
|
||||
isLMS?: boolean;
|
||||
questions?: CommunityQuestionData;
|
||||
}
|
||||
|
||||
let { isLMS = false, questions }: Props = $props();
|
||||
let { questions }: Props = $props();
|
||||
|
||||
let searchValue = $state('');
|
||||
let selectedId = $state('');
|
||||
@@ -80,7 +80,7 @@
|
||||
{#each filteredQuestions as question}
|
||||
<Item.Root variant="outline">
|
||||
{#snippet child({ props })}
|
||||
<a href="{isLMS ? '/lms' : $currentOrgPath}/community/{question.slug}" {...props}>
|
||||
<a href="{$basePath}/community/{question.slug}" {...props}>
|
||||
<Vote value={question.votes} />
|
||||
<Item.Content class="gap-y-0.5">
|
||||
<Item.Title class="mt-0">
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@
|
||||
import { courseApi } from '$features/course/api';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { currentOrg, isFreePlan, currentOrgPath } from '$lib/utils/store/org';
|
||||
import { globalStore } from '$lib/utils/store/app';
|
||||
import { isStudentExperience } from '$lib/utils/store/app';
|
||||
import { getNavItemRoute, getLessonsRoute } from '$features/course/utils/functions';
|
||||
import { useSidebar } from '@cio/ui/base/sidebar';
|
||||
import { IconButton } from '@cio/ui/custom/icon-button';
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
let { path, id, isStudent = false }: Props = $props();
|
||||
|
||||
const coursesListPath = $derived($globalStore.isStudent ? '/lms/mylearning' : `${$currentOrgPath}/courses`);
|
||||
const coursesListPath = $derived($isStudentExperience ? '/lms/mylearning' : `${$currentOrgPath}/courses`);
|
||||
const contentData = $derived(getCourseContent(courseApi.course));
|
||||
const sidebar = useSidebar();
|
||||
const contentCount = $derived.by(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { globalStore } from '$lib/utils/store/app';
|
||||
import { basePath, globalStore } from '$lib/utils/store/app';
|
||||
import * as DropdownMenu from '@cio/ui/base/dropdown-menu';
|
||||
import RocketIcon from '@lucide/svelte/icons/rocket';
|
||||
import BellPlusIcon from '@lucide/svelte/icons/bell-plus';
|
||||
@@ -11,8 +11,6 @@
|
||||
import ChevronsUpDownIcon from '@lucide/svelte/icons/chevrons-up-down';
|
||||
import ThemeToggle from './theme-toggle.svelte';
|
||||
|
||||
import { currentOrgPath } from '$lib/utils/store/org';
|
||||
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { logout } from '$lib/utils/functions/logout';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
@@ -38,10 +36,7 @@
|
||||
|
||||
{#snippet usertrigger()}
|
||||
<DropdownMenu.Label class="p-0">
|
||||
<a
|
||||
href={`${!$globalStore.isOrgSite ? $currentOrgPath : '/lms'}/settings`}
|
||||
class="flex items-center gap-2 px-1 py-1.5 text-left text-sm"
|
||||
>
|
||||
<a href={`${$basePath}/settings`} class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
||||
{@render avatarblock()}
|
||||
</a>
|
||||
</DropdownMenu.Label>
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
import * as Avatar from '@cio/ui/base/avatar';
|
||||
import * as Sidebar from '@cio/ui/base/sidebar';
|
||||
import { Skeleton } from '@cio/ui/base/skeleton';
|
||||
import { currentOrg, currentOrgPath } from '$lib/utils/store/org';
|
||||
import { currentOrg } from '$lib/utils/store/org';
|
||||
import { shortenName } from '$lib/utils/functions/string';
|
||||
import { globalStore } from '$lib/utils/store/app';
|
||||
|
||||
const orgPath = $derived($globalStore.isOrgSite ? '/lms' : $currentOrgPath);
|
||||
import { basePath } from '$lib/utils/store/app';
|
||||
</script>
|
||||
|
||||
<Sidebar.Menu>
|
||||
@@ -16,7 +14,7 @@
|
||||
class="ui:data-[state=open]:bg-sidebar-accent ui:data-[state=open]:text-sidebar-accent-foreground"
|
||||
>
|
||||
{#snippet child({ props })}
|
||||
<a href={orgPath} {...props}>
|
||||
<a href={$basePath} {...props}>
|
||||
{#if $currentOrg.name}
|
||||
<Avatar.Root class="flex size-6! items-center justify-center rounded-md!">
|
||||
<Avatar.Image src={$currentOrg.avatarUrl} alt={$currentOrg.name} />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import { PUBLIC_IS_SELFHOSTED } from '$env/static/public';
|
||||
import { currentOrgPath } from './org';
|
||||
|
||||
export const globalStore = writable<{
|
||||
isDark: boolean;
|
||||
@@ -11,3 +13,20 @@ export const globalStore = writable<{
|
||||
orgSiteName: '',
|
||||
isStudent: undefined
|
||||
});
|
||||
|
||||
/**
|
||||
* Single source of truth: is this a student experience?
|
||||
* Cloud: orgSite is always student. Self-hosted: check role.
|
||||
*/
|
||||
export const isStudentExperience = derived(globalStore, ($gs) => {
|
||||
const isCloud = PUBLIC_IS_SELFHOSTED !== 'true';
|
||||
if (isCloud) return $gs.isOrgSite;
|
||||
return $gs.isStudent ?? false;
|
||||
});
|
||||
|
||||
/**
|
||||
* The root path for navigation: '/lms' for students, '/org/{siteName}' for admin/teacher
|
||||
*/
|
||||
export const basePath = derived([isStudentExperience, currentOrgPath], ([$isStudent, $orgPath]) =>
|
||||
$isStudent ? '/lms' : $orgPath
|
||||
);
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
<Page.Title>{$t('community.title')}</Page.Title>
|
||||
</Page.HeaderContent>
|
||||
<Page.Action>
|
||||
<AskCommunityButton isLMS={true} />
|
||||
<AskCommunityButton />
|
||||
</Page.Action>
|
||||
</Page.Header>
|
||||
<Page.Body>
|
||||
{#snippet child()}
|
||||
<CommunityPage isLMS={true} />
|
||||
<CommunityPage />
|
||||
{/snippet}
|
||||
</Page.Body>
|
||||
</Page.Root>
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
<title>Question - ClassroomIO</title>
|
||||
</svelte:head>
|
||||
|
||||
<CommunityQuestionPage slug={data.slug} isLMS={true} />
|
||||
<CommunityQuestionPage slug={data.slug} />
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</Page.Header>
|
||||
<Page.Body>
|
||||
{#snippet child()}
|
||||
<AskCommunityPage isLMS={true} />
|
||||
<AskCommunityPage />
|
||||
{/snippet}
|
||||
</Page.Body>
|
||||
</Page.Root>
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
<title>Question - ClassroomIO</title>
|
||||
</svelte:head>
|
||||
|
||||
<CommunityQuestionPage slug={data.slug} question={data.question} isLMS={false} />
|
||||
<CommunityQuestionPage slug={data.slug} question={data.question} />
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</Page.Header>
|
||||
<Page.Body>
|
||||
{#snippet child()}
|
||||
<AskCommunityPage isLMS={false} />
|
||||
<AskCommunityPage />
|
||||
{/snippet}
|
||||
</Page.Body>
|
||||
</Page.Root>
|
||||
|
||||
Reference in New Issue
Block a user