Changes
Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
co-authored by
renee-png
parent
3e1aaed513
commit
07fe4df9b3
@@ -34,6 +34,13 @@ interface CaseOption {
|
||||
default_hourly_rate: number | null;
|
||||
}
|
||||
|
||||
interface FeeItem {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export function HeaderTimer() {
|
||||
const { user } = useAuth();
|
||||
const { timer, elapsedMs, isRunning, hasStarted, setClient, setCase, setDescription, start, pause, resume, reset, consume } = useTimer();
|
||||
@@ -44,22 +51,33 @@ export function HeaderTimer() {
|
||||
const [profileRate, setProfileRate] = useState<number | null>(null);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [billable, setBillable] = useState(true);
|
||||
const [feeItems, setFeeItems] = useState<FeeItem[]>([]);
|
||||
const [feeItemId, setFeeItemId] = useState<string>("");
|
||||
|
||||
// Load clients + cases the user can access (RLS handles filtering)
|
||||
useEffect(() => {
|
||||
if (!user?.id) return;
|
||||
(async () => {
|
||||
const [{ data: cs }, { data: ks }, { data: prof }] = await Promise.all([
|
||||
const [{ data: cs }, { data: ks }, { data: prof }, { data: fees }] = await Promise.all([
|
||||
supabase.from("clients").select("id, name").order("name"),
|
||||
supabase
|
||||
.from("cases")
|
||||
.select("id, case_number, title, client_id, default_hourly_rate")
|
||||
.order("case_number", { ascending: false }),
|
||||
supabase.from("profiles").select("hourly_rate").eq("id", user.id).maybeSingle(),
|
||||
supabase
|
||||
.from("fee_schedule_items")
|
||||
.select("id, name, description, amount")
|
||||
.eq("active", true)
|
||||
.eq("billable", true)
|
||||
.eq("category", "time")
|
||||
.order("sort_order")
|
||||
.order("name"),
|
||||
]);
|
||||
setClients(cs ?? []);
|
||||
setCases(ks ?? []);
|
||||
setProfileRate((prof as any)?.hourly_rate ?? null);
|
||||
setFeeItems((fees ?? []) as FeeItem[]);
|
||||
})();
|
||||
}, [user?.id]);
|
||||
|
||||
@@ -73,7 +91,21 @@ export function HeaderTimer() {
|
||||
[cases, timer.caseId],
|
||||
);
|
||||
|
||||
const effectiveRate = activeCase?.default_hourly_rate ?? profileRate ?? 0;
|
||||
const selectedFee = useMemo(
|
||||
() => feeItems.find((f) => f.id === feeItemId) ?? null,
|
||||
[feeItems, feeItemId],
|
||||
);
|
||||
|
||||
const effectiveRate =
|
||||
selectedFee?.amount ?? activeCase?.default_hourly_rate ?? profileRate ?? 0;
|
||||
|
||||
const handleSelectFee = (id: string) => {
|
||||
setFeeItemId(id);
|
||||
const fee = feeItems.find((f) => f.id === id);
|
||||
if (fee && !timer.description.trim()) {
|
||||
setDescription(fee.description?.trim() || fee.name);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!user?.id) return toast.error("Not signed in");
|
||||
@@ -100,6 +132,7 @@ export function HeaderTimer() {
|
||||
description: `${formatCurrency(hours * effectiveRate)} at ${formatCurrency(effectiveRate)}/hr`,
|
||||
});
|
||||
setBillable(true);
|
||||
setFeeItemId("");
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
@@ -107,6 +140,7 @@ export function HeaderTimer() {
|
||||
if (hasStarted && !confirm("Discard the running timer?")) return;
|
||||
reset();
|
||||
setBillable(true);
|
||||
setFeeItemId("");
|
||||
};
|
||||
|
||||
const dotClass = isRunning
|
||||
|
||||
Reference in New Issue
Block a user