fix: show validation message in community ask page (#553)

* fix: show validation message in community ask page

* fix course app build issues
This commit is contained in:
Rotimi Best
2025-05-16 12:08:42 +01:00
committed by GitHub
parent 8d4a7b9ccf
commit 512fe06722
6 changed files with 71 additions and 69 deletions
+3 -1
View File
@@ -5,7 +5,9 @@ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
const config = { const config = {
// Consult https://svelte.dev/docs/kit/integrations // Consult https://svelte.dev/docs/kit/integrations
// for more information about preprocessors // for more information about preprocessors
preprocess: vitePreprocess(), preprocess: vitePreprocess({
script: true
}),
kit: { kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
@@ -8,11 +8,6 @@
export let onDelete = () => {}; export let onDelete = () => {};
export let onCancel = () => {}; export let onCancel = () => {};
async function handleDelete() {
onDelete();
$deleteConfirmation.open = false;
}
</script> </script>
<Modal <Modal
@@ -22,9 +17,9 @@
modalHeading={$t('course.navItem.lessons.exercises.all_exercises.delete_confirmation.title')} modalHeading={$t('course.navItem.lessons.exercises.all_exercises.delete_confirmation.title')}
> >
<div> <div>
<h1 class="dark:text-white text-lg"> <p class="mt-0 text-base dark:text-white">
{$t('course.navItem.lessons.exercises.all_exercises.delete_confirmation.sure')} {$t('course.navItem.lessons.exercises.all_exercises.delete_confirmation.sure')}
</h1> </p>
<div class="mt-5 flex items-center justify-between"> <div class="mt-5 flex items-center justify-between">
<PrimaryButton <PrimaryButton
@@ -24,9 +24,9 @@
modalHeading={$t('course.navItem.people.delete_confirmation.title')} modalHeading={$t('course.navItem.people.delete_confirmation.title')}
> >
<div> <div>
<h1 class="mt-0 text-lg dark:text-white"> <p class="mt-0 text-base dark:text-white">
{$t('course.navItem.people.delete_confirmation.sure')} <strong>{email}</strong>? {$t('course.navItem.people.delete_confirmation.sure')} <strong>{email}</strong>?
</h1> </p>
<div class="mt-5 flex items-center justify-between"> <div class="mt-5 flex items-center justify-between">
<PrimaryButton <PrimaryButton
@@ -1,7 +1,7 @@
<script> <script>
import Modal from '$lib/components/Modal/index.svelte'; import Modal from '$lib/components/Modal/index.svelte';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants'; import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { t } from '$lib/utils/functions/translations'; import { t } from '$lib/utils/functions/translations';
export let onDelete = () => {}; export let onDelete = () => {};
@@ -20,10 +20,10 @@
: $t('community.delete.comment')}" : $t('community.delete.comment')}"
> >
<div> <div>
<h1 class="dark:text-white text-lg"> <p class="mt-0 text-base dark:text-white">
{$t('community.delete.sure')} {$t('community.delete.sure')}
{isQuestion ? $t('community.delete.question') : $t('community.delete.comment')}? {isQuestion ? $t('community.delete.question') : $t('community.delete.comment')}?
</h1> </p>
<div class="mt-5 flex items-center justify-between"> <div class="mt-5 flex items-center justify-between">
<PrimaryButton <PrimaryButton
@@ -1,32 +1,32 @@
<script lang="ts"> <script lang="ts">
import { browser } from '$app/environment';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import pluralize from 'pluralize';
import TrashCanIcon from 'carbon-icons-svelte/lib/TrashCan.svelte';
import { Dropdown, SkeletonPlaceholder, SkeletonText } from 'carbon-components-svelte';
import ArrowLeftIcon from 'carbon-icons-svelte/lib/ArrowLeft.svelte';
import Vote from '$lib/components/Vote/index.svelte';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import Avatar from '$lib/components/Avatar/index.svelte'; import Avatar from '$lib/components/Avatar/index.svelte';
import { courses } from '$lib/components/Courses/store';
import TextField from '$lib/components/Form/TextField.svelte';
import IconButton from '$lib/components/IconButton/index.svelte'; import IconButton from '$lib/components/IconButton/index.svelte';
import CheckmarkOutlineIcon from 'carbon-icons-svelte/lib/CheckmarkOutline.svelte'; import DeleteModal from '$lib/components/Org/Community/DeleteModal.svelte';
import { currentOrgPath, isOrgAdmin, currentOrg } from '$lib/utils/store/org'; import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import { profile } from '$lib/utils/store/user'; import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { snackbar } from '$lib/components/Snackbar/store';
import TextEditor from '$lib/components/TextEditor/index.svelte';
import Vote from '$lib/components/Vote/index.svelte';
import { calDateDiff } from '$lib/utils/functions/date';
import { supabase } from '$lib/utils/functions/supabase'; import { supabase } from '$lib/utils/functions/supabase';
import { t } from '$lib/utils/functions/translations';
import { import {
askCommunityValidation, askCommunityValidation,
commentInCommunityValidation commentInCommunityValidation
} from '$lib/utils/functions/validator'; } from '$lib/utils/functions/validator';
import { snackbar } from '$lib/components/Snackbar/store';
import TextField from '$lib/components/Form/TextField.svelte';
import DeleteModal from '$lib/components/Org/Community/DeleteModal.svelte';
import TextEditor from '$lib/components/TextEditor/index.svelte';
import { calDateDiff } from '$lib/utils/functions/date';
import { browser } from '$app/environment';
import { fetchCourses } from '$lib/utils/services/courses'; import { fetchCourses } from '$lib/utils/services/courses';
import { t } from '$lib/utils/functions/translations'; import { currentOrg, currentOrgPath, isOrgAdmin } from '$lib/utils/store/org';
import { courses } from '$lib/components/Courses/store'; import { profile } from '$lib/utils/store/user';
import type { Course } from '$lib/utils/types'; import type { Course } from '$lib/utils/types';
import { Dropdown, SkeletonPlaceholder, SkeletonText } from 'carbon-components-svelte';
import ArrowLeftIcon from 'carbon-icons-svelte/lib/ArrowLeft.svelte';
import CheckmarkOutlineIcon from 'carbon-icons-svelte/lib/CheckmarkOutline.svelte';
import TrashCanIcon from 'carbon-icons-svelte/lib/TrashCan.svelte';
import pluralize from 'pluralize';
export let data; export let data;
const { slug } = data; const { slug } = data;
@@ -382,23 +382,23 @@
}} }}
onDelete={() => handleDelete(false)} onDelete={() => handleDelete(false)}
/> />
<section class="max-w-3xl mx-auto md:mx-10 lg:mb-20"> <section class="mx-auto max-w-3xl md:mx-10 lg:mb-20">
{#if !question} {#if !question}
<div class="py-10 px-5 mb-3"> <div class="mb-3 px-5 py-10">
<SkeletonText style="width: 25%;" /> <SkeletonText style="width: 25%;" />
<SkeletonText style="width: 100%; margin-bottom: 2rem" /> <SkeletonText style="width: 100%; margin-bottom: 2rem" />
<SkeletonPlaceholder style="width: 100%; height: 20rem;" /> <SkeletonPlaceholder style="width: 100%; height: 20rem;" />
</div> </div>
{:else} {:else}
<div class="py-10 px-5"> <div class="px-5 py-10">
<a <a
class="text-gray-500 dark:text-white text-md flex items-center" class="text-md flex items-center text-gray-500 dark:text-white"
href={`${$currentOrgPath}/community`} href={`${$currentOrgPath}/community`}
> >
<ArrowLeftIcon size={24} class="carbon-icon dark:text-white" /> <ArrowLeftIcon size={24} class="carbon-icon dark:text-white" />
{$t('community.ask.go_back')} {$t('community.ask.go_back')}
</a> </a>
<div class="my-5 flex justify-between items-center"> <div class="my-5 flex items-center justify-between">
{#if isEditMode} {#if isEditMode}
<TextField <TextField
bind:value={editContent.title} bind:value={editContent.title}
@@ -406,7 +406,7 @@
errorMessage={errors.title} errorMessage={errors.title}
/> />
<Dropdown <Dropdown
class="w-[25%] h-full" class="h-full w-[25%]"
size="xl" size="xl"
label={$t('community.ask.select_course')} label={$t('community.ask.select_course')}
items={fetchedCourses.map((course) => ({ id: course.id, text: course.title }))} items={fetchedCourses.map((course) => ({ id: course.id, text: course.title }))}
@@ -441,17 +441,17 @@
{/if} {/if}
{/if} {/if}
</div> </div>
<div class="my-1 px-1 rounded-lg border border-1 border-gray"> <div class="border-1 border-gray my-1 rounded-lg border px-1">
<header class="flex items-center justify-between leading-none p-2"> <header class="flex items-center justify-between p-2 leading-none">
<div class="flex items-center no-underline hover:underline text-black"> <div class="flex items-center text-black no-underline hover:underline">
<Avatar <Avatar
src={question.author.avatar} src={question.author.avatar}
name={question.author.name} name={question.author.name}
width="w-7" width="w-7"
height="h-7" height="h-7"
/> />
<p class="dark:text-white ml-2 text-sm">{question.author.name}</p> <p class="ml-2 text-sm dark:text-white">{question.author.name}</p>
<p class="dark:text-white ml-2 text-sm text-gray-500"> <p class="ml-2 text-sm text-gray-500 dark:text-white">
{question.createdAt} {question.createdAt}
</p> </p>
</div> </div>
@@ -487,18 +487,18 @@
</div> </div>
{#each question.comments as comment} {#each question.comments as comment}
<div class="my-5 px-1 flex items-start"> <div class="my-5 flex items-start px-1">
<Vote <Vote
value={comment.votes} value={comment.votes}
upVote={() => upvoteQuestion('comment', comment.id)} upVote={() => upvoteQuestion('comment', comment.id)}
disabled={voted.comment[comment.id]} disabled={voted.comment[comment.id]}
/> />
<div class="w-full rounded-lg border border-1 border-gray"> <div class="border-1 border-gray w-full rounded-lg border">
<header class="flex items-center justify-between leading-none p-2"> <header class="flex items-center justify-between p-2 leading-none">
<div class="flex items-center text-black"> <div class="flex items-center text-black">
<Avatar src={comment.avatar} name={comment.name} width="w-7" height="h-7" /> <Avatar src={comment.avatar} name={comment.name} width="w-7" height="h-7" />
<p class="dark:text-white ml-2 text-sm">{comment.name}</p> <p class="ml-2 text-sm dark:text-white">{comment.name}</p>
<p class="dark:text-white ml-2 text-sm text-gray-500"> <p class="ml-2 text-sm text-gray-500 dark:text-white">
{comment.createdAt} {comment.createdAt}
</p> </p>
</div> </div>
@@ -528,7 +528,7 @@
<hr /> <hr />
<div> <div class="mt-4">
{#if !editorInstance} {#if !editorInstance}
<TextEditor <TextEditor
bind:value={comment} bind:value={comment}
@@ -537,7 +537,7 @@
/> />
{/if} {/if}
<div class="flex justify-end mr-2"> <div class="mt-2 flex justify-end">
<PrimaryButton label={$t('community.ask.comment')} onClick={submitComment} /> <PrimaryButton label={$t('community.ask.comment')} onClick={submitComment} />
</div> </div>
</div> </div>
@@ -1,25 +1,26 @@
<script lang="ts"> <script lang="ts">
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { courses } from '$lib/components/Courses/store';
import TextField from '$lib/components/Form/TextField.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { snackbar } from '$lib/components/Snackbar/store';
import TextEditor from '$lib/components/TextEditor/index.svelte';
import generateSlug from '$lib/utils/functions/generateSlug';
import { supabase } from '$lib/utils/functions/supabase';
import { t } from '$lib/utils/functions/translations';
import { askCommunityValidation } from '$lib/utils/functions/validator';
import { fetchCourses } from '$lib/utils/services/courses';
import { currentOrg, currentOrgPath } from '$lib/utils/store/org';
import { profile } from '$lib/utils/store/user';
import type { Course } from '$lib/utils/types';
import { Dropdown } from 'carbon-components-svelte'; import { Dropdown } from 'carbon-components-svelte';
import ArrowLeftIcon from 'carbon-icons-svelte/lib/ArrowLeft.svelte'; import ArrowLeftIcon from 'carbon-icons-svelte/lib/ArrowLeft.svelte';
import { currentOrgPath, currentOrg } from '$lib/utils/store/org';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import { askCommunityValidation } from '$lib/utils/functions/validator';
import { supabase } from '$lib/utils/functions/supabase';
import { snackbar } from '$lib/components/Snackbar/store';
import generateSlug from '$lib/utils/functions/generateSlug';
import TextEditor from '$lib/components/TextEditor/index.svelte';
import TextField from '$lib/components/Form/TextField.svelte';
import { profile } from '$lib/utils/store/user';
import { fetchCourses } from '$lib/utils/services/courses';
import { t } from '$lib/utils/functions/translations';
import { courses } from '$lib/components/Courses/store';
import type { Course } from '$lib/utils/types';
let errors: { let errors: {
title?: string; title?: string;
courseId?: string; courseId?: string;
body?: string;
} = {}; } = {};
let fields = { let fields = {
title: '', title: '',
@@ -85,17 +86,17 @@
<title>Ask the Community - ClassroomIO</title> <title>Ask the Community - ClassroomIO</title>
</svelte:head> </svelte:head>
<section class="w-full md:max-w-3xl md:mx-auto"> <section class="w-full md:mx-auto md:max-w-3xl">
<div class="p-5"> <div class="p-5">
<a <a
class="text-gray-500 dark:text-white text-md flex items-center" class="text-md flex items-center text-gray-500 dark:text-white"
href={`${$currentOrgPath}/community`} href={`${$currentOrgPath}/community`}
> >
<ArrowLeftIcon size={24} class="carbon-icon dark:text-white" /> <ArrowLeftIcon size={24} class="carbon-icon dark:text-white" />
{$t('community.ask.go_back')} {$t('community.ask.go_back')}
</a> </a>
<div class="flex items-center gap-12 justify-between"> <div class="flex items-center justify-between gap-12">
<h1 class="dark:text-white text-2xl md:text-3xl font-bold">{$t('community.ask.ask_the')}</h1> <h1 class="text-2xl font-bold dark:text-white md:text-3xl">{$t('community.ask.ask_the')}</h1>
<PrimaryButton <PrimaryButton
label={$t('community.ask.publish')} label={$t('community.ask.publish')}
variant={VARIANTS.CONTAINED_DARK} variant={VARIANTS.CONTAINED_DARK}
@@ -104,7 +105,7 @@
</div> </div>
</div> </div>
<div class="mb-3 p-2 flex gap-x-5 justify-between"> <div class="mb-3 flex justify-between gap-x-5 p-2">
<TextField <TextField
bind:value={fields.title} bind:value={fields.title}
placeholder={$t('community.ask.title')} placeholder={$t('community.ask.title')}
@@ -112,7 +113,7 @@
className="w-[75%]" className="w-[75%]"
/> />
<Dropdown <Dropdown
class="w-[25%] h-full" class="h-full w-[25%]"
size="xl" size="xl"
label={$t('community.ask.select_course')} label={$t('community.ask.select_course')}
invalid={!!errors.courseId} invalid={!!errors.courseId}
@@ -127,5 +128,9 @@
placeholder={$t('community.ask.ask_community')} placeholder={$t('community.ask.ask_community')}
onChange={(html) => (fields.body = html)} onChange={(html) => (fields.body = html)}
/> />
{#if errors.body}
<p class="mt-2 text-sm text-red-500">{errors.body}</p>
{/if}
</div> </div>
</section> </section>