The /inbox surface drops "Genehmigungen" framing in favour of "Inbox" and renders the unified feed. - shape-list.ts: factor renderApprovalRow out of renderApprovalList so it can be reused alongside renderProjectEventInboxRow inside the new renderInboxList (row_action="inbox"). Project_event rows show a compact stream layout with an Öffnen link pointing at the right project tab (deadlines / appointments / notes). - filter-bar gets two new axes: unread_only (binary chip cluster) + inbox_focus (4-chip coarse cluster: Alles / Genehmigungen / +Termine / +Fristen). Both round-trip via url-codec; inbox_focus translates to (sources, project_event.event_types, approval_request.entity_types) at the bar's resolve step (applyInboxFocusOverlay). - FilterSpec gains a top-level unread_only flag; the bar writes it when the user toggles the chip; the server overlays the cursor. - /inbox header: new "Alles als gelesen markieren" button POSTs /api/inbox/mark-all-seen with up_to=<newest visible row> for race-safety against a second tab. - INBOX_AXES adds project + project_event_kind as advanced override chips so power users can still narrow per kind. - i18n: inbox.title.feed / inbox.heading.feed / inbox.action.mark_all_seen / inbox.action.open / inbox.empty.feed / views.bar.unread_only.* / views.bar.inbox_focus.* (DE + EN). - url-codec round-trip tests for the two new axes.
92 lines
3.8 KiB
TypeScript
92 lines
3.8 KiB
TypeScript
import { h } from "./jsx";
|
|
import { Sidebar } from "./components/Sidebar";
|
|
import { PaliadinWidget } from "./components/PaliadinWidget";
|
|
import { BottomNav } from "./components/BottomNav";
|
|
import { Footer } from "./components/Footer";
|
|
import { PWAHead } from "./components/PWAHead";
|
|
|
|
// /inbox — t-paliad-249 unified inbox feed.
|
|
//
|
|
// Since t-paliad-249 the page is a thin shell around the FilterBar +
|
|
// result list as before, but the InboxSystemView now spans both
|
|
// approval_request and project_event sources. Rows render via
|
|
// shape-list.ts's row_action="inbox" dispatch — approval rows keep
|
|
// the existing diff + approve/reject/revoke markup, project_event
|
|
// rows render as compact stream items.
|
|
//
|
|
// The legacy `?tab=` URL is preserved by the client: ?tab=mine maps
|
|
// to ?a_role=self_requested before the bar mounts so old bookmarks
|
|
// (sidebar bell, Genehmigungen email links) keep landing on the
|
|
// expected sub-view.
|
|
|
|
export function renderInbox(): string {
|
|
return "<!DOCTYPE html>" + (
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<meta name="theme-color" content="#BFF355" />
|
|
<PWAHead />
|
|
<title data-i18n="inbox.title.feed">Inbox — Paliad</title>
|
|
<link rel="stylesheet" href="/assets/global.css" />
|
|
</head>
|
|
<body className="has-sidebar">
|
|
<Sidebar currentPath="/inbox" />
|
|
<BottomNav currentPath="/inbox" />
|
|
|
|
<main>
|
|
<section className="tool-page">
|
|
<div className="container">
|
|
<div className="tool-header">
|
|
<div className="entity-header-row">
|
|
<div>
|
|
<h1 data-i18n="inbox.heading.feed">Inbox</h1>
|
|
<p className="tool-subtitle" data-i18n="inbox.subtitle.feed">
|
|
Neuigkeiten zu Ihren Projekten und offene Genehmigungen.
|
|
</p>
|
|
</div>
|
|
<div className="inbox-header-actions">
|
|
<button
|
|
type="button"
|
|
id="inbox-mark-all-seen"
|
|
className="btn-secondary"
|
|
data-i18n="inbox.action.mark_all_seen"
|
|
>
|
|
Alles als gelesen markieren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="inbox-filter-bar" />
|
|
|
|
<div className="agenda-loading" id="inbox-loading" data-i18n="agenda.loading">Lädt …</div>
|
|
<div className="entity-empty" id="inbox-empty" style="display:none" />
|
|
<div id="inbox-results" />
|
|
|
|
{/* t-paliad-154 — admin-only nudge surfaced when:
|
|
- the user is global_admin
|
|
- the inbox is empty (no pending / mine)
|
|
- no approval_policies row exists firm-wide
|
|
Hidden in all other cases. Wires via /api/admin/approval-policies/seeded. */}
|
|
<div className="inbox-admin-nudge" id="inbox-admin-nudge" style="display:none">
|
|
<h3 data-i18n="inbox.empty.admin_nudge.title">Noch keine Genehmigungspflichten konfiguriert?</h3>
|
|
<p data-i18n="inbox.empty.admin_nudge.body">
|
|
Lege fest, welche Lifecycle-Events 4-Augen-Prüfung erfordern.
|
|
</p>
|
|
<a href="/admin/approval-policies" className="btn-primary btn-cta-lime" data-i18n="inbox.empty.admin_nudge.cta">
|
|
Genehmigungspflichten konfigurieren
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<Footer />
|
|
<PaliadinWidget />
|
|
</main>
|
|
|
|
<script src="/assets/inbox.js" defer />
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|