diff --git a/src/db/answers.ts b/src/db/answers.ts new file mode 100644 index 0000000..2e8b12e --- /dev/null +++ b/src/db/answers.ts @@ -0,0 +1,7 @@ +import { eq } from "drizzle-orm"; +import { db } from "."; +import { surveyAnswersTable } from "./schema"; + +export async function deleteAnswers(participandId: number) { + await db.delete(surveyAnswersTable).where(eq(surveyAnswersTable.participantId, participandId)); +} \ No newline at end of file diff --git a/src/lib/components/WarningDialog.svelte b/src/lib/components/WarningDialog.svelte new file mode 100644 index 0000000..fe7ba1c --- /dev/null +++ b/src/lib/components/WarningDialog.svelte @@ -0,0 +1,33 @@ + + + +

{title}

+
+ {@render children?.()} +
+ {#if buttons} + {@render buttons()} + {:else} +
+ + +
+ {/if} +
diff --git a/src/lib/components/icons/DeleteIcon.svelte b/src/lib/components/icons/DeleteIcon.svelte new file mode 100644 index 0000000..d32b1eb --- /dev/null +++ b/src/lib/components/icons/DeleteIcon.svelte @@ -0,0 +1,14 @@ + + + diff --git a/src/lib/components/icons/LinkIcon.svelte b/src/lib/components/icons/LinkIcon.svelte index ed73c49..e1be358 100644 --- a/src/lib/components/icons/LinkIcon.svelte +++ b/src/lib/components/icons/LinkIcon.svelte @@ -1,4 +1,4 @@ - + + + diff --git a/src/routes/(app)/survey/[surveyId]/+page.server.ts b/src/routes/(app)/survey/[surveyId]/+page.server.ts index fe619d3..4a419df 100644 --- a/src/routes/(app)/survey/[surveyId]/+page.server.ts +++ b/src/routes/(app)/survey/[surveyId]/+page.server.ts @@ -1,12 +1,13 @@ -import { error } from '@sveltejs/kit'; -import type { PageServerLoad } from './$types'; +import { error, redirect } from '@sveltejs/kit'; +import type { PageServerLoad, RouteParams } from './$types'; import { loadSurvey } from '$lib/queries'; import debug from 'debug'; +import { deleteAnswers } from '../../../../db/answers'; const log = debug('survey:admin'); -export const load: PageServerLoad = async ({ params, locals }) => { +async function loadSurveyData(params: RouteParams, locals: App.Locals) { const surveyId = parseInt(params.surveyId); if (isNaN(surveyId)) { @@ -24,4 +25,26 @@ export const load: PageServerLoad = async ({ params, locals }) => { error(404, 'Survey not found'); } return surveyData; +} + +export const load: PageServerLoad = async ({ params, locals }) => { + return await loadSurveyData(params, locals); +} + +export const actions = { + deleteAnswers: async ({ params, locals, request }) => { + const survey = await loadSurveyData(params, locals); + + let formData = await request.formData(); + const participantId = parseInt(formData.get('participantId')?.toString() ?? ''); + + if (isNaN(participantId)) { + log('Invalid participant ID when trying to delete answers: %s', formData.get('participandId')?.toString()); + error(400, 'Invalid participant ID'); + } + + await deleteAnswers(participantId); + + redirect(303, survey.id.toString()); + } } \ No newline at end of file diff --git a/src/routes/(app)/survey/[surveyId]/+page.svelte b/src/routes/(app)/survey/[surveyId]/+page.svelte index 52f43d4..c2863e9 100644 --- a/src/routes/(app)/survey/[surveyId]/+page.svelte +++ b/src/routes/(app)/survey/[surveyId]/+page.svelte @@ -11,6 +11,9 @@ import { goto } from '$app/navigation'; import { success } from '$lib/toast'; import MarkdownBlock from '$lib/components/MarkdownBlock.svelte'; + import MenuIcon from '$lib/components/icons/MenuIcon.svelte'; + import DeleteIcon from '$lib/components/icons/DeleteIcon.svelte'; + import WarningDialog from '$lib/components/WarningDialog.svelte'; let { data }: { data: PageData } = $props(); @@ -26,7 +29,10 @@ navigator.clipboard.writeText(link); } - let dialogRef: HTMLDialogElement | null = null; + let deleteSurveyDialogRef: HTMLDialogElement | null = $state(null); + let deleteAnswersDialogRef: HTMLDialogElement | null = $state(null); + + let participantAnswersDeletionCandidateId = $state(null); async function deleteSurvey() { await fetch('', { @@ -50,7 +56,7 @@ + {#if participant.answers.length > 0} + + {/if} {/each} @@ -92,20 +111,27 @@ - -

Delete survey

-

- Are you sure you want to delete the survey. This action cannot be undone. -

-
- - -
- + +

Are you sure you want to delete the survey.

+

This action cannot be undone.

+
+ + {}} bind:dialogRef={deleteAnswersDialogRef}> +
+ +

+ Are you sure you want to remove this user's ratings? This will delete whatever answers the + user has given and allow them to submit new ratings instead. +

+

This action cannot be undone.

+
+ {#snippet buttons()} +
+ + +
+ {/snippet} +
diff --git a/src/routes/[accessToken]/+page.server.ts b/src/routes/[accessToken]/+page.server.ts index 3c9de58..42a1db8 100644 --- a/src/routes/[accessToken]/+page.server.ts +++ b/src/routes/[accessToken]/+page.server.ts @@ -24,7 +24,7 @@ export const load: PageServerLoad = async ({ params, url }) => { if (await db.$count(surveyAnswersTable, eq(surveyAnswersTable.participantId, results[0].survey_access_table.id)) > 0) { log_load('Answers already submitted: %s', params.accessToken); - error(400, 'Answers already submitted'); + error(400, 'You have already submitted your answers. If you feel that this is wrong, please contact the survey creator to reset your answers.'); } const survey = results[0].surveys_table; @@ -57,7 +57,7 @@ export const actions = { if (await db.$count(surveyAnswersTable, eq(surveyAnswersTable.participantId, results[0].survey_access_table.id)) > 0) { log_store('Answers already submitted: %s', params.accessToken); - error(400, 'Answers already submitted'); + error(400, 'You have already submitted your answers. If you feel that this is wrong, please contact the survey creator to reset your answers.'); } const survey = results[0].surveys_table;