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
@@ -1,13 +1,13 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { page } from '$app/state';
import Box from '$lib/components/Box/index.svelte';
import NewFeedModal from '$lib/components/Course/components/NewsFeed/NewFeedModal.svelte';
import NewsFeedCard from '$lib/components/Course/components/NewsFeed/NewsFeedCard.svelte';
import NewsFeedLoader from '$lib/components/Course/components/NewsFeed/NewsFeedLoader.svelte';
import { isNewFeedModal, newsFeed } from '$lib/components/Course/components/NewsFeed/store';
import { group } from '$lib/components/Course/store';
import CourseContainer from '$lib/components/CourseContainer/index.svelte';
import { CourseContainer } from '$lib/components/CourseContainer';
import { PageBody, PageNav } from '$lib/components/Page';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import RoleBasedSecurity from '$lib/components/RoleBasedSecurity/index.svelte';
@@ -23,32 +23,35 @@
handleEditFeed,
toggleFeedIsPinned
} from '$lib/utils/services/newsfeed';
import {
NOTIFICATION_NAME,
triggerSendEmail
} from '$lib/utils/services/notification/notification';
import { NOTIFICATION_NAME, triggerSendEmail } from '$lib/utils/services/notification/notification';
import { currentOrg } from '$lib/utils/store/org';
import { profile } from '$lib/utils/store/user';
import type { Feed } from '$lib/utils/types/feed';
import type { CurrentOrg } from '$lib/utils/types/org';
import PinFilled from 'carbon-icons-svelte/lib/PinFilled.svelte';
import PinIcon from '@lucide/svelte/icons/pin';
import { onMount } from 'svelte';
export let data;
let { data = $bindable() } = $props();
let createdComment;
let edit = false;
let isLoading = false;
let editFeed: Feed;
let author = {
id: '',
username: '',
fullname: '',
avatar_url: ''
};
let edit = $state(false);
let isLoading = $state(false);
let editFeed: Feed | null = $state(null);
let query = new URLSearchParams($page.url.search);
let query = new URLSearchParams(page.url.search);
let feedId = query.get('feedId') || '';
const author = $derived.by(() => {
const groupMember = $group.people.find((person) => person.profile_id === $profile.id);
return {
id: groupMember?.id || '',
username: $profile.username || '',
fullname: $profile.fullname || '',
avatar_url: $profile.avatar_url || ''
};
});
const onEdit = (id: string, content: string) => {
handleEditFeed(id, content);
@@ -81,9 +84,7 @@
let reactedAuthorIds: string[] = reactedFeed.reaction[reactionType];
if (reactedAuthorIds.includes(authorId)) {
reactedAuthorIds = reactedAuthorIds.filter(
(reactionAuthorId) => reactionAuthorId !== authorId
);
reactedAuthorIds = reactedAuthorIds.filter((reactionAuthorId) => reactionAuthorId !== authorId);
} else {
reactedAuthorIds = [...reactedAuthorIds, authorId];
}
@@ -199,10 +200,12 @@
snackbar.error('snackbar.course.error.news_feed_fail');
}
if (data) {
$newsFeed = data.map((feedItem) => ({
...feedItem,
isPinned: feedItem.is_pinned
}));
$newsFeed = data
.map((feedItem) => ({
...feedItem,
isPinned: feedItem.is_pinned
}))
.sort((a, b) => Number(b.isPinned) - Number(a.isPinned));
}
} catch (error) {
snackbar.error('snackbar.course.error.feed_fetch_error');
@@ -211,17 +214,6 @@
}
};
function setAuthor(groups, profileId) {
const currentGroupMember = groups.people.find((person) => person.profile_id === profileId);
author = {
id: currentGroupMember?.id || '',
username: $profile.username || '',
fullname: $profile.fullname || '',
avatar_url: $profile.avatar_url || ''
};
}
function getPageRoles(org: CurrentOrg) {
const roles: number[] = [1, 2];
@@ -232,13 +224,12 @@
return roles;
}
$: initNewsFeed(data.courseId);
$: setAuthor($group, $profile.id);
$: $newsFeed = $newsFeed.sort((a, b) => Number(b.isPinned) - Number(a.isPinned));
onMount(() => {
initNewsFeed(data.courseId);
});
</script>
<CourseContainer bind:courseId={data.courseId}>
<CourseContainer courseId={data.courseId}>
<RoleBasedSecurity
allowedRoles={getPageRoles($currentOrg)}
onDenied={() => {
@@ -246,7 +237,7 @@
}}
>
<PageNav title={$t('course.navItem.news_feed.heading')} disableSticky={true}>
<slot:fragment slot="widget">
{#snippet widget()}
<RoleBasedSecurity allowedRoles={[1, 2]}>
<PrimaryButton
className="mr-2"
@@ -254,7 +245,7 @@
onClick={() => ($isNewFeedModal.open = true)}
/>
</RoleBasedSecurity>
</slot:fragment>
{/snippet}
</PageNav>
<PageBody width="max-w-4xl px-3">
@@ -290,7 +281,7 @@
{#each $newsFeed as feed}
{#if feed.isPinned}
<div class="mb-3 flex items-center gap-2">
<PinFilled size={16} />
<PinIcon size={16} class="filled" />
<p class="text-sm">{$t('course.navItem.news_feed.pinned')}</p>
</div>