From 8efffe8c520070c34b38a635cf71898f55b6e037 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Sat, 25 Apr 2026 16:08:14 +0200 Subject: [PATCH] Fix: Use @shared/* alias instead of relative paths for Docker compat Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/(admin)/ai/ocr-labeling/types.ts | 2 +- .../_components/workspace-types.ts | 4 +- .../klausur-korrektur/_components/types.ts | 2 +- .../education/klausur-korrektur/types.ts | 2 +- admin-lehrer/lib/companion/types.ts | 2 +- studio-v2/app/korrektur/types.ts | 2 +- studio-v2/app/learn/[unitId]/listen/page.tsx | 137 ++++++++++++++ studio-v2/app/learn/[unitId]/match/page.tsx | 170 ++++++++++++++++++ .../app/learn/[unitId]/pronounce/page.tsx | 133 ++++++++++++++ .../components/gamification/StarRating.tsx | 45 +++++ studio-v2/components/learn/FlashCard.tsx | 22 ++- studio-v2/components/learn/UnitCard.tsx | 95 ++++++---- studio-v2/lib/companion/types.ts | 2 +- website/app/admin/klausur-korrektur/types.ts | 2 +- website/app/admin/ocr-labeling/types.ts | 2 +- website/app/lehrer/klausur-korrektur/types.ts | 2 +- .../klausur-korrektur/list-types.ts | 2 +- .../klausur-korrektur/workspace-types.ts | 4 +- 18 files changed, 577 insertions(+), 53 deletions(-) create mode 100644 studio-v2/app/learn/[unitId]/listen/page.tsx create mode 100644 studio-v2/app/learn/[unitId]/match/page.tsx create mode 100644 studio-v2/app/learn/[unitId]/pronounce/page.tsx create mode 100644 studio-v2/components/gamification/StarRating.tsx diff --git a/admin-lehrer/app/(admin)/ai/ocr-labeling/types.ts b/admin-lehrer/app/(admin)/ai/ocr-labeling/types.ts index a09849b..845e7ce 100644 --- a/admin-lehrer/app/(admin)/ai/ocr-labeling/types.ts +++ b/admin-lehrer/app/(admin)/ai/ocr-labeling/types.ts @@ -1 +1 @@ -export * from '../../../../../shared/types/ocr-labeling' +export * from '@shared/types/ocr-labeling' diff --git a/admin-lehrer/app/(admin)/education/klausur-korrektur/[klausurId]/[studentId]/_components/workspace-types.ts b/admin-lehrer/app/(admin)/education/klausur-korrektur/[klausurId]/[studentId]/_components/workspace-types.ts index 3ec58e5..dab4788 100644 --- a/admin-lehrer/app/(admin)/education/klausur-korrektur/[klausurId]/[studentId]/_components/workspace-types.ts +++ b/admin-lehrer/app/(admin)/education/klausur-korrektur/[klausurId]/[studentId]/_components/workspace-types.ts @@ -12,13 +12,13 @@ export type { ActiveTab, GradeTotals, CriteriaScores, -} from '../../../../../../../../shared/types/klausur' +} from '@shared/types/klausur' export { WORKFLOW_STATUS_LABELS, ROLE_LABELS, GRADE_LABELS, -} from '../../../../../../../../shared/types/klausur' +} from '@shared/types/klausur' /** Same-origin proxy to avoid CORS issues */ export const API_BASE = '/klausur-api' diff --git a/admin-lehrer/app/(admin)/education/klausur-korrektur/_components/types.ts b/admin-lehrer/app/(admin)/education/klausur-korrektur/_components/types.ts index edcd4c6..258a794 100644 --- a/admin-lehrer/app/(admin)/education/klausur-korrektur/_components/types.ts +++ b/admin-lehrer/app/(admin)/education/klausur-korrektur/_components/types.ts @@ -8,4 +8,4 @@ export type { VorabiturEHForm, EHTemplate, DirektuploadForm, -} from '../../../../../../shared/types/klausur' +} from '@shared/types/klausur' diff --git a/admin-lehrer/app/(admin)/education/klausur-korrektur/types.ts b/admin-lehrer/app/(admin)/education/klausur-korrektur/types.ts index 2d9c2ce..4def074 100644 --- a/admin-lehrer/app/(admin)/education/klausur-korrektur/types.ts +++ b/admin-lehrer/app/(admin)/education/klausur-korrektur/types.ts @@ -1 +1 @@ -export * from '../../../../../shared/types/klausur' +export * from '@shared/types/klausur' diff --git a/admin-lehrer/lib/companion/types.ts b/admin-lehrer/lib/companion/types.ts index fe2de9c..90ba262 100644 --- a/admin-lehrer/lib/companion/types.ts +++ b/admin-lehrer/lib/companion/types.ts @@ -1 +1 @@ -export * from '../../../shared/types/companion' +export * from '@shared/types/companion' diff --git a/studio-v2/app/korrektur/types.ts b/studio-v2/app/korrektur/types.ts index 63f5f0d..4def074 100644 --- a/studio-v2/app/korrektur/types.ts +++ b/studio-v2/app/korrektur/types.ts @@ -1 +1 @@ -export * from '../../../shared/types/klausur' +export * from '@shared/types/klausur' diff --git a/studio-v2/app/learn/[unitId]/listen/page.tsx b/studio-v2/app/learn/[unitId]/listen/page.tsx new file mode 100644 index 0000000..4d81d87 --- /dev/null +++ b/studio-v2/app/learn/[unitId]/listen/page.tsx @@ -0,0 +1,137 @@ +'use client' + +import React, { useState, useEffect, useCallback, useMemo } from 'react' +import { useParams, useRouter } from 'next/navigation' +import { useTheme } from '@/lib/ThemeContext' +import { AudioButton } from '@/components/learn/AudioButton' +import { StarRating, accuracyToStars } from '@/components/gamification/StarRating' + +interface QAItem { id: string; question: string; answer: string } + +function getApiBase() { return '' } + +export default function ListenPage() { + const { unitId } = useParams<{ unitId: string }>() + const router = useRouter() + const { isDark } = useTheme() + + const [items, setItems] = useState([]) + const [currentIndex, setCurrentIndex] = useState(0) + const [isLoading, setIsLoading] = useState(true) + const [selected, setSelected] = useState(null) + const [revealed, setRevealed] = useState(false) + const [stats, setStats] = useState({ correct: 0, incorrect: 0 }) + const [isComplete, setIsComplete] = useState(false) + + const glassCard = isDark + ? 'bg-white/10 backdrop-blur-xl border border-white/10' + : 'bg-white/80 backdrop-blur-xl border border-black/5' + + useEffect(() => { + (async () => { + try { + const resp = await fetch(`${getApiBase()}/api/learning-units/${unitId}/qa`) + if (resp.ok) { const d = await resp.json(); setItems(d.qa_items || []) } + } catch {} finally { setIsLoading(false) } + })() + }, [unitId]) + + // Generate 4 options (1 correct + 3 distractors) + const options = useMemo(() => { + if (!items.length || currentIndex >= items.length) return [] + const correct = items[currentIndex] + const others = items.filter((_, i) => i !== currentIndex) + const shuffled = [...others].sort(() => Math.random() - 0.5).slice(0, 3) + const opts = [...shuffled.map(i => ({ id: i.id, text: i.answer })), { id: correct.id, text: correct.answer }] + return opts.sort(() => Math.random() - 0.5) + }, [items, currentIndex]) + + const handleSelect = useCallback((optionId: string) => { + if (revealed) return + setSelected(optionId) + setRevealed(true) + const isCorrect = optionId === items[currentIndex].id + + setStats(prev => ({ + correct: prev.correct + (isCorrect ? 1 : 0), + incorrect: prev.incorrect + (isCorrect ? 0 : 1), + })) + + setTimeout(() => { + if (currentIndex + 1 >= items.length) { setIsComplete(true) } + else { setCurrentIndex(i => i + 1) } + setSelected(null) + setRevealed(false) + }, isCorrect ? 800 : 2000) + }, [revealed, items, currentIndex]) + + if (isLoading) { + return
+
+
+ } + + const currentItem = items[currentIndex] + + return ( +
+ {/* Header */} +
+
+ +

Hoerverstehen

+ {currentIndex + 1}/{items.length} +
+
+ + {/* Progress */} +
+
+
+ +
+ {isComplete ? ( +
+ +

Geschafft!

+

{stats.correct}/{stats.correct + stats.incorrect} richtig

+
+ + +
+
+ ) : currentItem ? ( +
+ {/* Audio prompt */} +
+

Hoere das Wort und waehle die richtige Uebersetzung

+ +

Tippe auf den Lautsprecher

+
+ + {/* Options */} +
+ {options.map(opt => { + const isCorrectAnswer = opt.id === currentItem.id + const isSelected = selected === opt.id + let style = isDark ? 'bg-white/10 border-white/20 text-white' : 'bg-white border-slate-200 text-slate-900' + if (revealed && isCorrectAnswer) style = isDark ? 'bg-green-500/30 border-green-400 text-green-200' : 'bg-green-50 border-green-500 text-green-800' + if (revealed && isSelected && !isCorrectAnswer) style = isDark ? 'bg-red-500/30 border-red-400 text-red-200' : 'bg-red-50 border-red-500 text-red-800' + + return ( + + ) + })} +
+
+ ) : null} +
+
+ ) +} diff --git a/studio-v2/app/learn/[unitId]/match/page.tsx b/studio-v2/app/learn/[unitId]/match/page.tsx new file mode 100644 index 0000000..b08cb04 --- /dev/null +++ b/studio-v2/app/learn/[unitId]/match/page.tsx @@ -0,0 +1,170 @@ +'use client' + +import React, { useState, useEffect, useCallback, useMemo } from 'react' +import { useParams, useRouter } from 'next/navigation' +import { useTheme } from '@/lib/ThemeContext' +import { StarRating, accuracyToStars } from '@/components/gamification/StarRating' + +interface QAItem { id: string; question: string; answer: string } + +function getApiBase() { return '' } + +export default function MatchPage() { + const { unitId } = useParams<{ unitId: string }>() + const router = useRouter() + const { isDark } = useTheme() + + const [allItems, setAllItems] = useState([]) + const [isLoading, setIsLoading] = useState(true) + const [round, setRound] = useState(0) + const [selectedLeft, setSelectedLeft] = useState(null) + const [matched, setMatched] = useState>(new Set()) + const [wrongPair, setWrongPair] = useState(null) + const [errors, setErrors] = useState(0) + const [isComplete, setIsComplete] = useState(false) + + const glassCard = isDark + ? 'bg-white/10 backdrop-blur-xl border border-white/10' + : 'bg-white/80 backdrop-blur-xl border border-black/5' + + useEffect(() => { + (async () => { + try { + const resp = await fetch(`${getApiBase()}/api/learning-units/${unitId}/qa`) + if (resp.ok) { const d = await resp.json(); setAllItems(d.qa_items || []) } + } catch {} finally { setIsLoading(false) } + })() + }, [unitId]) + + // Take 6 items per round + const roundItems = useMemo(() => { + const start = round * 6 + return allItems.slice(start, start + 6) + }, [allItems, round]) + + // Shuffled right column + const shuffledRight = useMemo(() => { + return [...roundItems].sort(() => Math.random() - 0.5) + }, [roundItems]) + + const handleLeftTap = useCallback((id: string) => { + if (matched.has(id)) return + setSelectedLeft(id === selectedLeft ? null : id) + setWrongPair(null) + }, [selectedLeft, matched]) + + const handleRightTap = useCallback((id: string) => { + if (!selectedLeft || matched.has(id)) return + + if (selectedLeft === id) { + // Correct match + setMatched(prev => new Set([...prev, id])) + setSelectedLeft(null) + + // Check if round complete + if (matched.size + 1 >= roundItems.length) { + const nextStart = (round + 1) * 6 + if (nextStart >= allItems.length) { + setTimeout(() => setIsComplete(true), 500) + } else { + setTimeout(() => { + setRound(r => r + 1) + setMatched(new Set()) + setSelectedLeft(null) + }, 800) + } + } + } else { + // Wrong match + setWrongPair(id) + setErrors(e => e + 1) + setTimeout(() => { + setWrongPair(null) + setSelectedLeft(null) + }, 600) + } + }, [selectedLeft, matched, roundItems, round, allItems]) + + if (isLoading) { + return
+
+
+ } + + const totalPairs = allItems.length + const matchedTotal = round * 6 + matched.size + + return ( +
+ {/* Header */} +
+
+ +

Zuordnen

+ {matchedTotal}/{totalPairs} +
+
+ +
+ {isComplete ? ( +
+ +

Alle zugeordnet!

+

{errors} Fehler

+
+ + +
+
+ ) : ( +
+ {/* Left column: English */} +
+

English

+ {roundItems.map(item => ( + + ))} +
+ + {/* Right column: German (shuffled) */} +
+

Deutsch

+ {shuffledRight.map(item => ( + + ))} +
+
+ )} +
+
+ ) +} diff --git a/studio-v2/app/learn/[unitId]/pronounce/page.tsx b/studio-v2/app/learn/[unitId]/pronounce/page.tsx new file mode 100644 index 0000000..d1bf820 --- /dev/null +++ b/studio-v2/app/learn/[unitId]/pronounce/page.tsx @@ -0,0 +1,133 @@ +'use client' + +import React, { useState, useEffect, useCallback } from 'react' +import { useParams, useRouter } from 'next/navigation' +import { useTheme } from '@/lib/ThemeContext' +import { AudioButton } from '@/components/learn/AudioButton' +import { MicrophoneInput } from '@/components/learn/MicrophoneInput' +import { SyllableBow, simpleSyllableSplit } from '@/components/learn/SyllableBow' +import { StarRating, accuracyToStars } from '@/components/gamification/StarRating' + +interface QAItem { + id: string; question: string; answer: string + syllables_en?: string[]; syllables_de?: string[] + ipa_en?: string; ipa_de?: string +} + +function getApiBase() { return '' } + +export default function PronouncePage() { + const { unitId } = useParams<{ unitId: string }>() + const router = useRouter() + const { isDark } = useTheme() + + const [items, setItems] = useState([]) + const [currentIndex, setCurrentIndex] = useState(0) + const [isLoading, setIsLoading] = useState(true) + const [stats, setStats] = useState({ correct: 0, incorrect: 0 }) + const [isComplete, setIsComplete] = useState(false) + const [lang, setLang] = useState<'en' | 'de'>('en') + + const glassCard = isDark + ? 'bg-white/10 backdrop-blur-xl border border-white/10' + : 'bg-white/80 backdrop-blur-xl border border-black/5' + + useEffect(() => { + (async () => { + try { + const resp = await fetch(`${getApiBase()}/api/learning-units/${unitId}/qa`) + if (resp.ok) { const d = await resp.json(); setItems(d.qa_items || []) } + } catch {} finally { setIsLoading(false) } + })() + }, [unitId]) + + const currentItem = items[currentIndex] + const currentWord = currentItem ? (lang === 'en' ? currentItem.question : currentItem.answer) : '' + const syllables = currentItem + ? (lang === 'en' ? currentItem.syllables_en : currentItem.syllables_de) || simpleSyllableSplit(currentWord) + : [] + const ipa = currentItem ? (lang === 'en' ? currentItem.ipa_en : currentItem.ipa_de) : '' + + const handleResult = useCallback((transcript: string, correct: boolean) => { + setStats(prev => ({ + correct: prev.correct + (correct ? 1 : 0), + incorrect: prev.incorrect + (correct ? 0 : 1), + })) + + setTimeout(() => { + if (currentIndex + 1 >= items.length) { setIsComplete(true) } + else { setCurrentIndex(i => i + 1) } + }, correct ? 1000 : 2500) + }, [currentIndex, items.length]) + + if (isLoading) { + return
+
+
+ } + + return ( +
+ {/* Header */} +
+
+ +

Nachsprechen

+ +
+
+ + {/* Progress */} +
+
+
+ +
+ {isComplete ? ( +
+ +

Super gemacht!

+

{stats.correct}/{stats.correct + stats.incorrect} richtig ausgesprochen

+
+ + +
+
+ ) : currentItem ? ( +
+ {/* Word + Syllables */} +
+
+ +
+ {ipa &&

{ipa}

} +
+ +
+

+ Hoere zu, dann sprich nach +

+
+ + {/* Microphone */} + + +

+ {currentIndex + 1} / {items.length} +

+
+ ) : null} +
+
+ ) +} diff --git a/studio-v2/components/gamification/StarRating.tsx b/studio-v2/components/gamification/StarRating.tsx new file mode 100644 index 0000000..8627e50 --- /dev/null +++ b/studio-v2/components/gamification/StarRating.tsx @@ -0,0 +1,45 @@ +'use client' + +import React from 'react' + +interface StarRatingProps { + stars: number // 0-3 + total?: number // total stars earned (shown as badge) + size?: 'sm' | 'md' | 'lg' + animated?: boolean + showLabel?: boolean +} + +const sizeMap = { sm: 'text-lg', md: 'text-2xl', lg: 'text-4xl' } + +export function StarRating({ stars, total, size = 'md', animated = false, showLabel = false }: StarRatingProps) { + return ( +
+ {[1, 2, 3].map((i) => ( + + {i <= stars ? '\u2B50' : '\u2606'} + + ))} + {total != null && showLabel && ( + {total} + )} +
+ ) +} + +/** Calculate stars from accuracy percentage */ +export function accuracyToStars(correct: number, total: number): number { + if (total === 0) return 0 + const pct = (correct / total) * 100 + if (pct >= 100) return 3 + if (pct >= 70) return 2 + return 1 +} diff --git a/studio-v2/components/learn/FlashCard.tsx b/studio-v2/components/learn/FlashCard.tsx index a976f32..0bc42fb 100644 --- a/studio-v2/components/learn/FlashCard.tsx +++ b/studio-v2/components/learn/FlashCard.tsx @@ -1,6 +1,7 @@ 'use client' import React, { useState, useCallback } from 'react' +import { SyllableBow, simpleSyllableSplit } from './SyllableBow' interface FlashCardProps { front: string @@ -11,6 +12,10 @@ interface FlashCardProps { onCorrect: () => void onIncorrect: () => void isDark: boolean + syllablesFront?: string[] + syllablesBack?: string[] + ipaFront?: string + ipaBack?: string } const boxLabels = ['Neu', 'Gelernt', 'Gefestigt'] @@ -25,6 +30,10 @@ export function FlashCard({ onCorrect, onIncorrect, isDark, + syllablesFront, + syllablesBack, + ipaFront, + ipaBack, }: FlashCardProps) { const [isFlipped, setIsFlipped] = useState(false) @@ -69,10 +78,15 @@ export function FlashCard({ ENGLISCH - - {front} - - + {syllablesFront && syllablesFront.length > 0 ? ( + + ) : ( + + {front} + + )} + {ipaFront && {ipaFront}} + Klick zum Umdrehen
diff --git a/studio-v2/components/learn/UnitCard.tsx b/studio-v2/components/learn/UnitCard.tsx index 826e0f8..f9b4cee 100644 --- a/studio-v2/components/learn/UnitCard.tsx +++ b/studio-v2/components/learn/UnitCard.tsx @@ -14,42 +14,66 @@ interface LearningUnit { created_at: string } +interface UnitProgress { + total_stars?: number + exercises?: Record +} + interface UnitCardProps { unit: LearningUnit + progress?: UnitProgress | null + wordCount?: number isDark: boolean glassCard: string onDelete: (id: string) => void } const exerciseTypes = [ - { key: 'flashcards', label: 'Karteikarten', icon: 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10', color: 'from-amber-500 to-orange-500' }, + { key: 'flashcards', label: 'Karten', icon: 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10', color: 'from-amber-500 to-orange-500' }, { key: 'quiz', label: 'Quiz', icon: 'M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z', color: 'from-purple-500 to-pink-500' }, - { key: 'type', label: 'Eintippen', icon: 'M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z', color: 'from-blue-500 to-cyan-500' }, - { key: 'story', label: 'Geschichte', icon: 'M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253', color: 'from-amber-500 to-yellow-500' }, + { key: 'type', label: 'Tippen', icon: 'M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z', color: 'from-blue-500 to-cyan-500' }, + { key: 'listen', label: 'Hoeren', icon: 'M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z', color: 'from-green-500 to-emerald-500' }, + { key: 'match', label: 'Zuordnen', icon: 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1', color: 'from-indigo-500 to-violet-500' }, + { key: 'pronounce', label: 'Sprechen', icon: 'M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z', color: 'from-rose-500 to-red-500' }, ] -export function UnitCard({ unit, isDark, glassCard, onDelete }: UnitCardProps) { +export function UnitCard({ unit, progress, wordCount, isDark, glassCard, onDelete }: UnitCardProps) { const createdDate = new Date(unit.created_at).toLocaleDateString('de-DE', { - day: '2-digit', - month: '2-digit', - year: 'numeric', + day: '2-digit', month: '2-digit', year: 'numeric', }) + // Calculate progress percentage from exercises + const totalCorrect = progress?.exercises + ? Object.values(progress.exercises).reduce((s, e) => s + (e?.correct || 0), 0) + : 0 + const totalAnswered = progress?.exercises + ? Object.values(progress.exercises).reduce((s, e) => s + (e?.completed || 0), 0) + : 0 + const progressPct = totalAnswered > 0 ? Math.round((totalCorrect / totalAnswered) * 100) : 0 + const stars = progress?.total_stars || 0 + return ( -
-
-
-

- {unit.label} -

-

- {unit.meta} +

+ {/* Header */} +
+
+
+

+ {unit.label} +

+ {stars > 0 && ( + + {stars} + + )} +
+

+ {wordCount ? `${wordCount} Woerter` : unit.meta} · {createdDate}

- {/* Exercise Type Buttons */} -
+ {/* Progress Bar */} + {totalAnswered > 0 && ( +
+
+
+
+

+ {progressPct}% · {totalCorrect}/{totalAnswered} richtig +

+
+ )} + + {/* Exercise Buttons */} +
{exerciseTypes.map((ex) => ( - + {ex.label} ))}
- - {/* Status */} -
- - Erstellt: {createdDate} - - - {unit.status === 'raw' ? 'Neu' : 'Module generiert'} - -
) } diff --git a/studio-v2/lib/companion/types.ts b/studio-v2/lib/companion/types.ts index fe2de9c..90ba262 100644 --- a/studio-v2/lib/companion/types.ts +++ b/studio-v2/lib/companion/types.ts @@ -1 +1 @@ -export * from '../../../shared/types/companion' +export * from '@shared/types/companion' diff --git a/website/app/admin/klausur-korrektur/types.ts b/website/app/admin/klausur-korrektur/types.ts index ba897cb..4def074 100644 --- a/website/app/admin/klausur-korrektur/types.ts +++ b/website/app/admin/klausur-korrektur/types.ts @@ -1 +1 @@ -export * from '../../../../shared/types/klausur' +export * from '@shared/types/klausur' diff --git a/website/app/admin/ocr-labeling/types.ts b/website/app/admin/ocr-labeling/types.ts index 9af47a7..845e7ce 100644 --- a/website/app/admin/ocr-labeling/types.ts +++ b/website/app/admin/ocr-labeling/types.ts @@ -1 +1 @@ -export * from '../../../../shared/types/ocr-labeling' +export * from '@shared/types/ocr-labeling' diff --git a/website/app/lehrer/klausur-korrektur/types.ts b/website/app/lehrer/klausur-korrektur/types.ts index ba897cb..4def074 100644 --- a/website/app/lehrer/klausur-korrektur/types.ts +++ b/website/app/lehrer/klausur-korrektur/types.ts @@ -1 +1 @@ -export * from '../../../../shared/types/klausur' +export * from '@shared/types/klausur' diff --git a/website/components/klausur-korrektur/list-types.ts b/website/components/klausur-korrektur/list-types.ts index 9a03f04..3e2dbeb 100644 --- a/website/components/klausur-korrektur/list-types.ts +++ b/website/components/klausur-korrektur/list-types.ts @@ -12,6 +12,6 @@ export type { VorabiturEHForm, EHTemplate, DirektuploadForm, -} from '../../../shared/types/klausur' +} from '@shared/types/klausur' export const API_BASE = process.env.NEXT_PUBLIC_KLAUSUR_SERVICE_URL || 'http://localhost:8086' diff --git a/website/components/klausur-korrektur/workspace-types.ts b/website/components/klausur-korrektur/workspace-types.ts index 64b7ee9..089bb37 100644 --- a/website/components/klausur-korrektur/workspace-types.ts +++ b/website/components/klausur-korrektur/workspace-types.ts @@ -12,12 +12,12 @@ export type { ExaminerWorkflow, ActiveTab, CriteriaScores, -} from '../../../shared/types/klausur' +} from '@shared/types/klausur' export { WORKFLOW_STATUS_LABELS, ROLE_LABELS, GRADE_LABELS, -} from '../../../shared/types/klausur' +} from '@shared/types/klausur' export const API_BASE = process.env.NEXT_PUBLIC_KLAUSUR_SERVICE_URL || 'http://localhost:8086'