From cb39b22aaccecacf91e1fffdc6b5f8e58795517b Mon Sep 17 00:00:00 2001 From: smaubio <118258478+smaubio@users.noreply.github.com> Date: Fri, 10 Apr 2026 10:00:45 +0200 Subject: [PATCH] feat: add AnnotationInfoView and AnnotationPhase intro screen before annotation starts --- src/app/annotate/[experimentId]/page.tsx | 20 +-- .../AnnotationViews/AnnotationInfoView.tsx | 119 ++++++++++++++++++ .../AnnotationViews/AnnotationPhase.tsx | 33 +++++ .../CalibrationViews/CalibrationInfoView.tsx | 2 +- .../OnboardingViews/OnboardingInfoView.tsx | 2 +- 5 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 src/components/AnnotationViews/AnnotationInfoView.tsx create mode 100644 src/components/AnnotationViews/AnnotationPhase.tsx diff --git a/src/app/annotate/[experimentId]/page.tsx b/src/app/annotate/[experimentId]/page.tsx index 3e032c7..05da7db 100644 --- a/src/app/annotate/[experimentId]/page.tsx +++ b/src/app/annotate/[experimentId]/page.tsx @@ -2,11 +2,11 @@ import { redirect, notFound } from 'next/navigation'; import { headers } from 'next/headers'; import Link from 'next/link'; import { auth } from '@/lib/auth'; -import { getAnnotationEntries} from '@/app/actions/annotations'; +import { getAnnotationEntries, getAnnotationProgress } from '@/app/actions/annotations'; import { isCalibrationDone } from '@/app/actions/calibration-scoring'; import { isOnboardingDone } from '@/app/actions/onboarding'; import { getExperimentById } from '@/app/actions/experiment'; -import AnnotationPageView from '@/components/AnnotationViews/AnnotationPageView'; +import AnnotationPhase from '@/components/AnnotationViews/AnnotationPhase'; import OnboardingPhase from '@/components/OnboardingViews/OnboardingPhase'; import CalibrationPhase from '@/components/CalibrationViews/CalibrationPhase'; @@ -44,8 +44,11 @@ export default async function AnnotatePage({ params }: Props) { return ; } - const prototype = await getExperimentById(experimentId).then(exp => exp?.annotationTool || null); - const entries = await getAnnotationEntries(experimentId); + const [prototype, entries, { done }] = await Promise.all([ + getExperimentById(experimentId).then(exp => exp?.annotationTool || null), + getAnnotationEntries(experimentId), + getAnnotationProgress(experimentId), + ]); if (entries.length === 0) { return ( @@ -68,10 +71,11 @@ export default async function AnnotatePage({ params }: Props) { } return ( - 0} /> ); } diff --git a/src/components/AnnotationViews/AnnotationInfoView.tsx b/src/components/AnnotationViews/AnnotationInfoView.tsx new file mode 100644 index 0000000..82b0180 --- /dev/null +++ b/src/components/AnnotationViews/AnnotationInfoView.tsx @@ -0,0 +1,119 @@ +'use client'; + +import { useEffect } from 'react'; + +interface AnnotationInfoViewProps { + onContinue: () => void; + hasExistingAnswers: boolean; +} + +export default function AnnotationInfoView({ + onContinue, + hasExistingAnswers, +}: AnnotationInfoViewProps) { + useEffect(() => { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + }, []); + + return ( +
+
+
+ {/* Header */} +
+

Bewertungsphase

+
+ + {/* Info Section */} +
+

Was ist deine Aufgabe?

+

+ Du hörst kurze Audioaufnahmen, die von einem KI-Modell generiert wurden. Pro Aufnahme bewertest du zwei Dinge: +

+
+
+

Authentizität

+

Klingt es so, wie jemand aus dieser Region wirklich sprechen würde, mit der typischen Ausdrucksweise dieser Region? Oder klingt es eher wie eine Imitation?

+
+
+

Sicherheit

+

Wie sicher bist du dir bei deiner Einschätzung?

+
+
+
+

Keine Trickfragen

+

Jede Aufnahme wurde tatsächlich im angegebenen Dialekt generiert.

+
+
+ + {/* Instructions Section */} +
+

Wie funktioniert es?

+
    +
  1. + + 1 + + Du hörst eine synthetische Audioaufnahme +
  2. +
  3. + + 2 + + Du bewertest, wie authentisch die Aufnahme nach dem angegebenen Dialekt klingt +
  4. +
  5. + + 3 + + Du gibst an, wie sicher du dir bei deiner Wahl bist +
  6. +
  7. + + 4 + + Dies wiederholst du für weitere Aufnahmen +
  8. +
+
+ + {/* Hints Section */} +
+
    +
  • + + Die Aufnahmen sind aufgrund deiner Kalibrierungsergebnisse sortiert – du siehst zuerst Dialekte, die du gut erkennst. Du kannst aber jederzeit vor- und zurückspringen. +
  • +
  • + + Du kannst die Bewertung jederzeit unterbrechen und später dort weitermachen, wo du aufgehört hast. +
  • +
+
+ + {/* Status */} + {hasExistingAnswers && ( +
+

+ ✓ Du hast diese Einführung bereits gesehen. Du kannst direkt mit der Bewertung weitermachen. +

+
+ )} + + {/* Action Button */} +
+ +
+
+
+
+ ); +} diff --git a/src/components/AnnotationViews/AnnotationPhase.tsx b/src/components/AnnotationViews/AnnotationPhase.tsx new file mode 100644 index 0000000..d70bd63 --- /dev/null +++ b/src/components/AnnotationViews/AnnotationPhase.tsx @@ -0,0 +1,33 @@ +'use client'; + +import { useState } from 'react'; +import { type DatasetEntryForAnnotation } from '@/lib/dialects'; +import AnnotationInfoView from './AnnotationInfoView'; +import AnnotationPageView from './AnnotationPageView'; + +interface AnnotationPhaseProps { + entries: DatasetEntryForAnnotation[]; + experimentId: number; + viewType: string; + hasExistingAnswers: boolean; +} + +export default function AnnotationPhase({ + entries, + experimentId, + viewType, + hasExistingAnswers, +}: AnnotationPhaseProps) { + const [showInfoPage, setShowInfoPage] = useState(true); + + if (showInfoPage) { + return ( + setShowInfoPage(false)} + hasExistingAnswers={hasExistingAnswers} + /> + ); + } + + return ; +} diff --git a/src/components/CalibrationViews/CalibrationInfoView.tsx b/src/components/CalibrationViews/CalibrationInfoView.tsx index c07866d..ff1fbd8 100644 --- a/src/components/CalibrationViews/CalibrationInfoView.tsx +++ b/src/components/CalibrationViews/CalibrationInfoView.tsx @@ -72,7 +72,7 @@ export default function CalibrationInfoView({ {/* Participation Section */} -
+

Die Kalibrierung umfasst 28 Aufnahmen und dauert etwa 5–10 Minuten.

diff --git a/src/components/OnboardingViews/OnboardingInfoView.tsx b/src/components/OnboardingViews/OnboardingInfoView.tsx index 294e012..7dba16f 100644 --- a/src/components/OnboardingViews/OnboardingInfoView.tsx +++ b/src/components/OnboardingViews/OnboardingInfoView.tsx @@ -60,7 +60,7 @@ export default function OnboardingInfoView({ {/* Participation Section */} -
+

Du entscheidest selbst, wie viele Aufnahmen du bewertest. Die gesamte Teilnahme inklusive Formular, Kalibrierung und 50 bewerteten Aufnahmen dauert etwa 30 Minuten. Unter allen Teilnehmenden, die 50 oder mehr Aufnahmen bewertet haben, verlosen wir 3x [Platzhalter]-Gutscheine im Wert von je [x].- CHF!