feat: Trigger confirm warning for unsaved changes (#547)
* added the triger warning for the settings page * all done * added translation to the window message * window issue now fixed
This commit is contained in:
@@ -199,7 +199,7 @@
|
|||||||
$: courseLink = `${$currentOrgDomain}/course/${$course.slug}`;
|
$: courseLink = `${$currentOrgDomain}/course/${$course.slug}`;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<UnsavedChanges {hasUnsavedChanges} />
|
<UnsavedChanges bind:hasUnsavedChanges />
|
||||||
|
|
||||||
<DeleteModal onDelete={handleDeleteCourse} bind:open={openDeleteModal} />
|
<DeleteModal onDelete={handleDeleteCourse} bind:open={openDeleteModal} />
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,33 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Grid, Row, Column, RadioButtonGroup, RadioButton } from 'carbon-components-svelte';
|
import { handleOpenWidget } from '$lib/components/CourseLandingPage/store';
|
||||||
import TrashCan from 'carbon-icons-svelte/lib/TrashCan.svelte';
|
import TextArea from '$lib/components/Form/TextArea.svelte';
|
||||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
import TextField from '$lib/components/Form/TextField.svelte';
|
||||||
import Save from 'carbon-icons-svelte/lib/Save.svelte';
|
|
||||||
import IconButton from '$lib/components/IconButton/index.svelte';
|
import IconButton from '$lib/components/IconButton/index.svelte';
|
||||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||||
import SectionTitle from '../SectionTitle.svelte';
|
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||||
import { Toggle } from 'carbon-components-svelte';
|
|
||||||
import TextField from '$lib/components/Form/TextField.svelte';
|
|
||||||
import TextArea from '$lib/components/Form/TextArea.svelte';
|
|
||||||
import { currentOrg } from '$lib/utils/store/org';
|
|
||||||
import { getSupabase } from '$lib/utils/functions/supabase';
|
|
||||||
import { snackbar } from '$lib/components/Snackbar/store';
|
import { snackbar } from '$lib/components/Snackbar/store';
|
||||||
import { landingPageSettings } from './store';
|
import UnsavedChanges from '$lib/components/UnsavedChanges/index.svelte';
|
||||||
import type { OrgLandingPageJson } from './store';
|
|
||||||
import UploadWidget from '$lib/components/UploadWidget/index.svelte';
|
import UploadWidget from '$lib/components/UploadWidget/index.svelte';
|
||||||
import { handleOpenWidget } from '$lib/components/CourseLandingPage/store';
|
import { getSupabase } from '$lib/utils/functions/supabase';
|
||||||
import { t } from '$lib/utils/functions/translations';
|
import { t } from '$lib/utils/functions/translations';
|
||||||
|
import { currentOrg } from '$lib/utils/store/org';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
Grid,
|
||||||
|
RadioButton,
|
||||||
|
RadioButtonGroup,
|
||||||
|
Row,
|
||||||
|
Toggle
|
||||||
|
} from 'carbon-components-svelte';
|
||||||
|
import Save from 'carbon-icons-svelte/lib/Save.svelte';
|
||||||
|
import TrashCan from 'carbon-icons-svelte/lib/TrashCan.svelte';
|
||||||
|
import SectionTitle from '../SectionTitle.svelte';
|
||||||
|
import type { OrgLandingPageJson } from './store';
|
||||||
|
import { landingPageSettings } from './store';
|
||||||
|
|
||||||
let isSaving = false;
|
let isSaving = false;
|
||||||
let creatingNewQuestion = false;
|
let creatingNewQuestion = false;
|
||||||
|
let hasUnsavedChanges = false;
|
||||||
let widgetKey = '';
|
let widgetKey = '';
|
||||||
const banner = [
|
const banner = [
|
||||||
{ value: 'video', label: `${$t('settings.landing_page.actions.banner_type.video')}` },
|
{ value: 'video', label: `${$t('settings.landing_page.actions.banner_type.video')}` },
|
||||||
@@ -97,6 +105,7 @@
|
|||||||
} else {
|
} else {
|
||||||
$currentOrg.landingpage = $landingPageSettings;
|
$currentOrg.landingpage = $landingPageSettings;
|
||||||
snackbar.success('snackbar.success_update');
|
snackbar.success('snackbar.success_update');
|
||||||
|
hasUnsavedChanges = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isSaving = false;
|
isSaving = false;
|
||||||
@@ -118,15 +127,19 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: setDefault($currentOrg?.landingpage as unknown as OrgLandingPageJson);
|
$: setDefault($currentOrg?.landingpage as unknown as OrgLandingPageJson);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Grid class="border-c rounded border-gray-200 dark:border-neutral-600 w-full mt-5 relative">
|
<UnsavedChanges bind:hasUnsavedChanges />
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<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 py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}>
|
<Column sm={4} md={4} lg={4}>
|
||||||
<SectionTitle>{$t('settings.landing_page.heading')}</SectionTitle>
|
<SectionTitle>{$t('settings.landing_page.heading')}</SectionTitle>
|
||||||
<Toggle bind:toggled={$landingPageSettings.header.show} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.header.show}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray">{$t('settings.landing_page.hide_section')}</span>
|
<span slot="labelA" style="color: gray">{$t('settings.landing_page.hide_section')}</span>
|
||||||
<span slot="labelB" style="color: gray">{$t('settings.landing_page.show_section')}</span>
|
<span slot="labelB" style="color: gray">{$t('settings.landing_page.show_section')}</span>
|
||||||
</Toggle>
|
</Toggle>
|
||||||
@@ -136,6 +149,7 @@
|
|||||||
label={$t('settings.landing_page.title')}
|
label={$t('settings.landing_page.title')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
||||||
bind:value={$landingPageSettings.header.title}
|
bind:value={$landingPageSettings.header.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="w-full mb-5"
|
className="w-full mb-5"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -143,6 +157,7 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.highlight')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.highlight')}
|
||||||
className="w-full mb-5"
|
className="w-full mb-5"
|
||||||
bind:value={$landingPageSettings.header.titleHighlight}
|
bind:value={$landingPageSettings.header.titleHighlight}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextArea
|
<TextArea
|
||||||
@@ -151,6 +166,7 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
||||||
className="w-full mb-5"
|
className="w-full mb-5"
|
||||||
bind:value={$landingPageSettings.header.subtitle}
|
bind:value={$landingPageSettings.header.subtitle}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
isAIEnabled={true}
|
isAIEnabled={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -160,14 +176,20 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.label')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.label')}
|
||||||
className="w-full mt-3 mb-5"
|
className="w-full mt-3 mb-5"
|
||||||
bind:value={$landingPageSettings.header.action.label}
|
bind:value={$landingPageSettings.header.action.label}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<div class="gap-2 mb-5">
|
<div class="mb-5 gap-2">
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.landing_page.actions.link')}
|
label={$t('settings.landing_page.actions.link')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.link')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.link')}
|
||||||
bind:value={$landingPageSettings.header.action.link}
|
bind:value={$landingPageSettings.header.action.link}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<Toggle bind:toggled={$landingPageSettings.header.action.redirect} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.header.action.redirect}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray"
|
<span slot="labelA" style="color: gray"
|
||||||
>{$t('settings.landing_page.actions.no_redirect')}</span
|
>{$t('settings.landing_page.actions.no_redirect')}</span
|
||||||
>
|
>
|
||||||
@@ -181,18 +203,20 @@
|
|||||||
<RadioButtonGroup
|
<RadioButtonGroup
|
||||||
legendText={$t('settings.landing_page.actions.banner_type.heading')}
|
legendText={$t('settings.landing_page.actions.banner_type.heading')}
|
||||||
bind:selected={$landingPageSettings.header.banner.type}
|
bind:selected={$landingPageSettings.header.banner.type}
|
||||||
class="mt-10 mb-5"
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
class="mb-5 mt-10"
|
||||||
>
|
>
|
||||||
{#each banner as item}
|
{#each banner as item}
|
||||||
<RadioButton value={item.value} labelText={item.label} />
|
<RadioButton value={item.value} labelText={item.label} />
|
||||||
{/each}
|
{/each}
|
||||||
</RadioButtonGroup>
|
</RadioButtonGroup>
|
||||||
{#if $landingPageSettings.header.banner.type === 'video'}
|
{#if $landingPageSettings.header.banner.type === 'video'}
|
||||||
<div class="gap-2 mt-3 mb-5">
|
<div class="mb-5 mt-3 gap-2">
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.landing_page.actions.link')}
|
label={$t('settings.landing_page.actions.link')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.video')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.video')}
|
||||||
bind:value={$landingPageSettings.header.banner.video}
|
bind:value={$landingPageSettings.header.banner.video}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -207,11 +231,15 @@
|
|||||||
<img
|
<img
|
||||||
alt="bannerImage"
|
alt="bannerImage"
|
||||||
src={$landingPageSettings.header.banner.image}
|
src={$landingPageSettings.header.banner.image}
|
||||||
class="mt-2 rounded-md w-full"
|
class="mt-2 w-full rounded-md"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Toggle bind:toggled={$landingPageSettings.header.banner.show} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.header.banner.show}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray"
|
<span slot="labelA" style="color: gray"
|
||||||
>{$t('settings.landing_page.actions.hide_banner')}</span
|
>{$t('settings.landing_page.actions.hide_banner')}</span
|
||||||
>
|
>
|
||||||
@@ -220,13 +248,16 @@
|
|||||||
>
|
>
|
||||||
</Toggle>
|
</Toggle>
|
||||||
{#if $handleOpenWidget.open && widgetKey === 'banner'}
|
{#if $handleOpenWidget.open && widgetKey === 'banner'}
|
||||||
<UploadWidget bind:imageURL={$landingPageSettings.header.banner.image} />
|
<UploadWidget
|
||||||
|
bind:imageURL={$landingPageSettings.header.banner.image}
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- background -->
|
<!-- background -->
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<p class="font-bold mb-4">{$t('settings.landing_page.background.title')}</p>
|
<p class="mb-4 font-bold">{$t('settings.landing_page.background.title')}</p>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
variant={VARIANTS.OUTLINED}
|
variant={VARIANTS.OUTLINED}
|
||||||
label={$t('settings.landing_page.about.select_image')}
|
label={$t('settings.landing_page.about.select_image')}
|
||||||
@@ -238,7 +269,7 @@
|
|||||||
<img
|
<img
|
||||||
alt="backgroundImage"
|
alt="backgroundImage"
|
||||||
src={$landingPageSettings.header.background.image}
|
src={$landingPageSettings.header.background.image}
|
||||||
class="mt-2 rounded-md w-full"
|
class="mt-2 w-full rounded-md"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -252,16 +283,24 @@
|
|||||||
</Toggle>
|
</Toggle>
|
||||||
|
|
||||||
{#if $handleOpenWidget.open && widgetKey === 'background'}
|
{#if $handleOpenWidget.open && widgetKey === 'background'}
|
||||||
<UploadWidget bind:imageURL={$landingPageSettings.header.background.image} />
|
<UploadWidget
|
||||||
|
bind:imageURL={$landingPageSettings.header.background.image}
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.landing_page.about.heading')}</SectionTitle>
|
><SectionTitle>{$t('settings.landing_page.about.heading')}</SectionTitle>
|
||||||
<Toggle bind:toggled={$landingPageSettings.aboutUs.show} size="sm">
|
|
||||||
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.aboutUs.show}
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray">{$t('settings.landing_page.hide_section')}</span>
|
<span slot="labelA" style="color: gray">{$t('settings.landing_page.hide_section')}</span>
|
||||||
<span slot="labelB" style="color: gray">{$t('settings.landing_page.show_section')}</span>
|
<span slot="labelB" style="color: gray">{$t('settings.landing_page.show_section')}</span>
|
||||||
</Toggle></Column
|
</Toggle></Column
|
||||||
@@ -271,6 +310,7 @@
|
|||||||
label={$t('settings.landing_page.about.title')}
|
label={$t('settings.landing_page.about.title')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
||||||
bind:value={$landingPageSettings.aboutUs.title}
|
bind:value={$landingPageSettings.aboutUs.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -280,6 +320,7 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.content')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.content')}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
bind:value={$landingPageSettings.aboutUs.content}
|
bind:value={$landingPageSettings.aboutUs.content}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
isAIEnabled={true}
|
isAIEnabled={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -295,7 +336,7 @@
|
|||||||
<img
|
<img
|
||||||
alt="About us"
|
alt="About us"
|
||||||
src={$landingPageSettings.aboutUs.imageUrl}
|
src={$landingPageSettings.aboutUs.imageUrl}
|
||||||
class="mt-2 rounded-md w-full"
|
class="mt-2 w-full rounded-md"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $handleOpenWidget.open && widgetKey === 'about-us'}
|
{#if $handleOpenWidget.open && widgetKey === 'about-us'}
|
||||||
@@ -305,10 +346,14 @@
|
|||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.landing_page.courses.heading')}</SectionTitle>
|
><SectionTitle>{$t('settings.landing_page.courses.heading')}</SectionTitle>
|
||||||
<Toggle bind:toggled={$landingPageSettings.courses.show} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.courses.show}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray"
|
<span slot="labelA" style="color: gray"
|
||||||
>{$t('settings.landing_page.courses.hide_section')}</span
|
>{$t('settings.landing_page.courses.hide_section')}</span
|
||||||
>
|
>
|
||||||
@@ -322,26 +367,33 @@
|
|||||||
label={$t('settings.landing_page.courses.title')}
|
label={$t('settings.landing_page.courses.title')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
||||||
bind:value={$landingPageSettings.courses.title}
|
bind:value={$landingPageSettings.courses.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.landing_page.courses.title_highlight')}
|
label={$t('settings.landing_page.courses.title_highlight')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.highlight')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.highlight')}
|
||||||
bind:value={$landingPageSettings.courses.titleHighlight}
|
bind:value={$landingPageSettings.courses.titleHighlight}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
label={$t('settings.landing_page.courses.subtitle')}
|
label={$t('settings.landing_page.courses.subtitle')}
|
||||||
labelClassName="font-light"
|
labelClassName="font-light"
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
||||||
bind:value={$landingPageSettings.courses.subtitle}
|
bind:value={$landingPageSettings.courses.subtitle}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
isAIEnabled={true}
|
isAIEnabled={true}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.landing_page.faq.heading')}</SectionTitle>
|
><SectionTitle>{$t('settings.landing_page.faq.heading')}</SectionTitle>
|
||||||
<Toggle bind:toggled={$landingPageSettings.faq.show} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.faq.show}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray">{$t('settings.landing_page.faq.hide_section')}</span
|
<span slot="labelA" style="color: gray">{$t('settings.landing_page.faq.hide_section')}</span
|
||||||
>
|
>
|
||||||
<span slot="labelB" style="color: gray">{$t('settings.landing_page.faq.show_section')}</span
|
<span slot="labelB" style="color: gray">{$t('settings.landing_page.faq.show_section')}</span
|
||||||
@@ -353,6 +405,7 @@
|
|||||||
label={$t('settings.landing_page.faq.title')}
|
label={$t('settings.landing_page.faq.title')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
||||||
bind:value={$landingPageSettings.faq.title}
|
bind:value={$landingPageSettings.faq.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
/>
|
/>
|
||||||
{#each $landingPageSettings.faq.questions as item (item.id)}
|
{#each $landingPageSettings.faq.questions as item (item.id)}
|
||||||
@@ -363,6 +416,7 @@
|
|||||||
'course.navItem.lessons.exercises.all_exercises.write_your_question_here'
|
'course.navItem.lessons.exercises.all_exercises.write_your_question_here'
|
||||||
)}
|
)}
|
||||||
bind:value={item.title}
|
bind:value={item.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
/>
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
@@ -373,6 +427,7 @@
|
|||||||
)}
|
)}
|
||||||
bind:value={item.content}
|
bind:value={item.content}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
isAIEnabled={true}
|
isAIEnabled={true}
|
||||||
/>
|
/>
|
||||||
<IconButton onClick={() => deleteFaq(item.id)}>
|
<IconButton onClick={() => deleteFaq(item.id)}>
|
||||||
@@ -387,6 +442,7 @@
|
|||||||
'course.navItem.lessons.exercises.all_exercises.write_your_question_here'
|
'course.navItem.lessons.exercises.all_exercises.write_your_question_here'
|
||||||
)}
|
)}
|
||||||
bind:value={newQuestion.title}
|
bind:value={newQuestion.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
/>
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
@@ -394,6 +450,7 @@
|
|||||||
labelClassName="font-light"
|
labelClassName="font-light"
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_answer_here')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_answer_here')}
|
||||||
bind:value={newQuestion.content}
|
bind:value={newQuestion.content}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
isAIEnabled={true}
|
isAIEnabled={true}
|
||||||
/>
|
/>
|
||||||
@@ -419,10 +476,14 @@
|
|||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.landing_page.contact_us.heading')}</SectionTitle>
|
><SectionTitle>{$t('settings.landing_page.contact_us.heading')}</SectionTitle>
|
||||||
<Toggle bind:toggled={$landingPageSettings.contact.show} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.contact.show}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray"
|
<span slot="labelA" style="color: gray"
|
||||||
>{$t('settings.landing_page.contact_us.hide_section')}</span
|
>{$t('settings.landing_page.contact_us.hide_section')}</span
|
||||||
>
|
>
|
||||||
@@ -436,6 +497,7 @@
|
|||||||
label={$t('settings.landing_page.contact_us.title')}
|
label={$t('settings.landing_page.contact_us.title')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
||||||
bind:value={$landingPageSettings.contact.title}
|
bind:value={$landingPageSettings.contact.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -444,6 +506,7 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.highlight')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.highlight')}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
bind:value={$landingPageSettings.contact.titleHighlight}
|
bind:value={$landingPageSettings.contact.titleHighlight}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
label={$t('settings.landing_page.contact_us.subtitle')}
|
label={$t('settings.landing_page.contact_us.subtitle')}
|
||||||
@@ -451,6 +514,7 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
||||||
className="mt-3 mb-5"
|
className="mt-3 mb-5"
|
||||||
bind:value={$landingPageSettings.contact.subtitle}
|
bind:value={$landingPageSettings.contact.subtitle}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
isAIEnabled={true}
|
isAIEnabled={true}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -458,20 +522,26 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.number')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.number')}
|
||||||
className="mt-3 mb-5"
|
className="mt-3 mb-5"
|
||||||
bind:value={$landingPageSettings.contact.phone}
|
bind:value={$landingPageSettings.contact.phone}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.landing_page.contact_us.email')}
|
label={$t('settings.landing_page.contact_us.email')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.email')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.email')}
|
||||||
className="mt-3 mb-5"
|
className="mt-3 mb-5"
|
||||||
bind:value={$landingPageSettings.contact.email}
|
bind:value={$landingPageSettings.contact.email}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.landing_page.mailing_list.heading')}</SectionTitle>
|
><SectionTitle>{$t('settings.landing_page.mailing_list.heading')}</SectionTitle>
|
||||||
<Toggle bind:toggled={$landingPageSettings.mailinglist.show} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.mailinglist.show}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray"
|
<span slot="labelA" style="color: gray"
|
||||||
>{$t('settings.landing_page.mailing_list.hide_section')}</span
|
>{$t('settings.landing_page.mailing_list.hide_section')}</span
|
||||||
>
|
>
|
||||||
@@ -485,6 +555,7 @@
|
|||||||
label={$t('settings.landing_page.mailing_list.title')}
|
label={$t('settings.landing_page.mailing_list.title')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_title')}
|
||||||
bind:value={$landingPageSettings.mailinglist.title}
|
bind:value={$landingPageSettings.mailinglist.title}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
/>
|
/>
|
||||||
<TextArea
|
<TextArea
|
||||||
@@ -493,6 +564,7 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.write_your_subtitle')}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
bind:value={$landingPageSettings.mailinglist.subtitle}
|
bind:value={$landingPageSettings.mailinglist.subtitle}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
isAIEnabled={true}
|
isAIEnabled={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -501,14 +573,19 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.label')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.label')}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
bind:value={$landingPageSettings.mailinglist.buttonLabel}
|
bind:value={$landingPageSettings.mailinglist.buttonLabel}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="flex lg:flex-row flex-col py-7">
|
<Row class="flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.landing_page.footer.heading')}</SectionTitle>
|
><SectionTitle>{$t('settings.landing_page.footer.heading')}</SectionTitle>
|
||||||
<Toggle bind:toggled={$landingPageSettings.footer.show} size="sm">
|
<Toggle
|
||||||
|
bind:toggled={$landingPageSettings.footer.show}
|
||||||
|
size="sm"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
>
|
||||||
<span slot="labelA" style="color: gray"
|
<span slot="labelA" style="color: gray"
|
||||||
>{$t('settings.landing_page.footer.hide_section')}</span
|
>{$t('settings.landing_page.footer.hide_section')}</span
|
||||||
>
|
>
|
||||||
@@ -522,6 +599,7 @@
|
|||||||
label={$t('settings.landing_page.footer.facebook')}
|
label={$t('settings.landing_page.footer.facebook')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.facebook')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.facebook')}
|
||||||
bind:value={$landingPageSettings.footer.facebook}
|
bind:value={$landingPageSettings.footer.facebook}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
/>
|
/>
|
||||||
<!-- <TextField
|
<!-- <TextField
|
||||||
@@ -535,16 +613,18 @@
|
|||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.twitter')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.twitter')}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
bind:value={$landingPageSettings.footer.twitter}
|
bind:value={$landingPageSettings.footer.twitter}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.landing_page.footer.linkedin')}
|
label={$t('settings.landing_page.footer.linkedin')}
|
||||||
placeholder={$t('course.navItem.lessons.exercises.all_exercises.linkedin')}
|
placeholder={$t('course.navItem.lessons.exercises.all_exercises.linkedin')}
|
||||||
className="mb-5"
|
className="mb-5"
|
||||||
bind:value={$landingPageSettings.footer.linkedin}
|
bind:value={$landingPageSettings.footer.linkedin}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
<div class="sticky desktop float-right bottom-12 mr-2 z-[120]">
|
<div class="desktop sticky bottom-12 z-[120] float-right mr-2">
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
label={$t('settings.landing_page.save_changes')}
|
label={$t('settings.landing_page.save_changes')}
|
||||||
isLoading={isSaving}
|
isLoading={isSaving}
|
||||||
@@ -555,12 +635,12 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="absolute
|
class="mobile
|
||||||
mobile right-6 bottom-8 z-[120]"
|
absolute bottom-8 right-6 z-[120]"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
<IconButton onClick={handleSave} disabled={isSaving}>
|
<IconButton onClick={handleSave} disabled={isSaving}>
|
||||||
<Save size={40} class=" bg-blue-700 p-1 rounded-full" />
|
<Save size={40} class=" rounded-full bg-blue-700 p-1" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { Column, Grid, Row } from 'carbon-components-svelte';
|
||||||
|
import FlashFilled from 'carbon-icons-svelte/lib/FlashFilled.svelte';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import ColorPicker from 'svelte-awesome-color-picker';
|
import ColorPicker from 'svelte-awesome-color-picker';
|
||||||
import { Grid, Row, Column } from 'carbon-components-svelte';
|
|
||||||
import FlashFilled from 'carbon-icons-svelte/lib/FlashFilled.svelte';
|
|
||||||
|
|
||||||
import { isFreePlan } from '$lib/utils/store/org';
|
|
||||||
import { t } from '$lib/utils/functions/translations';
|
|
||||||
import { supabase } from '$lib/utils/functions/supabase';
|
|
||||||
import { snackbar } from '$lib/components/Snackbar/store';
|
import { snackbar } from '$lib/components/Snackbar/store';
|
||||||
import { currentOrg, currentOrgPath } from '$lib/utils/store/org';
|
import { supabase } from '$lib/utils/functions/supabase';
|
||||||
|
import { injectCustomTheme, setCustomTheme, setTheme } from '$lib/utils/functions/theme';
|
||||||
|
import { t } from '$lib/utils/functions/translations';
|
||||||
import { updateOrgNameValidation } from '$lib/utils/functions/validator';
|
import { updateOrgNameValidation } from '$lib/utils/functions/validator';
|
||||||
import { setTheme, setCustomTheme, injectCustomTheme } from '$lib/utils/functions/theme';
|
import { currentOrg, currentOrgPath, isFreePlan } from '$lib/utils/store/org';
|
||||||
|
|
||||||
import SectionTitle from '../SectionTitle.svelte';
|
|
||||||
import TextField from '$lib/components/Form/TextField.svelte';
|
import TextField from '$lib/components/Form/TextField.svelte';
|
||||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||||
import UploadImage from '$lib/components/UploadImage/index.svelte';
|
|
||||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||||
|
import UnsavedChanges from '$lib/components/UnsavedChanges/index.svelte';
|
||||||
|
import UploadImage from '$lib/components/UploadImage/index.svelte';
|
||||||
|
import SectionTitle from '../SectionTitle.svelte';
|
||||||
|
|
||||||
let avatar;
|
let avatar;
|
||||||
|
let hasUnsavedChanges = false;
|
||||||
|
|
||||||
type Error = {
|
type Error = {
|
||||||
orgName: string;
|
orgName: string;
|
||||||
@@ -123,7 +124,7 @@
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
snackbar.success('snackbar.course_settings.success.update_successful');
|
snackbar.success('snackbar.course_settings.success.update_successful');
|
||||||
|
hasUnsavedChanges = false;
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let message = error as string;
|
let message = error as string;
|
||||||
@@ -151,17 +152,19 @@
|
|||||||
$: isCustomTheme = hex && !hex.includes('theme-');
|
$: isCustomTheme = hex && !hex.includes('theme-');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Grid class="border-c rounded border-gray-200 dark:border-neutral-600 w-full mt-5">
|
<UnsavedChanges bind:hasUnsavedChanges />
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Grid class="border-c mt-5 w-full rounded border-gray-200 dark:border-neutral-600">
|
||||||
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}>
|
<Column sm={4} md={4} lg={4}>
|
||||||
<SectionTitle>
|
<SectionTitle>
|
||||||
{$t('settings.organization.organization_profile.heading')}
|
{$t('settings.organization.organization_profile.heading')}
|
||||||
</SectionTitle>
|
</SectionTitle>
|
||||||
</Column>
|
</Column>
|
||||||
<Column sm={8} md={8} lg={8} class="mt-2 lg:mt-0 flex flex-col items-center lg:items-start">
|
<Column sm={8} md={8} lg={8} class="mt-2 flex flex-col items-center lg:mt-0 lg:items-start">
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.organization.organization_profile.organization_name')}
|
label={$t('settings.organization.organization_profile.organization_name')}
|
||||||
bind:value={$currentOrg.name}
|
bind:value={$currentOrg.name}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
className="w-full lg:w-60 mb-5"
|
className="w-full lg:w-60 mb-5"
|
||||||
errorMessage={errors.orgName}
|
errorMessage={errors.orgName}
|
||||||
/>
|
/>
|
||||||
@@ -170,6 +173,7 @@
|
|||||||
src={$currentOrg.avatar_url}
|
src={$currentOrg.avatar_url}
|
||||||
shape="rounded-md"
|
shape="rounded-md"
|
||||||
widthHeight="w-24 h-24"
|
widthHeight="w-24 h-24"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
label={$t('settings.organization.organization_profile.update_organization')}
|
label={$t('settings.organization.organization_profile.update_organization')}
|
||||||
@@ -180,7 +184,7 @@
|
|||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c relative">
|
<Row class="border-bottom-c relative flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.organization.organization_profile.theme.heading')}</SectionTitle
|
><SectionTitle>{$t('settings.organization.organization_profile.theme.heading')}</SectionTitle
|
||||||
></Column
|
></Column
|
||||||
@@ -193,57 +197,57 @@
|
|||||||
<div class="flex items-center gap-5">
|
<div class="flex items-center gap-5">
|
||||||
<button
|
<button
|
||||||
class="rounded-full border-2 {$currentOrg.theme === themes.default &&
|
class="rounded-full border-2 {$currentOrg.theme === themes.default &&
|
||||||
'border-[#1d4ee2]'} flex items-center justify-center h-fit"
|
'border-[#1d4ee2]'} flex h-fit items-center justify-center"
|
||||||
on:click={handleChangeTheme(themes.default)}
|
on:click={handleChangeTheme(themes.default)}
|
||||||
>
|
>
|
||||||
<div class="w-6 h-6 md:w-6 md:h-6 bg-[#1d4ee2] rounded-full m-1" />
|
<div class="m-1 h-6 w-6 rounded-full bg-[#1d4ee2] md:h-6 md:w-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="rounded-full border-2 {$currentOrg.theme === themes.rose &&
|
class="rounded-full border-2 {$currentOrg.theme === themes.rose &&
|
||||||
'border-[#be1241]'} flex items-center justify-center h-fit"
|
'border-[#be1241]'} flex h-fit items-center justify-center"
|
||||||
on:click={handleChangeTheme(themes.rose)}
|
on:click={handleChangeTheme(themes.rose)}
|
||||||
>
|
>
|
||||||
<div class="w-6 h-6 md:w-6 md:h-6 bg-[#be1241] rounded-full m-1" />
|
<div class="m-1 h-6 w-6 rounded-full bg-[#be1241] md:h-6 md:w-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="rounded-full border-2 {$currentOrg.theme === themes.green &&
|
class="rounded-full border-2 {$currentOrg.theme === themes.green &&
|
||||||
'border-[#0c891b]'} flex items-center justify-center h-fit"
|
'border-[#0c891b]'} flex h-fit items-center justify-center"
|
||||||
on:click={handleChangeTheme(themes.green)}
|
on:click={handleChangeTheme(themes.green)}
|
||||||
>
|
>
|
||||||
<div class="w-6 h-6 md:w-6 md:h-6 bg-[#0c891b] rounded-full m-1" />
|
<div class="m-1 h-6 w-6 rounded-full bg-[#0c891b] md:h-6 md:w-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="rounded-full border-2 {$currentOrg.theme === themes.orange &&
|
class="rounded-full border-2 {$currentOrg.theme === themes.orange &&
|
||||||
'border-[#cc4902]'} flex items-center justify-center h-fit"
|
'border-[#cc4902]'} flex h-fit items-center justify-center"
|
||||||
on:click={handleChangeTheme(themes.orange)}
|
on:click={handleChangeTheme(themes.orange)}
|
||||||
>
|
>
|
||||||
<div class="w-6 h-6 md:w-6 md:h-6 bg-[#cc4902] rounded-full m-1" />
|
<div class="m-1 h-6 w-6 rounded-full bg-[#cc4902] md:h-6 md:w-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="rounded-full border-2 {$currentOrg.theme === themes.violet &&
|
class="rounded-full border-2 {$currentOrg.theme === themes.violet &&
|
||||||
'border-[#cf00ce]'} flex items-center justify-center h-fit"
|
'border-[#cf00ce]'} flex h-fit items-center justify-center"
|
||||||
on:click={handleChangeTheme(themes.violet)}
|
on:click={handleChangeTheme(themes.violet)}
|
||||||
>
|
>
|
||||||
<div class="w-6 h-6 md:w-6 md:h-6 bg-[#cf00ce] rounded-full m-1" />
|
<div class="m-1 h-6 w-6 rounded-full bg-[#cf00ce] md:h-6 md:w-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="w-fit h-auto border-2 {isCustomTheme
|
class="h-auto w-fit border-2 {isCustomTheme
|
||||||
? 'border-primary-700'
|
? 'border-primary-700'
|
||||||
: 'dark:border-neutral-700'} rounded-full relative group"
|
: 'dark:border-neutral-700'} group relative rounded-full"
|
||||||
>
|
>
|
||||||
<!-- plus icon positioned over the color picker -->
|
<!-- plus icon positioned over the color picker -->
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 flex items-center justify-center pointer-events-none transition-opacity duration-200"
|
class="pointer-events-none absolute inset-0 flex items-center justify-center transition-opacity duration-200"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="w-6 h-6 text-{isCustomTheme
|
class="h-6 w-6 text-{isCustomTheme
|
||||||
? 'white'
|
? 'white'
|
||||||
: 'black'} dark:text-white z-10 opacity-100"
|
: 'black'} z-10 opacity-100 dark:text-white"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
@@ -259,7 +263,7 @@
|
|||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}>
|
<Column sm={4} md={4} lg={4}>
|
||||||
<SectionTitle>
|
<SectionTitle>
|
||||||
{$t('settings.organization.organization_profile.customize_lms.heading')}
|
{$t('settings.organization.organization_profile.customize_lms.heading')}
|
||||||
@@ -281,7 +285,7 @@
|
|||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle
|
><SectionTitle
|
||||||
>{$t('settings.organization.organization_profile.custom_domain.heading')}</SectionTitle
|
>{$t('settings.organization.organization_profile.custom_domain.heading')}</SectionTitle
|
||||||
@@ -306,7 +310,7 @@
|
|||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
<Row class="flex lg:flex-row flex-col py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}
|
<Column sm={4} md={4} lg={4}
|
||||||
><SectionTitle>{$t('settings.organization.organization_profile.team.heading')}</SectionTitle
|
><SectionTitle>{$t('settings.organization.organization_profile.team.heading')}</SectionTitle
|
||||||
></Column
|
></Column
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
|
||||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||||
import { snackbar } from '$lib/components/Snackbar/store';
|
import { snackbar } from '$lib/components/Snackbar/store';
|
||||||
|
import UnsavedChanges from '$lib/components/UnsavedChanges/index.svelte';
|
||||||
import UploadImage from '$lib/components/UploadImage/index.svelte';
|
import UploadImage from '$lib/components/UploadImage/index.svelte';
|
||||||
import generateUUID from '$lib/utils/functions/generateUUID';
|
import generateUUID from '$lib/utils/functions/generateUUID';
|
||||||
import { supabase } from '$lib/utils/functions/supabase';
|
import { supabase } from '$lib/utils/functions/supabase';
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
let loading = false;
|
let loading = false;
|
||||||
let hasLangChanged = false;
|
let hasLangChanged = false;
|
||||||
let locale = '';
|
let locale = '';
|
||||||
|
let hasUnsavedChanges = false;
|
||||||
|
|
||||||
let errors = {};
|
let errors = {};
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@
|
|||||||
if (hasLangChanged) {
|
if (hasLangChanged) {
|
||||||
handleLocaleChange(locale);
|
handleLocaleChange(locale);
|
||||||
}
|
}
|
||||||
|
hasUnsavedChanges = false;
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let message = error.message;
|
let message = error.message;
|
||||||
@@ -83,16 +85,22 @@
|
|||||||
$: locale = !locale ? $profile.locale : locale;
|
$: locale = !locale ? $profile.locale : locale;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Grid class="border-c rounded border-gray-200 dark:border-neutral-600 w-full mt-5">
|
<UnsavedChanges bind:hasUnsavedChanges />
|
||||||
<Row class="flex flex-col lg:flex-row items-center lg:items-start py-7 border-bottom-c ">
|
<Grid class="border-c mt-5 w-full rounded border-gray-200 dark:border-neutral-600">
|
||||||
|
<Row class="border-bottom-c flex flex-col items-center py-7 lg:flex-row lg:items-start ">
|
||||||
<Column sm={4} md={8} lg={4} class="mt-2 md:mt-0">
|
<Column sm={4} md={8} lg={4} class="mt-2 md:mt-0">
|
||||||
<SectionTitle>{$t('settings.profile.profile_picture.heading')}</SectionTitle>
|
<SectionTitle>{$t('settings.profile.profile_picture.heading')}</SectionTitle>
|
||||||
</Column>
|
</Column>
|
||||||
<Column sm={2} md={4} lg={8} class="mt-2 lg:mt-0">
|
<Column sm={2} md={4} lg={8} class="mt-2 lg:mt-0">
|
||||||
<UploadImage bind:avatar src={$profile.avatar_url} widthHeight="w-16 h-16 lg:w-24 lg:h-24" />
|
<UploadImage
|
||||||
|
bind:avatar
|
||||||
|
src={$profile.avatar_url}
|
||||||
|
widthHeight="w-16 h-16 lg:w-24 lg:h-24"
|
||||||
|
on:change={() => (hasUnsavedChanges = true)}
|
||||||
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
<Row class="flex flex-col lg:flex-row py-7 border-bottom-c">
|
<Row class="border-bottom-c flex flex-col py-7 lg:flex-row">
|
||||||
<Column sm={4} md={4} lg={4}>
|
<Column sm={4} md={4} lg={4}>
|
||||||
<SectionTitle>{$t('settings.profile.personal_information.heading')}</SectionTitle>
|
<SectionTitle>{$t('settings.profile.personal_information.heading')}</SectionTitle>
|
||||||
</Column>
|
</Column>
|
||||||
@@ -102,24 +110,32 @@
|
|||||||
bind:value={$profile.fullname}
|
bind:value={$profile.fullname}
|
||||||
className="w-full lg:w-60 mb-4"
|
className="w-full lg:w-60 mb-4"
|
||||||
errorMessage={$t(errors.fullname)}
|
errorMessage={$t(errors.fullname)}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.profile.personal_information.username')}
|
label={$t('settings.profile.personal_information.username')}
|
||||||
bind:value={$profile.username}
|
bind:value={$profile.username}
|
||||||
className="w-full lg:w-60 mb-4"
|
className="w-full lg:w-60 mb-4"
|
||||||
errorMessage={$t(errors.username)}
|
errorMessage={$t(errors.username)}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={$t('settings.profile.personal_information.email')}
|
label={$t('settings.profile.personal_information.email')}
|
||||||
bind:value={$profile.email}
|
bind:value={$profile.email}
|
||||||
className="w-full lg:w-60 mb-4"
|
className="w-full lg:w-60 mb-4"
|
||||||
errorMessage={$t(errors.email)}
|
errorMessage={$t(errors.email)}
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
|
/>
|
||||||
|
<LanguagePicker
|
||||||
|
onChange={() => (hasUnsavedChanges = true)}
|
||||||
|
bind:hasLangChanged
|
||||||
|
bind:value={locale}
|
||||||
|
className="w-full lg:w-60 mb-4"
|
||||||
/>
|
/>
|
||||||
<LanguagePicker bind:hasLangChanged bind:value={locale} className="w-full lg:w-60 mb-4" />
|
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row class="m-5 w-full flex items-center gap-2 lg:justify-center">
|
<Row class="m-5 flex w-full items-center gap-2 lg:justify-center">
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
label={$t('settings.profile.update_profile')}
|
label={$t('settings.profile.update_profile')}
|
||||||
variant={VARIANTS.CONTAINED_DARK}
|
variant={VARIANTS.CONTAINED_DARK}
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { beforeNavigate } from '$app/navigation';
|
import { beforeNavigate } from '$app/navigation';
|
||||||
|
import { t } from '$lib/utils/functions/translations';
|
||||||
|
|
||||||
export let hasUnsavedChanges = false;
|
export let hasUnsavedChanges = false;
|
||||||
export let message = 'You have unsaved changes. Are you sure you want to leave?';
|
|
||||||
|
|
||||||
beforeNavigate(({ cancel }) => {
|
beforeNavigate(({ cancel }) => {
|
||||||
if (!shouldAbandonChanges()) cancel();
|
if (!shouldAbandonChanges()) {
|
||||||
});
|
cancel();
|
||||||
|
} else {
|
||||||
|
// User clicked OK, reset the flag
|
||||||
|
hasUnsavedChanges = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function shouldAbandonChanges() {
|
function shouldAbandonChanges() {
|
||||||
if (!hasUnsavedChanges) return true;
|
if (!hasUnsavedChanges) return true;
|
||||||
return confirm(message);
|
return window.confirm($t('common.unsaved_changes.message'));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
on:beforeunload={(e) => {
|
on:beforeunload={(e) => {
|
||||||
const result = shouldAbandonChanges();
|
const result = shouldAbandonChanges();
|
||||||
if (!result) e.preventDefault();
|
if (!result) e.preventDefault();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Camera from 'carbon-icons-svelte/lib/Camera.svelte';
|
|
||||||
import { Loading } from 'carbon-components-svelte';
|
|
||||||
import { t } from '$lib/utils/functions/translations';
|
import { t } from '$lib/utils/functions/translations';
|
||||||
|
import { Loading } from 'carbon-components-svelte';
|
||||||
|
import Camera from 'carbon-icons-svelte/lib/Camera.svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
export let avatar: string | undefined;
|
export let avatar: string | undefined;
|
||||||
export let src: string | undefined;
|
export let src: string | undefined;
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
export let isUploading = false;
|
export let isUploading = false;
|
||||||
|
|
||||||
let fileinput: HTMLInputElement;
|
let fileinput: HTMLInputElement;
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
const onFileSelected = (e: Event<HTMLInputElement>) => {
|
const onFileSelected = (e: Event<HTMLInputElement>) => {
|
||||||
const image = e.target.files[0];
|
const image = e.target.files[0];
|
||||||
@@ -28,6 +30,7 @@
|
|||||||
reader.readAsDataURL(image);
|
reader.readAsDataURL(image);
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
avatar = image;
|
avatar = image;
|
||||||
|
dispatch('change');
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
src = e.target?.result || undefined;
|
src = e.target?.result || undefined;
|
||||||
errorMessage = null; // Clear error message on successful load
|
errorMessage = null; // Clear error message on successful load
|
||||||
@@ -35,18 +38,18 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="width-fit p-3 flex {flexDirection} items-center justify-between gap-5">
|
<section class="width-fit flex p-3 {flexDirection} items-center justify-between gap-5">
|
||||||
<div
|
<div
|
||||||
class="avatar-container {widthHeight ||
|
class="avatar-container {widthHeight ||
|
||||||
'setwidthheight'} pointer border-2 border-gray-200 dark:border-neutral-600 relative {shape}"
|
'setwidthheight'} pointer relative border-2 border-gray-200 dark:border-neutral-600 {shape}"
|
||||||
>
|
>
|
||||||
{#if src}
|
{#if src}
|
||||||
<img class="w-full h-full {shape}" {src} alt="Avatar" />
|
<img class="h-full w-full {shape}" {src} alt="Avatar" />
|
||||||
{:else if avatar}
|
{:else if avatar}
|
||||||
<img class="w-full h-full {shape}" src={avatar} alt="Avatar" />
|
<img class="h-full w-full {shape}" src={avatar} alt="Avatar" />
|
||||||
{:else}
|
{:else}
|
||||||
<img
|
<img
|
||||||
class="w-full h-full {shape}"
|
class="h-full w-full {shape}"
|
||||||
src="https://cdn4.iconfinder.com/data/icons/small-n-flat/24/user-alt-512.png"
|
src="https://cdn4.iconfinder.com/data/icons/small-n-flat/24/user-alt-512.png"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
@@ -57,7 +60,7 @@
|
|||||||
<button
|
<button
|
||||||
class="width-fit text-primary-700 flex flex-col items-center text-sm {isDisabled ||
|
class="width-fit text-primary-700 flex flex-col items-center text-sm {isDisabled ||
|
||||||
isUploading
|
isUploading
|
||||||
? 'opacity-50 cursor-not-allowed'
|
? 'cursor-not-allowed opacity-50'
|
||||||
: 'cursor-pointer'}"
|
: 'cursor-pointer'}"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (!isDisabled || isUploading) {
|
if (!isDisabled || isUploading) {
|
||||||
@@ -73,7 +76,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<span class="ml-2">{$t('settings.profile.profile_picture.upload_image')}</span>
|
<span class="ml-2">{$t('settings.profile.profile_picture.upload_image')}</span>
|
||||||
</button>
|
</button>
|
||||||
<p class="text-xs text-center text-gray-500">
|
<p class="text-center text-xs text-gray-500">
|
||||||
{$t('settings.profile.profile_picture.file_size')}
|
{$t('settings.profile.profile_picture.file_size')}
|
||||||
{maxFileSizeInMb}MB<br />
|
{maxFileSizeInMb}MB<br />
|
||||||
{$t('settings.profile.profile_picture.accepted')}: jpeg, jpg, png, webp
|
{$t('settings.profile.profile_picture.accepted')}: jpeg, jpg, png, webp
|
||||||
|
|||||||
@@ -1553,5 +1553,10 @@
|
|||||||
"assignment_completion_description": "Prozentsatz der abgeschlossenen Aufgaben",
|
"assignment_completion_description": "Prozentsatz der abgeschlossenen Aufgaben",
|
||||||
"average_grade": "Durchschnittsnote",
|
"average_grade": "Durchschnittsnote",
|
||||||
"average_grade_description": "Durchschnittsnote aller abgeschlossenen Aufgaben"
|
"average_grade_description": "Durchschnittsnote aller abgeschlossenen Aufgaben"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "Sie haben nicht gerettete Änderungen. Bist du sicher, dass du gehen willst?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1600,5 +1600,11 @@
|
|||||||
"not_valid": "Not valid email"
|
"not_valid": "Not valid email"
|
||||||
},
|
},
|
||||||
"invalid_type_error": "Must not be empty"
|
"invalid_type_error": "Must not be empty"
|
||||||
|
},
|
||||||
|
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "You have unsaved changes. Are you sure you want to leave?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1553,5 +1553,10 @@
|
|||||||
"assignment_completion_description": "Porcentaje de tareas completadas",
|
"assignment_completion_description": "Porcentaje de tareas completadas",
|
||||||
"average_grade": "Calificación promedio",
|
"average_grade": "Calificación promedio",
|
||||||
"average_grade_description": "Calificación promedio de todas las tareas completadas"
|
"average_grade_description": "Calificación promedio de todas las tareas completadas"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "Tienes cambios no salvos. ¿Estás seguro de que quieres irte?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1553,5 +1553,10 @@
|
|||||||
"assignment_completion_description": "Pourcentage de missions terminées",
|
"assignment_completion_description": "Pourcentage de missions terminées",
|
||||||
"average_grade": "Note moyenne",
|
"average_grade": "Note moyenne",
|
||||||
"average_grade_description": "Note moyenne de tous les devoirs terminés"
|
"average_grade_description": "Note moyenne de tous les devoirs terminés"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "Vous avez des changements non sauvés. Êtes-vous sûr de vouloir partir?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1553,5 +1553,10 @@
|
|||||||
"assignment_completion_description": "पूर्ण किये गये कार्यों का प्रतिशत",
|
"assignment_completion_description": "पूर्ण किये गये कार्यों का प्रतिशत",
|
||||||
"average_grade": "औसत क्षेणी",
|
"average_grade": "औसत क्षेणी",
|
||||||
"average_grade_description": "सभी पूर्ण किए गए असाइनमेंट का औसत ग्रेड"
|
"average_grade_description": "सभी पूर्ण किए गए असाइनमेंट का औसत ग्रेड"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "आपके पास अनसुना परिवर्तन हैं। क्या आपकी वाकई छोड़ने की इच्छा है?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1553,5 +1553,10 @@
|
|||||||
"assignment_completion_description": "Porcentagem de tarefas concluídas",
|
"assignment_completion_description": "Porcentagem de tarefas concluídas",
|
||||||
"average_grade": "Nota Média",
|
"average_grade": "Nota Média",
|
||||||
"average_grade_description": "Nota média de todas as tarefas concluídas"
|
"average_grade_description": "Nota média de todas as tarefas concluídas"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "Você tem mudanças não salvas. Tem certeza de que deseja sair?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1553,5 +1553,10 @@
|
|||||||
"assignment_completion_description": "Процент выполненных заданий",
|
"assignment_completion_description": "Процент выполненных заданий",
|
||||||
"average_grade": "Средняя оценка",
|
"average_grade": "Средняя оценка",
|
||||||
"average_grade_description": "Средняя оценка за все выполненные задания"
|
"average_grade_description": "Средняя оценка за все выполненные задания"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "У вас есть неспасенные изменения. Вы уверены, что хотите уйти?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1553,5 +1553,10 @@
|
|||||||
"assignment_completion_description": "Tỷ lệ bài tập đã hoàn thành",
|
"assignment_completion_description": "Tỷ lệ bài tập đã hoàn thành",
|
||||||
"average_grade": "Điểm trung bình",
|
"average_grade": "Điểm trung bình",
|
||||||
"average_grade_description": "Điểm trung bình của tất cả các bài tập đã hoàn thành"
|
"average_grade_description": "Điểm trung bình của tất cả các bài tập đã hoàn thành"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"unsaved_changes": {
|
||||||
|
"message": "Bạn có những thay đổi chưa được lưu. Bạn có chắc bạn muốn rời đi?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user