import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { api } from "../api"; import CategorySelect from "../components/CategorySelect"; import Icon from "../components/Icon"; import IconChip from "../components/IconChip"; import Money from "../components/Money"; import { useToast } from "../toast"; import { useConfirm } from "../confirm"; import { useSettings } from "../settings"; import { gruppenFuer } from "../kategorien"; import { formatDate } from "../format"; // Was unterwegs erfasst wurde – per Kurzbefehl vom Telefon. Die Einträge bleiben // hier stehen, auch nachdem sie gebucht sind: Der spätere Kontoauszug gleicht // gegen sie ab, damit dieselbe Zahlung nicht ein zweites Mal in den Saldo läuft. export default function Eingang() { const { t } = useTranslation(); const { toast } = useToast(); const confirm = useConfirm(); const { baseCurrency } = useSettings(); const [rows, setRows] = useState(null); const [accounts, setAccounts] = useState([]); const [groups, setGroups] = useState([]); const expenseGroups = useMemo(() => gruppenFuer(groups, "expense"), [groups]); const incomeGroups = useMemo(() => gruppenFuer(groups, "income"), [groups]); const accountById = useMemo( () => Object.fromEntries(accounts.map((a) => [a.id, a])), [accounts]); async function laden() { try { const [items, acc, cat] = await Promise.all([ api.listInbox(), api.listAccounts(), api.listCategories(), ]); setRows(items); setAccounts(acc); setGroups(cat); } catch (e) { toast(e.message, "error"); } } useEffect(() => { laden(); }, []); async function zuordnen(item, categoryId) { if (categoryId == null) return; try { await api.setInboxCategory(item.id, categoryId); setRows((r) => r.map((x) => (x.id === item.id ? { ...x, category_id: categoryId } : x))); } catch (e) { toast(e.message, "error"); } } async function buchen(item) { try { await api.bookInboxItem(item.id); laden(); } catch (e) { toast(e.message, "error"); } } async function alleBuchen() { try { const r = await api.bookAllInbox(); toast(t("inbox.bookedN", { n: r.gebucht })); laden(); } catch (e) { toast(e.message, "error"); } } async function verwerfen(item) { if (!(await confirm({ title: t("inbox.discard"), message: t("inbox.discardConfirm"), danger: true, confirmLabel: t("inbox.discard"), }))) return; try { await api.discardInboxItem(item.id); laden(); } catch (e) { toast(e.message, "error"); } } if (rows === null) return
…
; return (

{t("inbox.title")}

{t("inbox.intro")}

{rows.some((r) => r.status === "pending" && r.account_id) && ( )}
{rows.length === 0 ? (
{t("inbox.empty")}
) : (
{rows.map((item) => { const konto = accountById[item.account_id]; const ausgabe = item.amount_cents < 0; return (
{item.payee || t("inbox.noText")}
{/* Jede Angabe für sich unzertrennlich: Auf dem Telefon brach sonst „Revolut CHF" um oder wurde gekürzt – und genau die Währung im Namen unterscheidet die Konten. */} {formatDate(item.date)} {" · "} {konto?.name || "—"} {item.source === "shortcut" && ` · ${t("inbox.viaShortcut")}`} {item.source === "mail" && ` · ${t("inbox.viaMail")}`} {item.status === "unclear" && ` · ${t("inbox.unclear")}`} {item.status === "booked" && ` · ${t("inbox.booked")}`}
zuordnen(item, id)} /> {item.status !== "booked" && item.account_id && ( )}
); })}
)}
); }