feat: org and course student analytics page (#509)

* UI initialization

* feat: structure API

* feat: audience & people analytics

* feat: quick changes

* feat: add comments

* redesign course student page

* chore: make requests to db more efficient

* clean up analytics page for course

* feat: finish up audience analytics page

* chore: minor UI tweaks

* translate all

* replace inserts of log in events to update

* catch error if last_login isn't inserted

---------

Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
Adeyemi Adetunji
2024-12-30 02:59:10 +01:00
committed by GitHub
co-authored by Rotimi Best
parent 381776f388
commit f69bf920a9
46 changed files with 1916 additions and 437 deletions
@@ -0,0 +1,56 @@
import { type ClassValue, clsx } from 'clsx';
import { cubicOut } from 'svelte/easing';
import type { TransitionConfig } from 'svelte/transition';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
type FlyAndScaleParams = {
y?: number;
x?: number;
start?: number;
duration?: number;
};
export const flyAndScale = (
node: Element,
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
): TransitionConfig => {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
const scaleConversion = (valueA: number, scaleA: [number, number], scaleB: [number, number]) => {
const [minA, maxA] = scaleA;
const [minB, maxB] = scaleB;
const percentage = (valueA - minA) / (maxA - minA);
const valueB = percentage * (maxB - minB) + minB;
return valueB;
};
const styleToString = (style: Record<string, number | string | undefined>): string => {
return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined) return str;
return str + `${key}:${style[key]};`;
}, '');
};
return {
duration: params.duration ?? 200,
delay: 0,
css: (t) => {
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
return styleToString({
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
opacity: t
});
},
easing: cubicOut
};
};
@@ -10,5 +10,9 @@ export const calDateDiff = (date: string | number | Date): string => {
export const getGreeting = () => {
const date = new Date();
const hours = date.getHours();
return hours < 12 ? 'dashboard.morning_heading' : hours < 18 ? 'dashboard.afternoon_heading' : 'dashboard.evening_heading';
return hours < 12
? 'dashboard.morning_heading'
: hours < 18
? 'dashboard.afternoon_heading'
: 'dashboard.evening_heading';
};
@@ -1,5 +1,5 @@
import { createClient, SupabaseClient } from '@supabase/supabase-js';
import { config } from '$lib/config';
import { createClient, SupabaseClient } from '@supabase/supabase-js';
export let supabase: SupabaseClient;
@@ -22,3 +22,8 @@ export const isSupabaseTokenInLocalStorage = () => {
return false;
};
export const getAccessToken = async () => {
const { data } = await getSupabase().auth.getSession();
return data.session?.access_token || '';
};
@@ -1,17 +1,10 @@
import { LOCALE } from '$lib/utils/types';
import i18n from '@sveltekit-i18n/base';
import parser from '@sveltekit-i18n/parser-icu';
import { writable } from 'svelte/store';
import i18n, { type Config } from 'sveltekit-i18n';
interface Params {
dateValue: number;
value: number;
download: number;
award: number;
val: Date;
}
export const config: Config<Partial<Params>> = {
// parser: parser(),
export const config = {
parser: parser(),
loaders: [
{
locale: 'en',