diff --git a/src/app/actions/experiment.ts b/src/app/actions/experiment.ts index 89b5edc..c5acdcc 100644 --- a/src/app/actions/experiment.ts +++ b/src/app/actions/experiment.ts @@ -2,6 +2,8 @@ import db from '@/lib/db'; import { experiment } from '@/lib/model/experiment'; +import { annotation } from '@/lib/model/annotation'; +import { participant } from '@/lib/model/participant'; import { and, eq } from 'drizzle-orm'; import { revalidatePath } from 'next/cache'; import { auth, requireAdmin } from '@/lib/auth'; @@ -144,3 +146,24 @@ export async function getExperimentById(id: number) { throw new Error('Failed to fetch experiment'); } } + +export async function clearExperimentData(id: number) { + const result = await requireAdmin(); + if (!result.authenticated || !result.admin) { + throw new Error('Unauthorized'); + } + + try { + // Delete all annotations for this experiment + await db.delete(annotation).where(eq(annotation.experimentId, id)); + + // Delete all participants for this experiment + await db.delete(participant).where(eq(participant.experimentId, id)); + + revalidatePath(`/admin/experiments/${id}`); + return { success: true }; + } catch (error) { + console.error('Error clearing experiment data:', error); + throw new Error('Failed to clear experiment data'); + } +} diff --git a/src/app/admin/experiments/[id]/page.tsx b/src/app/admin/experiments/[id]/page.tsx index a664425..b4f5941 100644 --- a/src/app/admin/experiments/[id]/page.tsx +++ b/src/app/admin/experiments/[id]/page.tsx @@ -4,6 +4,7 @@ import { experiment } from '@/lib/model/experiment'; import { eq } from 'drizzle-orm'; import EditableExperimentHeader from '@/components/EditableExperimentHeader'; import DeleteExperimentButton from '@/components/DeleteExperimentButton'; +import ClearExperimentDataButton from '@/components/ClearExperimentDataButton'; import UploadCalibrationModal from '@/components/UploadCalibrationModal'; import CalibrationListModal from '@/components/CalibrationListModal'; import { requireAdmin } from '@/lib/auth'; @@ -68,6 +69,7 @@ export default async function ExperimentPage({ params }: ExperimentPageProps) {
+
diff --git a/src/components/ClearExperimentDataButton.tsx b/src/components/ClearExperimentDataButton.tsx new file mode 100644 index 0000000..4650553 --- /dev/null +++ b/src/components/ClearExperimentDataButton.tsx @@ -0,0 +1,89 @@ +'use client'; + +import { useState } from 'react'; +import { clearExperimentData } from '@/app/actions/experiment'; + +interface ClearExperimentDataButtonProps { + experimentId: number; + experimentName: string; +} + +export default function ClearExperimentDataButton({ experimentId, experimentName }: ClearExperimentDataButtonProps) { + const [isConfirming, setIsConfirming] = useState(false); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(false); + + async function handleConfirm() { + setLoading(true); + setError(null); + setSuccess(false); + + try { + await clearExperimentData(experimentId); + setIsConfirming(false); + setSuccess(true); + // Clear success message after 3 seconds + setTimeout(() => setSuccess(false), 3000); + } catch (err) { + const message = err instanceof Error ? err.message : 'Failed to clear experiment data'; + setError(message); + } finally { + setLoading(false); + } + } + + if (isConfirming) { + return ( +
+
+

+ Clear all data for "{experimentName}"? +

+

+ This will permanently delete all annotations and participant data for this experiment. This action cannot be undone. +

+ + {error && ( +
+ {error} +
+ )} + +
+ + +
+
+
+ ); + } + + return ( + <> + + {success && ( +
+ Data cleared successfully +
+ )} + + ); +}