import { browser, dev } from '$app/environment'; import { derived, writable } from 'svelte/store'; import merge from 'lodash/merge'; import type { AccountOrg } from '$features/app/types'; import type { OrgTeamMember } from '../types/org'; import { PLAN } from '@cio/utils/plans'; import { PUBLIC_IS_SELFHOSTED } from '$env/static/public'; import { ROLE, TENANT_ROOT_DOMAIN } from '@cio/utils/constants'; import { STEPS } from '../constants/quiz'; import type { Writable } from 'svelte/store'; /** Deep-merge with this when hydrating an org from the API so nested `customization` keys stay stable. */ export const DEFAULT_ORG_CUSTOMIZATION = { apps: { poll: true, comments: true }, course: { grading: true, newsfeed: true }, dashboard: { exercise: true, community: true, bannerText: '', bannerImage: '' }, auth: { backgroundImage: '' } } as NonNullable; export function mergeAccountOrgFromServer(org: AccountOrg): AccountOrg { return { ...org, customization: merge({}, DEFAULT_ORG_CUSTOMIZATION, org.customization ?? {}) as AccountOrg['customization'] }; } export const orgs = writable([]); export const currentOrg: Writable = writable({ avatarUrl: '', createdAt: '', customCode: '', customDomain: '', customization: { ...DEFAULT_ORG_CUSTOMIZATION }, disableEmailPassword: false, disableGoogleAuth: false, disableSignup: false, disableSignupMessage: '', favicon: '', id: '', isCustomDomainVerified: false, isRestricted: false, landingpage: {}, name: '', parentOrganizationId: null, plans: [], readOnlyUntil: null, roleId: 0, settings: {}, siteName: '', theme: '' }); export const isSecondaryWorkspace = derived(currentOrg, ($currentOrg) => Boolean($currentOrg.parentOrganizationId)); export const isPrimaryWorkspace = derived( currentOrg, ($currentOrg) => Boolean($currentOrg.id) && !$currentOrg.parentOrganizationId ); export const orgTeam = writable([]); export const isOrgAdmin = derived(currentOrg, ($currentOrg) => { if ($currentOrg.roleId === 0) return null; return $currentOrg.roleId === ROLE.ADMIN; }); const getActivePlan = (org: AccountOrg) => { return org.plans.find((p) => p.isActive); }; export const currentOrgPlan = derived(currentOrg, ($currentOrg) => getActivePlan($currentOrg)); 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; const browserOrigin = dev && browser && window.location.origin; return browserOrigin ? browserOrigin : $currentOrg.customDomain && $currentOrg.isCustomDomainVerified ? `https://${$currentOrg.customDomain}` : $currentOrg.siteName ? `https://${$currentOrg.siteName}.${TENANT_ROOT_DOMAIN}` : ''; }); export const isFreePlan = derived(currentOrg, ($currentOrg) => { if (!$currentOrg.id || PUBLIC_IS_SELFHOSTED === 'true') return false; const plan = getActivePlan($currentOrg); return !plan || plan.planName === PLAN.BASIC; }); export const isEnterprisePlan = derived(currentOrg, ($currentOrg) => { if (PUBLIC_IS_SELFHOSTED === 'true') return true; const plan = getActivePlan($currentOrg); return plan?.planName === PLAN.ENTERPRISE; }); export const currentOrgMaxAudience = derived(currentOrgPlan, ($plan) => !$plan ? 20 : $plan.planName === PLAN.EARLY_ADOPTER ? 10000 : $plan.planName === PLAN.ENTERPRISE ? Number.MAX_SAFE_INTEGER : 20 ); // Quiz export const createQuizModal = writable({ open: false, openEdit: false, title: '', id: null }); export const deleteModal = writable({ id: null, open: false, isQuestion: false }); interface QuizOption { id: number; label: string; isCorrect: boolean; } interface QuizQuestion { id: number; label: string; type: string; options: QuizOption[]; } interface QuizStore { uuid: string; title: string; questions: QuizQuestion[]; timelimit: string; theme: string; pin: string; } export const quizStore = writable({ uuid: '', title: '', questions: [], timelimit: '10s', theme: 'standard', pin: '' }); export const playQuizStore = writable({ step: STEPS.CONNECT_TO_PLAY });