Files
werte-next/components/WerteForm.tsx
T
admin de452b55df Eingaben und Liste weiter feinjustieren
Desktop zeigt weiterhin 15 Einträge, Handy/Tablet-Hochformat nur die
letzten 5 (responsive Anzeige + separater Ladezustand). Datum, Zeit
und Zucker schmaler gemacht, damit sie bei Tablet-Hochformat nicht
überlappen und beim schmalen Smartphone nicht aus dem Rahmen ragen;
Zucker-Feldhöhe an die übrigen Felder angeglichen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 10:31:13 +02:00

294 lines
10 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`;
// Datum/Zeit/Zucker: schmaler, damit sie bei Tablet-Hochformat (sm:) und schmalem Smartphone nicht überlappen bzw. aus dem Rahmen ragen.
// py-1.5 statt py-1 gleicht die geringere Zeilenhöhe von text-xs aus, damit die Felder gleich hoch wie die übrigen (text-sm) Felder bleiben.
const compactInputClass = "w-full min-w-0 px-1 py-1.5 text-xs rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-none";
const compactNumberInputClass = `${compactInputClass} [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`;
// Datum/Zeit: nochmal 10px schmaler als die übrigen kompakten Felder.
const dateTimeInputClass = "w-[calc(100%-10px)] min-w-0 px-1 py-1.5 text-xs rounded border-2 border-gray-400 bg-white focus:border-blue-500 focus:outline-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={dateTimeInputClass}
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={dateTimeInputClass}
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={compactNumberInputClass}
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>
);
}