Add persistent workday records with localStorage integration and reset functionality

This commit is contained in:
T.Landgraf committed 2026-08-14 08:41:42 +02:00
1 parent b541fcd11b
commit 21ed1e7744
1 file changed
+77 -29
+77 -29
View File
@@ -4,6 +4,29 @@ import * as React from 'react';
type Workday = 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday';
interface DayRecord {
start: string;
end: string;
breakMins: number;
workedHrs: number;
overtimeMinutes: number;
}
type Records = Partial<Record<Workday, DayRecord>>;
const STORAGE_KEY = 'workTrackerRecords';
const DEFAULT_RECORD: DayRecord = { start: '', end: '', breakMins: 0, workedHrs: 0, overtimeMinutes: 0 };
const loadRecords = (): Records => {
try {
const raw = localStorage.getItem(STORAGE_KEY);
return raw ? JSON.parse(raw) : {};
} catch {
return {};
}
};
const toMinutes = (time: string): number | null => {
const match = /^(\d{2}):(\d{2})$/.exec(time);
if (!match) return null;
@@ -18,29 +41,48 @@ const fromMinutes = (mins: number): string => {
function App() {
const [selectedDay, setSelectedDay] = React.useState<Workday>('Monday');
const [workStart, setWorkStart] = React.useState<string>('');
const [workEnd, setWorkEnd] = React.useState<string>('');
const [breakMins, setBreakMins] = React.useState<number>(0);
const [workedHrs, setWorkedHrs] = React.useState<number>(0);
const [overtimeMinutes, setOvertimeMinutes] = React.useState<number>(0);
const [records, setRecords] = React.useState<Records>(loadRecords);
const record = records[selectedDay] ?? DEFAULT_RECORD;
React.useEffect(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(records));
}, [records]);
const updateRecord = (patch: Partial<DayRecord>) => {
setRecords((prev) => ({
...prev,
[selectedDay]: { ...(prev[selectedDay] ?? DEFAULT_RECORD), ...patch },
}));
};
const getHourDiff = () => {
const start = toMinutes(workStart);
const end = toMinutes(workEnd);
const start = toMinutes(record.start);
const end = toMinutes(record.end);
if (start === null || end === null) return 0;
return (end - start) / 60 - breakMins / 60;
return (end - start) / 60 - record.breakMins / 60;
}
const getWeeklyBalance = () => {
const days: Workday[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday'];
return days.reduce((sum, day) => sum + (records[day]?.overtimeMinutes ?? 0), 0);
}
const getWorkEndTime = () => {
const start = toMinutes(workStart);
const start = toMinutes(record.start);
if (start === null) return '—';
return fromMinutes(start + 8 * 60 + breakMins);
const balance = selectedDay === 'Friday' ? getWeeklyBalance() : 0;
return fromMinutes(start + 8 * 60 - balance + record.breakMins);
}
const handleSave = () => {
const hours = getHourDiff();
setWorkedHrs(hours);
setOvertimeMinutes(Math.round((hours - 8) * 60));
updateRecord({ workedHrs: hours, overtimeMinutes: Math.round((hours - 8) * 60) });
}
const handleReset = () => {
localStorage.removeItem(STORAGE_KEY);
setRecords({});
}
return (
@@ -48,48 +90,54 @@ function App() {
<Stack>
<SegmentedControl
data={['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']}
onChange={(value) => {
setWorkStart('');
setWorkEnd('');
setSelectedDay(value as Workday);
}}
onChange={(value) => setSelectedDay(value as Workday)}
className={"mt-2"}
/>
<TimePicker
value={workStart}
value={record.start}
label={"Arbeitsbeginn"}
onChange={setWorkStart}
onChange={(value) => updateRecord({ start: value })}
format="24h"
clearable
/>
<TimePicker
value={workEnd}
value={record.end}
label={"Arbeitsende"}
onChange={setWorkEnd}
onChange={(value) => updateRecord({ end: value })}
format="24h"
clearable
/>
<NumberInput
label={"Pause in Minuten"}
value={breakMins}
onChange={(val) => setBreakMins(Number(val))}
value={record.breakMins}
onChange={(val) => updateRecord({ breakMins: Number(val) })}
onKeyDown={(event) => {
if (event.key === 'Enter') handleSave();
}}
/>
<Button onClick={handleSave}>
Speichern
</Button>
<Text>Gearbeitete Stunden heute: {workedHrs.toFixed(2)}</Text>
<Text>Gearbeitete Stunden heute: {record.workedHrs.toFixed(2)}</Text>
{selectedDay === 'Friday' && (
<Text c={"green"}>Übertragen aus Montag bis Donnerstag: {getWeeklyBalance()} Minuten</Text>
)}
<Text>Wann du gehen kannst für 8 Stunden: {getWorkEndTime()}</Text>
{overtimeMinutes === 0 && (
{record.overtimeMinutes === 0 && (
<Text>Du hast genau 8 Stunden gearbeitet.</Text>
)}
{overtimeMinutes > 0 && (
<Text c="yellow">Überstunden: {overtimeMinutes} Minuten</Text>
{record.overtimeMinutes > 0 && (
<Text c="yellow">Überstunden: {record.overtimeMinutes} Minuten</Text>
)}
{overtimeMinutes < 0 && (
<Text>Fehlende Minuten für 8 Stunden: {-overtimeMinutes} Minuten</Text>
{record.overtimeMinutes < 0 && (
<Text c={"red"}>Fehlende Minuten für 8 Stunden: {-record.overtimeMinutes} Minuten</Text>
)}
<Button color="red" variant="outline" onClick={handleReset}>
Reset saved records
</Button>
</Stack>
</Center>
);