- In-app reminders: task due (skips rescheduled tasks, catch-up wording) and a per-user morning digest step in the daily job - Frontend: "Als Nächstes" on the colony page, "Heute" on the dashboard, inspection-due card, season chip, apiary overview fields, cleanup sheet for ended colonies - Frontend: plausibility warnings that stay until dismissed, withdrawal spans in the calendar, notification bell with categories and links, notification settings in the profile - ARCHITECTURE.md: T4a sections 11.1-11.10, assumptions 31-41, handler table and daily job step order Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
import { toast } from "sonner";
|
|
import type { PlausibilityWarning } from "./types";
|
|
|
|
/** Warnings about food safety must not time out: they stay until dismissed. */
|
|
function mustStay(warnings: readonly PlausibilityWarning[]): boolean {
|
|
return warnings.some(
|
|
(warning) =>
|
|
warning.severity === "WARNUNG" || warning.severity === "BESTAETIGEN",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* After a successful save: "<saved> · 1 Warnung" plus one line per text. The
|
|
* record is saved either way; warnings only point at something to check.
|
|
* A WARNUNG or BESTAETIGEN stays until the person dismisses it. Does nothing
|
|
* for an empty list - the caller shows its own success then.
|
|
*/
|
|
export function toastWarnings(
|
|
warnings: readonly PlausibilityWarning[],
|
|
savedLabel = "Gespeichert",
|
|
): void {
|
|
if (warnings.length === 0) return;
|
|
const count = warnings.length;
|
|
const title = `${savedLabel} \u00b7 ${count} ${count === 1 ? "Warnung" : "Warnungen"}`;
|
|
const description = warnings.map((warning) => warning.message).join("\n");
|
|
if (!mustStay(warnings)) {
|
|
toast.warning(title, {
|
|
description,
|
|
classNames: { description: "whitespace-pre-line" },
|
|
});
|
|
return;
|
|
}
|
|
toast.warning(title, {
|
|
description,
|
|
duration: Infinity,
|
|
closeButton: true,
|
|
action: { label: "Verstanden", onClick: () => undefined },
|
|
classNames: {
|
|
description: "whitespace-pre-line",
|
|
actionButton: "min-h-11 min-w-11",
|
|
closeButton: "size-11",
|
|
},
|
|
});
|
|
}
|