iOS-App angefangen; Import-Modi; MHD-Formatierung; Gebinde in Ablauf-Ansichten
iOS (neu, ios/):
- SwiftUI-App: Login (Server + Keychain-Token), Kamera-Scanner (EAN/UPC/Code128),
Einlagern mit mehreren Chargen und eigenem MHD, Auslagern mit Chargenauswahl
oder FEFO, Artikelsuche, Anlegen mit Open-Food-Facts-Vorbefuellung.
- Home-Screen-Shortcuts: Schnellaktionen (langer Druck) und URL-Schema
projectgood://checkin | ://checkout fuer eigene Symbole via Kurzbefehle.
- project.yml (XcodeGen) + README mit Build-Anleitung. NICHT kompiliert - auf
diesem Rechner ist kein Xcode vorhanden.
Import-Modi (wie besprochen sinnvoll):
- add (Standard, nichts loeschen), replace_listed (Bestaende der in der Datei
genannten Produkte ersetzen - fuer Inventur), replace_all (alles ersetzen).
Geleerte Bestaende werden als Korrektur-Bewegung protokolliert; die Oberflaeche
fragt bei den zerstoerenden Modi nach.
Anzeige:
- "Bald ablaufend"/"Abgelaufen" zeigen jetzt das Gebinde ("1 Glas") mit der
Basiseinheit klein darunter (ExpiringItem liefert die Einheiten mit).
- MHD als Zeitspanne mit korrektem Numerus: "in 3 Tagen", "in 1 Woche",
"vor 2 Wochen", dazu heute/morgen/gestern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,30 @@ export function isExpired(dateStr) {
|
||||
return d != null && d < 0;
|
||||
}
|
||||
|
||||
// MHD lesbar als Zeitspanne: "in 3 Tagen", "in 1 Woche", "vor 2 Wochen".
|
||||
// Deutsch nach "in"/"vor" steht im Dativ: 1 Tag / 3 Tagen, 1 Woche / 2 Wochen.
|
||||
export function relativeExpiry(daysLeft) {
|
||||
if (daysLeft == null) return "";
|
||||
if (daysLeft === 0) return "heute";
|
||||
if (daysLeft === 1) return "morgen";
|
||||
if (daysLeft === -1) return "gestern";
|
||||
|
||||
const abs = Math.abs(daysLeft);
|
||||
let value;
|
||||
let unit;
|
||||
if (abs < 7) {
|
||||
value = abs;
|
||||
unit = value === 1 ? "Tag" : "Tagen";
|
||||
} else if (abs < 60) {
|
||||
value = Math.round(abs / 7);
|
||||
unit = value === 1 ? "Woche" : "Wochen";
|
||||
} else {
|
||||
value = Math.round(abs / 30);
|
||||
unit = value === 1 ? "Monat" : "Monaten";
|
||||
}
|
||||
return daysLeft > 0 ? `in ${value} ${unit}` : `vor ${value} ${unit}`;
|
||||
}
|
||||
|
||||
// CSS-Zeilenklasse je MHD: rot wenn abgelaufen, gelb wenn innerhalb der Warnfrist.
|
||||
export function expiryRowClass(dateStr, warnDays = 7) {
|
||||
const d = daysUntil(dateStr);
|
||||
@@ -85,6 +109,23 @@ export function buildUnitOptions(product, units) {
|
||||
return opts;
|
||||
}
|
||||
|
||||
// Leitangabe einer Menge in Artikeleinheiten (Gebinde), sonst in der Produkteinheit.
|
||||
// Erwartet ein Objekt mit quantity, package_size, package_label, unit_name, unit_factor, base_unit.
|
||||
export function articlePrimary(item) {
|
||||
if (item.package_size > 0) {
|
||||
return `${fmt(item.quantity / item.package_size)} ${item.package_label || "Packung"}`;
|
||||
}
|
||||
return `${fmt(item.quantity / (item.unit_factor || 1))} ${item.unit_name || unitShort(item.base_unit)}`;
|
||||
}
|
||||
|
||||
// Untermenge in der Basiseinheit – nur wenn sie sich von der Leitangabe unterscheidet.
|
||||
export function articleSecondary(item) {
|
||||
if (item.package_size > 0 || (item.unit_factor || 1) !== 1) {
|
||||
return `${fmt(item.quantity)} ${unitShort(item.base_unit)}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Bestand eines Produkts in seiner Anzeigeeinheit, z.B. "1,5 Kilogramm".
|
||||
export function stockLabel(product) {
|
||||
const factor = product.unit_factor || 1;
|
||||
|
||||
Reference in New Issue
Block a user