feat(blister-form): update blister form structure to include separate start date and time fields
This commit is contained in:
+50
-6
@@ -42,7 +42,7 @@ type PlannerRow = {
|
||||
enough: boolean;
|
||||
};
|
||||
|
||||
type FormBlister = { usage: string; every: string; start: string };
|
||||
type FormBlister = { usage: string; every: string; startDate: string; startTime: string };
|
||||
|
||||
type FormState = {
|
||||
name: string;
|
||||
@@ -59,7 +59,15 @@ type FormState = {
|
||||
blisters: FormBlister[];
|
||||
};
|
||||
|
||||
const defaultBlister = (): FormBlister => ({ usage: "1", every: "1", start: toInputValue(new Date().toISOString()) });
|
||||
const defaultBlister = (): FormBlister => {
|
||||
const now = new Date();
|
||||
return {
|
||||
usage: "1",
|
||||
every: "1",
|
||||
startDate: toDateValue(now),
|
||||
startTime: toTimeValue(now)
|
||||
};
|
||||
};
|
||||
|
||||
const defaultForm = (): FormState => ({ name: "", genericName: "", takenBy: "", packCount: "1", stripsPerPack: "1", tabsPerStrip: "1", looseTablets: "0", pillWeightMg: "", expiryDate: "", notes: "", intakeRemindersEnabled: false, blisters: [defaultBlister()] });
|
||||
|
||||
@@ -659,7 +667,12 @@ function AppContent() {
|
||||
expiryDate: med.expiryDate ? med.expiryDate.slice(0, 10) : "",
|
||||
notes: med.notes ?? "",
|
||||
intakeRemindersEnabled: med.intakeRemindersEnabled ?? false,
|
||||
blisters: med.blisters.map((s) => ({ usage: String(s.usage), every: String(s.every), start: toInputValue(s.start) })),
|
||||
blisters: med.blisters.map((s) => ({
|
||||
usage: String(s.usage),
|
||||
every: String(s.every),
|
||||
startDate: toDateValue(s.start),
|
||||
startTime: toTimeValue(s.start)
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -691,7 +704,11 @@ function AppContent() {
|
||||
expiryDate: form.expiryDate || null,
|
||||
notes: form.notes.trim() || null,
|
||||
intakeRemindersEnabled: form.intakeRemindersEnabled,
|
||||
blisters: form.blisters.map((s) => ({ usage: Number(s.usage) || 0, every: Math.max(1, Number(s.every) || 1), start: toIsoString(s.start) })),
|
||||
blisters: form.blisters.map((s) => ({
|
||||
usage: Number(s.usage) || 0,
|
||||
every: Math.max(1, Number(s.every) || 1),
|
||||
start: toIsoString(combineDateAndTime(s.startDate, s.startTime))
|
||||
})),
|
||||
};
|
||||
|
||||
const method = editingId ? "PUT" : "POST";
|
||||
@@ -1349,8 +1366,12 @@ function AppContent() {
|
||||
<input type="number" min="1" value={s.every} onChange={(e) => setBlisterValue(idx, "every", e.target.value)} />
|
||||
</label>
|
||||
<label>
|
||||
{t('form.blisters.start')}
|
||||
<input type="datetime-local" step="60" value={s.start} onChange={(e) => setBlisterValue(idx, "start", e.target.value)} />
|
||||
{t('form.blisters.startDate')}
|
||||
<input type="date" value={s.startDate} onChange={(e) => setBlisterValue(idx, "startDate", e.target.value)} />
|
||||
</label>
|
||||
<label>
|
||||
{t('form.blisters.startTime')}
|
||||
<input type="time" value={s.startTime} onChange={(e) => setBlisterValue(idx, "startTime", e.target.value)} />
|
||||
</label>
|
||||
</div>
|
||||
{form.blisters.length > 1 && (
|
||||
@@ -2246,6 +2267,29 @@ function toIsoString(value: string) {
|
||||
return Number.isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString();
|
||||
}
|
||||
|
||||
function toDateValue(date: Date | string): string {
|
||||
const d = typeof date === 'string' ? new Date(date) : date;
|
||||
if (Number.isNaN(d.getTime())) {
|
||||
const now = new Date();
|
||||
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function toTimeValue(date: Date | string): string {
|
||||
const d = typeof date === 'string' ? new Date(date) : date;
|
||||
if (Number.isNaN(d.getTime())) {
|
||||
const now = new Date();
|
||||
return `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
|
||||
}
|
||||
return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function combineDateAndTime(dateStr: string, timeStr: string): string {
|
||||
// Combine separate date and time strings into ISO format
|
||||
return `${dateStr}T${timeStr}`;
|
||||
}
|
||||
|
||||
function toInputValue(value: string) {
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
|
||||
@@ -119,7 +119,8 @@
|
||||
"everyDays": "Alle (Tage)",
|
||||
"every": "alle",
|
||||
"from": "ab",
|
||||
"start": "Start (Datum/Uhrzeit)"
|
||||
"startDate": "Datum",
|
||||
"startTime": "Uhrzeit"
|
||||
}
|
||||
},
|
||||
"planner": {
|
||||
|
||||
@@ -121,7 +121,8 @@
|
||||
"everyDays": "Every (days)",
|
||||
"every": "every",
|
||||
"from": "from",
|
||||
"start": "Start (date/time)"
|
||||
"startDate": "Date",
|
||||
"startTime": "Time"
|
||||
}
|
||||
},
|
||||
"planner": {
|
||||
|
||||
+52
-1
@@ -280,9 +280,17 @@ body {
|
||||
.blister-pill { display: flex; gap: 0.4rem; flex-wrap: wrap; }
|
||||
.blister-row { display: flex; flex-direction: column; gap: 0.75rem; background: var(--bg-tertiary); border: 1px solid var(--border-primary); padding: 1rem; border-radius: 8px; margin-bottom: 0.65rem; transition: background 200ms ease; }
|
||||
[data-theme=\"light\"] .blister-row { background: var(--bg-tertiary); }
|
||||
.blister-row .blister-inputs { display: grid; grid-template-columns: 1fr 1fr 2fr; gap: 1rem; align-items: end; }
|
||||
.blister-row .blister-inputs { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 0.75rem; align-items: end; }
|
||||
.blister-row button { align-self: flex-end; width: auto; }
|
||||
.blister-row:last-child { margin-bottom: 0; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.blister-row .blister-inputs {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.blisters h3 { margin: 0; }
|
||||
.gap { gap: 0.6rem; }
|
||||
|
||||
@@ -960,6 +968,8 @@ textarea {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.setting-row {
|
||||
@@ -973,6 +983,13 @@ textarea {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.setting-row {
|
||||
padding: 0.75rem;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.setting-row.inline {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
@@ -1282,6 +1299,30 @@ textarea {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* Notification Matrix Mobile */
|
||||
@media (max-width: 480px) {
|
||||
.notification-matrix {
|
||||
margin: 0 -0.5rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.matrix-header,
|
||||
.matrix-row {
|
||||
grid-template-columns: 1fr 60px 60px;
|
||||
padding: 0.6rem 0.75rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.matrix-channel,
|
||||
.matrix-header .matrix-label {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.matrix-row .matrix-label {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Settings Grid - Two column layout */
|
||||
.settings-grid {
|
||||
display: grid;
|
||||
@@ -1376,6 +1417,16 @@ textarea {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.channel-content {
|
||||
padding: 0 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.channel-toggle {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.channel-config {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user