2023-10-29 12:07:34 +00:00
< script lang = "ts" >
2025-11-24 01:00:50 +01:00
import { page } from '$app/state' ;
2024-12-28 23:11:55 +01:00
2025-12-22 02:36:48 +01:00
import { OrgLandingPage , PlayQuiz } from '$features/org' ;
import { Snackbar } from '$features/ui' ;
import { UpgradeModal , PageLoadProgress , PageRestricted } from '$features/ui' ;
2025-11-24 01:00:50 +01:00
import { user } from '$lib/utils/store/user' ;
2024-12-26 07:23:46 +01:00
import { setTheme } from '$lib/utils/functions/theme' ;
import { initOrgAnalytics } from '$lib/utils/services/posthog' ;
2026-03-09 11:18:22 +01:00
import { setupCloudAnalytics } from '$lib/utils/functions/appSetup' ;
2024-12-26 07:23:46 +01:00
import { globalStore } from '$lib/utils/store/app' ;
2026-03-09 11:18:22 +01:00
import { currentOrg , isOrgStudent } from '$lib/utils/store/org' ;
2025-12-22 02:36:48 +01:00
import { appInitApi } from '$features/app/init.svelte' ;
2024-12-26 07:23:46 +01:00
import merge from 'lodash/merge' ;
import { onMount } from 'svelte' ;
import { MetaTags } from 'svelte-meta-tags' ;
2025-11-24 01:00:50 +01:00
import { authClient } from '$lib/utils/services/auth/client' ;
2025-12-22 02:36:48 +01:00
import { isPublicRoute } from '$lib/utils/functions/routes/isPublicRoute' ;
2020-12-24 20:32:05 +02:00
2025-11-01 16:18:29 +01:00
import { ModeWatcher } from '@cio/ui/base/dark-mode' ;
import '../app.css' ;
2021-07-12 05:55:57 +03:00
2025-11-01 15:49:29 +01:00
let { data , children } = $props ();
2023-08-14 06:22:03 +01:00
2025-12-22 02:36:48 +01:00
let path = $derived ( page . url . pathname );
2021-07-31 23:06:14 +03:00
2025-11-24 01:00:50 +01:00
function intialAppSetup() {
2023-05-13 07:16:32 +01:00
console . log (
'Welcome to ClassroomIO, we are grateful you chose us.' ,
2025-11-24 01:00:50 +01:00
page . url . host ,
2025-11-08 05:34:17 +01:00
` \ nIs student domain: ${ data . isOrgSite } ` ,
data
2023-05-13 07:16:32 +01:00
);
2021-11-10 16:20:17 +02:00
2026-03-09 11:18:22 +01:00
setupCloudAnalytics ();
2023-08-02 19:35:27 +01:00
2025-11-24 01:00:50 +01:00
if ( data . locals . user ) {
user . set ({
... $user ,
isLoggedIn : true ,
currentSession : data.locals.user
});
}
2021-09-17 06:33:49 +03:00
2025-11-24 01:00:50 +01:00
console . log ( 'user' , $user );
// Authentication Steps
2025-11-08 18:22:41 +01:00
if ( ! data . isOrgSite || ! data . org ) return ;
2026-03-09 11:18:22 +01:00
$globalStore . orgSiteName = data . orgSiteName || '' ;
2025-11-08 18:27:00 +01:00
$globalStore . isOrgSite = data . isOrgSite ;
2025-11-08 18:22:41 +01:00
2025-11-08 18:27:00 +01:00
currentOrg . set ( data . org );
2025-11-08 18:22:41 +01:00
2025-11-08 18:27:00 +01:00
// Setup internal analytics
2026-03-09 11:18:22 +01:00
if ( data . orgSiteName ) {
initOrgAnalytics ( data . orgSiteName );
}
2025-11-08 18:22:41 +01:00
2026-03-09 11:18:22 +01:00
const theme = data . org ? . theme ;
if ( theme ) {
setTheme ( theme );
}
2025-11-08 18:22:41 +01:00
}
onMount (() => {
2026-03-11 12:01:26 +01:00
const loadingIndicator = document . getElementById ( 'app-loading-indicator' );
if ( loadingIndicator ) {
loadingIndicator . style . display = 'none' ;
}
2025-11-24 01:00:50 +01:00
intialAppSetup ();
2025-11-08 18:22:41 +01:00
2025-11-24 01:00:50 +01:00
if ( data . skipAuth ) return ;
2021-07-31 23:06:14 +03:00
});
2025-11-24 01:00:50 +01:00
const session = authClient . useSession ();
const isSessionReady = $derived ( ! $session . isPending && ! $session . isRefetching && $session . data );
2020-12-24 20:32:05 +02:00
2025-12-22 02:36:48 +01:00
// 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 (() => {
2025-12-25 05:09:27 +01:00
if ( $session . isPending || $session . isRefetching || !! $session . data ) {
2025-12-22 02:36:48 +01:00
console . log ( 'session is pending or refetching' );
return ;
}
// No need to require login for public routes
2026-03-09 11:18:22 +01:00
if ( isPublicRoute ( path ) && ( path !== '/' || data . isOrgSite )) {
return ;
}
2025-12-22 02:36:48 +01:00
if ( ! $session . data && path !== '/login' ) {
console . log ( 'session data is not available, go to login' );
window . location . href = '/login' ;
}
});
2025-11-24 01:00:50 +01:00
$effect (() => {
// this means the session cookie 'classroomio.session_data' expired and we need to trigger a new session
2025-12-22 02:36:48 +01:00
// 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.
2025-11-24 01:00:50 +01:00
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
});
}
});
2026-03-09 11:18:22 +01:00
$effect (() => {
// Means it hasn't been set yet.
if ( $isOrgStudent === null ) return ;
if ( $isOrgStudent !== $globalStore . isStudent ) {
globalStore . update (( s ) => ({ ... s , isStudent : !! $isOrgStudent }));
}
});
2025-11-24 01:00:50 +01:00
const metaTags = $derived ( merge ( data . baseMetaTags , page . data . pageMetaTags ));
</ script >
2022-12-30 13:08:54 +01:00
2026-03-09 11:18:22 +01:00
< div >
< ModeWatcher />
2025-11-01 16:18:29 +01:00
2026-03-09 11:18:22 +01:00
< MetaTags {... metaTags } />
2024-08-01 14:04:50 +01:00
2026-03-09 11:18:22 +01:00
< UpgradeModal />
2024-12-28 23:11:55 +01:00
2026-03-09 11:18:22 +01:00
< Snackbar />
2021-05-07 03:43:37 +03:00
2026-03-09 11:18:22 +01:00
{ #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 } / >
2024-11-19 19:45:31 +01:00
2026-03-09 11:18:22 +01:00
{ @render children ? .()}
{ /if }
</ div >
2021-05-07 03:43:37 +03:00
2020-12-24 20:32:05 +02:00
< style >
2021-05-06 08:22:25 +03:00
: global ( : root ) {
2021-07-28 22:29:23 +03:00
--main-primary-color : rgba ( 29 , 78 , 216 , 1 );
2021-05-06 08:22:25 +03:00
--border-color : #eaecef ;
2023-09-26 11:23:54 +01:00
}
2023-04-23 22:28:18 +00:00
2023-08-20 21:28:55 +01:00
: global ( . dark svg . dark ) {
2023-05-05 20:19:45 +00:00
fill : #fff ;
}
2023-05-11 15:15:18 +00:00
: global ( . border-c ) {
border : 1 px solid var ( -- border - color );
}
: global ( . border-bottom-c ) {
border-bottom : 1 px solid var ( -- border - color );
}
2023-08-07 09:53:07 +00:00
2023-08-24 07:32:19 +00:00
: global ( . cards-container ) {
width : 90 % ;
margin : 0 auto ;
padding : 0 ;
display : grid ;
grid-template-columns : repeat ( auto - fill , minmax ( 300 px , 1 fr ));
column-gap : 12 px ;
row-gap : 12 px ;
}
2023-09-12 11:31:20 +00:00
2023-09-08 09:17:05 +00:00
@ 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 ( 250 px , 1 fr ));
column-gap : 12 px ;
row-gap : 12 px ;
}
}
2020-12-24 20:32:05 +02:00
</ style >