import { useCallback, useEffect, useState } from "react"; import { bucketsCreate, bucketsDelete, bucketsList, bucketsUpdate } from "@/lib/client/buckets"; import type { Bucket } from "@/lib/client/buckets"; import type { ApiResult } from "@/lib/client/fetch-json"; type CreateBucketInput = { name: string; description?: string; iconKey?: string | null; budgetLimitDollars?: number | null; position?: number; tags?: string[]; necessity?: "NECESSARY" | "BOTH" | "UNNECESSARY"; windowDays?: number; }; type UpdateBucketInput = CreateBucketInput & { id: number }; export default function useBuckets(activeGroupId?: number | null) { const [buckets, setBuckets] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); function isError(result: ApiResult): result is { error: { code: string; message: string } } { return "error" in result; } const load = useCallback(async () => { if (!activeGroupId) { setError(""); setBuckets([]); setLoading(false); return; } setLoading(true); setError(""); const result = await bucketsList(); if (isError(result)) { setError(result.error.message || ""); setBuckets([]); } else { setBuckets(result.data.buckets || []); } setLoading(false); }, [activeGroupId]); const createBucket = useCallback(async (input: CreateBucketInput) => { setError(""); const result = await bucketsCreate(input); if (isError(result)) { setError(result.error.message || ""); return false; } await load(); return true; }, [load]); const updateBucket = useCallback(async (input: UpdateBucketInput) => { setError(""); const result = await bucketsUpdate(input); if (isError(result)) { setError(result.error.message || ""); return false; } await load(); return true; }, [load]); const reorderBuckets = useCallback(async (ordered: Bucket[]) => { setError(""); const updates = ordered.map((bucket, index) => bucketsUpdate({ id: bucket.id, name: bucket.name, description: bucket.description || undefined, iconKey: bucket.iconKey, budgetLimitDollars: bucket.budgetLimitDollars, position: index, tags: bucket.tags, necessity: bucket.necessity, windowDays: bucket.windowDays })); const results = await Promise.all(updates); const failed = results.find(result => isError(result)); if (failed && "error" in failed) { setError(failed.error.message || ""); return false; } await load(); return true; }, [load]); const deleteBucket = useCallback(async (id: number | string) => { setError(""); const result = await bucketsDelete({ id }); if (isError(result)) { setError(result.error.message || ""); return false; } await load(); return true; }, [load]); useEffect(() => { load(); }, [load]); return { buckets, loading, error, createBucket, updateBucket, reorderBuckets, deleteBucket, reload: load }; }