import React, { useEffect, useState } from 'react'; import { Icon } from '../ui/Icon'; import { useIsMobile, useGrow } from '../../lib/hooks'; import { WEEKDAYS_LONG, WEEKDAYS_SHORT, addDays, colorFor, formatDuration, fromIso, todayIso } from '../../lib/format'; import type { TimeEntry } from '../../types'; interface Props { from: string; entries: TimeEntry[]; readOnly: boolean; dailyTarget: number; onAdd: (date: string) => void; onEdit: (entry: TimeEntry) => void; onCopy: (entry: TimeEntry) => void; } /** * Wochenansicht wie ein moderner Stundenzettel: sieben Spalten, jede Buchung * als Karte mit Kundenfarbe. Auf dem Handy ein Tagesstreifen mit Liste. */ export const WeekView: React.FC = ({ from, entries, readOnly, dailyTarget, onAdd, onEdit, onCopy }) => { const isMobile = useIsMobile(); const today = todayIso(); const days = Array.from({ length: 7 }, (_, i) => addDays(from, i)); const byDay = (date: string) => entries.filter((e) => e.entry_date === date); const [selected, setSelected] = useState(() => (today >= from && today <= days[6] ? today : from)); useEffect(() => { setSelected(today >= from && today <= addDays(from, 6) ? today : from); }, [from, today]); if (isMobile) { const list = byDay(selected); const total = list.reduce((s, e) => s + e.minutes, 0); return (
{days.map((date, i) => { const minutes = byDay(date).reduce((s, e) => s + e.minutes, 0); const active = date === selected; return ( ); })}

{WEEKDAYS_LONG[days.indexOf(selected)]}

{formatDuration(total)} h

{list.map((entry, i) => ( onEdit(entry)} onCopy={() => onCopy(entry)} readOnly={readOnly} large /> ))} {list.length === 0 && ( )}
); } return (
{days.map((date, i) => { const list = byDay(date); const minutes = list.reduce((s, e) => s + e.minutes, 0); const weekend = i >= 5; const isToday = date === today; return (

{WEEKDAYS_SHORT[i]}

{fromIso(date).getDate()}.

{minutes ? formatDuration(minutes) : ''}

{!weekend && }
{list.map((entry, j) => ( onEdit(entry)} onCopy={() => onCopy(entry)} readOnly={readOnly} /> ))} {!readOnly && ( )}
); })}
); }; const DayMeter: React.FC<{ minutes: number; target: number }> = ({ minutes, target }) => { const grown = useGrow(minutes); const p = target ? Math.min(100, (minutes / target) * 100) : 0; return (
= 100 ? 'bg-brand-500' : 'bg-brand-300'}`} style={{ width: grown ? `${p}%` : 0 }} />
); }; export const EntryCard: React.FC<{ entry: TimeEntry; index: number; onClick: () => void; onCopy?: () => void; readOnly: boolean; large?: boolean }> = ({ entry, index, onClick, onCopy, readOnly, large, }) => { const color = colorFor(entry.customer_id, entry.customer_color); const canCopy = !readOnly && !!onCopy; return ( // Kopier-Knopf als Geschwister der Karte - ein Button im Button ist kein gueltiges HTML.
{canCopy && ( )}
); };