mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 01:40:01 +00:00
Budget Workbook: step through all clients with prev/next
Add prev/next buttons and a "Client N of M" indicator around the association picker so a budget can be built for every client in turn. Cycles in name order and wraps; direct dropdown selection still works. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import jsPDF from "jspdf";
|
||||
import autoTable from "jspdf-autotable";
|
||||
import { Building2, RefreshCw, Save, Upload, Download, FileText, Loader2, RotateCcw } from "lucide-react";
|
||||
import { Building2, RefreshCw, Save, Upload, Download, FileText, Loader2, RotateCcw, ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { useAssociation } from "@/contexts/AssociationContext";
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
@@ -65,6 +65,14 @@ export default function BudgetWorkbookPage() {
|
||||
[associations],
|
||||
);
|
||||
|
||||
// Step through every client in order so a budget can be built for each.
|
||||
const assocIdx = sortedAssoc.findIndex((a: any) => a.id === selectedAssociation?.id);
|
||||
const stepAssoc = (delta: number) => {
|
||||
if (sortedAssoc.length === 0) return;
|
||||
const next = assocIdx < 0 ? 0 : (assocIdx + delta + sortedAssoc.length) % sortedAssoc.length;
|
||||
setSelectedAssociation(sortedAssoc[next]);
|
||||
};
|
||||
|
||||
const from = `${fy}-01-01`;
|
||||
const to = monthEnd(fy, through);
|
||||
|
||||
@@ -402,15 +410,30 @@ export default function BudgetWorkbookPage() {
|
||||
<h1 className="text-2xl font-semibold">Budget Workbook</h1>
|
||||
<p className="text-sm text-muted-foreground mt-0.5">Build next year's budget from YTD actuals through a chosen month.</p>
|
||||
</div>
|
||||
<Select value={selectedAssociation?.id ?? ""} onValueChange={(id) => setSelectedAssociation(sortedAssoc.find((a: any) => a.id === id) ?? null)}>
|
||||
<SelectTrigger className="w-[240px]">
|
||||
<Building2 className="h-4 w-4 mr-2 text-muted-foreground" />
|
||||
<SelectValue placeholder={loadingAssociations ? "Loading…" : "Select association"} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{sortedAssoc.map((a: any) => <SelectItem key={a.id} value={a.id}>{a.name}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="flex items-end gap-2">
|
||||
<Button variant="outline" size="icon" className="h-10 w-10 shrink-0" title="Previous client"
|
||||
onClick={() => stepAssoc(-1)} disabled={sortedAssoc.length <= 1}>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="flex flex-col">
|
||||
<Select value={selectedAssociation?.id ?? ""} onValueChange={(id) => setSelectedAssociation(sortedAssoc.find((a: any) => a.id === id) ?? null)}>
|
||||
<SelectTrigger className="w-[240px]">
|
||||
<Building2 className="h-4 w-4 mr-2 text-muted-foreground" />
|
||||
<SelectValue placeholder={loadingAssociations ? "Loading…" : "Select association"} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{sortedAssoc.map((a: any) => <SelectItem key={a.id} value={a.id}>{a.name}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{sortedAssoc.length > 0 && assocIdx >= 0 && (
|
||||
<span className="text-[11px] text-muted-foreground text-center mt-1">Client {assocIdx + 1} of {sortedAssoc.length}</span>
|
||||
)}
|
||||
</div>
|
||||
<Button variant="outline" size="icon" className="h-10 w-10 shrink-0" title="Next client"
|
||||
onClick={() => stepAssoc(1)} disabled={sortedAssoc.length <= 1}>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!associationId ? (
|
||||
|
||||
Reference in New Issue
Block a user