feat: Subscriber portal web — login, dashboard, invoices, tickets (FIBEROPS-243-246)

- New route group app/(portal)/ separate from admin app
- Minimal portal layout with FiberOps branding, no admin nav
- portal-auth-store.ts: Zustand store with portal_token in localStorage
- portal-api.ts: Axios instance using portal_token + X-Tenant-Slug
- Login page: tenant slug + account number + password form
- Dashboard: account info, subscription details, balance due, quick links
- Invoices page: table with status badges (PAID/PARTIAL/OVERDUE/SENT)
- Tickets page: ticket list + New Ticket modal (POST /portal/tickets)
- Client detail profile tab: Portal Access Enabled/Disabled field
- portalAccessEnabled added to Client type
This commit is contained in:
2026-04-01 00:36:10 +00:00
parent 45325b3e1b
commit eaa03c69e0
9 changed files with 759 additions and 0 deletions

19
app/(portal)/layout.tsx Normal file
View File

@@ -0,0 +1,19 @@
'use client';
export default function PortalLayout({ children }: { children: React.ReactNode }) {
return (
<div style={{ minHeight: '100vh', backgroundColor: '#F8FAFC', fontFamily: 'Fira Sans, sans-serif' }}>
<header style={{ backgroundColor: '#ffffff', borderBottom: '1px solid #E2E8F0', padding: '0 24px' }}>
<div style={{ maxWidth: 1200, margin: '0 auto', display: 'flex', alignItems: 'center', height: 56 }}>
<span style={{ fontSize: 20, fontWeight: 700, color: '#0891B2', letterSpacing: '-0.02em' }}>
FiberOps
</span>
<span style={{ marginLeft: 8, fontSize: 13, color: '#64748B', fontWeight: 500 }}>
Subscriber Portal
</span>
</div>
</header>
<main>{children}</main>
</div>
);
}