Files

104 lines
3.9 KiB
TypeScript

import { getVoucherStatus } from "./voucher-status";
import { isExpiringSoon } from "./vouchers";
export type ViewVoucher = {
id: number;
name: string;
anbieter: string;
ablaufdatum: Date | string | null;
createdAt: Date | string;
status: string;
wertTyp: string;
kategorie: string | null;
};
export type VoucherFilter = { q: string; status: string; kategorie: string; typ: string };
function statusMatch(v: ViewVoucher, status: string): boolean {
if (!status) return true;
const s = getVoucherStatus({ status: v.status, ablaufdatum: v.ablaufdatum ? new Date(v.ablaufdatum) : null });
if (status === "eingeloest") return s === "eingeloest";
if (status === "abgelaufen") return s === "abgelaufen";
if (status === "bald") return s === "aktiv" && isExpiringSoon(v.ablaufdatum);
if (status === "aktiv") return s === "aktiv";
return true;
}
export function filterVouchers<T extends ViewVoucher>(list: T[], f: VoucherFilter): T[] {
const q = f.q.trim().toLowerCase();
return list.filter((v) => {
if (!statusMatch(v, f.status)) return false;
if (f.kategorie === "ohne") {
if (v.kategorie) return false;
} else if (f.kategorie && v.kategorie !== f.kategorie) {
return false;
}
if ((f.typ === "euro" || f.typ === "prozent") && v.wertTyp !== f.typ) return false;
if (q && !(v.name.toLowerCase().includes(q) || v.anbieter.toLowerCase().includes(q))) return false;
return true;
});
}
export type SortKey = "neu" | "ablauf" | "name" | "anbieter";
function timeOrInfinity(d: Date | string | null): number {
if (!d) return Number.POSITIVE_INFINITY;
return new Date(d).getTime();
}
export function sortVouchers<T extends ViewVoucher>(list: T[], sort: string): T[] {
const arr = [...list];
if (sort === "ablauf") return arr.sort((a, b) => timeOrInfinity(a.ablaufdatum) - timeOrInfinity(b.ablaufdatum));
if (sort === "name") return arr.sort((a, b) => a.name.localeCompare(b.name, "de"));
if (sort === "anbieter")
return arr.sort(
(a, b) => a.anbieter.localeCompare(b.anbieter, "de") || a.name.localeCompare(b.name, "de")
);
return arr.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
}
export type GroupKey = "keine" | "anbieter" | "kategorie" | "ablauf";
export function ablaufGruppe(v: ViewVoucher): string {
const s = getVoucherStatus({ status: v.status, ablaufdatum: v.ablaufdatum ? new Date(v.ablaufdatum) : null });
if (s === "eingeloest") return "Eingelöst";
if (!v.ablaufdatum) return "Ohne Ablaufdatum";
if (s === "abgelaufen") return "Abgelaufen";
if (isExpiringSoon(v.ablaufdatum)) return "Bald fällig";
return "Später fällig";
}
const ABLAUF_REIHENFOLGE = ["Bald fällig", "Später fällig", "Ohne Ablaufdatum", "Abgelaufen", "Eingelöst"];
export function groupVouchers<T extends ViewVoucher>(list: T[], gruppe: string): { title: string; items: T[] }[] {
if (gruppe === "anbieter" || gruppe === "kategorie") {
const map = new Map<string, T[]>();
for (const v of list) {
const key = gruppe === "anbieter" ? v.anbieter : v.kategorie?.trim() || "Ohne Kategorie";
const items = map.get(key) ?? [];
items.push(v);
map.set(key, items);
}
return [...map.entries()]
.sort(([a], [b]) => a.localeCompare(b, "de"))
.map(([title, items]) => ({ title, items }));
}
if (gruppe === "ablauf") {
const map = new Map<string, T[]>();
for (const v of list) {
const key = ablaufGruppe(v);
const items = map.get(key) ?? [];
items.push(v);
map.set(key, items);
}
return ABLAUF_REIHENFOLGE.filter((t) => map.has(t)).map((title) => ({ title, items: map.get(title) as T[] }));
}
return [{ title: "", items: list }];
}
export function listCategories(list: { kategorie: string | null }[]): string[] {
return [...new Set(list.map((v) => v.kategorie?.trim()).filter((k): k is string => !!k))].sort((a, b) =>
a.localeCompare(b, "de")
);
}