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 { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import jsPDF from "jspdf";
|
import jsPDF from "jspdf";
|
||||||
import autoTable from "jspdf-autotable";
|
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 { toast } from "sonner";
|
||||||
import { useAssociation } from "@/contexts/AssociationContext";
|
import { useAssociation } from "@/contexts/AssociationContext";
|
||||||
import { supabase } from "@/integrations/supabase/client";
|
import { supabase } from "@/integrations/supabase/client";
|
||||||
@@ -65,6 +65,14 @@ export default function BudgetWorkbookPage() {
|
|||||||
[associations],
|
[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 from = `${fy}-01-01`;
|
||||||
const to = monthEnd(fy, through);
|
const to = monthEnd(fy, through);
|
||||||
|
|
||||||
@@ -402,15 +410,30 @@ export default function BudgetWorkbookPage() {
|
|||||||
<h1 className="text-2xl font-semibold">Budget Workbook</h1>
|
<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>
|
<p className="text-sm text-muted-foreground mt-0.5">Build next year's budget from YTD actuals through a chosen month.</p>
|
||||||
</div>
|
</div>
|
||||||
<Select value={selectedAssociation?.id ?? ""} onValueChange={(id) => setSelectedAssociation(sortedAssoc.find((a: any) => a.id === id) ?? null)}>
|
<div className="flex items-end gap-2">
|
||||||
<SelectTrigger className="w-[240px]">
|
<Button variant="outline" size="icon" className="h-10 w-10 shrink-0" title="Previous client"
|
||||||
<Building2 className="h-4 w-4 mr-2 text-muted-foreground" />
|
onClick={() => stepAssoc(-1)} disabled={sortedAssoc.length <= 1}>
|
||||||
<SelectValue placeholder={loadingAssociations ? "Loading…" : "Select association"} />
|
<ChevronLeft className="h-4 w-4" />
|
||||||
</SelectTrigger>
|
</Button>
|
||||||
<SelectContent>
|
<div className="flex flex-col">
|
||||||
{sortedAssoc.map((a: any) => <SelectItem key={a.id} value={a.id}>{a.name}</SelectItem>)}
|
<Select value={selectedAssociation?.id ?? ""} onValueChange={(id) => setSelectedAssociation(sortedAssoc.find((a: any) => a.id === id) ?? null)}>
|
||||||
</SelectContent>
|
<SelectTrigger className="w-[240px]">
|
||||||
</Select>
|
<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>
|
</div>
|
||||||
|
|
||||||
{!associationId ? (
|
{!associationId ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user