Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
7.4 KiB
7.4 KiB
Title: Client Portal – Account Page Plan Date: 2025-08-08
Intro and Background / Rationale
- Goal: Add a first-class “Account” destination in the client portal where a client user can see their company details, current contract line, and invoices. Include a “Cancel Subscription” button stub (no backend wiring yet).
- Why: Today, billing info lives under Billing and company details under Company Settings. A concise Account page surfaced from the profile menu improves discoverability for end users and consolidates the most common read-only account tasks in one place.
- Scope: UI changes only. Read-only data fetch for company details, contract line, and invoices. Add a non-functional cancel subscription button stub for future wiring.
Phased To‑Do List (Dependent Order)
- Add “Account” to profile dropdown
- Scaffold
client-portal/accountroute and page - Fetch and display company details (read-only)
- Fetch and display contract line (+ cancel subscription stub)
- Fetch and display invoices list
- Handle permissions, empty, and loading states
- Final UX polish, instrumentation IDs, and docs
Project Background Details, Detailed Plan, Files to Modify, Etc.
Navigation and Entry Point
- Location:
server/src/components/layout/ClientPortalLayout.tsx- Add a new dropdown item labeled “Account” in the top-right profile dropdown alongside “Profile” and “Sign out”.
- Behavior:
onSelect={() => router.push('/client-portal/account')}. - Follow existing Radix Dropdown structure and styles; ensure unique element IDs per AI coding standards.
New Route and Page
- Add:
server/src/app/client-portal/account/page.tsx- Client component that renders a new
ClientAccountcomposite component (see below). - Title: “Account”.
- Sections: Company Details, Contract Line, Invoices.
- Keep page simple and fast: render minimal, high-signal information. Defer heavier interactions to their dedicated pages (e.g., Billing).
- Client component that renders a new
Data Sources (Server Actions already present)
-
Company Details
- Use:
getCurrentUser()→getUserCompanyId(user.user_id)→getCompanyById(companyId) - Locations:
server/src/lib/actions/user-actions/userActions.ts(getCurrentUser, getUserCompanyId)server/src/lib/actions/company-actions/companyActions.ts(getCompanyById)
- Permissions:
getCompanyByIdenforcesclient.readpermission; handle “no permission” with a friendly message.
- Use:
-
Contract Line
- Use:
getClientContractLine()fromserver/src/lib/actions/client-portal-actions/client-billing.ts - Displays: plan name, billing frequency, service category if present. If none, show “No active plan”.
- Use:
-
Invoices
- Use:
getClientInvoices()fromserver/src/lib/actions/client-portal-actions/client-billing.ts - Permissions: Function internally checks
billing:readwithclient === true; handle “no access” gracefully and hide the list (like BillingOverview does). - Optional drill-in: For later phases,
getInvoiceForRendering(invoiceId)for a quick detail dialog. Initial phase can link to/client-portal/billingfor full invoice exploration.
- Use:
Existing Components and Reuse Guidance
- BillingOverview exists:
server/src/components/client-portal/billing/BillingOverview.tsxand related tabs. It covers deeper billing dashboards and usage metrics. The Account page should present a compact summary to avoid duplication and heavy load; deep dives remain under Billing. - Account folder stubs exist:
server/src/components/client-portal/account/{BillingSection,ProfileSection,ServicesSection}.tsx, but these importserver/src/lib/actions/accountwhich does not exist. Treat these as legacy/out-of-date stubs and DO NOT reuse. Instead, use the already implemented client-portal actions noted above.
ClientAccount Component (new)
- Location:
server/src/components/client-portal/account/ClientAccount.tsx - Responsibilities:
- Read-only Company Details card: company name, website (properties.website/url), possibly logo if readily available via
getCompanyById(returnslogoUrl). - Contract Line card: plan name, billing frequency, service category (if any), and a “Cancel Subscription” button stub.
- Button ID:
cancel-subscription-button(no-op for now; show toast “Not implemented”).
- Button ID:
- Invoices table: invoice number, invoice date, total, status. Provide “View in Billing” link to
/client-portal/billingfor details.
- Read-only Company Details card: company name, website (properties.website/url), possibly logo if readily available via
- Loading/Empty/Error:
- Show lightweight skeletons while loading.
- If no permission for invoices, hide invoices section and show a subtle note.
- If no active plan, show a neutral empty state.
Files To Modify / Add
- Modify
server/src/components/layout/ClientPortalLayout.tsx: add “Account” item to dropdown.
- Add
server/src/app/client-portal/account/page.tsx: page that renders ClientAccount.server/src/components/client-portal/account/ClientAccount.tsx: new composite component implementing the three sections using existing server actions.
UI / Implementation Notes
- Follow docs/AI_coding_standards.md:
- Use
server/src/components/ui/*components; ensure all interactive elements have uniqueidattributes. - Use our custom Dialog if/when needed.
- Keep accessible labels and sensible empty states.
- Use
- Permissions:
- Company details require
client.read(enforced by action). Invoices list requiresbilling.readfor client portal (enforced by action). Contract Line fetch is allowed for all authenticated client users. - Gracefully handle lack of permissions with non-blocking messaging.
- Company details require
- Performance:
- Minimal queries on initial render; sequential fetch with
useEffectis acceptable (pattern used by existing components). Avoid large charts or heavy usage aggregations here.
- Minimal queries on initial render; sequential fetch with
- Navigation:
- Keep top “Billing” nav as-is. Account page is purposefully lightweight; link out to Billing for deeper needs.
Out of Scope (Future Work)
- Wiring “Cancel Subscription” to actual subscription management flow and backend.
- Adding invoice detail dialog in Account page (use Billing page for details in v1).
- Payment methods management; leave under Billing settings.
Acceptance Criteria
- Profile dropdown shows “Account” and navigates to
/client-portal/account. - Account page renders for an authenticated client user.
- Company details card shows company name and website when available (and logo if present in
getCompanyById). - Contract Line card shows current plan or a clear empty state; includes a visible, non-functional “Cancel Subscription” button.
- Invoices table appears when the user has invoice access; otherwise, it’s hidden or shows a friendly note.
- All interactive elements have stable IDs; errors and loading states are handled cleanly.
Implementor’s Scratchpad
- Company details: reuse the minimal subset of
CompanyDetailsSettingsfields but as read-only; avoid write actions here. - Data fetching pattern: mimic
BillingOverviewandClientProfilewith client components calling server actions inuseEffect. - IDs to add:
account-nav-item(dropdown),cancel-subscription-button,view-in-billing-link,invoices-table,company-details-card,billing-plan-card. - Edge cases:
- No company found for user → show an inline warning card.
- No plan found → neutral empty state.
- No invoices or no permission → hide table and show a note.
- Testing notes:
- Verify as client user with/without billing read permission.
- Verify empty states for new tenants without invoices.
- Quick pass on responsive layout.