import React, { useEffect, useMemo, useRef, useState } from 'react'; import { ArrowUpDown, Calendar, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Plus, Trash2, User } from 'lucide-react'; import { useTranslation } from '../../i18n/LanguageContext'; const toIsoDate = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }; const parseIsoDate = (value) => { if (!value || !value.includes('-')) return null; const [year, month, day] = value.split('-').map(Number); return new Date(year, month - 1, day); }; const getCalendarDays = (monthDate) => { const startOfMonth = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1); const offset = (startOfMonth.getDay() + 6) % 7; const calendarStart = new Date(startOfMonth.getFullYear(), startOfMonth.getMonth(), 1 - offset); return Array.from({ length: 42 }, (_, index) => { const day = new Date(calendarStart.getFullYear(), calendarStart.getMonth(), calendarStart.getDate() + index); return { key: toIsoDate(day), date: day, isoValue: toIsoDate(day), isCurrentMonth: day.getMonth() === monthDate.getMonth() }; }); }; const PatList = ({ patTypes, assessments, overview, assessmentShareTokens = {}, testsVisible = true, onCreate, onEdit, onDelete, getPatTypeColor, getAchievement }) => { const t = useTranslation(); const datePickerRef = useRef(null); const [showCreateMenu, setShowCreateMenu] = useState(false); const [activeDatePicker, setActiveDatePicker] = useState(null); const [sortConfig, setSortConfig] = useState({ key: 'datum', direction: 'desc' }); const [filters, setFilters] = useState({ name: '', datum: '' }); const [visibleMonth, setVisibleMonth] = useState(() => { const today = new Date(); return new Date(today.getFullYear(), today.getMonth(), 1); }); const patTypeOptions = Object.keys(patTypes || {}); const openAssessments = assessments.filter((assessment) => !assessment.isFinalized); const finalizedAssessments = assessments.filter((assessment) => assessment.isFinalized); const getResultValue = (assessment) => assessment.exercises.reduce((sum, ex) => sum + (ex.points || 0), 0); const normalize = (value) => String(value || '').toLowerCase().trim(); const formatDateForFilter = (value) => { if (!value || !value.includes('-')) return ''; const [year, month, day] = value.split('-'); return `${day}.${month}.${year}`; }; const formatDateForRow = (value) => { if (!value || !value.includes('-')) return value || ''; const [year, month, day] = value.split('-'); return `${year}.${month}.${day}`; }; const monthLabel = useMemo( () => new Intl.DateTimeFormat('de-DE', { month: 'long', year: 'numeric' }).format(visibleMonth), [visibleMonth] ); const calendarDays = useMemo(() => getCalendarDays(visibleMonth), [visibleMonth]); useEffect(() => { if (!activeDatePicker) return undefined; const handlePointerDown = (event) => { if (datePickerRef.current && !datePickerRef.current.contains(event.target)) { setActiveDatePicker(null); } }; const handleKeyDown = (event) => { if (event.key === 'Escape') { setActiveDatePicker(null); } }; document.addEventListener('mousedown', handlePointerDown); document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('mousedown', handlePointerDown); document.removeEventListener('keydown', handleKeyDown); }; }, [activeDatePicker]); const matchesFilters = (assessment) => { const matchesName = !filters.name || normalize(assessment.name).includes(normalize(filters.name)); const matchesDate = !filters.datum || normalize(assessment.datum).includes(normalize(filters.datum)); return matchesName && matchesDate; }; const getSortValue = (assessment, key) => { if (key === 'name') return (assessment.name || '').toLowerCase(); if (key === 'datum') return assessment.datum || ''; if (key === 'result') return getResultValue(assessment); return ''; }; const sortAssessments = (entries) => [...entries].sort((left, right) => { const leftValue = getSortValue(left, sortConfig.key); const rightValue = getSortValue(right, sortConfig.key); if (leftValue < rightValue) return sortConfig.direction === 'asc' ? -1 : 1; if (leftValue > rightValue) return sortConfig.direction === 'asc' ? 1 : -1; return 0; }); const sortedOpenAssessments = useMemo( () => sortAssessments(openAssessments.filter(matchesFilters)), [openAssessments, sortConfig, filters] ); const sortedFinalizedAssessments = useMemo( () => sortAssessments(finalizedAssessments.filter(matchesFilters)), [finalizedAssessments, sortConfig, filters] ); const handleSort = (key) => { setSortConfig((current) => current.key === key ? { key, direction: current.direction === 'asc' ? 'desc' : 'asc' } : { key, direction: key === 'datum' ? 'desc' : 'asc' } ); }; const renderSortIcon = (key) => { if (sortConfig.key !== key) { return