Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
23 KiB
Invoicing Frontend Overhaul Plan
Overview
Transform the invoicing experience by combining "Generate Invoices" and "Invoices" tabs into a single, cohesive "Invoicing" tab with three sub-tabs (Generate, Drafts, Finalized). This follows the same design patterns established in your contract improvements.
Goals
- Unified workflow: Generate → Review Drafts → Finalize all in one place
- Consistent design: Apply contract UI improvements (badges, status indicators, client drawers, contract names)
- Less tab switching: Everything invoice-related in one location
- Clear mental model: Three explicit stages of invoicing
Current State Analysis
Existing Components
- GenerateInvoices.tsx: Container for three invoice types (automatic, manual, prepayment)
- AutomaticInvoices.tsx: Two-column layout with billing cycles (Ready to Invoice | Already Invoiced)
- ManualInvoices.tsx: Create/edit manual invoices with line items
- PrepaymentInvoices.tsx: Generate prepayment invoices for credit
- Invoices.tsx: Draft/Finalized tabs with invoice list and preview
What's Working Well
- ✅ Two-column layout in AutomaticInvoices (Ready | Already Invoiced)
- ✅ Contract names shown in billing cycle tables
- ✅ Client names are clickable (open drawer)
- ✅ Badge system for status indicators
- ✅ Preview functionality with template selection
- ✅ Bulk actions for invoices
Pain Points to Address
- ❌ Generate Invoices and Invoices are separate tabs (extra navigation)
- ❌ Users must switch tabs to see draft invoices after generation
- ❌ Invoice status not immediately clear (need to click between tabs)
- ❌ Manual and prepayment invoices hidden in dropdown selector
File Changes
1. Create New InvoicingHub Component
File: /server/src/components/billing-dashboard/InvoicingHub.tsx
Purpose: Main container for all invoicing functionality
Key Features:
- Three-tab layout using CustomTabs: Generate | Drafts | Finalized
- State management for active tab, filters, search
- Coordinate data loading across all tabs
- Empty states for each tab with helpful guidance
- URL state management for deep linking (
?tab=invoicing&subtab=generate)
Props:
interface InvoicingHubProps {
initialServices: IService[];
}
State:
const [activeSubTab, setActiveSubTab] = useState<'generate' | 'drafts' | 'finalized'>('generate');
const [refreshTrigger, setRefreshTrigger] = useState(0);
2. Create Generate Tab Component
File: /server/src/components/billing-dashboard/invoicing/GenerateTab.tsx
Purpose: Consolidate all invoice generation methods in one place
Sections:
-
Quick Actions Card (top)
- Buttons: Generate Automatic | Create Manual | Create Prepayment
- Active button shows corresponding form below
-
Automatic Invoices (default active)
- Migrate content from AutomaticInvoices.tsx
- Two-column DataTable layout:
- Left: Ready to Invoice (with contract names, client links, badges)
- Right: Already Invoiced (with reverse action)
- Preview functionality
- Bulk selection and generation
-
Manual Invoices (when activated)
- Render ManualInvoices component
- Enhanced with contract selection dropdown
- Better validation and error messages
-
Prepayment Invoices (when activated)
- Render PrepaymentInvoices component
- Integrated into main layout
Improvements:
- ✨ Quick Start Guide for first-time users (similar to contracts)
- ✨ Enhanced filtering: by client, contract, status
- ✨ Contract dropdown in manual invoice creation
- ✨ Success message with "View in Drafts" link after generation
Key Imports:
import AutomaticInvoices from '../AutomaticInvoices';
import ManualInvoices from '../ManualInvoices';
import PrepaymentInvoices from '../PrepaymentInvoices';
import { QuickStartGuide } from './QuickStartGuide';
3. Create Drafts Tab Component
File: /server/src/components/billing-dashboard/invoicing/DraftsTab.tsx
Purpose: Review and manage draft invoices before finalization
Layout: Split view (60/40)
- Left Side (60%): Invoice list DataTable
- Right Side (40%): Preview panel (when invoice selected)
DataTable Columns:
- Checkbox (bulk select)
- Invoice Number
- Client (clickable → drawer)
- Contract (filterable)
- Amount
- Credit Applied
- Date
- Actions (dropdown menu)
Actions Menu:
- Preview (click row or action)
- Manage Items (edit manual items)
- Finalize Invoice
- Download PDF
- Send Email
Bulk Actions Dropdown (top-right):
- Finalize Selected
- Download PDFs
- Send Emails
Filters (top-left):
- Search by client/invoice number
- Filter by contract (dropdown)
- Filter by date range
- Filter by amount range
Preview Panel:
- Template selector dropdown
- Invoice preview (using TemplateRenderer)
- Credit information (if applicable)
- Action buttons:
- Finalize Invoice (primary)
- Download PDF
- Send Email
- Edit Items
Empty State:
No draft invoices
Generate invoices from the Generate tab to see them here.
[Go to Generate Tab] button
4. Create Finalized Tab Component
File: /server/src/components/billing-dashboard/invoicing/FinalizedTab.tsx
Purpose: View and manage finalized invoices
Layout: Same split view as Drafts (60/40)
DataTable Columns (adds one column):
- Checkbox
- Invoice Number
- Client (clickable)
- Contract (filterable)
- Amount
- Credit Applied
- Date
- Finalized Date (new)
- Actions
Actions Menu:
- Preview
- Download PDF
- Send Email
- Unfinalize (for corrections)
Bulk Actions:
- Download PDFs
- Send Emails
- Unfinalize Selected
Additional Features:
- Export to CSV
- Date range filtering (finalized date)
- Historical reporting view
Preview Panel:
- Read-only preview
- Download/Email buttons
- Unfinalize option (with warning)
5. Shared Invoice Preview Component
File: /server/src/components/billing-dashboard/invoicing/InvoicePreviewPanel.tsx
Purpose: Reusable preview panel for both Drafts and Finalized tabs
Props:
interface InvoicePreviewPanelProps {
invoiceId: string | null;
templates: IInvoiceTemplate[];
selectedTemplateId: string | null;
onTemplateChange: (templateId: string) => void;
onFinalize?: () => Promise<void>;
onDownload?: () => Promise<void>;
onEmail?: () => Promise<void>;
onEdit?: () => void;
isFinalized: boolean;
}
Features:
- Template selector (CustomSelect with icons)
- Loading state while fetching invoice data
- Error display
- Invoice preview using TemplateRenderer
- Credit expiration info
- Contextual action buttons based on invoice status
6. Quick Start Guide for Invoicing
File: /server/src/components/billing-dashboard/invoicing/InvoicingQuickStart.tsx
Purpose: Help first-time users understand invoicing workflow
Content:
- Set up contracts first → Link to Contracts tab
- Billing cycles generate automatically → Explanation
- Review drafts before finalizing → Best practice
- Finalized invoices are immutable → Warning
Pattern: Follow QuickStartGuide.tsx from contracts (expandable/dismissible)
7. Update BillingDashboard
File: /server/src/components/billing-dashboard/BillingDashboard.tsx
Changes:
// OLD tabs array
const tabs = [
'contracts',
'generate-invoices', // ❌ Remove
'invoices', // ❌ Remove
'invoice-templates',
// ...
];
// NEW tabs array
const tabs = [
'contracts',
'invoicing', // ✅ Add (replaces both)
'invoice-templates',
// ...
];
Tab Content:
<Tabs.Content value="invoicing">
<InvoicingHub initialServices={initialServices} />
</Tabs.Content>
Remove:
generate-invoicestab contentinvoicestab content
8. Keep Supporting Components (with enhancements)
ManualInvoices.tsx
Enhancements:
- Add contract selection dropdown (optional)
- Link invoice to contract if selected
- Better validation messages
- Show contract context when editing automatic invoice
PrepaymentInvoices.tsx
Enhancements:
- Improved layout to match manual invoices
- Contract association option
- Clear explanation of credit application
AutomaticInvoices.tsx
Changes:
- May keep as-is and import into GenerateTab
- OR refactor into smaller sub-components:
- ReadyToInvoiceTable.tsx
- AlreadyInvoicedTable.tsx
- BillingCyclePreview.tsx
UI/UX Improvements
Visual Consistency
Badge System:
// Status badges
Active: bg-green-100 text-green-800 border-green-200
Early: bg-yellow-100 text-yellow-800 border-yellow-200
Invoiced: bg-blue-100 text-blue-800 border-blue-200
Draft: bg-gray-100 text-gray-800 border-gray-200
Finalized: bg-green-100 text-green-800 border-green-200
Icons (from lucide-react):
- FileText: Invoices
- DollarSign: Amounts
- Clock: Billing cycles
- CheckCircle: Finalized
- AlertTriangle: Warnings
- Eye: Preview
- Download: PDF download
- Mail: Email
- MoreVertical: Actions menu
Spacing:
- Card padding:
p-6 - Section gaps:
space-y-4 - Button groups:
gap-2 - Table row height: Consistent with contracts
Colors:
- Primary actions: Blue (#3B82F6)
- Success: Green (#10B981)
- Warning: Yellow (#F59E0B)
- Danger: Red (#EF4444)
- Gradients:
from-blue-600 to-purple-600
User Interactions
Client Names:
- Clickable links (blue, underline on hover)
- Opens ClientDetails in drawer
- Quick view mode enabled
Contract Names:
- Display prominently in all tables
- Filterable via dropdown
- Click → navigate to contract detail?
Search:
- Global search across client, invoice number, contract
- Debounced input (300ms)
- Clear button when active
Filters:
- DropdownMenu components
- Multiple filters can be active
- "Clear all filters" button when any active
- Filter counts shown in button text
Bulk Actions:
- Checkbox selection (individual + select all)
- Actions button disabled when no selection
- Show count in button: "Actions (3 selected)"
- Confirmation dialogs for destructive actions
Row Click:
- Click row → select for preview
- Don't trigger on checkbox/button clicks (stopPropagation)
- Highlight selected row
- Cursor pointer on hover
Empty States
No Billing Cycles (Generate tab):
🎯 Ready to Invoice Clients
No billing cycles are ready yet. Billing cycles generate automatically
based on your client contracts and billing frequencies.
[Quick Start Guide]
- Set up contracts for your clients
- Configure billing frequencies
- Billing cycles will appear here when ready
[View Contracts] button
No Drafts:
📋 No Draft Invoices
You don't have any draft invoices yet.
Generate invoices from the Generate tab, and they'll appear here
for review before finalization.
[Go to Generate Tab] button
No Finalized:
✅ No Finalized Invoices
Finalized invoices will appear here once you've approved and
finalized your drafts.
Tip: Always review invoices in the Drafts tab before finalizing.
[View Drafts] button
Search/Filter No Results:
🔍 No invoices found
Try adjusting your search or filter criteria.
[Clear Filters] button
Data Flow
Generate Tab Data Flow
On Mount:
- Load
periodsviagetAvailableBillingPeriods() - Load
invoicedPeriodsviagetInvoicedBillingCycles() - Load
clientsviagetAllClients() - Load
servicesviagetServices()
User Actions:
- Select billing cycles → Enable "Generate" button
- Click "Generate Invoices" → Call
generateInvoice(billingCycleId)for each - On success → Refresh data + Show success message + Link to Drafts tab
- Click "Create Manual" → Show ManualInvoices form
- Click "Create Prepayment" → Show PrepaymentInvoices form
State Management:
const [selectedPeriods, setSelectedPeriods] = useState<Set<string>>(new Set());
const [isGenerating, setIsGenerating] = useState(false);
const [activeForm, setActiveForm] = useState<'automatic' | 'manual' | 'prepayment'>('automatic');
Drafts Tab Data Flow
On Mount:
- Load all invoices via
fetchAllInvoices() - Filter:
invoices.filter(inv => !inv.finalized_at) - Load templates via
getInvoiceTemplates()
On Invoice Selection:
- Set
selectedInvoiceIdin state - Call
getInvoiceForRendering(selectedInvoiceId) - Map to WasmInvoiceViewModel via
mapDbInvoiceToWasmViewModel() - Render in preview panel
User Actions:
- Click row → Preview invoice
- Click "Finalize" →
finalizeInvoice(invoiceId)→ Move to Finalized tab - Click "Edit Items" → Open ManualInvoices in edit mode
- Click "Download PDF" →
scheduleInvoiceZipAction([invoiceId])→ Auto-finalize - Click "Send Email" →
scheduleInvoiceEmailAction([invoiceId])→ Auto-finalize
State Management:
const [selectedInvoiceId, setSelectedInvoiceId] = useState<string | null>(null);
const [selectedTemplateId, setSelectedTemplateId] = useState<string | null>(null);
const [detailedInvoiceData, setDetailedInvoiceData] = useState<WasmInvoiceViewModel | null>(null);
const [isPreviewLoading, setIsPreviewLoading] = useState(false);
Finalized Tab Data Flow
On Mount:
- Load all invoices via
fetchAllInvoices() - Filter:
invoices.filter(inv => inv.finalized_at) - Load templates via
getInvoiceTemplates()
Preview: Same as Drafts tab
User Actions:
- Click "Download PDF" →
scheduleInvoiceZipAction([invoiceId]) - Click "Send Email" →
scheduleInvoiceEmailAction([invoiceId]) - Click "Unfinalize" →
unfinalizeInvoice(invoiceId)(with warning dialog)
Implementation Phases
✅ Phase 0: Planning & Documentation
- Analyze current state
- Design new structure
- Create this plan document
- Get approval from user
Phase 1: Component Structure Setup
Goal: Create skeleton components and routing
Tasks:
- Create
/server/src/components/billing-dashboard/invoicing/directory - Create
InvoicingHub.tsxwith basic tab structure - Create empty
GenerateTab.tsx,DraftsTab.tsx,FinalizedTab.tsx - Update
BillingDashboard.tsxrouting - Test tab navigation works
Files Created:
/server/src/components/billing-dashboard/InvoicingHub.tsx/server/src/components/billing-dashboard/invoicing/GenerateTab.tsx/server/src/components/billing-dashboard/invoicing/DraftsTab.tsx/server/src/components/billing-dashboard/invoicing/FinalizedTab.tsx
Files Modified:
/server/src/components/billing-dashboard/BillingDashboard.tsx
Testing:
- Navigate to billing tab
- Click Invoicing tab
- Sub-tabs render without errors
- URL state updates correctly
- Empty states show properly
Approval Required: ✋ Wait for user approval before proceeding
Phase 2: Generate Tab Implementation
Goal: Fully functional invoice generation
Tasks:
- Migrate AutomaticInvoices content into GenerateTab
- Add tab/button switcher for automatic/manual/prepayment
- Integrate ManualInvoices component
- Integrate PrepaymentInvoices component
- Add InvoicingQuickStart guide
- Implement contract filtering
- Add success messaging with "View in Drafts" link
- Test full generation workflow
Files Modified:
/server/src/components/billing-dashboard/invoicing/GenerateTab.tsx
Files Created:
/server/src/components/billing-dashboard/invoicing/InvoicingQuickStart.tsx
Testing:
- Generate automatic invoices
- Create manual invoice
- Create prepayment invoice
- Filter by contract
- Filter by client
- Success message appears with correct link
- Billing cycles update correctly
Approval Required: ✋ Wait for user approval before proceeding
Phase 3: Drafts & Finalized Tabs
Goal: Complete invoice review and finalization workflow
Tasks:
- Create InvoicePreviewPanel shared component
- Implement DraftsTab with split view
- Implement FinalizedTab with split view
- Add filtering and search
- Implement bulk actions
- Add empty states
- Test preview functionality
- Test finalization workflow
Files Created:
/server/src/components/billing-dashboard/invoicing/InvoicePreviewPanel.tsx
Files Modified:
/server/src/components/billing-dashboard/invoicing/DraftsTab.tsx/server/src/components/billing-dashboard/invoicing/FinalizedTab.tsx
Testing:
- Preview invoice in drafts
- Finalize single invoice
- Bulk finalize multiple invoices
- Download PDF (single & bulk)
- Send email (single & bulk)
- Unfinalize invoice
- Filter by contract/client/date
- Search functionality
Approval Required: ✋ Wait for user approval before proceeding
Phase 4: Visual Polish & Enhancements
Goal: Consistent, beautiful UI matching contract patterns
Tasks:
- Apply badge system consistently
- Add icons throughout
- Implement loading states
- Add error boundaries
- Polish empty states
- Add tooltips and help text
- Ensure responsive design
- Cross-tab navigation links
- Accessibility improvements (ARIA labels, keyboard nav)
- Loading skeletons for tables
Files Modified:
- All InvoicingHub components
Testing:
- Visual consistency check
- Loading states appear correctly
- Error handling works
- Responsive on mobile/tablet
- Keyboard navigation works
- Screen reader compatibility
Approval Required: ✋ Wait for user approval before proceeding
Phase 5: Testing & Documentation
Goal: Production-ready, documented code
Tasks:
- End-to-end testing of full workflow
- Contract integration testing
- Edge case testing (no contracts, no invoices, errors)
- Update
docs/billing-improvement-plan.md - Create user-facing changelog
- Performance testing (large invoice lists)
- Final code review
Deliverables:
- Updated documentation
- Test coverage report
- Changelog for users
- Performance benchmarks
Approval Required: ✋ Wait for user approval before deploying
Success Metrics
User Experience
- ✅ Single unified location for all invoicing tasks
- ✅ Reduced clicks: Generate → Finalize in <10 clicks
- ✅ Improved draft invoice discoverability
- ✅ Clear invoice status at a glance
- ✅ No tab switching required for basic workflow
Technical
- ✅ Reuse all existing actions (no backend changes needed)
- ✅ Maintain all existing functionality
- ✅ No breaking changes to data flow
- ✅ Clean component structure
- ✅ Type-safe implementation
Design
- ✅ Consistent with contract module design
- ✅ Proper loading/error states
- ✅ Helpful empty states
- ✅ Accessible (WCAG 2.1 AA)
- ✅ Responsive design
Technical Notes
Actions to Reuse
// Invoice Generation
import { generateInvoice, previewInvoice } from '@/lib/actions/invoiceGeneration';
import { generateManualInvoice } from '@/lib/actions/manualInvoiceActions';
import { createPrepaymentInvoice } from '@/lib/actions/creditActions';
// Invoice Queries
import { fetchAllInvoices, getInvoiceForRendering, getInvoiceLineItems } from '@/lib/actions/invoiceQueries';
// Invoice Modification
import { finalizeInvoice, unfinalizeInvoice, updateInvoiceManualItems } from '@/lib/actions/invoiceModification';
// Billing Cycles
import { getAvailableBillingPeriods, getInvoicedBillingCycles } from '@/lib/actions/billingCycleActions';
// Jobs
import { scheduleInvoiceZipAction } from '@/lib/actions/job-actions/scheduleInvoiceZipAction';
import { scheduleInvoiceEmailAction } from '@/lib/actions/job-actions/scheduleInvoiceEmailAction';
Component Reuse
// UI Components
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { DataTable } from '@/components/ui/DataTable';
import { CustomTabs } from '@/components/ui/CustomTabs';
import { Input } from '@/components/ui/Input';
import CustomSelect from '@/components/ui/CustomSelect';
import { Checkbox } from '@/components/ui/Checkbox';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/DropdownMenu';
// Billing Components
import { TemplateRenderer } from './TemplateRenderer';
import { ClientPicker } from '@/components/clients/ClientPicker';
import ClientDetails from '@/components/clients/ClientDetails';
// Context
import { useDrawer } from '@/context/DrawerContext';
URL State Management
// Read from URL
const searchParams = useSearchParams();
const activeSubTab = searchParams?.get('subtab') || 'generate';
const selectedInvoiceId = searchParams?.get('invoiceId');
// Update URL
const router = useRouter();
const updateUrl = (params: Record<string, string | null>) => {
const newParams = new URLSearchParams(searchParams?.toString() || '');
Object.entries(params).forEach(([key, value]) => {
if (value === null) newParams.delete(key);
else newParams.set(key, value);
});
router.push(`/msp/billing?${newParams.toString()}`);
};
Type Safety
// Use existing interfaces
import { IInvoice, InvoiceViewModel } from '@/interfaces/invoice.interfaces';
import { IClientBillingCycle } from '@/interfaces/billing.interfaces';
import { IClient } from '@/interfaces';
import { WasmInvoiceViewModel } from '@/lib/invoice-renderer/types';
// Adapters
import { mapDbInvoiceToWasmViewModel } from '@/lib/adapters/invoiceAdapters';
Migration Path
During Development
- Keep existing GenerateInvoices.tsx and Invoices.tsx files
- They continue to work while building new InvoicingHub
- Test new components in isolation
On Deployment
- Switch BillingDashboard to use InvoicingHub
- Old tabs become inaccessible but code remains
- Can roll back quickly if issues arise
After Stabilization
- Monitor for issues for 1-2 weeks
- Delete old GenerateInvoices.tsx component
- Keep Invoices.tsx content as reference
- Clean up unused imports
Questions & Decisions
Q1: Should manual invoices have contract association?
Decision: Yes, but optional. Add contract dropdown to ManualInvoices.tsx for better organization.
Q2: Keep AutomaticInvoices.tsx as-is or refactor?
Decision: Keep as-is initially, import whole component into GenerateTab. Can refactor later if needed.
Q3: Preview in Drafts tab: split view or modal?
Decision: Split view (60/40) for better workflow. User can see list and preview simultaneously.
Q4: Should we show contract filter in all tabs?
Decision: Yes, contracts are central to billing. Show in all tabs for consistency.
Q5: Delete old components immediately or keep as backup?
Decision: Keep for 1-2 weeks after deployment, then delete. Easy rollback if needed.
Open Questions for User
- Should we add a "Revenue Dashboard" to the Invoicing hub showing monthly revenue, outstanding invoices, etc?
- Do you want invoice numbering patterns to be configurable per client/contract?
- Should we add invoice status workflow (Draft → Sent → Paid → Closed)?
- Any specific reports you want built into the Finalized tab?
- Should contract expiration warnings show in the invoicing interface?
References
- Existing Plan:
/docs/billing-improvement-plan.md - Contract Pattern:
/server/src/components/billing-dashboard/contracts/Contracts.tsx - Quick Start Guide:
/server/src/components/billing-dashboard/contracts/QuickStartGuide.tsx - Current Invoicing:
/server/src/components/billing-dashboard/Invoices.tsx - Current Generation:
/server/src/components/billing-dashboard/GenerateInvoices.tsx
Document Version: 1.0 Created: 2025-10-09 Status: Awaiting Phase 1 Approval