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,30 +0,0 @@
import isSubmissionEarly from './isSubmissionEarly';
describe('isSubmissionEarly', () => {
test('should return true when createdAt is earlier than dueDate', () => {
const dueDate = Date.now();
const createdAt = new Date('2023-12-15');
const result = isSubmissionEarly(createdAt, dueDate);
expect(result).toBe(true);
});
test('should return true when both createdAt and dueDate are null', () => {
const dueDate = null;
const createdAt = null;
const result = isSubmissionEarly(createdAt, dueDate);
expect(result).toBe(true);
});
test('should return true when createdAt is the same as dueDate', () => {
const dueDate = new Date('2023-12-15');
const createdAt = new Date('2023-12-15');
const result = isSubmissionEarly(createdAt, dueDate);
expect(result).toBe(true);
});
test('should return false when createdAt is later than dueDate', () => {
const dueDate = new Date('2023-12-15');
const createdAt = new Date('2023-12-16');
const result = isSubmissionEarly(createdAt, dueDate);
expect(result).toBe(false);
});
});
@@ -83,7 +83,7 @@ export async function getProfile({
}
// Check if user has profile
let {
const {
data: profileData,
error,
status
@@ -1,18 +0,0 @@
import { isCourseFree } from './course';
describe('course.ts', () => {
test('Should return True when cost is 0', () => {
const result = isCourseFree(0);
expect(result).toBeTruthy();
});
test('Should return true when cost is negative', () => {
const result = isCourseFree(-10);
expect(result).toBeTruthy();
});
test('Should return True when cost is Not A Number', () => {
const result = isCourseFree(NaN);
expect(result).toBeTruthy();
});
});
@@ -1,36 +0,0 @@
import { calDateDiff, getGreeting } from './date';
describe('calDateDiff', () => {
test('should return the correct time difference when the input date is in the past', () => {
const inputDate = new Date('2022-01-01');
const expectedOutput = '2 years ago';
const result = calDateDiff(inputDate);
expect(result).toBe(expectedOutput);
});
test('should return the correct time difference when the input date is a number', () => {
const inputDate = new Date(1640995200000); // January 1, 2022
const expectedOutput = '2 years ago';
const result = calDateDiff(inputDate);
expect(result).toBe(expectedOutput);
});
});
describe('getGreeting', () => {
test("should return 'Good Morning' when the current time is before 12pm", () => {
jest.useFakeTimers().setSystemTime(new Date('2023-12-10T00:21:01.691Z'));
expect(getGreeting()).toBe('Good Morning');
});
test("should return 'Good Afternoon' when the current time is after 12pm", () => {
jest.useFakeTimers().setSystemTime(new Date('2023-12-10T14:21:01.691Z'));
expect(getGreeting()).toBe('Good Afternoon');
});
test("should return 'Good Evening' when the current time is after 6pm", () => {
jest.useFakeTimers().setSystemTime(new Date('2023-12-10T19:21:01.691Z'));
expect(getGreeting()).toBe('Good Evening');
});
});
@@ -1,46 +0,0 @@
import { formatYoutubeVideo, getEmbedId } from './formatYoutubeVideo';
describe('format youtube video', () => {
test('should return the same url when given a valid youtube embed url', () => {
const url = 'https://www.youtube.com/embed/qajK1J1neAM';
const errors = { video: '' };
const result = formatYoutubeVideo(url, errors);
expect(result).toBe(url);
});
test('should return the correct embed url when given a youtube url with a start time parameter', () => {
const url = 'https://www.youtube.com/watch?v=qajK1J1neAM&start=123';
const errors = { video: '' };
const result = formatYoutubeVideo(url, errors);
expect(result).toBe('https://www.youtube.com/embed/qajK1J1neAM');
});
});
describe('getEmbedId', () => {
test('should return the correct embed id when the url contains "embed"', () => {
const url = 'https://www.youtube.com/embed/qajK1J1neAM';
const expectedEmbedId = 'qajK1J1neAM';
const result = getEmbedId(url);
expect(result).toBe(expectedEmbedId);
});
test('should return an empty string when the url does not contain "watch" or "embed" and is not in the format "youtu.be/"', () => {
const url = 'https://www.youtube.com/invalid-url';
const expectedEmbedId = '';
const result = getEmbedId(url);
expect(result).toBe(expectedEmbedId);
});
test('should return an empty string when the url is an empty string', () => {
const url = '';
const expectedEmbedId = '';
const result = getEmbedId(url);
expect(result).toBe(expectedEmbedId);
});
});
@@ -1,25 +0,0 @@
import genUniqueId from './genUniqueId';
describe('Generate Unique Ids', () => {
test('should start with letter', () => {
const result = genUniqueId();
const firstChar = result.charAt(0);
expect(firstChar).toMatch(/[a-zA-Z]/);
});
test('should not contain special characters', () => {
const result = genUniqueId();
expect(result).toMatch(/^[a-zA-Z0-9]+$/);
});
test('should return different ids on multiple calls', () => {
const result1 = genUniqueId();
const result2 = genUniqueId();
expect(result1).not.toEqual(result2);
});
test('multiple calls in closer time frames should have same first 3 letters', () => {
const result1 = genUniqueId();
const result2 = genUniqueId();
expect(result1.substring(0, 4)).toEqual(result2.substring(0, 4));
});
});
@@ -1,17 +0,0 @@
import generateSlug from './generateSlug';
describe('generateSlug', () => {
test('should return a string with lowercase letters and hyphens when given a valid title', () => {
const title = 'This is a Valid Title';
const expected = 'this-is-a-valid-title' + `-${new Date().getTime()}`;
const result = generateSlug(title);
expect(result).toBe(expected);
});
test('should include the current timestamp at the end of the string', () => {
const title = 'This is a Valid Title';
const result = generateSlug(title);
const timestamp = result.split('-').pop();
expect(Number(timestamp)).toBeGreaterThan(0);
});
});
@@ -1,26 +0,0 @@
import generateUUID from './generateUUID';
import { isUUID } from './isUUID';
// This test suite tests both the generateUUID and isUUID functions
describe('GenerateUUID', () => {
test('should be true when tested with the uuid function', () => {
const result = generateUUID();
expect(isUUID(result)).toBe(true);
});
test('should generate unique UUIDs each time', () => {
const uuid1 = generateUUID();
const uuid2 = generateUUID();
expect(uuid1).not.toBe(uuid2);
});
test('should return true for a valid UUID', () => {
const uuid = '123e4567-e89b-12d3-a456-426614174000';
expect(isUUID(uuid)).toBe(true);
});
test('should return false for an invalid UUID', () => {
const uuid = 'invalid-uuid';
expect(isUUID(uuid)).toBe(false);
});
});
@@ -1,9 +1,9 @@
export default function generateUUID() {
// Public Domain/MIT
var d = new Date().getTime(); //Timestamp
var d2 = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0; //Time in microseconds since page-load or 0 if unsupported
let d = new Date().getTime(); //Timestamp
let d2 = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0; //Time in microseconds since page-load or 0 if unsupported
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16; //random number between 0 and 16
let r = Math.random() * 16; //random number between 0 and 16
if (d > 0) {
//Use timestamp until depleted
r = (d + r) % 16 | 0;
@@ -1,27 +0,0 @@
import getCurrencyFormatter from './getCurrencyFormatter';
describe('GetCurrencyFormatter', () => {
test('should return a new instance of Intl.NumberFormat with the correct locale and currency options when currency is "NGN"', () => {
const result = getCurrencyFormatter('NGN');
expect(result).toBeInstanceOf(Intl.NumberFormat);
expect(result.resolvedOptions().locale).toBe('en-NG');
expect(result.resolvedOptions().currency).toBe('NGN');
expect(result.resolvedOptions().minimumFractionDigits).toBe(2);
});
test('should return a new instance of Intl.NumberFormat with the correct locale and currency options when currency is "USD"', () => {
const result = getCurrencyFormatter('USD');
expect(result).toBeInstanceOf(Intl.NumberFormat);
expect(result.resolvedOptions().locale).toBe('en-US');
expect(result.resolvedOptions().currency).toBe('USD');
expect(result.resolvedOptions().minimumFractionDigits).toBe(2);
});
test('should return a new instance of Intl.NumberFormat with the correct locale and currency options when currency is "EUR"', () => {
const result = getCurrencyFormatter('EUR');
expect(result).toBeInstanceOf(Intl.NumberFormat);
expect(result.resolvedOptions().locale).toBe('en-US');
expect(result.resolvedOptions().currency).toBe('EUR');
expect(result.resolvedOptions().minimumFractionDigits).toBe(2);
});
});
@@ -1,23 +0,0 @@
import { isObject } from './isObject';
describe('isObject', () => {
test('should return true for an empty object', () => {
const obj = {};
expect(isObject(obj)).toBe(true);
});
test('should return false for a non-object', () => {
const obj = 'not an object';
expect(isObject(obj)).toBe(false);
});
test('should return true for a nested object', () => {
const obj = { prop1: { prop2: 'value2' } };
expect(isObject(obj)).toBe(true);
});
test('should return true for an object with properties', () => {
const obj = { prop1: 'value1', prop2: 'value2' };
expect(isObject(obj)).toBe(true);
});
});
@@ -1,3 +0,0 @@
export default (created_at, due_date) => {
return !!due_date ? !!(new Date(created_at).getTime() <= new Date(due_date).getTime()) : true;
};
@@ -0,0 +1,3 @@
export default (created_at, due_date) => {
return due_date ? !!(new Date(created_at).getTime() <= new Date(due_date).getTime()) : true;
};
@@ -1,5 +1,5 @@
export function isUUID(uuid: string) {
let s = '' + uuid;
const s = '' + uuid;
const m: RegExpMatchArray | null = s.match(
'^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
@@ -1,60 +0,0 @@
import { genQuizPin, generateSitename } from './org';
describe('Generate Quiz Pin', () => {
test('should return a random 6-digit pin', () => {
const result = genQuizPin();
expect(result.toString().length).toBe(6);
});
test('should return random pin each time', () => {
const result1 = genQuizPin();
const result2 = genQuizPin();
expect(result1).not.toBe(result2);
});
test('should generate a pin between 100000 and 999999', () => {
const result = genQuizPin();
expect(result).toBeGreaterThanOrEqual(100000);
expect(result).toBeLessThanOrEqual(999999);
});
test('should not generate a negative pin', () => {
const result = genQuizPin();
expect(result).toBeGreaterThanOrEqual(0);
});
test('should generate an integer pin', () => {
const result = genQuizPin();
expect(Number.isInteger(result)).toBe(true);
});
test('should not generate a zero pin', () => {
const result = genQuizPin();
expect(result).not.toBe(0);
});
});
describe('Generate Site name', () => {
test('should return slug-like string', () => {
const result = generateSitename('classroom org international');
const expected = 'classroom-org-international';
expect(result).toBe(expected);
});
test('should remove special characters', () => {
const result = generateSitename('classroom@ org! international');
const expected = 'classroom-org-international';
expect(result).toBe(expected);
});
test('should return empty string when orgName is an empty string', () => {
const result = generateSitename('');
const expected = '';
expect(result).toBe(expected);
});
test('should return slug-like string with all uppercase characters converted to lowercase', () => {
const result = generateSitename('Classroom Org International');
const expected = 'classroom-org-international';
expect(result).toBe(expected);
});
});
@@ -1,8 +1,8 @@
import { goto } from '$app/navigation';
export function genQuizPin(): number {
var minm = 100000;
var maxm = 999999;
const minm = 100000;
const maxm = 999999;
return Math.floor(Math.random() * (maxm - minm + 1)) + minm;
}
@@ -1,38 +0,0 @@
import { removeDuplicate } from './removeDuplicate';
describe('removeDuplicate', () => {
test('should remove duplicate elements of an array', () => {
const result = removeDuplicate([1, 1, 2, 3, 3, 4, 5]);
const expected = [1, 2, 3, 4, 5];
expect(result).toStrictEqual(expected);
expect(result.length).toBe(5);
});
test('should return an empty array', () => {
const result = removeDuplicate([]);
const expected = [];
expect(result).toStrictEqual(expected);
expect(result.length).toBe(0);
});
test('should return an array with the same element', () => {
const result = removeDuplicate([1]);
const expected = [1];
expect(result).toStrictEqual(expected);
expect(result.length).toBe(1);
});
test('should return an array with only one element', () => {
const result = removeDuplicate([1, 1, 1, 1]);
const expected = [1];
expect(result).toStrictEqual(expected);
expect(result.length).toBe(1);
});
test('should return an array with the unique elements in the same order as the original array', () => {
const result = removeDuplicate([1, 2, 3, 4, 5, 1, 2, 3, 4, 5]);
const expected = [1, 2, 3, 4, 5];
expect(result).toStrictEqual(expected);
expect(result.length).toBe(5);
});
});
@@ -1,26 +0,0 @@
import showAppsSideBar from './showAppsSideBar';
describe('ShowAppSideBar', () => {
test("should return true when path includes '/lessons/' and does not include 'landingpage'", () => {
const path = '/lessons/example';
const result = showAppsSideBar(path);
expect(result).toBe(true);
});
test("should return false when path does not include '/lessons/'", () => {
const path = '/home';
const result = showAppsSideBar(path);
expect(result).toBe(false);
});
test("should return false when path includes 'landingpage'", () => {
const path = '/lessons/landingpage';
const result = showAppsSideBar(path);
expect(result).toBe(false);
});
test('should return false when path is empty', () => {
const path = '';
const result = showAppsSideBar(path);
expect(result).toBe(false);
});
});
@@ -1,28 +0,0 @@
import { capitalizeFirstLetter } from './string';
describe('capitalize first letter', () => {
test('should return the same string with the first letter capitalized', () => {
const result = capitalizeFirstLetter('classroom');
expect(result).toEqual('Classroom');
});
test('should return an empty string when given an empty string', () => {
const result = capitalizeFirstLetter('');
expect(result).toEqual('');
});
test('should return the same string when given a string with all uppercase letters', () => {
const result = capitalizeFirstLetter('UPPERCASE');
expect(result).toEqual('UPPERCASE');
});
test('should return the same string when given a string with a non-alphabetical first character', () => {
const result = capitalizeFirstLetter('123abc');
expect(result).toEqual('123abc');
});
test('should return the first letter of the first word capitalized when given a sentence', () => {
const result = capitalizeFirstLetter('classroomio is an open source project');
expect(result).toEqual('Classroomio is an open source project');
});
});
@@ -12,17 +12,13 @@ export let supabase: SupabaseClient;
export const getServerSupabase = () => {
if (supabase) return supabase;
supabase = createClient(
config.supabaseConfig.url,
env.PRIVATE_SUPABASE_SERVICE_ROLE || 'some-key-here',
{
auth: {
persistSession: false,
autoRefreshToken: false,
detectSessionInUrl: false
}
supabase = createClient(config.supabaseConfig.url, env.PRIVATE_SUPABASE_SERVICE_ROLE || 'some-key-here', {
auth: {
persistSession: false,
autoRefreshToken: false,
detectSessionInUrl: false
}
);
});
return supabase;
};
@@ -0,0 +1,29 @@
export function once(fn) {
return function (event) {
// @ts-ignore
if (fn) fn.call(this, event);
fn = null;
};
}
export function preventDefault(fn?: Function) {
return function (event: Event) {
event.preventDefault();
if (!fn) return;
// @ts-ignore
fn.call(this, event);
};
}
export function stopPropagation(fn?: Function) {
return function (event: Event) {
event.stopPropagation();
if (!fn) return;
// @ts-ignore
fn.call(this, event);
};
}
@@ -1,14 +1,14 @@
import { env } from '$env/dynamic/public';
var win, output, textarea;
let win, output, textarea;
// Follow this guide to get source code: https://editor.codecogs.com/docs/3-Tiny_MCE_v6.php
export const addMathPlugin = (tinymce: any) => {
tinymce.PluginManager.add('eqneditor', function (editor, url) {
// Load necessary javascript for editor from CodeCogs
var sl = new tinymce.dom.ScriptLoader();
const sl = new tinymce.dom.ScriptLoader();
sl.add('https://assets.cdn.clsrio.com/eqneditor.api.min.js');
var loaded = sl.loadQueue();
const loaded = sl.loadQueue();
// Load custom CSS
tinymce.DOM.loadCSS('https://assets.cdn.clsrio.com/eqneditor_1.css');
@@ -44,7 +44,7 @@ export const addMathPlugin = (tinymce: any) => {
);
function showDialog(inp = '') {
var http = 'https:' == document.location.protocol ? 'https://' : 'http://';
const http = 'https:' == document.location.protocol ? 'https://' : 'http://';
win = editor.windowManager.open({
title: 'Equation Editor',
@@ -124,8 +124,8 @@ export const addMathPlugin = (tinymce: any) => {
.addHistoryMenu(new EqEditor.History('history'));
EqEditor.Toolbar.link('toolbar').addTextArea(textarea);
var nodes = document.getElementById('history')?.childNodes || [];
for (var i = 0; i < nodes.length; i++) {
const nodes = document.getElementById('history')?.childNodes || [];
for (let i = 0; i < nodes.length; i++) {
nodes[i].style.padding = 'revert';
}
@@ -146,7 +146,7 @@ export const addMathPlugin = (tinymce: any) => {
editor.on('dblclick', function (e) {
if (e.target.nodeName.toLowerCase() == 'img') {
var sName = e.target.src.match(/(gif|svg)\.image\?(.*)/);
const sName = e.target.src.match(/(gif|svg)\.image\?(.*)/);
if (sName != null) showDialog(sName[2]);
}
});
@@ -59,8 +59,7 @@ export const config = {
]
};
export const { t, loading, locales, locale, initialized, translations, loadTranslations } =
new i18n(config);
export const { t, loading, locales, locale, initialized, translations, loadTranslations } = new i18n(config);
export const selectedLocale = writable<string>('en');
@@ -73,7 +72,7 @@ loading.subscribe(async ($loading) => {
}
});
export function handleLocaleChange(newLocale: string) {
export function handleLocaleChange(newLocale: LOCALE) {
if (!newLocale) {
return;
}
@@ -83,11 +82,7 @@ export function handleLocaleChange(newLocale: string) {
selectedLocale.set(newLocale);
}
export function lessonFallbackNote(
note: string,
translation: Record<LOCALE, string>,
locale: LOCALE
) {
export function lessonFallbackNote(note: string, translation: Record<LOCALE, string>, locale: LOCALE) {
if (!translation) {
return note;
}
@@ -1,28 +0,0 @@
import { validateEmail } from './validateEmail';
describe('validate email', () => {
test('should return true for a valid email format', () => {
const result = validateEmail('[email protected]');
expect(result).toBeTruthy();
});
test('should return false for an empty email', () => {
const result = validateEmail('');
expect(result).toBeFalsy();
});
test('should return true for a valid email with uppercase letters', () => {
const result = validateEmail('[email protected]');
expect(result).toBeTruthy();
});
test('should return false for an invalid email format', () => {
const result = validateEmail('test@example');
expect(result).toBeFalsy();
});
test('should return true for a valid email with special characters', () => {
const result = validateEmail('[email protected]');
expect(result).toBeTruthy();
});
});
@@ -2,141 +2,40 @@ import z from 'zod';
import { get } from 'svelte/store';
import isNumber from 'lodash/isNumber';
import { validateEmail } from './validateEmail';
import { t as _t, initialized } from '$lib/utils/functions/translations';
import { t, initialized } from '$lib/utils/functions/translations';
const t = {
get: (key: string) => {
const isInitialized = get(initialized);
if (!isInitialized) return key;
return _t.get(key);
}
};
const getOrgNameValidation = () =>
z
function getOrgNameValidation() {
return z
.string()
.min(5, { message: `${t.get('validations.organization_name.min_char')}` })
.refine((val) => !/^[-]|[-]$/.test(val), {
message: `${t.get('validations.organization_name.hyphen_rule')}`
});
}
const getSiteNameValidation = () =>
z
function getSiteNameValidation() {
return z
.string()
.min(5, { message: `${t.get('validations.site_name.min_char')}` })
.refine((val) => !/^[-]|[-]$/.test(val), {
message: `${t.get('validations.site_name.hyphen_rule')}`
});
const getNewsfeedValidation = () =>
z.string().min(5, { message: `${t.get('validations.news_feed.min_char')}` });
const lessonSchema = z.object({
title: z.string().nonempty({ message: `${t.get('validations.lesson_schema.empty_title')}` }),
lesson_at: z.string().optional(),
call_url: z.string().nullable().optional(),
is_unlocked: z.boolean().optional()
});
const createQuizValidationSchema = z.object({
title: z.string().min(6, {
message: `${t.get('validations.course_payment.full_name.min_char')}`
})
});
const askCommunityValidationSchema = z.object({
title: z.string().min(6, {
message: `${t.get('validations.ask_community.title.min_char')}`
}),
body: z.string().min(20, {
message: `${t.get('validations.ask_community.body.min_char')}`
}),
courseId: z.string().min(36, {
message: `${t.get('validations.ask_community.course_id.select_course')}`
})
});
const commentInCommunityValidationSchema = z.object({
comment: z.string().min(6, {
message: `${t.get('validations.comment_in_community.min_char')}`
})
});
const orgLandingpageValidationSchema = z.object({
name: z.string().min(6, {
message: `${t.get('validations.org_landing_page.name.min_char')}`
}),
email: z.string().email({
message: `${t.get('validations.org_landing_page.email.invalid_email')}`
}),
phone: z.string().min(6, {
message: `${t.get('validations.org_landing_page.phone.min_char')}`
}),
message: z.string().min(20, {
message: `${t.get('validations.org_landing_page.message.min_char')}`
})
});
const forgotValidationSchema = z.object({
email: z.string().email({
message: `${t.get('validations.forgot.invalid_email')}`
})
});
const authValidationSchema = z.object({
email: z.string().email({
message: 'validations.auth.email.invalid_email'
}),
password: z.string().min(6, {
message: 'validations.auth.password.min_char'
})
});
const resetValidationSchema = z.object({
password: z.string().min(6, {
message: `${t.get('validations.reset.password.min_char')}`
})
});
const onboardingValidationSchema = {
stepOne: z.object({
fullname: z
.string()
.min(5, { message: `${t.get('validations.onboarding.step_one.full_name.min_char')}` }),
orgName: getOrgNameValidation(),
siteName: getSiteNameValidation()
}),
stepTwo: z.object({
goal: z
.string({
required_error: `${t.get('validations.onboarding.step_two.goal.required')}`
})
.min(1),
source: z
.string({
required_error: `${t.get('validations.onboarding.step_two.source.required')}`
})
.min(1)
})
};
const saveCertificateSchema = z.object({
description: z.string().max(200, 'course.navItem.certificates.description_error'),
is_certificate_downloadable: z.boolean(),
certificate_theme: z.string()
});
}
function getNewsfeedValidation() {
return z.string().min(5, { message: `${t.get('validations.news_feed.min_char')}` });
}
export const saveCertificateValidation = (fields = {}) => {
const { error } = saveCertificateSchema.safeParse(fields);
const schema = z.object({
description: z.string().max(200, 'course.navItem.certificates.description_error'),
is_certificate_downloadable: z.boolean(),
certificate_theme: z.string()
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};
const updateProfileValidationSchema = z.object({
email: z.string().email({ message: 'validations.user_profile.email' }),
username: z.string().nonempty({ message: 'validations.user_profile.username' }),
fullname: z.string().min(5, { message: 'validations.user_profile.fullname' })
});
export const getConfirmPasswordError = ({ password, confirmPassword }) => {
return password > 6 && confirmPassword > 6 && password !== confirmPassword
? `${t.get('validations.confirm_password.not_match')}`
@@ -173,12 +72,30 @@ export const processErrors = (error, mapToId?: boolean) => {
};
export const authValidation = (fields = {}) => {
const { error } = authValidationSchema.safeParse(fields);
const schema = z.object({
email: z.string().email({
message: 'validations.auth.email.invalid_email'
}),
password: z.string().min(6, {
message: 'validations.auth.password.min_char'
})
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};
export const lessonValidation = (lesson = {}) => {
const { error } = lessonSchema.safeParse(lesson);
const schema = z.object({
title: z.string().nonempty({ message: `${t.get('validations.lesson_schema.empty_title')}` }),
lesson_at: z.string().optional(),
call_url: z.string().nullable().optional(),
is_unlocked: z.boolean().optional()
});
const { error } = schema.safeParse(lesson);
return processErrors(error);
};
@@ -197,24 +114,70 @@ export const coursePaymentValidation = (fields = {}) => {
};
export const resetValidation = (fields = {}) => {
const { error } = resetValidationSchema.safeParse(fields);
const schema = z.object({
password: z.string().min(6, {
message: `${t.get('validations.reset.password.min_char')}`
})
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};
export const forgotValidation = (fields = {}) => {
const { error } = forgotValidationSchema.safeParse(fields);
const schema = z.object({
email: z.string().email({
message: `${t.get('validations.forgot.invalid_email')}`
})
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};
export const orgLandingpageValidation = (fields = {}) => {
const { error } = orgLandingpageValidationSchema.safeParse(fields);
const schema = z.object({
name: z.string().min(6, {
message: `${t.get('validations.org_landing_page.name.min_char')}`
}),
email: z.string().email({
message: `${t.get('validations.org_landing_page.email.invalid_email')}`
}),
phone: z.string().min(6, {
message: `${t.get('validations.org_landing_page.phone.min_char')}`
}),
message: z.string().min(20, {
message: `${t.get('validations.org_landing_page.message.min_char')}`
})
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};
export const onboardingValidation = (fields = {}, step) => {
const onboardingValidationSchema = {
stepOne: z.object({
fullname: z
.string()
.min(5, { message: `${t.get('validations.onboarding.step_one.full_name.min_char')}` }),
orgName: getOrgNameValidation(),
siteName: getSiteNameValidation()
}),
stepTwo: z.object({
goal: z
.string({
required_error: `${t.get('validations.onboarding.step_two.goal.required')}`
})
.min(1),
source: z
.string({
required_error: `${t.get('validations.onboarding.step_two.source.required')}`
})
.min(1)
})
};
const schema =
step === 1 ? onboardingValidationSchema.stepOne : onboardingValidationSchema.stepTwo;
const { error } = schema.safeParse(fields);
@@ -223,7 +186,11 @@ export const onboardingValidation = (fields = {}, step) => {
};
export const updateProfileValidation = (fields = {}) => {
const schema = updateProfileValidationSchema;
const schema = z.object({
email: z.string().email({ message: 'validations.user_profile.email' }),
username: z.string().nonempty({ message: 'validations.user_profile.username' }),
fullname: z.string().min(5, { message: 'validations.user_profile.fullname' })
});
const { error } = schema.safeParse(fields);
return processErrors(error);
@@ -297,19 +264,42 @@ export const updateProfileEmailValidation = (email) => {
};
export const createQuizValidation = (fields = {}) => {
const { error } = createQuizValidationSchema.safeParse(fields);
const schema = z.object({
title: z.string().min(6, {
message: `${t.get('validations.course_payment.full_name.min_char')}`
})
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};
export const askCommunityValidation = (fields = {}) => {
const { error } = askCommunityValidationSchema.safeParse(fields);
const schema = z.object({
title: z.string().min(6, {
message: `${t.get('validations.ask_community.title.min_char')}`
}),
body: z.string().min(20, {
message: `${t.get('validations.ask_community.body.min_char')}`
}),
courseId: z.string().min(36, {
message: `${t.get('validations.ask_community.course_id.select_course')}`
})
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};
export const commentInCommunityValidation = (fields = {}) => {
const { error } = commentInCommunityValidationSchema.safeParse(fields);
const schema = z.object({
comment: z.string().min(6, {
message: `${t.get('validations.comment_in_community.min_char')}`
})
});
const { error } = schema.safeParse(fields);
return processErrors(error);
};