Skip to content

Commit c8595a4

Browse files
fix: enable quiz only upon all prerequisites completed (#532)
Co-authored-by: santosral <sralphian029@gmail.com>
1 parent da1bfa5 commit c8595a4

14 files changed

Lines changed: 39 additions & 91 deletions

File tree

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
"db:deploy": "prisma migrate deploy",
1414
"db:reset": "prisma migrate reset",
1515
"db:seed": "node --import=tsx prisma/seed.ts",
16-
"db:seed:quiz-journeys": "node --import=tsx prisma/seed-quiz-journeys.ts",
1716
"check": "svelte-kit sync && svelte-check --fail-on-warnings",
1817
"format": "prettier --check \"**/*.{svelte,js,ts,md,html,css,json,yaml}\"",
1918
"lint": "eslint \"**/*.{svelte,js,ts}\"",
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
Warnings:
3+
4+
- The values [QUIZ] on the enum `ContentType` will be removed. If these variants are still used in the database, this will fail.
5+
6+
*/
7+
-- AlterEnum
8+
BEGIN;
9+
CREATE TYPE "ContentType_new" AS ENUM ('PODCAST', 'VIDEO');
10+
ALTER TABLE "learning_unit_contents" ALTER COLUMN "type" TYPE "ContentType_new" USING ("type"::text::"ContentType_new");
11+
ALTER TYPE "ContentType" RENAME TO "ContentType_old";
12+
ALTER TYPE "ContentType_new" RENAME TO "ContentType";
13+
DROP TYPE "public"."ContentType_old";
14+
COMMIT;

prisma/schema.prisma

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ model LearningUnitSources {
155155

156156
enum ContentType {
157157
PODCAST
158-
QUIZ
159158
VIDEO
160159
}
161160

prisma/seed.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,6 @@ const learningUnits: Prisma.LearningUnitCreateInput[] = [
353353
},
354354
],
355355
},
356-
questionAnswers: {
357-
create: questionAnswers,
358-
},
359356
contents: {
360357
create: [{ type: ContentType.PODCAST, url: 'http://localhost:5173' }],
361358
},
@@ -436,9 +433,6 @@ const learningUnits: Prisma.LearningUnitCreateInput[] = [
436433
questionAnswers: {
437434
create: questionAnswers,
438435
},
439-
contents: {
440-
create: [{ type: ContentType.QUIZ }],
441-
},
442436
},
443437
{
444438
id: uuidv7(),
@@ -479,14 +473,14 @@ const learningUnits: Prisma.LearningUnitCreateInput[] = [
479473
},
480474
contents: {
481475
create: [
482-
{ type: ContentType.VIDEO, url: 'https://vimeo.com/1172996293' },
476+
{ type: ContentType.VIDEO, url: 'http://localhost:5173' },
483477
{ type: ContentType.PODCAST, url: 'http://localhost:5173' },
484478
],
485479
},
486480
},
487481
{
488482
id: uuidv7(),
489-
title: 'AI Podcast/Video/Quiz Unit',
483+
title: 'AI Podcast/Video Unit',
490484
status: LearningUnitStatus.PUBLISHED,
491485
summary,
492486
objectives,
@@ -521,14 +515,10 @@ const learningUnits: Prisma.LearningUnitCreateInput[] = [
521515
},
522516
],
523517
},
524-
questionAnswers: {
525-
create: questionAnswers,
526-
},
527518
contents: {
528519
create: [
529520
{ type: ContentType.VIDEO, url: 'http://localhost:5173' },
530521
{ type: ContentType.PODCAST, url: 'http://localhost:5173' },
531-
{ type: ContentType.QUIZ },
532522
],
533523
},
534524
},
@@ -773,7 +763,7 @@ const learningUnits: Prisma.LearningUnitCreateInput[] = [
773763
},
774764
contents: {
775765
create: [
776-
{ type: ContentType.VIDEO, url: 'https://vimeo.com/1172996293' },
766+
{ type: ContentType.VIDEO, url: 'http://localhost:5173' },
777767
{ type: ContentType.PODCAST, url: 'http://localhost:5173' },
778768
],
779769
},

