* chore: fix storybook build * chore: implement theming * community list not showing properly * refactor: migrate Chip component to @cio/ui/custom/chip - Updated imports for the Chip component across multiple files to use the new location in the @cio/ui package. - Replaced the previous Chip implementation with a new version that utilizes a Badge for better styling and functionality. - Adjusted related components to ensure consistent usage of the updated Chip component. * fix: align course sidebar design to match organization design (#611) * fix: align course sidebar design to match organization design * feat: add hideSearch prop to AppHeader and update sidebar layout --------- Co-authored-by: Rotimi Best <best@classroomio.com> * refactor: replace PrimaryButton with Button component across multiple files - Updated various components to use the new Button component from @cio/ui/base/button instead of the deprecated PrimaryButton. - Ensured consistent button usage throughout the application for improved styling and functionality. - Removed the PrimaryButton component and its associated constants from the codebase. * refactor: standardize button and input usage across components - Replaced instances of deprecated components such as TextField, TextArea, and IconButton with their updated counterparts (InputField, TextareaField, and updated IconButton). - Ensured consistent event handling by changing `onClick` to `onclick` for better alignment with Svelte's event binding conventions. - Removed unused components and streamlined imports to enhance code maintainability and readability. * chore: themeing, course card, use $features * refactor: centralize UI components and update modal implementations - Refactored various components to centralize UI elements, improving discoverability and maintainability. - Replaced deprecated modal components with the new Dialog component for consistent modal behavior across the application. - Removed unused components and streamlined imports to enhance code clarity and reduce complexity. * feat: add new documentation and refactor org and lms UI components - Introduced new documentation files for Auth Flow, Breadcrumbs Refactoring, Page and Route Creation, and Route Page Setup to enhance developer onboarding and reference. - Refactored various UI components, including the Course Sidebar and Lesson Modal, to improve layout and functionality. - Removed deprecated components and streamlined imports for better maintainability. - Updated translations across multiple languages to ensure consistency in user experience. * refactor: update UI components and improve styling consistency - Refactored various components to enhance styling consistency, including updates to button and text color classes. - Removed deprecated components and streamlined imports for better maintainability. - Replaced instances of PageBody with a more flexible Page component structure across multiple routes. - Updated translations and UI elements to align with the new design system. - Deleted unused components to reduce code complexity and improve clarity. * update output.css --------- Co-authored-by: Abdulmuizz Hamzat <103611443+canhamzacode@users.noreply.github.com>
183 lines
5.1 KiB
Svelte
183 lines
5.1 KiB
Svelte
<script lang="ts">
|
|
import { page } from '$app/state';
|
|
|
|
import { OrgLandingPage, PlayQuiz } from '$features/org';
|
|
import { Snackbar } from '$features/ui';
|
|
import { UpgradeModal, PageLoadProgress, PageRestricted } from '$features/ui';
|
|
import { user } from '$lib/utils/store/user';
|
|
import { setupAnalytics } from '$lib/utils/functions/appSetup';
|
|
import { setTheme } from '$lib/utils/functions/theme';
|
|
import { initOrgAnalytics } from '$lib/utils/services/posthog';
|
|
import { globalStore } from '$lib/utils/store/app';
|
|
import { currentOrg } from '$lib/utils/store/org';
|
|
import { appInitApi } from '$features/app/init.svelte';
|
|
import merge from 'lodash/merge';
|
|
import { onMount } from 'svelte';
|
|
import { MetaTags } from 'svelte-meta-tags';
|
|
import { authClient } from '$lib/utils/services/auth/client';
|
|
import { isPublicRoute } from '$lib/utils/functions/routes/isPublicRoute';
|
|
|
|
import { ModeWatcher } from '@cio/ui/base/dark-mode';
|
|
|
|
import '../app.css';
|
|
|
|
let { data, children } = $props();
|
|
|
|
let path = $derived(page.url.pathname);
|
|
|
|
function intialAppSetup() {
|
|
console.log(
|
|
'Welcome to ClassroomIO, we are grateful you chose us.',
|
|
page.url.host,
|
|
`\nIs student domain: ${data.isOrgSite}`,
|
|
data
|
|
);
|
|
|
|
setupAnalytics();
|
|
|
|
if (data.locals.user) {
|
|
user.set({
|
|
...$user,
|
|
isLoggedIn: true,
|
|
currentSession: data.locals.user
|
|
});
|
|
}
|
|
|
|
console.log('user', $user);
|
|
|
|
// Authentication Steps
|
|
if (!data.isOrgSite || !data.org) return;
|
|
|
|
$globalStore.orgSiteName = data.orgSiteName;
|
|
$globalStore.isOrgSite = data.isOrgSite;
|
|
|
|
currentOrg.set(data.org);
|
|
|
|
// Setup internal analytics
|
|
initOrgAnalytics(data.orgSiteName);
|
|
|
|
setTheme(data.org?.theme);
|
|
}
|
|
|
|
onMount(() => {
|
|
intialAppSetup();
|
|
|
|
if (data.skipAuth) return;
|
|
});
|
|
|
|
const session = authClient.useSession();
|
|
const isSessionReady = $derived(!$session.isPending && !$session.isRefetching && $session.data);
|
|
|
|
// The goal of this effect is to make sure that we do a redirect to /login if the session data is expired
|
|
// This should be happening on the hooks.server.ts but we've made the home page public so we can show a loading spinner while the app is initializing OR an error message if the backend is down.
|
|
$effect(() => {
|
|
if ($session.isPending || $session.isRefetching) {
|
|
console.log('session is pending or refetching');
|
|
return;
|
|
}
|
|
console.log('path', path);
|
|
console.log('isPublicRoute', isPublicRoute(path));
|
|
|
|
// No need to require login for public routes
|
|
if (isPublicRoute(path)) return;
|
|
|
|
if (!$session.data && path !== '/login') {
|
|
console.log('session data is not available, go to login');
|
|
window.location.href = '/login';
|
|
}
|
|
});
|
|
|
|
$effect(() => {
|
|
// this means the session cookie 'classroomio.session_data' expired and we need to trigger a new session
|
|
// triggering a new session will update the session data in the cookies so that our hooks.server.ts doesn't always have to hit the DB when checking if user is logged in or not. Without the session cookie, every page navigation or route would always hit the database to check if user is logged in or not.
|
|
if (!data.locals.fromSessions && isSessionReady) {
|
|
authClient.getSession().then(() => {
|
|
console.log('triggered new session');
|
|
});
|
|
}
|
|
});
|
|
|
|
$effect(() => {
|
|
if (isSessionReady && !appInitApi.isInitializedAndReady && !appInitApi.loading) {
|
|
console.log('setting up account with session data');
|
|
|
|
appInitApi.setupApp($session.data as App.Locals, {
|
|
isOrgSite: data.isOrgSite,
|
|
orgSiteName: data.orgSiteName
|
|
});
|
|
}
|
|
});
|
|
|
|
const metaTags = $derived(merge(data.baseMetaTags, page.data.pageMetaTags));
|
|
</script>
|
|
|
|
<ModeWatcher />
|
|
|
|
<MetaTags {...metaTags} />
|
|
|
|
<UpgradeModal />
|
|
|
|
<Snackbar />
|
|
|
|
{#if data.org?.isRestricted || $currentOrg.isRestricted}
|
|
<PageRestricted />
|
|
{:else if data.skipAuth}
|
|
<PlayQuiz />
|
|
{:else if data.isOrgSite && data.org && path === '/'}
|
|
<OrgLandingPage orgSiteName={data.orgSiteName} org={data.org} />
|
|
{:else}
|
|
<PageLoadProgress zIndex={10000} />
|
|
|
|
{@render children?.()}
|
|
{/if}
|
|
|
|
<style>
|
|
:global(:root) {
|
|
--main-primary-color: rgba(29, 78, 216, 1);
|
|
--border-color: #eaecef;
|
|
}
|
|
|
|
:global(.dark svg.dark) {
|
|
fill: #fff;
|
|
}
|
|
|
|
:global(.border-c) {
|
|
border: 1px solid var(--border-color);
|
|
}
|
|
|
|
:global(.border-bottom-c) {
|
|
border-bottom: 1px solid var(--border-color);
|
|
}
|
|
|
|
:global(.plyr__controls) {
|
|
background:
|
|
url(/logo-192.png) 99% 70% no-repeat,
|
|
linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5)) !important;
|
|
background-size:
|
|
50px auto,
|
|
auto !important;
|
|
}
|
|
|
|
:global(.cards-container) {
|
|
width: 90%;
|
|
margin: 0 auto;
|
|
padding: 0;
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
column-gap: 12px;
|
|
row-gap: 12px;
|
|
}
|
|
|
|
@media screen and (max-width: 768px) {
|
|
:global(.cards-container) {
|
|
width: 95%;
|
|
margin: 0 auto;
|
|
padding: 0;
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
column-gap: 12px;
|
|
row-gap: 12px;
|
|
}
|
|
}
|
|
</style>
|