Files
werte-next/components/WerteForm.tsx
T
admin ee16942742 Formular und Liste responsiv gestalten
Eingabemaske als CSS-Grid statt starrer Tabelle, damit sie auf dem
Smartphone vollständig sichtbar bleibt (2/4/8 Spalten je nach
Breite). Einträge-Liste zeigt unterhalb von 768px eine zweizeilige
Kartenansicht statt der breiten Tabelle. Anzahl geladener Einträge
von 15 auf 5 reduziert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 09:46:18 +02:00

288 lines
9.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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, useEffect } from 'react';
import { CreateWerteEntry, WerteEntry } from '@/types/werte';
interface WerteFormProps {
onSuccess: () => void;
selectedEntry?: WerteEntry | null;
}
export default function WerteForm({ onSuccess, selectedEntry }: WerteFormProps) {
const [formData, setFormData] = useState<CreateWerteEntry>({
Datum: '',
Zeit: '',
Zucker: '',
Essen: 'nüchtern',
Gewicht: '',
DruckS: '',
DruckD: '',
Puls: '',
});
const [isSubmitting, setIsSubmitting] = useState(false);
const [weekday, setWeekday] = useState('');
const [editId, setEditId] = useState<number | null>(null);
useEffect(() => {
if (selectedEntry) {
// Load selected entry for editing
const dateStr = selectedEntry.Datum.toString().split('T')[0];
const timeStr = selectedEntry.Zeit.toString().substring(0, 5);
setFormData({
Datum: dateStr,
Zeit: timeStr,
Zucker: selectedEntry.Zucker || '',
Essen: selectedEntry.Essen || '',
Gewicht: selectedEntry.Gewicht || '',
DruckS: selectedEntry.DruckS || '',
DruckD: selectedEntry.DruckD || '',
Puls: selectedEntry.Puls || '',
});
setEditId(selectedEntry.ID || null);
// Parse date to avoid timezone issues
const [year, month, day] = dateStr.split('T')[0].split('-');
const date = new Date(Number(year), Number(month) - 1, Number(day));
updateWeekday(date);
} else {
// Initialize with current date and time for new entry
const now = new Date();
const dateStr = now.toISOString().split('T')[0];
const timeStr = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
setFormData(prev => ({
...prev,
Datum: dateStr,
Zeit: timeStr,
}));
setEditId(null);
updateWeekday(now);
}
}, [selectedEntry]);
const updateWeekday = (date: Date) => {
const weekdays = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
setWeekday(weekdays[date.getDay()]);
};
const handleDateChange = (dateStr: string) => {
setFormData(prev => ({ ...prev, Datum: dateStr }));
// Parse date to avoid timezone issues
const [year, month, day] = dateStr.split('-');
const date = new Date(Number(year), Number(month) - 1, Number(day));
updateWeekday(date);
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
try {
const url = editId ? `/api/werte/${editId}` : '/api/werte';
const method = editId ? 'PUT' : 'POST';
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});
if (response.ok) {
// Reset form but keep date and time
const now = new Date();
const timeStr = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
setFormData(prev => ({
...prev,
Zeit: timeStr,
Zucker: '',
Essen: 'nüchtern',
Gewicht: '',
DruckS: '',
DruckD: '',
Puls: '',
}));
setEditId(null);
onSuccess();
} else {
alert('Fehler beim Speichern!');
}
} catch (error) {
console.error('Error:', error);
alert('Fehler beim Speichern!');
} finally {
setIsSubmitting(false);
}
};
const handleReset = () => {
const now = new Date();
const dateStr = now.toISOString().split('T')[0];
const timeStr = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
setFormData({
Datum: dateStr,
Zeit: timeStr,
Zucker: '',
Essen: 'nüchtern',
Gewicht: '',
DruckS: '',
DruckD: '',
Puls: '',
});
setEditId(null);
updateWeekday(now);
};
const inputClass = "w-full min-w-0 px-2 py-1 text-sm rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-none";
const numberInputClass = `${inputClass} [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`;
return (
<div className="bg-[#CCCCFF] border border-black p-3 sm:p-6 rounded-lg mb-6">
{editId && (
<div className="mb-4 p-3 bg-blue-100 border border-blue-400 rounded text-sm text-blue-800">
<strong>Bearbeitungsmodus:</strong> Sie bearbeiten einen bestehenden Eintrag. Klicken Sie auf &quot;Aktualisieren&quot;, um die Änderungen zu speichern, oder &quot;Abbrechen&quot;, um zur Neuerfassung zurückzukehren.
</div>
)}
<form onSubmit={handleSubmit}>
<div className="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-8 gap-3 sm:gap-2">
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Datum
<span className="block text-[10px] font-normal">{weekday}</span>
</label>
<input
type="date"
className={inputClass}
value={formData.Datum}
onChange={(e) => handleDateChange(e.target.value)}
required
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Zeit
<span className="block text-[10px] font-normal invisible">.</span>
</label>
<input
type="time"
className={inputClass}
value={formData.Zeit}
onChange={(e) => setFormData(prev => ({ ...prev, Zeit: e.target.value }))}
required
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Zucker
<span className="block text-[10px] font-normal">mg/dl</span>
</label>
<input
type="number"
className={numberInputClass}
min={0}
max={999}
value={formData.Zucker}
onChange={(e) => setFormData(prev => ({ ...prev, Zucker: e.target.value }))}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Essen
<span className="block text-[10px] font-normal invisible">.</span>
</label>
<textarea
className={`${inputClass} resize-none align-middle`}
value={formData.Essen}
onChange={(e) => setFormData(prev => ({ ...prev, Essen: e.target.value }))}
rows={1}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Gewicht
<span className="block text-[10px] font-normal">kg</span>
</label>
<input
type="number"
step="0.1"
className={numberInputClass}
min={0}
max={300}
value={formData.Gewicht}
onChange={(e) => setFormData(prev => ({ ...prev, Gewicht: e.target.value }))}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Druck sys
<span className="block text-[10px] font-normal">mmHg</span>
</label>
<input
type="number"
className={numberInputClass}
min={0}
max={300}
value={formData.DruckS}
onChange={(e) => setFormData(prev => ({ ...prev, DruckS: e.target.value }))}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Druck dia
<span className="block text-[10px] font-normal">mmHg</span>
</label>
<input
type="number"
className={numberInputClass}
min={0}
max={200}
value={formData.DruckD}
onChange={(e) => setFormData(prev => ({ ...prev, DruckD: e.target.value }))}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-center">
Puls
<span className="block text-[10px] font-normal">bpm</span>
</label>
<input
type="number"
className={numberInputClass}
min={0}
max={250}
value={formData.Puls}
onChange={(e) => setFormData(prev => ({ ...prev, Puls: e.target.value }))}
/>
</div>
</div>
<div className="flex justify-center gap-2 sm:gap-4 mt-6">
<button
type="submit"
disabled={isSubmitting}
className="bg-[#85B7D7] hover:bg-[#6a9fc5] text-black font-medium py-2 px-8 rounded-lg transition-colors disabled:opacity-50"
>
{isSubmitting ? (editId ? 'Aktualisieren...' : 'Speichern...') : (editId ? 'Aktualisieren' : 'Speichern')}
</button>
<button
type="button"
onClick={handleReset}
className="bg-[#85B7D7] hover:bg-[#6a9fc5] text-black font-medium py-2 px-8 rounded-lg transition-colors"
>
{editId ? 'Abbrechen' : 'Löschen'}
</button>
</div>
</form>
</div>
);
}