@pfm-platform/budgets-data-access 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +73 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -235
- package/dist/index.d.ts +87 -235
- package/dist/index.js +75 -56
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
package/dist/index.cjs
CHANGED
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var reactQuery = require('@tanstack/react-query');
|
|
4
4
|
var shared = require('@pfm-platform/shared');
|
|
5
|
-
var axios = require('axios');
|
|
6
|
-
|
|
7
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
-
|
|
9
|
-
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
10
5
|
|
|
11
6
|
// src/queries/useBudgets.ts
|
|
12
7
|
|
|
@@ -18,33 +13,6 @@ var budgetKeys = {
|
|
|
18
13
|
details: () => [...budgetKeys.all, "detail"],
|
|
19
14
|
detail: (userId, budgetId) => [...budgetKeys.details(), userId, budgetId]
|
|
20
15
|
};
|
|
21
|
-
var api = axios__default.default.create({
|
|
22
|
-
baseURL: "/api",
|
|
23
|
-
headers: {
|
|
24
|
-
"Content-Type": "application/json"
|
|
25
|
-
},
|
|
26
|
-
timeout: 1e4
|
|
27
|
-
});
|
|
28
|
-
api.interceptors.request.use(
|
|
29
|
-
(config) => {
|
|
30
|
-
const token = localStorage.getItem("auth_token");
|
|
31
|
-
if (token) {
|
|
32
|
-
config.headers.Authorization = `Bearer ${token}`;
|
|
33
|
-
}
|
|
34
|
-
return config;
|
|
35
|
-
},
|
|
36
|
-
(error) => Promise.reject(error)
|
|
37
|
-
);
|
|
38
|
-
api.interceptors.response.use(
|
|
39
|
-
(response) => response,
|
|
40
|
-
(error) => {
|
|
41
|
-
if (error.response?.status === 401) {
|
|
42
|
-
localStorage.removeItem("auth_token");
|
|
43
|
-
window.location.href = "/login";
|
|
44
|
-
}
|
|
45
|
-
return Promise.reject(error);
|
|
46
|
-
}
|
|
47
|
-
);
|
|
48
16
|
|
|
49
17
|
// src/queries/useBudgets.ts
|
|
50
18
|
function useBudgets(params, options) {
|
|
@@ -52,20 +20,18 @@ function useBudgets(params, options) {
|
|
|
52
20
|
return reactQuery.useQuery({
|
|
53
21
|
queryKey: budgetKeys.list(userId, filters),
|
|
54
22
|
queryFn: async () => {
|
|
55
|
-
|
|
56
|
-
if (filters.
|
|
57
|
-
|
|
23
|
+
let query = shared.supabase.from("budgets").select("*, budget_tags(*), budget_accounts(*)").eq("user_id", userId);
|
|
24
|
+
if (filters.month !== void 0) {
|
|
25
|
+
query = query.eq("month", filters.month);
|
|
58
26
|
}
|
|
59
|
-
if (filters.
|
|
60
|
-
|
|
27
|
+
if (filters.year !== void 0) {
|
|
28
|
+
query = query.eq("year", filters.year);
|
|
61
29
|
}
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return shared.BudgetsResponseSchema.parse(response.data);
|
|
30
|
+
const { data, error } = await query.order("name");
|
|
31
|
+
if (error) throw error;
|
|
32
|
+
return { budgets: shared.BudgetsResponseSchema.parse(data) };
|
|
66
33
|
},
|
|
67
34
|
staleTime: 1e3 * 60 * 5,
|
|
68
|
-
// 5 minutes - budgets change less frequently than transactions
|
|
69
35
|
...options
|
|
70
36
|
});
|
|
71
37
|
}
|
|
@@ -74,23 +40,41 @@ function useBudget(params, options) {
|
|
|
74
40
|
return reactQuery.useQuery({
|
|
75
41
|
queryKey: budgetKeys.detail(userId, budgetId),
|
|
76
42
|
queryFn: async () => {
|
|
77
|
-
const
|
|
78
|
-
|
|
43
|
+
const { data, error } = await shared.supabase.from("budgets").select("*, budget_tags(*), budget_accounts(*)").eq("id", budgetId).single();
|
|
44
|
+
if (error) throw error;
|
|
45
|
+
return shared.BudgetWithRelationsSchema.parse(data);
|
|
79
46
|
},
|
|
80
47
|
staleTime: 1e3 * 60 * 5,
|
|
81
|
-
// 5 minutes
|
|
82
48
|
...options
|
|
83
49
|
});
|
|
84
50
|
}
|
|
85
51
|
function useCreateBudget(options) {
|
|
86
52
|
const queryClient = reactQuery.useQueryClient();
|
|
87
53
|
return reactQuery.useMutation({
|
|
88
|
-
mutationFn: async ({
|
|
54
|
+
mutationFn: async ({ data, tagNames, accountIds }) => {
|
|
89
55
|
const validated = shared.BudgetCreateSchema.parse(data);
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
56
|
+
const { data: created, error } = await shared.supabase.from("budgets").insert(validated).select().single();
|
|
57
|
+
if (error) throw error;
|
|
58
|
+
const budgetId = created.id;
|
|
59
|
+
if (tagNames && tagNames.length > 0) {
|
|
60
|
+
const tagRows = tagNames.map((tag_name) => ({
|
|
61
|
+
budget_id: budgetId,
|
|
62
|
+
tag_name
|
|
63
|
+
}));
|
|
64
|
+
const { error: tagError } = await shared.supabase.from("budget_tags").insert(tagRows);
|
|
65
|
+
if (tagError) throw tagError;
|
|
66
|
+
}
|
|
67
|
+
if (accountIds && accountIds.length > 0) {
|
|
68
|
+
const accountRows = accountIds.map((account_id) => ({
|
|
69
|
+
budget_id: budgetId,
|
|
70
|
+
account_id
|
|
71
|
+
}));
|
|
72
|
+
const { error: accountError } = await shared.supabase.from("budget_accounts").insert(accountRows);
|
|
73
|
+
if (accountError) throw accountError;
|
|
74
|
+
}
|
|
75
|
+
const { data: full, error: fetchError } = await shared.supabase.from("budgets").select("*, budget_tags(*), budget_accounts(*)").eq("id", budgetId).single();
|
|
76
|
+
if (fetchError) throw fetchError;
|
|
77
|
+
return shared.BudgetWithRelationsSchema.parse(full);
|
|
94
78
|
},
|
|
95
79
|
onSuccess: (_, { userId }) => {
|
|
96
80
|
queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });
|
|
@@ -101,12 +85,40 @@ function useCreateBudget(options) {
|
|
|
101
85
|
function useUpdateBudget(options) {
|
|
102
86
|
const queryClient = reactQuery.useQueryClient();
|
|
103
87
|
return reactQuery.useMutation({
|
|
104
|
-
mutationFn: async ({
|
|
88
|
+
mutationFn: async ({ budgetId, data, tagNames, accountIds }) => {
|
|
105
89
|
const validated = shared.BudgetUpdateSchema.parse(data);
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
90
|
+
const { id: _, ...updateData } = validated;
|
|
91
|
+
if (Object.keys(updateData).length > 0) {
|
|
92
|
+
const { error } = await shared.supabase.from("budgets").update(updateData).eq("id", budgetId);
|
|
93
|
+
if (error) throw error;
|
|
94
|
+
}
|
|
95
|
+
if (tagNames !== void 0) {
|
|
96
|
+
const { error: deleteTagError } = await shared.supabase.from("budget_tags").delete().eq("budget_id", budgetId);
|
|
97
|
+
if (deleteTagError) throw deleteTagError;
|
|
98
|
+
if (tagNames.length > 0) {
|
|
99
|
+
const tagRows = tagNames.map((tag_name) => ({
|
|
100
|
+
budget_id: budgetId,
|
|
101
|
+
tag_name
|
|
102
|
+
}));
|
|
103
|
+
const { error: insertTagError } = await shared.supabase.from("budget_tags").insert(tagRows);
|
|
104
|
+
if (insertTagError) throw insertTagError;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (accountIds !== void 0) {
|
|
108
|
+
const { error: deleteAccError } = await shared.supabase.from("budget_accounts").delete().eq("budget_id", budgetId);
|
|
109
|
+
if (deleteAccError) throw deleteAccError;
|
|
110
|
+
if (accountIds.length > 0) {
|
|
111
|
+
const accountRows = accountIds.map((account_id) => ({
|
|
112
|
+
budget_id: budgetId,
|
|
113
|
+
account_id
|
|
114
|
+
}));
|
|
115
|
+
const { error: insertAccError } = await shared.supabase.from("budget_accounts").insert(accountRows);
|
|
116
|
+
if (insertAccError) throw insertAccError;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const { data: full, error: fetchError } = await shared.supabase.from("budgets").select("*, budget_tags(*), budget_accounts(*)").eq("id", budgetId).single();
|
|
120
|
+
if (fetchError) throw fetchError;
|
|
121
|
+
return shared.BudgetWithRelationsSchema.parse(full);
|
|
110
122
|
},
|
|
111
123
|
onSuccess: (_, { userId, budgetId }) => {
|
|
112
124
|
queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });
|
|
@@ -120,12 +132,15 @@ function useUpdateBudget(options) {
|
|
|
120
132
|
function useDeleteBudget(options) {
|
|
121
133
|
const queryClient = reactQuery.useQueryClient();
|
|
122
134
|
return reactQuery.useMutation({
|
|
123
|
-
mutationFn: async ({
|
|
124
|
-
await
|
|
135
|
+
mutationFn: async ({ budgetId }) => {
|
|
136
|
+
const { error } = await shared.supabase.from("budgets").delete().eq("id", budgetId);
|
|
137
|
+
if (error) throw error;
|
|
125
138
|
},
|
|
126
139
|
onSuccess: (_, { userId, budgetId }) => {
|
|
127
|
-
queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });
|
|
128
140
|
queryClient.invalidateQueries({
|
|
141
|
+
queryKey: budgetKeys.list(userId)
|
|
142
|
+
});
|
|
143
|
+
queryClient.removeQueries({
|
|
129
144
|
queryKey: budgetKeys.detail(userId, budgetId)
|
|
130
145
|
});
|
|
131
146
|
},
|
|
@@ -133,7 +148,6 @@ function useDeleteBudget(options) {
|
|
|
133
148
|
});
|
|
134
149
|
}
|
|
135
150
|
|
|
136
|
-
exports.api = api;
|
|
137
151
|
exports.budgetKeys = budgetKeys;
|
|
138
152
|
exports.useBudget = useBudget;
|
|
139
153
|
exports.useBudgets = useBudgets;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/keys.ts","../src/client.ts","../src/queries/useBudgets.ts","../src/queries/useBudget.ts","../src/mutations/useCreateBudget.ts","../src/mutations/useUpdateBudget.ts","../src/mutations/useDeleteBudget.ts"],"names":["axios","useQuery","BudgetsResponseSchema","BudgetSchema","useQueryClient","useMutation","BudgetCreateSchema","BudgetUpdateSchema"],"mappings":";;;;;;;;;;;;;AAUO,IAAM,UAAA,GAAa;AAAA,EACxB,GAAA,EAAK,CAAC,SAAS,CAAA;AAAA,EACf,OAAO,MAAM,CAAC,GAAG,UAAA,CAAW,KAAK,MAAM,CAAA;AAAA,EACvC,IAAA,EAAM,CAAC,MAAA,EAAgB,OAAA,KACrB,CAAC,GAAG,UAAA,CAAW,KAAA,EAAM,EAAG,MAAA,EAAQ,OAAA,IAAW,EAAE,CAAA;AAAA,EAC/C,SAAS,MAAM,CAAC,GAAG,UAAA,CAAW,KAAK,QAAQ,CAAA;AAAA,EAC3C,MAAA,EAAQ,CAAC,MAAA,EAAgB,QAAA,KACvB,CAAC,GAAG,UAAA,CAAW,OAAA,EAAQ,EAAG,MAAA,EAAQ,QAAQ;AAC9C;ACXO,IAAM,GAAA,GAAMA,uBAAM,MAAA,CAAO;AAAA,EAC9B,OAAA,EAAS,MAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,cAAA,EAAgB;AAAA,GAClB;AAAA,EACA,OAAA,EAAS;AACX,CAAC;AAGD,GAAA,CAAI,aAAa,OAAA,CAAQ,GAAA;AAAA,EACvB,CAAC,MAAA,KAAW;AACV,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,CAAQ,YAAY,CAAA;AAC/C,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAA,CAAO,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,IAChD;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AAAA,EACA,CAAC,KAAA,KAAU,OAAA,CAAQ,MAAA,CAAO,KAAK;AACjC,CAAA;AAGA,GAAA,CAAI,aAAa,QAAA,CAAS,GAAA;AAAA,EACxB,CAAC,QAAA,KAAa,QAAA;AAAA,EACd,CAAC,KAAA,KAAU;AACT,IAAA,IAAI,KAAA,CAAM,QAAA,EAAU,MAAA,KAAW,GAAA,EAAK;AAElC,MAAA,YAAA,CAAa,WAAW,YAAY,CAAA;AACpC,MAAA,MAAA,CAAO,SAAS,IAAA,GAAO,QAAA;AAAA,IACzB;AACA,IAAA,OAAO,OAAA,CAAQ,OAAO,KAAK,CAAA;AAAA,EAC7B;AACF,CAAA;;;ACeO,SAAS,UAAA,CACd,QACA,OAAA,EACA;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,GAAU,IAAG,GAAI,MAAA;AAEjC,EAAA,OAAOC,mBAAA,CAAS;AAAA,IACd,QAAA,EAAU,UAAA,CAAW,IAAA,CAAK,MAAA,EAAQ,OAAO,CAAA;AAAA,IACzC,SAAS,YAAY;AAEnB,MAAA,MAAM,WAAA,GAAc,IAAI,eAAA,EAAgB;AAExC,MAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,QAAA,WAAA,CAAY,MAAA,CAAO,YAAA,EAAc,OAAA,CAAQ,UAAU,CAAA;AAAA,MACrD;AAEA,MAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,QAAA,WAAA,CAAY,MAAA,CAAO,UAAA,EAAY,OAAA,CAAQ,QAAQ,CAAA;AAAA,MACjD;AAEA,MAAA,MAAM,WAAA,GAAc,YAAY,QAAA,EAAS;AACzC,MAAA,MAAM,GAAA,GAAM,UAAU,MAAM,CAAA,QAAA,EAC1B,cAAc,CAAA,CAAA,EAAI,WAAW,KAAK,EACpC,CAAA,CAAA;AAEA,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAGlC,MAAA,OAAOC,4BAAA,CAAsB,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,IAClD,CAAA;AAAA,IACA,SAAA,EAAW,MAAO,EAAA,GAAK,CAAA;AAAA;AAAA,IACvB,GAAG;AAAA,GACJ,CAAA;AACH;ACzCO,SAAS,SAAA,CACd,QACA,OAAA,EACA;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAS,GAAI,MAAA;AAE7B,EAAA,OAAOD,mBAAAA,CAAS;AAAA,IACd,QAAA,EAAU,UAAA,CAAW,MAAA,CAAO,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAC5C,SAAS,YAAY;AACnB,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,GAAA,CAAI,UAAU,MAAM,CAAA,SAAA,EAAY,QAAQ,CAAA,CAAE,CAAA;AAGrE,MAAA,OAAOE,mBAAA,CAAa,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,IACzC,CAAA;AAAA,IACA,SAAA,EAAW,MAAO,EAAA,GAAK,CAAA;AAAA;AAAA,IACvB,GAAG;AAAA,GACJ,CAAA;AACH;ACAO,SAAS,gBACd,OAAA,EACA;AACA,EAAA,MAAM,cAAcC,yBAAA,EAAe;AAEnC,EAAA,OAAOC,sBAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,MAAK,KAA0B;AAE1D,MAAA,MAAM,SAAA,GAAYC,yBAAA,CAAmB,KAAA,CAAM,IAAI,CAAA;AAE/C,MAAA,MAAM,WAAW,MAAM,GAAA,CAAI,IAAA,CAAK,CAAA,OAAA,EAAU,MAAM,CAAA,QAAA,CAAA,EAAY;AAAA,QAC1D,MAAA,EAAQ;AAAA,OACT,CAAA;AAGD,MAAA,OAAOH,mBAAAA,CAAa,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,IACzC,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,EAAE,QAAO,KAAM;AAE5B,MAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,UAAA,CAAW,KAAA,IAAS,CAAA;AAAA,IAChE,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;ACtBO,SAAS,gBACd,OAAA,EACA;AACA,EAAA,MAAM,cAAcC,yBAAAA,EAAe;AAEnC,EAAA,OAAOC,sBAAAA,CAAY;AAAA,IACjB,YAAY,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,MAAK,KAA0B;AAEpE,MAAA,MAAM,SAAA,GAAYE,yBAAA,CAAmB,KAAA,CAAM,IAAI,CAAA;AAE/C,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,GAAA,CAAI,UAAU,MAAM,CAAA,SAAA,EAAY,QAAQ,CAAA,CAAA,EAAI;AAAA,QACrE,MAAA,EAAQ;AAAA,OACT,CAAA;AAGD,MAAA,OAAOJ,mBAAAA,CAAa,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AAAA,IACzC,CAAA;AAAA,IACA,WAAW,CAAC,CAAA,EAAG,EAAE,MAAA,EAAQ,UAAS,KAAM;AAEtC,MAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,UAAA,CAAW,KAAA,IAAS,CAAA;AAE9D,MAAA,WAAA,CAAY,iBAAA,CAAkB;AAAA,QAC5B,QAAA,EAAU,UAAA,CAAW,MAAA,CAAO,MAAA,EAAQ,QAAQ;AAAA,OAC7C,CAAA;AAAA,IACH,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;AC/BO,SAAS,gBACd,OAAA,EACA;AACA,EAAA,MAAM,cAAcC,yBAAAA,EAAe;AAEnC,EAAA,OAAOC,sBAAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,EAAE,MAAA,EAAQ,UAAS,KAA0B;AAC9D,MAAA,MAAM,IAAI,MAAA,CAAO,CAAA,OAAA,EAAU,MAAM,CAAA,SAAA,EAAY,QAAQ,CAAA,CAAE,CAAA;AAAA,IAEzD,CAAA;AAAA,IACA,WAAW,CAAC,CAAA,EAAG,EAAE,MAAA,EAAQ,UAAS,KAAM;AAEtC,MAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,UAAA,CAAW,KAAA,IAAS,CAAA;AAE9D,MAAA,WAAA,CAAY,iBAAA,CAAkB;AAAA,QAC5B,QAAA,EAAU,UAAA,CAAW,MAAA,CAAO,MAAA,EAAQ,QAAQ;AAAA,OAC7C,CAAA;AAAA,IACH,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH","file":"index.cjs","sourcesContent":["/**\n * Query key factory for Budget domain\n * Hierarchical structure for efficient cache invalidation\n */\n\nexport interface BudgetDateRangeFilters {\n start_date?: string; // RFC 3339 format\n end_date?: string; // RFC 3339 format\n}\n\nexport const budgetKeys = {\n all: ['budgets'] as const,\n lists: () => [...budgetKeys.all, 'list'] as const,\n list: (userId: string, filters?: BudgetDateRangeFilters) =>\n [...budgetKeys.lists(), userId, filters ?? {}] as const,\n details: () => [...budgetKeys.all, 'detail'] as const,\n detail: (userId: string, budgetId: number) =>\n [...budgetKeys.details(), userId, budgetId] as const,\n};\n","/**\n * Axios client for Budget API calls\n * Reuses pattern from accounts/transactions data-access\n */\n\nimport axios from 'axios';\n\nexport const api = axios.create({\n baseURL: '/api',\n headers: {\n 'Content-Type': 'application/json',\n },\n timeout: 10000,\n});\n\n// Request interceptor - Add auth token\napi.interceptors.request.use(\n (config) => {\n const token = localStorage.getItem('auth_token');\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error) => Promise.reject(error)\n);\n\n// Response interceptor - Handle 401 unauthorized\napi.interceptors.response.use(\n (response) => response,\n (error) => {\n if (error.response?.status === 401) {\n // Clear token and redirect to login\n localStorage.removeItem('auth_token');\n window.location.href = '/login';\n }\n return Promise.reject(error);\n }\n);\n","/**\n * Query hook for fetching budgets list\n * Legacy API: GET /users/{userId}/budgets\n * Optional filters: start_date, end_date (RFC 3339 format)\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { BudgetsResponseSchema, BudgetsResponse } from '@pfm-platform/shared';\nimport { budgetKeys, BudgetDateRangeFilters } from '../keys';\nimport { api } from '../client';\n\nexport interface UseBudgetsParams {\n userId: string;\n filters?: BudgetDateRangeFilters;\n}\n\n/**\n * Fetch budgets with optional date range filters\n * Uses Zod validation to ensure API response matches expected schema\n *\n * @param params - Query parameters with userId and optional date range filters\n * @param options - TanStack Query options\n * @returns Query result with validated budgets data\n *\n * @example\n * ```tsx\n * // Fetch all budgets\n * function BudgetsList() {\n * const { data, isLoading } = useBudgets({ userId: 'user123' });\n *\n * return (\n * <ul>\n * {data?.budgets.map(budget => (\n * <li key={budget.id}>{budget.name}</li>\n * ))}\n * </ul>\n * );\n * }\n *\n * // Fetch budgets for specific date range\n * function MonthBudgets() {\n * const { data } = useBudgets({\n * userId: 'user123',\n * filters: {\n * start_date: '2025-01-01T00:00:00Z',\n * end_date: '2025-01-31T23:59:59Z',\n * }\n * });\n *\n * return <BudgetList budgets={data?.budgets} />;\n * }\n * ```\n */\nexport function useBudgets(\n params: UseBudgetsParams,\n options?: Omit<UseQueryOptions<BudgetsResponse>, 'queryKey' | 'queryFn'>\n) {\n const { userId, filters = {} } = params;\n\n return useQuery({\n queryKey: budgetKeys.list(userId, filters),\n queryFn: async () => {\n // Build query parameters\n const queryParams = new URLSearchParams();\n\n if (filters.start_date) {\n queryParams.append('start_date', filters.start_date);\n }\n\n if (filters.end_date) {\n queryParams.append('end_date', filters.end_date);\n }\n\n const queryString = queryParams.toString();\n const url = `/users/${userId}/budgets${\n queryString ? `?${queryString}` : ''\n }`;\n\n const response = await api.get(url);\n\n // Validate response with Zod schema from Mini-Arc 1\n return BudgetsResponseSchema.parse(response.data);\n },\n staleTime: 1000 * 60 * 5, // 5 minutes - budgets change less frequently than transactions\n ...options,\n });\n}\n","/**\n * Query hook for fetching a single budget\n * Legacy API: GET /users/{userId}/budgets/{id}\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { BudgetSchema, Budget } from '@pfm-platform/shared';\nimport { budgetKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface UseBudgetParams {\n userId: string;\n budgetId: number;\n}\n\n/**\n * Fetch a single budget by ID\n * Uses Zod validation to ensure API response matches expected schema\n *\n * @param params - Query parameters with userId and budgetId\n * @param options - TanStack Query options\n * @returns Query result with validated budget data\n *\n * @example\n * ```tsx\n * function BudgetDetail({ budgetId }: { budgetId: number }) {\n * const { data, isLoading, error } = useBudget({\n * userId: 'user123',\n * budgetId\n * });\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * <h1>{data.name}</h1>\n * <p>Amount: ${data.budget_amount}</p>\n * <p>Spent: ${data.spent}</p>\n * <p>State: {data.state}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useBudget(\n params: UseBudgetParams,\n options?: Omit<UseQueryOptions<Budget>, 'queryKey' | 'queryFn'>\n) {\n const { userId, budgetId } = params;\n\n return useQuery({\n queryKey: budgetKeys.detail(userId, budgetId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/budgets/${budgetId}`);\n\n // Validate response with Zod schema from Mini-Arc 1\n return BudgetSchema.parse(response.data);\n },\n staleTime: 1000 * 60 * 5, // 5 minutes\n ...options,\n });\n}\n","/**\n * Mutation hook for creating a budget\n * Legacy API: POST /users/{userId}/budgets\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport {\n BudgetCreateSchema,\n BudgetSchema,\n Budget,\n BudgetCreate,\n} from '@pfm-platform/shared';\nimport { budgetKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface CreateBudgetParams {\n userId: string;\n data: BudgetCreate;\n}\n\n/**\n * Create a new budget\n * Validates input with Zod schema and invalidates related queries on success\n *\n * @param options - TanStack Mutation options\n * @returns Mutation result\n *\n * @example\n * ```tsx\n * function BudgetCreateForm() {\n * const createBudget = useCreateBudget();\n *\n * const handleSubmit = (formData) => {\n * createBudget.mutate({\n * userId: 'user123',\n * data: {\n * name: formData.name,\n * budget_amount: formData.amount,\n * tag_names: formData.tags,\n * account_list: formData.accounts,\n * show_on_dashboard: true,\n * other: {}\n * }\n * }, {\n * onSuccess: (newBudget) => {\n * toast.success('Budget created!');\n * router.push(`/budgets/${newBudget.id}`);\n * },\n * onError: (error) => {\n * toast.error(`Failed: ${error.message}`);\n * }\n * });\n * };\n *\n * return <form onSubmit={handleSubmit}>...</form>;\n * }\n * ```\n */\nexport function useCreateBudget(\n options?: Omit<UseMutationOptions<Budget, Error, CreateBudgetParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateBudgetParams) => {\n // Validate input with Zod schema from Mini-Arc 1\n const validated = BudgetCreateSchema.parse(data);\n\n const response = await api.post(`/users/${userId}/budgets`, {\n budget: validated,\n });\n\n // Validate response\n return BudgetSchema.parse(response.data);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate budget list queries for this user\n queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for updating a budget\n * Legacy API: PUT /users/{userId}/budgets/{id}\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport {\n BudgetUpdateSchema,\n BudgetSchema,\n Budget,\n BudgetUpdate,\n} from '@pfm-platform/shared';\nimport { budgetKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface UpdateBudgetParams {\n userId: string;\n budgetId: number;\n data: BudgetUpdate;\n}\n\n/**\n * Update an existing budget\n * Validates input with Zod schema and invalidates related queries on success\n *\n * @param options - TanStack Mutation options\n * @returns Mutation result\n *\n * @example\n * ```tsx\n * function BudgetEditForm({ budget }: { budget: Budget }) {\n * const updateBudget = useUpdateBudget();\n *\n * const handleSubmit = (formData) => {\n * updateBudget.mutate({\n * userId: 'user123',\n * budgetId: budget.id,\n * data: {\n * name: formData.name,\n * budget_amount: formData.amount,\n * tag_names: formData.tags,\n * account_list: formData.accounts,\n * show_on_dashboard: formData.showOnDashboard,\n * other: formData.metadata\n * }\n * }, {\n * onSuccess: () => {\n * toast.success('Budget updated!');\n * },\n * onError: (error) => {\n * toast.error(`Failed: ${error.message}`);\n * }\n * });\n * };\n *\n * return <form onSubmit={handleSubmit}>...</form>;\n * }\n * ```\n */\nexport function useUpdateBudget(\n options?: Omit<UseMutationOptions<Budget, Error, UpdateBudgetParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, budgetId, data }: UpdateBudgetParams) => {\n // Validate input with Zod schema from Mini-Arc 1\n const validated = BudgetUpdateSchema.parse(data);\n\n const response = await api.put(`/users/${userId}/budgets/${budgetId}`, {\n budget: validated,\n });\n\n // Validate response\n return BudgetSchema.parse(response.data);\n },\n onSuccess: (_, { userId, budgetId }) => {\n // Invalidate list queries\n queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });\n // Invalidate this specific budget\n queryClient.invalidateQueries({\n queryKey: budgetKeys.detail(userId, budgetId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for deleting a budget\n * Legacy API: DELETE /users/{userId}/budgets/{id}\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { budgetKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface DeleteBudgetParams {\n userId: string;\n budgetId: number;\n}\n\n/**\n * Delete a budget\n * Removes budget from user's budgets list\n * Invalidates related queries on success\n *\n * @param options - TanStack Mutation options\n * @returns Mutation result\n *\n * @example\n * ```tsx\n * function BudgetDeleteButton({ budgetId }: { budgetId: number }) {\n * const deleteBudget = useDeleteBudget();\n *\n * const handleDelete = () => {\n * if (confirm('Are you sure you want to delete this budget?')) {\n * deleteBudget.mutate({\n * userId: 'user123',\n * budgetId\n * }, {\n * onSuccess: () => {\n * toast.success('Budget deleted');\n * router.push('/budgets');\n * },\n * onError: (error) => {\n * toast.error(`Failed: ${error.message}`);\n * }\n * });\n * }\n * };\n *\n * return (\n * <button\n * onClick={handleDelete}\n * disabled={deleteBudget.isPending}\n * >\n * {deleteBudget.isPending ? 'Deleting...' : 'Delete'}\n * </button>\n * );\n * }\n * ```\n */\nexport function useDeleteBudget(\n options?: Omit<UseMutationOptions<void, Error, DeleteBudgetParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, budgetId }: DeleteBudgetParams) => {\n await api.delete(`/users/${userId}/budgets/${budgetId}`);\n // DELETE returns 204 No Content - no response body to validate\n },\n onSuccess: (_, { userId, budgetId }) => {\n // Invalidate list queries\n queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });\n // Invalidate this specific budget\n queryClient.invalidateQueries({\n queryKey: budgetKeys.detail(userId, budgetId),\n });\n },\n ...options,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/keys.ts","../src/queries/useBudgets.ts","../src/queries/useBudget.ts","../src/mutations/useCreateBudget.ts","../src/mutations/useUpdateBudget.ts","../src/mutations/useDeleteBudget.ts"],"names":["useQuery","supabase","BudgetsResponseSchema","BudgetWithRelationsSchema","useQueryClient","useMutation","BudgetCreateSchema","BudgetUpdateSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Query key factory for Budget domain\n * Following TanStack Query best practices for hierarchical cache keys\n *\n * Key structure:\n * - ['budgets'] - Root key for all budget queries\n * - ['budgets', 'list', userId, filters] - List of budgets for a user\n * - ['budgets', 'detail', userId, budgetId] - Single budget detail\n */\n\nexport interface BudgetFilters {\n month?: number;\n year?: number;\n}\n\nexport const budgetKeys = {\n all: ['budgets'] as const,\n\n lists: () => [...budgetKeys.all, 'list'] as const,\n\n list: (userId: string, filters?: BudgetFilters) =>\n [...budgetKeys.lists(), userId, filters ?? {}] as const,\n\n details: () => [...budgetKeys.all, 'detail'] as const,\n\n detail: (userId: string, budgetId: string) =>\n [...budgetKeys.details(), userId, budgetId] as const,\n};\n","/**\n * Query hook for fetching budgets list\n * Supabase: budgets table with budget_tags and budget_accounts joins\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { BudgetsResponseSchema, type BudgetWithRelations } from '@pfm-platform/shared';\nimport { budgetKeys, BudgetFilters } from '../keys';\nimport { supabase } from '../client';\n\nexport interface UseBudgetsParams {\n userId: string;\n filters?: BudgetFilters;\n}\n\nexport interface BudgetsData {\n budgets: BudgetWithRelations[];\n}\n\n/**\n * Fetch all budgets for a user from Supabase\n *\n * Returns `{ budgets: BudgetWithRelations[] }` to match the shape expected by\n * feature hooks (useBudgetProgress, useBudgetSummary, useBudgetsByMonth).\n */\nexport function useBudgets(\n params: UseBudgetsParams,\n options?: Omit<UseQueryOptions<BudgetsData>, 'queryKey' | 'queryFn'>\n) {\n const { userId, filters = {} } = params;\n\n return useQuery({\n queryKey: budgetKeys.list(userId, filters),\n queryFn: async (): Promise<BudgetsData> => {\n let query = supabase\n .from('budgets')\n .select('*, budget_tags(*), budget_accounts(*)')\n .eq('user_id', userId);\n\n if (filters.month !== undefined) {\n query = query.eq('month', filters.month);\n }\n\n if (filters.year !== undefined) {\n query = query.eq('year', filters.year);\n }\n\n const { data, error } = await query.order('name');\n\n if (error) throw error;\n\n return { budgets: BudgetsResponseSchema.parse(data) };\n },\n staleTime: 1000 * 60 * 5,\n ...options,\n });\n}\n","/**\n * Query hook for fetching a single budget\n * Supabase: budgets table with budget_tags and budget_accounts joins\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { BudgetWithRelationsSchema, type BudgetWithRelations } from '@pfm-platform/shared';\nimport { budgetKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface UseBudgetParams {\n userId: string;\n budgetId: string;\n}\n\n/**\n * Fetch a single budget by ID from Supabase\n */\nexport function useBudget(\n params: UseBudgetParams,\n options?: Omit<UseQueryOptions<BudgetWithRelations>, 'queryKey' | 'queryFn'>\n) {\n const { userId, budgetId } = params;\n\n return useQuery({\n queryKey: budgetKeys.detail(userId, budgetId),\n queryFn: async (): Promise<BudgetWithRelations> => {\n const { data, error } = await supabase\n .from('budgets')\n .select('*, budget_tags(*), budget_accounts(*)')\n .eq('id', budgetId)\n .single();\n\n if (error) throw error;\n\n return BudgetWithRelationsSchema.parse(data);\n },\n staleTime: 1000 * 60 * 5,\n ...options,\n });\n}\n","/**\n * Mutation hook for creating a budget\n * Supabase: INSERT into budgets, then optionally budget_tags and budget_accounts\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport {\n BudgetCreateSchema,\n BudgetWithRelationsSchema,\n type BudgetCreate,\n type BudgetWithRelations,\n} from '@pfm-platform/shared';\nimport { budgetKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface CreateBudgetParams {\n userId: string;\n data: BudgetCreate;\n tagNames?: string[];\n accountIds?: string[];\n}\n\n/**\n * Create a new budget with optional tag and account associations\n *\n * Multi-step: (1) insert budget, (2) insert budget_tags rows,\n * (3) insert budget_accounts rows, (4) re-fetch with relations.\n */\nexport function useCreateBudget(\n options?: Omit<UseMutationOptions<BudgetWithRelations, Error, CreateBudgetParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ data, tagNames, accountIds }: CreateBudgetParams) => {\n const validated = BudgetCreateSchema.parse(data);\n\n // Step 1: Insert budget\n const { data: created, error } = await supabase\n .from('budgets')\n .insert(validated)\n .select()\n .single();\n\n if (error) throw error;\n\n const budgetId = created.id;\n\n // Step 2: Insert budget_tags if provided\n if (tagNames && tagNames.length > 0) {\n const tagRows = tagNames.map((tag_name) => ({\n budget_id: budgetId,\n tag_name,\n }));\n const { error: tagError } = await supabase\n .from('budget_tags')\n .insert(tagRows);\n if (tagError) throw tagError;\n }\n\n // Step 3: Insert budget_accounts if provided\n if (accountIds && accountIds.length > 0) {\n const accountRows = accountIds.map((account_id) => ({\n budget_id: budgetId,\n account_id,\n }));\n const { error: accountError } = await supabase\n .from('budget_accounts')\n .insert(accountRows);\n if (accountError) throw accountError;\n }\n\n // Step 4: Re-fetch with relations\n const { data: full, error: fetchError } = await supabase\n .from('budgets')\n .select('*, budget_tags(*), budget_accounts(*)')\n .eq('id', budgetId)\n .single();\n\n if (fetchError) throw fetchError;\n\n return BudgetWithRelationsSchema.parse(full);\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for updating a budget\n * Supabase: UPDATE budgets, optionally replace budget_tags and budget_accounts\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport {\n BudgetUpdateSchema,\n BudgetWithRelationsSchema,\n type BudgetUpdate,\n type BudgetWithRelations,\n} from '@pfm-platform/shared';\nimport { budgetKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface UpdateBudgetParams {\n userId: string;\n budgetId: string;\n data: BudgetUpdate;\n tagNames?: string[];\n accountIds?: string[];\n}\n\n/**\n * Update an existing budget\n *\n * If tagNames or accountIds are provided, replaces all existing\n * junction rows (delete all, then insert new).\n */\nexport function useUpdateBudget(\n options?: Omit<UseMutationOptions<BudgetWithRelations, Error, UpdateBudgetParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ budgetId, data, tagNames, accountIds }: UpdateBudgetParams) => {\n const validated = BudgetUpdateSchema.parse(data);\n\n // Strip id before sending to Supabase .update()\n const { id: _, ...updateData } = validated;\n if (Object.keys(updateData).length > 0) {\n const { error } = await supabase\n .from('budgets')\n .update(updateData)\n .eq('id', budgetId);\n if (error) throw error;\n }\n\n // Replace budget_tags if provided\n if (tagNames !== undefined) {\n const { error: deleteTagError } = await supabase\n .from('budget_tags')\n .delete()\n .eq('budget_id', budgetId);\n if (deleteTagError) throw deleteTagError;\n\n if (tagNames.length > 0) {\n const tagRows = tagNames.map((tag_name) => ({\n budget_id: budgetId,\n tag_name,\n }));\n const { error: insertTagError } = await supabase\n .from('budget_tags')\n .insert(tagRows);\n if (insertTagError) throw insertTagError;\n }\n }\n\n // Replace budget_accounts if provided\n if (accountIds !== undefined) {\n const { error: deleteAccError } = await supabase\n .from('budget_accounts')\n .delete()\n .eq('budget_id', budgetId);\n if (deleteAccError) throw deleteAccError;\n\n if (accountIds.length > 0) {\n const accountRows = accountIds.map((account_id) => ({\n budget_id: budgetId,\n account_id,\n }));\n const { error: insertAccError } = await supabase\n .from('budget_accounts')\n .insert(accountRows);\n if (insertAccError) throw insertAccError;\n }\n }\n\n // Re-fetch with relations\n const { data: full, error: fetchError } = await supabase\n .from('budgets')\n .select('*, budget_tags(*), budget_accounts(*)')\n .eq('id', budgetId)\n .single();\n\n if (fetchError) throw fetchError;\n\n return BudgetWithRelationsSchema.parse(full);\n },\n onSuccess: (_, { userId, budgetId }) => {\n queryClient.invalidateQueries({ queryKey: budgetKeys.lists() });\n queryClient.invalidateQueries({\n queryKey: budgetKeys.detail(userId, budgetId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for deleting a budget\n * Supabase: DELETE FROM budgets WHERE id = ...\n * Junction rows cascade-delete via FK constraints.\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { budgetKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface DeleteBudgetParams {\n userId: string;\n budgetId: string;\n}\n\n/**\n * Delete a budget from Supabase (hard delete)\n * Junction rows in budget_tags and budget_accounts cascade-delete.\n */\nexport function useDeleteBudget(\n options?: Omit<\n UseMutationOptions<void, Error, DeleteBudgetParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ budgetId }: DeleteBudgetParams) => {\n const { error } = await supabase\n .from('budgets')\n .delete()\n .eq('id', budgetId);\n\n if (error) throw error;\n },\n onSuccess: (_, { userId, budgetId }) => {\n queryClient.invalidateQueries({\n queryKey: budgetKeys.list(userId),\n });\n queryClient.removeQueries({\n queryKey: budgetKeys.detail(userId, budgetId),\n });\n },\n ...options,\n });\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,297 +1,149 @@
|
|
|
1
1
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
2
|
import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
4
|
-
import * as axios from 'axios';
|
|
3
|
+
import { BudgetWithRelations, BudgetCreate, BudgetUpdate } from '@pfm-platform/shared';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Query key factory for Budget domain
|
|
8
|
-
*
|
|
7
|
+
* Following TanStack Query best practices for hierarchical cache keys
|
|
8
|
+
*
|
|
9
|
+
* Key structure:
|
|
10
|
+
* - ['budgets'] - Root key for all budget queries
|
|
11
|
+
* - ['budgets', 'list', userId, filters] - List of budgets for a user
|
|
12
|
+
* - ['budgets', 'detail', userId, budgetId] - Single budget detail
|
|
9
13
|
*/
|
|
10
|
-
interface
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
interface BudgetFilters {
|
|
15
|
+
month?: number;
|
|
16
|
+
year?: number;
|
|
13
17
|
}
|
|
14
18
|
declare const budgetKeys: {
|
|
15
19
|
all: readonly ["budgets"];
|
|
16
20
|
lists: () => readonly ["budgets", "list"];
|
|
17
|
-
list: (userId: string, filters?:
|
|
21
|
+
list: (userId: string, filters?: BudgetFilters) => readonly ["budgets", "list", string, BudgetFilters];
|
|
18
22
|
details: () => readonly ["budgets", "detail"];
|
|
19
|
-
detail: (userId: string, budgetId:
|
|
23
|
+
detail: (userId: string, budgetId: string) => readonly ["budgets", "detail", string, string];
|
|
20
24
|
};
|
|
21
25
|
|
|
22
26
|
interface UseBudgetsParams {
|
|
23
27
|
userId: string;
|
|
24
|
-
filters?:
|
|
28
|
+
filters?: BudgetFilters;
|
|
29
|
+
}
|
|
30
|
+
interface BudgetsData {
|
|
31
|
+
budgets: BudgetWithRelations[];
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
|
-
* Fetch budgets
|
|
28
|
-
* Uses Zod validation to ensure API response matches expected schema
|
|
29
|
-
*
|
|
30
|
-
* @param params - Query parameters with userId and optional date range filters
|
|
31
|
-
* @param options - TanStack Query options
|
|
32
|
-
* @returns Query result with validated budgets data
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```tsx
|
|
36
|
-
* // Fetch all budgets
|
|
37
|
-
* function BudgetsList() {
|
|
38
|
-
* const { data, isLoading } = useBudgets({ userId: 'user123' });
|
|
39
|
-
*
|
|
40
|
-
* return (
|
|
41
|
-
* <ul>
|
|
42
|
-
* {data?.budgets.map(budget => (
|
|
43
|
-
* <li key={budget.id}>{budget.name}</li>
|
|
44
|
-
* ))}
|
|
45
|
-
* </ul>
|
|
46
|
-
* );
|
|
47
|
-
* }
|
|
48
|
-
*
|
|
49
|
-
* // Fetch budgets for specific date range
|
|
50
|
-
* function MonthBudgets() {
|
|
51
|
-
* const { data } = useBudgets({
|
|
52
|
-
* userId: 'user123',
|
|
53
|
-
* filters: {
|
|
54
|
-
* start_date: '2025-01-01T00:00:00Z',
|
|
55
|
-
* end_date: '2025-01-31T23:59:59Z',
|
|
56
|
-
* }
|
|
57
|
-
* });
|
|
34
|
+
* Fetch all budgets for a user from Supabase
|
|
58
35
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* ```
|
|
36
|
+
* Returns `{ budgets: BudgetWithRelations[] }` to match the shape expected by
|
|
37
|
+
* feature hooks (useBudgetProgress, useBudgetSummary, useBudgetsByMonth).
|
|
62
38
|
*/
|
|
63
|
-
declare function useBudgets(params: UseBudgetsParams, options?: Omit<UseQueryOptions<
|
|
64
|
-
budgets: {
|
|
65
|
-
id: number;
|
|
66
|
-
month: number;
|
|
67
|
-
year: number;
|
|
68
|
-
name: string;
|
|
69
|
-
state: "under" | "risk" | "over";
|
|
70
|
-
spent: number;
|
|
71
|
-
budget_amount: number;
|
|
72
|
-
tag_names: string[];
|
|
73
|
-
links: {
|
|
74
|
-
accounts: number[];
|
|
75
|
-
budget_histories: number[];
|
|
76
|
-
};
|
|
77
|
-
}[];
|
|
78
|
-
}, Error>;
|
|
39
|
+
declare function useBudgets(params: UseBudgetsParams, options?: Omit<UseQueryOptions<BudgetsData>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<BudgetsData, Error>;
|
|
79
40
|
|
|
80
41
|
interface UseBudgetParams {
|
|
81
42
|
userId: string;
|
|
82
|
-
budgetId:
|
|
43
|
+
budgetId: string;
|
|
83
44
|
}
|
|
84
45
|
/**
|
|
85
|
-
* Fetch a single budget by ID
|
|
86
|
-
* Uses Zod validation to ensure API response matches expected schema
|
|
87
|
-
*
|
|
88
|
-
* @param params - Query parameters with userId and budgetId
|
|
89
|
-
* @param options - TanStack Query options
|
|
90
|
-
* @returns Query result with validated budget data
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* ```tsx
|
|
94
|
-
* function BudgetDetail({ budgetId }: { budgetId: number }) {
|
|
95
|
-
* const { data, isLoading, error } = useBudget({
|
|
96
|
-
* userId: 'user123',
|
|
97
|
-
* budgetId
|
|
98
|
-
* });
|
|
99
|
-
*
|
|
100
|
-
* if (isLoading) return <div>Loading...</div>;
|
|
101
|
-
* if (error) return <div>Error: {error.message}</div>;
|
|
102
|
-
*
|
|
103
|
-
* return (
|
|
104
|
-
* <div>
|
|
105
|
-
* <h1>{data.name}</h1>
|
|
106
|
-
* <p>Amount: ${data.budget_amount}</p>
|
|
107
|
-
* <p>Spent: ${data.spent}</p>
|
|
108
|
-
* <p>State: {data.state}</p>
|
|
109
|
-
* </div>
|
|
110
|
-
* );
|
|
111
|
-
* }
|
|
112
|
-
* ```
|
|
46
|
+
* Fetch a single budget by ID from Supabase
|
|
113
47
|
*/
|
|
114
|
-
declare function useBudget(params: UseBudgetParams, options?: Omit<UseQueryOptions<
|
|
115
|
-
id:
|
|
48
|
+
declare function useBudget(params: UseBudgetParams, options?: Omit<UseQueryOptions<BudgetWithRelations>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<{
|
|
49
|
+
id: string;
|
|
50
|
+
user_id: string;
|
|
51
|
+
name: string;
|
|
116
52
|
month: number;
|
|
117
53
|
year: number;
|
|
118
|
-
name: string;
|
|
119
|
-
state: "under" | "risk" | "over";
|
|
120
|
-
spent: number;
|
|
121
54
|
budget_amount: number;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
55
|
+
spent: number;
|
|
56
|
+
state: string;
|
|
57
|
+
show_on_dashboard: boolean;
|
|
58
|
+
budget_tags: {
|
|
59
|
+
budget_id: string;
|
|
60
|
+
tag_name: string;
|
|
61
|
+
}[];
|
|
62
|
+
budget_accounts: {
|
|
63
|
+
budget_id: string;
|
|
64
|
+
account_id: string;
|
|
65
|
+
}[];
|
|
66
|
+
created_at?: string | null | undefined;
|
|
67
|
+
updated_at?: string | null | undefined;
|
|
127
68
|
}, Error>;
|
|
128
69
|
|
|
129
70
|
interface CreateBudgetParams {
|
|
130
71
|
userId: string;
|
|
131
72
|
data: BudgetCreate;
|
|
73
|
+
tagNames?: string[];
|
|
74
|
+
accountIds?: string[];
|
|
132
75
|
}
|
|
133
76
|
/**
|
|
134
|
-
* Create a new budget
|
|
135
|
-
* Validates input with Zod schema and invalidates related queries on success
|
|
136
|
-
*
|
|
137
|
-
* @param options - TanStack Mutation options
|
|
138
|
-
* @returns Mutation result
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
141
|
-
* ```tsx
|
|
142
|
-
* function BudgetCreateForm() {
|
|
143
|
-
* const createBudget = useCreateBudget();
|
|
77
|
+
* Create a new budget with optional tag and account associations
|
|
144
78
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* userId: 'user123',
|
|
148
|
-
* data: {
|
|
149
|
-
* name: formData.name,
|
|
150
|
-
* budget_amount: formData.amount,
|
|
151
|
-
* tag_names: formData.tags,
|
|
152
|
-
* account_list: formData.accounts,
|
|
153
|
-
* show_on_dashboard: true,
|
|
154
|
-
* other: {}
|
|
155
|
-
* }
|
|
156
|
-
* }, {
|
|
157
|
-
* onSuccess: (newBudget) => {
|
|
158
|
-
* toast.success('Budget created!');
|
|
159
|
-
* router.push(`/budgets/${newBudget.id}`);
|
|
160
|
-
* },
|
|
161
|
-
* onError: (error) => {
|
|
162
|
-
* toast.error(`Failed: ${error.message}`);
|
|
163
|
-
* }
|
|
164
|
-
* });
|
|
165
|
-
* };
|
|
166
|
-
*
|
|
167
|
-
* return <form onSubmit={handleSubmit}>...</form>;
|
|
168
|
-
* }
|
|
169
|
-
* ```
|
|
79
|
+
* Multi-step: (1) insert budget, (2) insert budget_tags rows,
|
|
80
|
+
* (3) insert budget_accounts rows, (4) re-fetch with relations.
|
|
170
81
|
*/
|
|
171
|
-
declare function useCreateBudget(options?: Omit<UseMutationOptions<
|
|
172
|
-
id:
|
|
82
|
+
declare function useCreateBudget(options?: Omit<UseMutationOptions<BudgetWithRelations, Error, CreateBudgetParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
|
|
83
|
+
id: string;
|
|
84
|
+
user_id: string;
|
|
85
|
+
name: string;
|
|
173
86
|
month: number;
|
|
174
87
|
year: number;
|
|
175
|
-
name: string;
|
|
176
|
-
state: "under" | "risk" | "over";
|
|
177
|
-
spent: number;
|
|
178
88
|
budget_amount: number;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
89
|
+
spent: number;
|
|
90
|
+
state: string;
|
|
91
|
+
show_on_dashboard: boolean;
|
|
92
|
+
budget_tags: {
|
|
93
|
+
budget_id: string;
|
|
94
|
+
tag_name: string;
|
|
95
|
+
}[];
|
|
96
|
+
budget_accounts: {
|
|
97
|
+
budget_id: string;
|
|
98
|
+
account_id: string;
|
|
99
|
+
}[];
|
|
100
|
+
created_at?: string | null | undefined;
|
|
101
|
+
updated_at?: string | null | undefined;
|
|
184
102
|
}, Error, CreateBudgetParams, unknown>;
|
|
185
103
|
|
|
186
104
|
interface UpdateBudgetParams {
|
|
187
105
|
userId: string;
|
|
188
|
-
budgetId:
|
|
106
|
+
budgetId: string;
|
|
189
107
|
data: BudgetUpdate;
|
|
108
|
+
tagNames?: string[];
|
|
109
|
+
accountIds?: string[];
|
|
190
110
|
}
|
|
191
111
|
/**
|
|
192
112
|
* Update an existing budget
|
|
193
|
-
* Validates input with Zod schema and invalidates related queries on success
|
|
194
|
-
*
|
|
195
|
-
* @param options - TanStack Mutation options
|
|
196
|
-
* @returns Mutation result
|
|
197
113
|
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* function BudgetEditForm({ budget }: { budget: Budget }) {
|
|
201
|
-
* const updateBudget = useUpdateBudget();
|
|
202
|
-
*
|
|
203
|
-
* const handleSubmit = (formData) => {
|
|
204
|
-
* updateBudget.mutate({
|
|
205
|
-
* userId: 'user123',
|
|
206
|
-
* budgetId: budget.id,
|
|
207
|
-
* data: {
|
|
208
|
-
* name: formData.name,
|
|
209
|
-
* budget_amount: formData.amount,
|
|
210
|
-
* tag_names: formData.tags,
|
|
211
|
-
* account_list: formData.accounts,
|
|
212
|
-
* show_on_dashboard: formData.showOnDashboard,
|
|
213
|
-
* other: formData.metadata
|
|
214
|
-
* }
|
|
215
|
-
* }, {
|
|
216
|
-
* onSuccess: () => {
|
|
217
|
-
* toast.success('Budget updated!');
|
|
218
|
-
* },
|
|
219
|
-
* onError: (error) => {
|
|
220
|
-
* toast.error(`Failed: ${error.message}`);
|
|
221
|
-
* }
|
|
222
|
-
* });
|
|
223
|
-
* };
|
|
224
|
-
*
|
|
225
|
-
* return <form onSubmit={handleSubmit}>...</form>;
|
|
226
|
-
* }
|
|
227
|
-
* ```
|
|
114
|
+
* If tagNames or accountIds are provided, replaces all existing
|
|
115
|
+
* junction rows (delete all, then insert new).
|
|
228
116
|
*/
|
|
229
|
-
declare function useUpdateBudget(options?: Omit<UseMutationOptions<
|
|
230
|
-
id:
|
|
117
|
+
declare function useUpdateBudget(options?: Omit<UseMutationOptions<BudgetWithRelations, Error, UpdateBudgetParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<{
|
|
118
|
+
id: string;
|
|
119
|
+
user_id: string;
|
|
120
|
+
name: string;
|
|
231
121
|
month: number;
|
|
232
122
|
year: number;
|
|
233
|
-
name: string;
|
|
234
|
-
state: "under" | "risk" | "over";
|
|
235
|
-
spent: number;
|
|
236
123
|
budget_amount: number;
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
124
|
+
spent: number;
|
|
125
|
+
state: string;
|
|
126
|
+
show_on_dashboard: boolean;
|
|
127
|
+
budget_tags: {
|
|
128
|
+
budget_id: string;
|
|
129
|
+
tag_name: string;
|
|
130
|
+
}[];
|
|
131
|
+
budget_accounts: {
|
|
132
|
+
budget_id: string;
|
|
133
|
+
account_id: string;
|
|
134
|
+
}[];
|
|
135
|
+
created_at?: string | null | undefined;
|
|
136
|
+
updated_at?: string | null | undefined;
|
|
242
137
|
}, Error, UpdateBudgetParams, unknown>;
|
|
243
138
|
|
|
244
139
|
interface DeleteBudgetParams {
|
|
245
140
|
userId: string;
|
|
246
|
-
budgetId:
|
|
141
|
+
budgetId: string;
|
|
247
142
|
}
|
|
248
143
|
/**
|
|
249
|
-
* Delete a budget
|
|
250
|
-
*
|
|
251
|
-
* Invalidates related queries on success
|
|
252
|
-
*
|
|
253
|
-
* @param options - TanStack Mutation options
|
|
254
|
-
* @returns Mutation result
|
|
255
|
-
*
|
|
256
|
-
* @example
|
|
257
|
-
* ```tsx
|
|
258
|
-
* function BudgetDeleteButton({ budgetId }: { budgetId: number }) {
|
|
259
|
-
* const deleteBudget = useDeleteBudget();
|
|
260
|
-
*
|
|
261
|
-
* const handleDelete = () => {
|
|
262
|
-
* if (confirm('Are you sure you want to delete this budget?')) {
|
|
263
|
-
* deleteBudget.mutate({
|
|
264
|
-
* userId: 'user123',
|
|
265
|
-
* budgetId
|
|
266
|
-
* }, {
|
|
267
|
-
* onSuccess: () => {
|
|
268
|
-
* toast.success('Budget deleted');
|
|
269
|
-
* router.push('/budgets');
|
|
270
|
-
* },
|
|
271
|
-
* onError: (error) => {
|
|
272
|
-
* toast.error(`Failed: ${error.message}`);
|
|
273
|
-
* }
|
|
274
|
-
* });
|
|
275
|
-
* }
|
|
276
|
-
* };
|
|
277
|
-
*
|
|
278
|
-
* return (
|
|
279
|
-
* <button
|
|
280
|
-
* onClick={handleDelete}
|
|
281
|
-
* disabled={deleteBudget.isPending}
|
|
282
|
-
* >
|
|
283
|
-
* {deleteBudget.isPending ? 'Deleting...' : 'Delete'}
|
|
284
|
-
* </button>
|
|
285
|
-
* );
|
|
286
|
-
* }
|
|
287
|
-
* ```
|
|
144
|
+
* Delete a budget from Supabase (hard delete)
|
|
145
|
+
* Junction rows in budget_tags and budget_accounts cascade-delete.
|
|
288
146
|
*/
|
|
289
147
|
declare function useDeleteBudget(options?: Omit<UseMutationOptions<void, Error, DeleteBudgetParams>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<void, Error, DeleteBudgetParams, unknown>;
|
|
290
148
|
|
|
291
|
-
|
|
292
|
-
* Axios client for Budget API calls
|
|
293
|
-
* Reuses pattern from accounts/transactions data-access
|
|
294
|
-
*/
|
|
295
|
-
declare const api: axios.AxiosInstance;
|
|
296
|
-
|
|
297
|
-
export { type BudgetDateRangeFilters, type CreateBudgetParams, type DeleteBudgetParams, type UpdateBudgetParams, type UseBudgetParams, type UseBudgetsParams, api, budgetKeys, useBudget, useBudgets, useCreateBudget, useDeleteBudget, useUpdateBudget };
|
|
149
|
+
export { type BudgetFilters, type BudgetsData, type CreateBudgetParams, type DeleteBudgetParams, type UpdateBudgetParams, type UseBudgetParams, type UseBudgetsParams, budgetKeys, useBudget, useBudgets, useCreateBudget, useDeleteBudget, useUpdateBudget };
|