From 622ed1653b12a6a1f8597fb198676130c07424bb Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Mon, 15 Jun 2026 03:49:00 +0200 Subject: [PATCH] Account-Liste: Status-Spalte sortiert nach Premium-Restlaufzeit (Klick) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-Wunsch: in der Account-Liste auf "Status" klicken und nach Premium-Restlaufzeit sortieren (laengste<->kuerzeste). Da die Accounts pro Anbieter gruppiert sind, wird INNERHALB jeder Gruppe sortiert (dort sitzen die Premium-Tage). - Neuer Zustand accountStatusSort (none -> desc -> asc -> none) per Klick auf den Status-Spaltenkopf (mit ▼/▲-Indikator). - groupedAccountRows sortiert bei desc/asc jede Gruppe nach premiumUntilMs: Premium-Accounts nach Restlaufzeit (desc = laengste zuerst, asc = kuerzeste zuerst), Accounts ohne Premium/ohne Status bleiben am Ende. Reine Renderer-Aenderung. tsc=6, build ok. --- src/renderer/App.tsx | 25 +++++++++++++++++++++++-- src/renderer/styles.css | 2 ++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index cd7aa09..b03b232 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -2617,6 +2617,9 @@ export function App(): ReactElement { return rows; }, [configuredAccounts, settingsDraft, snapshot.settings]); + const [accountStatusSort, setAccountStatusSort] = useState<"none" | "desc" | "asc">("none"); + const cycleAccountStatusSort = (): void => setAccountStatusSort((s) => (s === "none" ? "desc" : s === "desc" ? "asc" : "none")); + const groupedAccountRows = useMemo(() => { const groups: { service: string; serviceLabel: string; rows: typeof accountRows }[] = []; const byService = new Map(); @@ -2630,8 +2633,26 @@ export function App(): ReactElement { } group.rows.push(row); } + if (accountStatusSort !== "none") { + const statuses = snapshot.settings?.debridAccountStatuses || {}; + const now = Date.now(); + const remainingMs = (row: (typeof accountRows)[number]): number => { + const st = row.accountId ? statuses[row.accountId] : null; + return st && st.premiumUntilMs && st.premiumUntilMs > now ? st.premiumUntilMs - now : -1; + }; + for (const group of groups) { + group.rows = [...group.rows].sort((a, b) => { + const ra = remainingMs(a); + const rb = remainingMs(b); + if (ra > 0 && rb > 0) return accountStatusSort === "desc" ? rb - ra : ra - rb; + if (ra > 0) return -1; + if (rb > 0) return 1; + return 0; + }); + } + } return groups; - }, [accountRows]); + }, [accountRows, accountStatusSort, snapshot.settings]); const [collapsedAccountGroups, setCollapsedAccountGroups] = useState>(() => { try { @@ -5403,7 +5424,7 @@ export function App(): ReactElement { Hoster Download-Traffic - Status + Status{accountStatusSort === "desc" ? " ▼" : accountStatusSort === "asc" ? " ▲" : ""} Benutzername Verfallsdatum Aktion diff --git a/src/renderer/styles.css b/src/renderer/styles.css index 453ab6b..1739eab 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -3321,6 +3321,8 @@ td { .acct2-expiry { font-variant-numeric: tabular-nums; color: var(--muted); } .acct2-head > span:nth-child(3), .acct2-traffic { text-align: center; } +.acct2-sortable { cursor: pointer; user-select: none; } +.acct2-sortable:hover { color: var(--text); } .acct2-user { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .acct2-status .account-validity-badge { margin-top: 0; } .acct2-nostatus { color: var(--muted); opacity: 0.6; font-variant-numeric: tabular-nums; }