Files
arbeitszeit/components/Einstellungen.tsx
T
admin 01a7ac8e0b Initiale Arbeitszeiterfassung (Next.js 16 + SQLite)
Web-App zur Erfassung der Arbeitszeit, Layout/Architektur an Projekt logbuch
angelehnt, mit grüner Grundfarbe und SQLite3 statt MySQL.

- Eingabemaske: Datum (mit Wochentag), Ort (Kunde FFM/Homeoffice/Andrena),
  Beginn/Ende, Reisezeit, Vertriebsunterstützung (default 2h), Kommentar (max 500)
- Berechnung: Arbeitszeit = Ende-Beginn; Mehrarbeit = Arbeitszeit - 8h - Pause
- Pause als globale Einstellung (Einstellungen-Tab)
- Tabs Eingabe/Liste/Einstellungen, letzte 10 Einträge unter der Maske
- Single-User-Login (Benutzer Birgit + Passwort fest in .env), JWT-Cookie via jose
- better-sqlite3, Docker-Setup für docker.citysensor.de

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:53:44 +02:00

71 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useState } from 'react';
interface Props {
pause: number;
onPauseChange: (pause: number) => void;
}
export default function Einstellungen({ pause, onPauseChange }: Props) {
const [raw, setRaw] = useState(String(pause).replace('.', ','));
const [saving, setSaving] = useState(false);
const [status, setStatus] = useState<'idle' | 'ok' | 'error'>('idle');
async function handleSave(e: React.FormEvent) {
e.preventDefault();
setSaving(true);
setStatus('idle');
const value = parseFloat(raw.replace(',', '.'));
try {
const res = await fetch('/api/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pause: value }),
});
if (!res.ok) throw new Error();
const data = await res.json();
onPauseChange(data.pause);
setRaw(String(data.pause).replace('.', ','));
setStatus('ok');
setTimeout(() => setStatus('idle'), 3000);
} catch {
setStatus('error');
} finally {
setSaving(false);
}
}
return (
<form onSubmit={handleSave} className="max-w-md space-y-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Pause (dezimale Stunden)
</label>
<input
type="text"
inputMode="decimal"
value={raw}
onChange={(e) => setRaw(e.target.value)}
className="w-32 px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-gray-900 text-sm focus:border-green-600 focus:outline-none"
/>
<p className="mt-1 text-xs text-gray-500">
Wird in der Mehrarbeit-Berechnung abgezogen: Mehrarbeit = Arbeitszeit 8 h Pause.
</p>
</div>
<div className="flex items-center gap-3">
<button
type="submit"
disabled={saving}
className="px-6 py-1.5 bg-[#86C28B] hover:bg-[#6FB075] text-black font-medium rounded-lg transition-colors disabled:opacity-50 text-sm"
>
{saving ? 'Speichern...' : 'Speichern'}
</button>
{status === 'ok' && <span className="text-green-700 text-sm">Gespeichert.</span>}
{status === 'error' && <span className="text-red-600 text-sm">Fehler beim Speichern.</span>}
</div>
</form>
);
}