Files
classroomio/apps/dashboard/src/lib/components/Org/Settings/CustomizeLms.svelte
T
Rotimi Best c7854efae3 feat: redo settings and all org pages. (#601)
* feat: new components, deploy storybook

* refactor: simplify component field definitions and enhance button loading state

- Removed unnecessary type imports and simplified the FIELDS array definitions across multiple components in Storybook.
- Updated button component to use a loading state instead of isLoading, improving clarity and consistency in props.
- Adjusted button stories to reflect the new loading prop and enhanced the button's loading visual feedback.
- Minor CSS adjustments for better layout and styling consistency.

* chore: add field, card, password components

* feat: improve page component & update AuthUI path

* chore: update bits-ui to version 2.14.4 and all org related UI's

- Updated bits-ui dependency in pnpm-lock.yaml and package.json to version 2.14.4.
- Refactored imports for RoleBasedSecurity and UpgradeBanner components to use the new ui feature directory.
- Removed unused Course components and related files to clean up the codebase.
- Enhanced various components to improve consistency and maintainability.

* chore: move all setting buttons to the top and update auth ui styles

* chore: remove svelte-loading-spinners and replace with @cio/ui/base/spinner

- Removed all instances of svelte-loading-spinners from the project.
- Updated components to use the new Spinner from @cio/ui/base/spinner.
- Cleaned up pnpm-lock.yaml and package.json to reflect the removal of svelte-loading-spinners.
- Added new CSS animations for rocket launch effects in app.css.
- Enhanced email change flow with updated verification messages in translations.

* chore: remove supabase file upload from dashboard and move to r2

* chore: update organization API and UI components

- Added new API methods for organization plan operations and team management.
- Introduced middleware for API key authentication and organization admin checks.
- Refactored organization-related components to utilize the new API structure.
- Updated various UI components to improve consistency and maintainability.
- Enhanced error handling and validation for organization-related actions.
- Removed deprecated services and streamlined the codebase.
2025-12-02 09:54:38 +01:00

188 lines
7.1 KiB
Svelte

<script lang="ts">
import { Label } from '@cio/ui/base/label';
import { Switch } from '@cio/ui/base/switch';
import SaveIcon from '@lucide/svelte/icons/save';
import { currentOrg } from '$lib/utils/store/org';
import { t } from '$lib/utils/functions/translations';
import { snackbar } from '$lib/components/Snackbar/store';
import { getSupabase } from '$lib/utils/functions/supabase';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import { handleOpenWidget } from '$lib/components/CourseLandingPage/store';
import { Row, Grid, Column } from './Layout';
import SectionTitle from '../SectionTitle.svelte';
import TextField from '$lib/components/Form/TextField.svelte';
import UploadWidget from '$lib/components/UploadWidget/index.svelte';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
const supabase = getSupabase();
let widgetKey = $state('');
let isSaving = $state(false);
function widgetControl(key: string) {
widgetKey = key;
$handleOpenWidget.open = true;
}
async function handleSave() {
isSaving = true;
const { error } = await supabase
.from('organization')
.update({ customization: $currentOrg.customization })
.match({ id: $currentOrg.id });
if (error) {
const message = error?.message || 'snackbar.lms.error.try_again';
console.error('Error updating customizations', message);
snackbar.error('snackbar.update_failed');
} else {
snackbar.success('snackbar.success_update');
}
isSaving = false;
}
</script>
<Grid class="border-c relative mt-5 w-full rounded border-gray-200 dark:border-neutral-600">
<Row class="border-bottom-c flex flex-col items-start py-7 lg:flex-row">
<Column sm={4} md={4} lg={4}>
<SectionTitle>{$t('components.settings.customize_lms.dashboard.title')}</SectionTitle>
</Column>
<Column sm={8} md={8} lg={8} class="space-y-2">
<div class="flex flex-col gap-3">
<p class="text-sm">{$t('components.settings.customize_lms.dashboard.community')}</p>
<div class="mb-3 flex items-center space-x-2">
<Switch bind:checked={$currentOrg.customization.dashboard.community} />
<Label class="text-sm">
{$currentOrg.customization.dashboard.community
? $t('components.settings.customize_lms.enabled')
: $t('components.settings.customize_lms.disabled')}
</Label>
</div>
</div>
<div class="flex flex-col gap-3">
<p class="text-sm">{$t('components.settings.customize_lms.dashboard.exercises')}</p>
<div class="mb-3 flex items-center space-x-2">
<Switch bind:checked={$currentOrg.customization.dashboard.exercise} />
<Label class="text-sm">
{$currentOrg.customization.dashboard.exercise
? $t('components.settings.customize_lms.enabled')
: $t('components.settings.customize_lms.disabled')}
</Label>
</div>
</div>
<div class="mb-3">
<p class="text-sm">{$t('components.settings.customize_lms.dashboard.banner_image')}</p>
<PrimaryButton
variant={VARIANTS.OUTLINED}
label={$t('components.settings.customize_lms.dashboard.banner_image_btn')}
className="mt-3"
onClick={() => widgetControl('banner-image')}
/>
{#if $currentOrg.customization.dashboard.bannerImage}
<img alt="Banner" src={$currentOrg.customization.dashboard.bannerImage} class="mt-2 w-full rounded-md" />
{/if}
{#if $handleOpenWidget.open && widgetKey === 'banner-image'}
<UploadWidget bind:imageURL={$currentOrg.customization.dashboard.bannerImage} />
{/if}
</div>
<div>
<p>{$t('components.settings.customize_lms.dashboard.banner_text')}</p>
<TextField
label={$t('components.settings.customize_lms.dashboard.banner_text_label')}
placeholder={$t('components.settings.customize_lms.dashboard.banner_text_placeholder')}
bind:value={$currentOrg.customization.dashboard.bannerText}
/>
</div>
</Column>
</Row>
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
<Column sm={4} md={4} lg={4}
><SectionTitle>{$t('components.settings.customize_lms.course.title')}</SectionTitle></Column
>
<Column sm={8} md={8} lg={8} class="space-y-4">
<div class="flex flex-col gap-3">
<p class="text-sm">{$t('components.settings.customize_lms.course.newsfeed')}</p>
<div class="flex items-center space-x-2">
<Switch bind:checked={$currentOrg.customization.course.newsfeed} />
<Label class="text-gray-600">
{$currentOrg.customization.course.newsfeed
? $t('components.settings.customize_lms.enabled')
: $t('components.settings.customize_lms.disabled')}
</Label>
</div>
</div>
<div class="flex flex-col gap-3">
<p class="text-sm">{$t('components.settings.customize_lms.course.grading')}</p>
<div class="flex items-center space-x-2">
<Switch bind:checked={$currentOrg.customization.course.grading} />
<Label class="text-gray-600">
{$currentOrg.customization.course.grading
? $t('components.settings.customize_lms.enabled')
: $t('components.settings.customize_lms.disabled')}
</Label>
</div>
</div>
</Column>
</Row>
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
<Column sm={4} md={4} lg={4}
><SectionTitle>{$t('components.settings.customize_lms.apps.title')}</SectionTitle></Column
>
<Column sm={8} md={8} lg={8} class="space-y-4">
<div class="flex flex-col gap-3">
<p class="text-sm">{$t('components.settings.customize_lms.apps.poll')}</p>
<div class="flex items-center space-x-2">
<Switch bind:checked={$currentOrg.customization.apps.poll} />
<Label class="text-gray-600">
{$currentOrg.customization.apps.poll
? $t('components.settings.customize_lms.enabled')
: $t('components.settings.customize_lms.disabled')}
</Label>
</div>
</div>
<div class="flex flex-col gap-3">
<p class="text-sm">{$t('components.settings.customize_lms.apps.live_comment')}</p>
<div class="flex items-center space-x-2">
<Switch bind:checked={$currentOrg.customization.apps.comments} />
<Label class="text-gray-600">
{$currentOrg.customization.apps.comments
? $t('components.settings.customize_lms.enabled')
: $t('components.settings.customize_lms.disabled')}
</Label>
</div>
</div>
</Column>
</Row>
<div class="sticky bottom-12 z-[120] float-right mr-2 hidden md:block">
<PrimaryButton
label={$t('components.settings.customize_lms.save')}
onClick={handleSave}
isLoading={isSaving}
isDisabled={isSaving}
/>
</div>
</Grid>
<div class="absolute bottom-8 right-6 z-[120] block md:hidden">
<PrimaryButton onClick={handleSave} isLoading={isSaving} isDisabled={isSaving}>
<SaveIcon size={16} />
</PrimaryButton>
</div>