feat: setup drizzle (#594)

* chore: migration to SvelteKit 2

* stage 1: migrate to svelte 5 and fix rerendering issues

* stage 2: fix more $: reactivity across dashboard

* fix merge conflicts

* chore: migrate code in main to svelte 5

* chore: update preventDefault

* chore: simplify tsconfig and remove unused mobileMenuRef in MobileMenu.svelte

* chore: enforce .ts across dashboard

* rename from classroomio-com to website

* stage-3: Replace carbon icon svelte with lucide icon

* update lock file

* chore: finish icon replacement

* fix: settings and setup page multiple rerender

* stage 3: More icon and rerendering fixes

* feat: setup drizzle and better auth

* fix: onboarding validation error showing translation key #586 (#593)

* fix: onboarding validation error showing translation key #586

* fix: remove debug log for profile update errors

* chore: add a clean command

* fix: remove message from email verification response
This commit is contained in:
Rotimi Best
2025-11-01 15:49:29 +01:00
committed by GitHub
parent 97fb446df5
commit b96d91cd7c
801 changed files with 22279 additions and 10834 deletions
@@ -12,12 +12,10 @@
import { blockedSubdomain } from '$lib/utils/constants/app';
import { getOrganizations } from '$lib/utils/services/org';
import { generateSitename } from '$lib/utils/functions/org';
import {
triggerSendEmail,
NOTIFICATION_NAME
} from '$lib/utils/services/notification/notification';
import { triggerSendEmail, NOTIFICATION_NAME } from '$lib/utils/services/notification/notification';
import { handleLocaleChange, t } from '$lib/utils/functions/translations';
import { LOCALE } from '$lib/utils/types';
import { untrack } from 'svelte';
interface OnboardingField {
fullname?: string;
@@ -35,17 +33,16 @@
}
const maxSteps = 2;
let fields: OnboardingField = {
let fields: OnboardingField = $state({
fullname: '',
orgName: '',
siteName: '',
locale: LOCALE.EN
};
let errors: OnboardingField = {};
let progress = 50;
let step = 1;
let loading = false;
let isSiteNameTouched = false;
});
let errors: OnboardingField = $state({});
let step = $state(1);
let loading = $state(false);
let isSiteNameTouched = $state(false);
let selectedId = 'en';
let dropdownItems = [
@@ -61,6 +58,8 @@
{ id: 'da', text: 'Danish' }
];
const progress = $derived(Math.round((step / maxSteps) * 100));
const educatorGoals: Goal[] = [
{
label: $t('onboarding.sell'),
@@ -116,15 +115,6 @@
fields.metadata = payload;
}
function setOrgSiteName(orgName: string | undefined, isTouched: boolean) {
if (!orgName || isTouched) return;
fields.siteName = orgName
?.toLowerCase()
?.replace(/\s+/g, '-')
?.replace(/[^a-zA-Z0-9-]/g, '');
}
const handleSubmit = async () => {
loading = true;
// Run validation
@@ -233,9 +223,30 @@
loading = false;
};
$: progress = Math.round((step / maxSteps) * 100);
$: fields.siteName = generateSitename(fields.siteName || '');
$: setOrgSiteName(fields.orgName, isSiteNameTouched);
function updateSiteName(sname?: string) {
if (!sname) return;
untrack(() => {
fields.siteName = generateSitename(sname);
});
}
$effect(() => {
updateSiteName(fields.siteName);
});
function setOrgSiteName(orgName: string | undefined, isTouched: boolean) {
if (!orgName || isTouched) return;
untrack(() => {
fields.siteName = orgName
?.toLowerCase()
?.replace(/\s+/g, '-')
?.replace(/[^a-zA-Z0-9-]/g, '');
});
}
$effect(() => {
setOrgSiteName(fields.orgName, isSiteNameTouched);
});
</script>
{#if $profile.id}
@@ -252,7 +263,7 @@
<div
class="mb-6 flex w-64 items-center justify-center rounded-2xl border border-gray-300 bg-gray-100 py-6 dark:bg-neutral-800"
>
<UserProfileIcon />
<UserProfileIcon size={16} />
<p class="ml-2 text-sm dark:text-white">{$profile.email}</p>
</div>
</div>
@@ -317,13 +328,7 @@
<!-- Loop through Goals -->
{#each educatorGoals as goal}
<label class="mb-1 inline-flex w-full items-center font-light dark:text-white">
<input
type="radio"
bind:group={fields.goal}
name="goal"
value={goal.value}
class="mr-2"
/>
<input type="radio" bind:group={fields.goal} name="goal" value={goal.value} class="mr-2" />
{goal.label}
</label>
{/each}
@@ -344,13 +349,7 @@
<!-- Loop through Goals -->
{#each sources as source}
<label class="mb-1 inline-flex w-full items-center font-light dark:text-white">
<input
type="radio"
bind:group={fields.source}
name="source"
value={source.value}
class="mr-2"
/>
<input type="radio" bind:group={fields.source} name="source" value={source.value} class="mr-2" />
{source.label}
</label>
{/each}
@@ -365,12 +364,7 @@
<!-- Language Picker -->
<div class="mt-10">
<span>{$t('content.toggle_label')}: </span>
<Dropdown
items={dropdownItems}
{selectedId}
on:select={handleSelect}
class="w-full"
/>
<Dropdown items={dropdownItems} {selectedId} on:select={handleSelect} class="w-full" />
</div>
</div>
</div>
@@ -380,10 +374,7 @@
<!-- Footer -->
<div class="mt-8 flex w-full items-center justify-between">
<div class="relative h-2 w-24 bg-gray-300">
<span
class="progress bg-primary-700 absolute left-0 top-0 h-full"
style="width: {progress}%;"
/>
<span class="progress bg-primary-700 absolute left-0 top-0 h-full" style="width: {progress}%;"></span>
</div>
<div class="flex">