src/lib/components/LearningUnitForm/LearningUnitForm.svelte

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script module lang="ts">
22
export interface UnitState {
33
title: string;
4-
contents: { type: 'VIDEO' | 'PODCAST' | 'QUIZ'; url: string | undefined }[];
4+
contents: { type: 'VIDEO' | 'PODCAST'; url: string | undefined }[];
55
collectionId: string;
66
summary: string;
77
objectives: string;
@@ -114,37 +114,17 @@
114114

115115
{#each unit.contents as item, i (i)}
116116
<div class="flex items-start gap-2">
117-
<Select
118-
id="contents-{i}-type"
119-
bind:value={item.type}
120-
onchange={() => {
121-
if (item.type === 'QUIZ') {
122-
unit = {
123-
...unit,
124-
contents: unit.contents.map((c, j) => (j === i ? { ...c, url: undefined } : c)),
125-
};
126-
} else {
127-
unit = {
128-
...unit,
129-
contents: unit.contents.map((c, j) =>
130-
j === i ? { ...c, url: c.url ?? '' } : c,
131-
),
132-
};
133-
}
134-
}}
135-
>
117+
<Select id="contents-{i}-type" bind:value={item.type}>
136118
{#each data.contentTypes as ct (ct)}
137119
<option value={ct}>{ct.toLowerCase()}</option>
138120
{/each}
139121
</Select>
140-
{#if item.type !== 'QUIZ'}
141-
<TextInput
142-
id="contents-{i}-url"
143-
type="url"
144-
bind:value={item.url}
145-
placeholder={item.type === 'VIDEO' ? 'https://...' : 'Podcast URL'}
146-
/>
147-
{/if}
122+
<TextInput
123+
id="contents-{i}-url"
124+
type="url"
125+
bind:value={item.url}
126+
placeholder={item.type === 'VIDEO' ? 'https://...' : 'Podcast URL'}
127+
/>
148128
<Button type="button" variant="secondary" onclick={() => removeContentItem(i)}>
149129
Remove
150130
</Button>

src/lib/components/LearningUnitForm/LearningUnitForm.test.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const BASE_DATA = {
2323
collections: [],
2424
contentTags: [],
2525
sourceTags: [],
26-
contentTypes: ['PODCAST', 'QUIZ', 'VIDEO'],
26+
contentTypes: ['PODCAST', 'VIDEO'],
2727
};
2828

2929
describe('LearningUnitForm - content items', () => {
@@ -74,18 +74,6 @@ describe('LearningUnitForm - content items', () => {
7474
expect(screen.getByPlaceholderText('https://...')).toBeInTheDocument();
7575
});
7676

77-
test('does not show URL input for QUIZ type', () => {
78-
render(LearningUnitForm, {
79-
props: {
80-
unit: { ...BASE_UNIT, contents: [{ type: 'QUIZ', url: undefined }] },
81-
data: BASE_DATA,
82-
form: null,
83-
onsubmit: vi.fn(),
84-
},
85-
});
86-
expect(screen.queryByPlaceholderText(/url/i)).not.toBeInTheDocument();
87-
});
88-
8977
test('removes a content item when Remove is clicked', async () => {
9078
const user = userEvent.setup();
9179
render(LearningUnitForm, {

src/lib/server/unit/validation.test.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,6 @@ describe('validateLearningUnitDraft - contents', () => {
5151
expect(validateLearningUnitDraft(fd).success).toBe(true);
5252
});
5353

54-
test('accepts QUIZ item without URL', () => {
55-
const fd = makeFormData({
56-
...BASE_DRAFT,
57-
contents: JSON.stringify([{ type: 'QUIZ', url: null }]),
58-
});
59-
const result = validateLearningUnitDraft(fd);
60-
expect(result.success).toBe(true);
61-
if (result.success) {
62-
expect(result.data.contents[0].url).toBeNull();
63-
}
64-
});
65-
6654
test('accepts empty contents in draft', () => {
6755
const fd = makeFormData({ ...BASE_DRAFT, contents: JSON.stringify([]) });
6856
expect(validateLearningUnitDraft(fd).success).toBe(true);
@@ -116,7 +104,7 @@ describe('validateLearningUnit - contents', () => {
116104
...BASE_PUBLISH,
117105
contents: JSON.stringify([
118106
{ type: 'VIDEO', url: 'https://example.com/video/123' },
119-
{ type: 'QUIZ', url: null },
107+
{ type: 'PODCAST', url: 'https://example.com/audio.mp3' },
120108
]),
121109
});
122110
expect(validateLearningUnit(fd).success).toBe(true);

src/lib/server/unit/validation.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ function parseContentItems(
5959

6060
if (!(Object.values(ContentType) as string[]).includes(item.type)) {
6161
err.type = ERROR_MESSAGES.INVALID_OPTION;
62-
} else if (item.type === ContentType.VIDEO || item.type === ContentType.PODCAST) {
62+
} else {
6363
if (!item.url || typeof item.url !== 'string' || item.url.trim().length === 0) {
6464
err.url = ERROR_MESSAGES.FIELD_REQUIRED;
6565
} else {
@@ -70,9 +70,6 @@ function parseContentItems(
7070
err.url = ERROR_MESSAGES.INVALID_DATA('URL');
7171
}
7272
}
73-
} else {
74-
// QUIZ: discard any URL
75-
item.url = null;
7673
}
7774

7875
if (Object.keys(err).length > 0) itemErrors[i] = err;

src/routes/(main)/(protected)/(core)/home/+page.server.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,6 @@ export const load: PageServerLoad = async (event) => {
185185
},
186186
where: {
187187
userId: user.id,
188-
learningUnit: {
189-
contents: {
190-
some: {
191-
type: { not: 'QUIZ' },
192-
},
193-
},
194-
},
195188
},
196189
orderBy: {
197190
createdAt: 'desc',

src/routes/(main)/(protected)/unit/[id]/+page.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const load: PageServerLoad = async (event) => {
208208
);
209209

210210
let aiLiteracyCompleted: boolean | null = null;
211-
if (inAILiteracyCollection && learningUnit.contents.some((item) => item.type === 'QUIZ')) {
211+
if (inAILiteracyCollection && isQuizAvailable) {
212212
const learningUnitCollectionArg = {
213213
where: {
214214
collectionId: learningUnit.collections.find(

0 commit comments

Comments
 (0)