@pfm-platform/accounts-data-access 0.2.0 → 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 +89 -160
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +124 -566
- package/dist/index.d.ts +124 -566
- package/dist/index.js +91 -157
- package/dist/index.js.map +1 -1
- package/package.json +7 -9
package/dist/index.cjs
CHANGED
|
@@ -2,112 +2,19 @@
|
|
|
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/useAccounts.ts
|
|
12
7
|
|
|
13
8
|
// src/keys.ts
|
|
14
9
|
var accountKeys = {
|
|
15
|
-
/**
|
|
16
|
-
* Root key for all account-related queries
|
|
17
|
-
*/
|
|
18
10
|
all: ["accounts"],
|
|
19
|
-
/**
|
|
20
|
-
* Key for all account list queries
|
|
21
|
-
*/
|
|
22
11
|
lists: () => [...accountKeys.all, "list"],
|
|
23
|
-
/**
|
|
24
|
-
* Key for a specific user's account list
|
|
25
|
-
* @param userId - User ID
|
|
26
|
-
*/
|
|
27
12
|
list: (userId) => [...accountKeys.lists(), userId],
|
|
28
|
-
/**
|
|
29
|
-
* Key for all account detail queries
|
|
30
|
-
*/
|
|
31
13
|
details: () => [...accountKeys.all, "detail"],
|
|
32
|
-
/**
|
|
33
|
-
* Key for a specific account detail
|
|
34
|
-
* @param userId - User ID
|
|
35
|
-
* @param accountId - Account ID
|
|
36
|
-
*/
|
|
37
14
|
detail: (userId, accountId) => [...accountKeys.details(), userId, accountId],
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*/
|
|
41
|
-
investments: () => [...accountKeys.all, "investments"],
|
|
42
|
-
/**
|
|
43
|
-
* Key for a specific account's investments
|
|
44
|
-
* @param userId - User ID
|
|
45
|
-
* @param accountId - Account ID
|
|
46
|
-
*/
|
|
47
|
-
investment: (userId, accountId) => [...accountKeys.investments(), userId, accountId],
|
|
48
|
-
/**
|
|
49
|
-
* Key for all account transaction queries
|
|
50
|
-
*/
|
|
51
|
-
transactions: () => [...accountKeys.all, "transactions"],
|
|
52
|
-
/**
|
|
53
|
-
* Key for a specific account's transactions
|
|
54
|
-
* @param userId - User ID
|
|
55
|
-
* @param accountId - Account ID
|
|
56
|
-
* @param page - Page number for pagination
|
|
57
|
-
*/
|
|
58
|
-
transaction: (userId, accountId, page) => [...accountKeys.transactions(), userId, accountId, page],
|
|
59
|
-
/**
|
|
60
|
-
* Key for all net worth queries
|
|
61
|
-
*/
|
|
62
|
-
networth: () => [...accountKeys.all, "networth"],
|
|
63
|
-
/**
|
|
64
|
-
* Key for a specific user's net worth summary
|
|
65
|
-
* @param userId - User ID
|
|
66
|
-
*/
|
|
67
|
-
networthSummary: (userId) => [...accountKeys.networth(), userId],
|
|
68
|
-
/**
|
|
69
|
-
* Key for all net worth account queries
|
|
70
|
-
*/
|
|
71
|
-
networthAccounts: () => [...accountKeys.networth(), "accounts"],
|
|
72
|
-
/**
|
|
73
|
-
* Key for a specific net worth account
|
|
74
|
-
* @param userId - User ID
|
|
75
|
-
* @param accountId - Net worth account ID
|
|
76
|
-
*/
|
|
77
|
-
networthAccount: (userId, accountId) => [...accountKeys.networthAccounts(), userId, accountId]
|
|
15
|
+
institutions: () => [...accountKeys.all, "institutions"],
|
|
16
|
+
institution: (userId) => [...accountKeys.institutions(), userId]
|
|
78
17
|
};
|
|
79
|
-
var api = axios__default.default.create({
|
|
80
|
-
baseURL: "/api",
|
|
81
|
-
headers: {
|
|
82
|
-
"Content-Type": "application/json"
|
|
83
|
-
},
|
|
84
|
-
timeout: 1e4
|
|
85
|
-
// 10 second timeout
|
|
86
|
-
});
|
|
87
|
-
api.interceptors.request.use(
|
|
88
|
-
(config) => {
|
|
89
|
-
const token = localStorage.getItem("auth_token");
|
|
90
|
-
if (token) {
|
|
91
|
-
config.headers.Authorization = `Bearer ${token}`;
|
|
92
|
-
}
|
|
93
|
-
return config;
|
|
94
|
-
},
|
|
95
|
-
(error) => {
|
|
96
|
-
return Promise.reject(error);
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
api.interceptors.response.use(
|
|
100
|
-
(response) => response,
|
|
101
|
-
(error) => {
|
|
102
|
-
if (error.response?.status === 401) {
|
|
103
|
-
localStorage.removeItem("auth_token");
|
|
104
|
-
if (typeof window !== "undefined") {
|
|
105
|
-
window.location.href = "/login";
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return Promise.reject(error);
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
18
|
|
|
112
19
|
// src/queries/useAccounts.ts
|
|
113
20
|
function useAccounts(params, options) {
|
|
@@ -115,11 +22,11 @@ function useAccounts(params, options) {
|
|
|
115
22
|
return reactQuery.useQuery({
|
|
116
23
|
queryKey: accountKeys.list(userId),
|
|
117
24
|
queryFn: async () => {
|
|
118
|
-
const
|
|
119
|
-
|
|
25
|
+
const { data, error } = await shared.supabase.from("accounts").select("*").eq("user_id", userId).order("name");
|
|
26
|
+
if (error) throw error;
|
|
27
|
+
return { accounts: shared.AccountsResponseSchema.parse(data) };
|
|
120
28
|
},
|
|
121
29
|
staleTime: 1e3 * 60 * 5,
|
|
122
|
-
// 5 minutes - accounts don't change frequently
|
|
123
30
|
...options
|
|
124
31
|
});
|
|
125
32
|
}
|
|
@@ -128,24 +35,61 @@ function useAccount(params, options) {
|
|
|
128
35
|
return reactQuery.useQuery({
|
|
129
36
|
queryKey: accountKeys.detail(userId, accountId),
|
|
130
37
|
queryFn: async () => {
|
|
131
|
-
const
|
|
132
|
-
|
|
38
|
+
const { data, error } = await shared.supabase.from("accounts").select("*").eq("id", accountId).eq("user_id", userId).single();
|
|
39
|
+
if (error) throw error;
|
|
40
|
+
return shared.AccountSchema.parse(data);
|
|
133
41
|
},
|
|
134
42
|
staleTime: 1e3 * 60 * 5,
|
|
135
|
-
// 5 minutes
|
|
136
43
|
...options
|
|
137
44
|
});
|
|
138
45
|
}
|
|
139
46
|
function useNetWorth(params, options) {
|
|
140
47
|
const { userId } = params;
|
|
141
48
|
return reactQuery.useQuery({
|
|
142
|
-
queryKey: accountKeys.
|
|
49
|
+
queryKey: [...accountKeys.all, "networth", userId],
|
|
143
50
|
queryFn: async () => {
|
|
144
|
-
const
|
|
145
|
-
|
|
51
|
+
const { data: accounts, error: accountsError } = await shared.supabase.from("networth_accounts").select("*").eq("user_id", userId);
|
|
52
|
+
if (accountsError) throw accountsError;
|
|
53
|
+
const { data: histories, error: historiesError } = await shared.supabase.from("networth_history").select("*").eq("user_id", userId).order("year", { ascending: true }).order("month", { ascending: true });
|
|
54
|
+
if (historiesError) throw historiesError;
|
|
55
|
+
const assets = (accounts || []).filter((a) => a.account_type === "asset").map((a) => ({
|
|
56
|
+
id: a.id,
|
|
57
|
+
name: a.name,
|
|
58
|
+
balance: String(a.balance),
|
|
59
|
+
account_type: a.account_type,
|
|
60
|
+
additional_networth_account: a.additional_networth_account
|
|
61
|
+
}));
|
|
62
|
+
const debts = (accounts || []).filter((a) => a.account_type === "debt").map((a) => ({
|
|
63
|
+
id: a.id,
|
|
64
|
+
name: a.name,
|
|
65
|
+
balance: String(a.balance),
|
|
66
|
+
account_type: a.account_type,
|
|
67
|
+
additional_networth_account: a.additional_networth_account
|
|
68
|
+
}));
|
|
69
|
+
const totalAssets = assets.reduce((sum, a) => sum + parseFloat(a.balance), 0);
|
|
70
|
+
const totalDebts = debts.reduce((sum, d) => sum + parseFloat(d.balance), 0);
|
|
71
|
+
const networthHistories = (histories || []).map((h) => ({
|
|
72
|
+
total: String(h.total),
|
|
73
|
+
total_asset: String(h.total_asset),
|
|
74
|
+
total_debt: String(h.total_debt),
|
|
75
|
+
month: String(h.month).padStart(2, "0"),
|
|
76
|
+
year: String(h.year),
|
|
77
|
+
since_last_month: String(h.since_last_month)
|
|
78
|
+
}));
|
|
79
|
+
return {
|
|
80
|
+
meta: {
|
|
81
|
+
net_worth: String(totalAssets - totalDebts),
|
|
82
|
+
net_worth_change: "0",
|
|
83
|
+
// TODO: compute from networth_history
|
|
84
|
+
total_assets: String(totalAssets),
|
|
85
|
+
total_debts: String(totalDebts)
|
|
86
|
+
},
|
|
87
|
+
assets,
|
|
88
|
+
debts,
|
|
89
|
+
networth_histories: networthHistories
|
|
90
|
+
};
|
|
146
91
|
},
|
|
147
92
|
staleTime: 1e3 * 60 * 5,
|
|
148
|
-
// 5 minutes - net worth doesn't change frequently
|
|
149
93
|
...options
|
|
150
94
|
});
|
|
151
95
|
}
|
|
@@ -153,27 +97,22 @@ function useCreateAccount(options) {
|
|
|
153
97
|
const queryClient = reactQuery.useQueryClient();
|
|
154
98
|
const { mode } = shared.useAppMode();
|
|
155
99
|
return reactQuery.useMutation({
|
|
156
|
-
mutationFn: async ({
|
|
100
|
+
mutationFn: async ({ data }) => {
|
|
157
101
|
const schema = mode === "admin" ? shared.AccountCreateSchemaAdmin : shared.AccountCreateSchemaUser;
|
|
158
102
|
const validated = schema.parse(data);
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
);
|
|
163
|
-
return shared.AccountSchema.parse(response.data);
|
|
103
|
+
const { data: created, error } = await shared.supabase.from("accounts").insert(validated).select().single();
|
|
104
|
+
if (error) throw error;
|
|
105
|
+
return shared.AccountSchema.parse(created);
|
|
164
106
|
},
|
|
165
|
-
onSuccess: (newAccount, variables,
|
|
107
|
+
onSuccess: (newAccount, variables, onMutateResult, context) => {
|
|
166
108
|
queryClient.setQueryData(
|
|
167
109
|
accountKeys.list(variables.userId),
|
|
168
110
|
(oldData) => {
|
|
169
|
-
if (!oldData
|
|
170
|
-
return {
|
|
171
|
-
...oldData,
|
|
172
|
-
accounts: [...oldData.accounts, newAccount]
|
|
173
|
-
};
|
|
111
|
+
if (!oldData) return { accounts: [newAccount] };
|
|
112
|
+
return { accounts: [...oldData.accounts, newAccount] };
|
|
174
113
|
}
|
|
175
114
|
);
|
|
176
|
-
options?.onSuccess?.(newAccount, variables,
|
|
115
|
+
options?.onSuccess?.(newAccount, variables, onMutateResult, context);
|
|
177
116
|
},
|
|
178
117
|
...options
|
|
179
118
|
});
|
|
@@ -181,13 +120,11 @@ function useCreateAccount(options) {
|
|
|
181
120
|
function useUpdateAccount(options) {
|
|
182
121
|
const queryClient = reactQuery.useQueryClient();
|
|
183
122
|
return reactQuery.useMutation({
|
|
184
|
-
mutationFn: async ({
|
|
123
|
+
mutationFn: async ({ accountId, data }) => {
|
|
185
124
|
const validated = shared.AccountUpdateSchema.parse(data);
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
);
|
|
190
|
-
return shared.AccountSchema.parse(response.data);
|
|
125
|
+
const { data: updated, error } = await shared.supabase.from("accounts").update(validated).eq("id", accountId).select().single();
|
|
126
|
+
if (error) throw error;
|
|
127
|
+
return shared.AccountSchema.parse(updated);
|
|
191
128
|
},
|
|
192
129
|
onSuccess: (_, { userId, accountId }) => {
|
|
193
130
|
queryClient.invalidateQueries({
|
|
@@ -203,8 +140,9 @@ function useUpdateAccount(options) {
|
|
|
203
140
|
function useDeleteAccount(options) {
|
|
204
141
|
const queryClient = reactQuery.useQueryClient();
|
|
205
142
|
return reactQuery.useMutation({
|
|
206
|
-
mutationFn: async ({
|
|
207
|
-
await
|
|
143
|
+
mutationFn: async ({ accountId }) => {
|
|
144
|
+
const { error } = await shared.supabase.from("accounts").delete().eq("id", accountId);
|
|
145
|
+
if (error) throw error;
|
|
208
146
|
},
|
|
209
147
|
onSuccess: (_, { userId, accountId }) => {
|
|
210
148
|
queryClient.invalidateQueries({
|
|
@@ -220,11 +158,10 @@ function useDeleteAccount(options) {
|
|
|
220
158
|
function useArchiveAccount(options) {
|
|
221
159
|
const queryClient = reactQuery.useQueryClient();
|
|
222
160
|
return reactQuery.useMutation({
|
|
223
|
-
mutationFn: async ({
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
);
|
|
227
|
-
return shared.AccountSchema.parse(response.data);
|
|
161
|
+
mutationFn: async ({ accountId }) => {
|
|
162
|
+
const { data, error } = await shared.supabase.from("accounts").update({ is_active: false }).eq("id", accountId).select().single();
|
|
163
|
+
if (error) throw error;
|
|
164
|
+
return shared.AccountSchema.parse(data);
|
|
228
165
|
},
|
|
229
166
|
onSuccess: (_, { userId, accountId }) => {
|
|
230
167
|
queryClient.invalidateQueries({
|
|
@@ -241,21 +178,18 @@ function useCreateNetWorthAccount(options) {
|
|
|
241
178
|
const queryClient = reactQuery.useQueryClient();
|
|
242
179
|
return reactQuery.useMutation({
|
|
243
180
|
mutationFn: async ({ userId, data }) => {
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
} else {
|
|
253
|
-
return shared.NetWorthDebtSchema.parse(response.data);
|
|
254
|
-
}
|
|
181
|
+
const { error } = await shared.supabase.from("networth_accounts").insert({
|
|
182
|
+
user_id: userId,
|
|
183
|
+
name: data.networth_account.name,
|
|
184
|
+
balance: parseFloat(data.networth_account.balance),
|
|
185
|
+
account_type: data.networth_account.account_type,
|
|
186
|
+
additional_networth_account: true
|
|
187
|
+
});
|
|
188
|
+
if (error) throw error;
|
|
255
189
|
},
|
|
256
190
|
onSuccess: (_, { userId }) => {
|
|
257
191
|
queryClient.invalidateQueries({
|
|
258
|
-
queryKey: accountKeys.
|
|
192
|
+
queryKey: [...accountKeys.all, "networth", userId]
|
|
259
193
|
});
|
|
260
194
|
},
|
|
261
195
|
...options
|
|
@@ -264,21 +198,17 @@ function useCreateNetWorthAccount(options) {
|
|
|
264
198
|
function useUpdateNetWorthAccount(options) {
|
|
265
199
|
const queryClient = reactQuery.useQueryClient();
|
|
266
200
|
return reactQuery.useMutation({
|
|
267
|
-
mutationFn: async ({
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
return shared.NetWorthAssetSchema.parse(response.data);
|
|
275
|
-
} catch {
|
|
276
|
-
return shared.NetWorthDebtSchema.parse(response.data);
|
|
277
|
-
}
|
|
201
|
+
mutationFn: async ({ accountId, data }) => {
|
|
202
|
+
const { error } = await shared.supabase.from("networth_accounts").update({
|
|
203
|
+
name: data.networth_account.name,
|
|
204
|
+
balance: parseFloat(data.networth_account.balance),
|
|
205
|
+
account_type: data.networth_account.account_type
|
|
206
|
+
}).eq("id", String(accountId));
|
|
207
|
+
if (error) throw error;
|
|
278
208
|
},
|
|
279
209
|
onSuccess: (_, { userId }) => {
|
|
280
210
|
queryClient.invalidateQueries({
|
|
281
|
-
queryKey: accountKeys.
|
|
211
|
+
queryKey: [...accountKeys.all, "networth", userId]
|
|
282
212
|
});
|
|
283
213
|
},
|
|
284
214
|
...options
|
|
@@ -287,13 +217,13 @@ function useUpdateNetWorthAccount(options) {
|
|
|
287
217
|
function useDeleteNetWorthAccount(options) {
|
|
288
218
|
const queryClient = reactQuery.useQueryClient();
|
|
289
219
|
return reactQuery.useMutation({
|
|
290
|
-
mutationFn: async ({
|
|
291
|
-
shared.
|
|
292
|
-
|
|
220
|
+
mutationFn: async ({ accountId }) => {
|
|
221
|
+
const { error } = await shared.supabase.from("networth_accounts").delete().eq("id", String(accountId));
|
|
222
|
+
if (error) throw error;
|
|
293
223
|
},
|
|
294
224
|
onSuccess: (_, { userId }) => {
|
|
295
225
|
queryClient.invalidateQueries({
|
|
296
|
-
queryKey: accountKeys.
|
|
226
|
+
queryKey: [...accountKeys.all, "networth", userId]
|
|
297
227
|
});
|
|
298
228
|
},
|
|
299
229
|
...options
|
|
@@ -301,7 +231,6 @@ function useDeleteNetWorthAccount(options) {
|
|
|
301
231
|
}
|
|
302
232
|
|
|
303
233
|
exports.accountKeys = accountKeys;
|
|
304
|
-
exports.api = api;
|
|
305
234
|
exports.useAccount = useAccount;
|
|
306
235
|
exports.useAccounts = useAccounts;
|
|
307
236
|
exports.useArchiveAccount = useArchiveAccount;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/keys.ts","../src/client.ts","../src/queries/useAccounts.ts","../src/queries/useAccount.ts","../src/queries/useNetWorth.ts","../src/mutations/useCreateAccount.ts","../src/mutations/useUpdateAccount.ts","../src/mutations/useDeleteAccount.ts","../src/mutations/useArchiveAccount.ts","../src/mutations/useCreateNetWorthAccount.ts","../src/mutations/useUpdateNetWorthAccount.ts","../src/mutations/useDeleteNetWorthAccount.ts"],"names":["axios","useQuery","AccountsResponseSchema","AccountSchema","NetWorthResponseSchema","useQueryClient","useAppMode","useMutation","AccountCreateSchemaAdmin","AccountCreateSchemaUser","AccountUpdateSchema","NetWorthAccountCreateSchema","NetWorthAssetSchema","NetWorthDebtSchema","NetWorthAccountUpdateSchema","NetWorthAccountDeleteSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Query key factory for Accounts domain\n * Following TanStack Query best practices for hierarchical cache keys\n *\n * Key structure:\n * - ['accounts'] - Root key for all account queries\n * - ['accounts', 'list', userId] - List of accounts for a user\n * - ['accounts', 'detail', userId, accountId] - Single account detail\n * - ['accounts', 'investments', userId, accountId] - Account investments\n * - ['accounts', 'transactions', userId, accountId, page] - Account transactions\n */\n\nexport const accountKeys = {\n /**\n * Root key for all account-related queries\n */\n all: ['accounts'] as const,\n\n /**\n * Key for all account list queries\n */\n lists: () => [...accountKeys.all, 'list'] as const,\n\n /**\n * Key for a specific user's account list\n * @param userId - User ID\n */\n list: (userId: string) => [...accountKeys.lists(), userId] as const,\n\n /**\n * Key for all account detail queries\n */\n details: () => [...accountKeys.all, 'detail'] as const,\n\n /**\n * Key for a specific account detail\n * @param userId - User ID\n * @param accountId - Account ID\n */\n detail: (userId: string, accountId: number) =>\n [...accountKeys.details(), userId, accountId] as const,\n\n /**\n * Key for all account investment queries\n */\n investments: () => [...accountKeys.all, 'investments'] as const,\n\n /**\n * Key for a specific account's investments\n * @param userId - User ID\n * @param accountId - Account ID\n */\n investment: (userId: string, accountId: number) =>\n [...accountKeys.investments(), userId, accountId] as const,\n\n /**\n * Key for all account transaction queries\n */\n transactions: () => [...accountKeys.all, 'transactions'] as const,\n\n /**\n * Key for a specific account's transactions\n * @param userId - User ID\n * @param accountId - Account ID\n * @param page - Page number for pagination\n */\n transaction: (userId: string, accountId: number, page: number) =>\n [...accountKeys.transactions(), userId, accountId, page] as const,\n\n /**\n * Key for all net worth queries\n */\n networth: () => [...accountKeys.all, 'networth'] as const,\n\n /**\n * Key for a specific user's net worth summary\n * @param userId - User ID\n */\n networthSummary: (userId: string) =>\n [...accountKeys.networth(), userId] as const,\n\n /**\n * Key for all net worth account queries\n */\n networthAccounts: () => [...accountKeys.networth(), 'accounts'] as const,\n\n /**\n * Key for a specific net worth account\n * @param userId - User ID\n * @param accountId - Net worth account ID\n */\n networthAccount: (userId: string, accountId: number) =>\n [...accountKeys.networthAccounts(), userId, accountId] as const,\n};\n","/**\n * Base API client for Accounts domain\n * Uses axios with interceptors for auth and error handling\n */\n\nimport axios from 'axios';\n\n/**\n * Axios instance configured for PFM API\n * Base URL can be overridden via VITE_API_BASE_URL environment variable\n */\nexport const api = axios.create({\n baseURL: '/api',\n headers: {\n 'Content-Type': 'application/json',\n },\n timeout: 10000, // 10 second timeout\n});\n\n/**\n * Request interceptor to add authentication token\n * Reads token from localStorage and adds to Authorization header\n */\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) => {\n return Promise.reject(error);\n }\n);\n\n/**\n * Response interceptor for global error handling\n * - 401: Redirect to login\n * - 403: Access forbidden\n * - 5xx: Server errors\n */\napi.interceptors.response.use(\n (response) => response,\n (error) => {\n if (error.response?.status === 401) {\n // Unauthorized - clear token and redirect to login\n localStorage.removeItem('auth_token');\n if (typeof window !== 'undefined') {\n window.location.href = '/login';\n }\n }\n return Promise.reject(error);\n }\n);\n","/**\n * Query hook for fetching all accounts for a user\n * Legacy API: GET /users/{userId}/accounts/all\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { AccountsResponseSchema, AccountsResponse } from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface UseAccountsParams {\n userId: string;\n}\n\n/**\n * Fetch all accounts for a user\n * Uses Zod validation to ensure API response matches expected schema\n *\n * @param params - Query parameters\n * @param options - TanStack Query options\n * @returns Query result with validated accounts data\n *\n * @example\n * ```tsx\n * function AccountsList() {\n * const { data, isLoading, error } = useAccounts({ userId: 'user123' });\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <ul>\n * {data.accounts.map(account => (\n * <li key={account.id}>{account.name}</li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useAccounts(\n params: UseAccountsParams,\n options?: Omit<\n UseQueryOptions<AccountsResponse>,\n 'queryKey' | 'queryFn'\n >\n) {\n const { userId } = params;\n\n return useQuery({\n queryKey: accountKeys.list(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/accounts/all`);\n\n // Validate response with Zod schema from Mini-Arc 1\n // This ensures type safety and catches API contract changes\n return AccountsResponseSchema.parse(response.data);\n },\n staleTime: 1000 * 60 * 5, // 5 minutes - accounts don't change frequently\n ...options,\n });\n}\n","/**\n * Query hook for fetching a single account by ID\n * Legacy API: GET /users/{userId}/accounts/{id}\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { AccountSchema, Account } from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface UseAccountParams {\n userId: string;\n accountId: number;\n}\n\n/**\n * Fetch a single account by ID\n * Uses Zod validation to ensure API response matches expected schema\n *\n * @param params - Query parameters\n * @param options - TanStack Query options\n * @returns Query result with validated account data\n *\n * @example\n * ```tsx\n * function AccountDetail({ accountId }: { accountId: number }) {\n * const { data, isLoading, error } = useAccount({\n * userId: 'user123',\n * accountId\n * });\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * <h2>{data.name}</h2>\n * <p>Balance: ${data.balance}</p>\n * <p>Type: {data.account_type}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useAccount(\n params: UseAccountParams,\n options?: Omit<UseQueryOptions<Account>, 'queryKey' | 'queryFn'>\n) {\n const { userId, accountId } = params;\n\n return useQuery({\n queryKey: accountKeys.detail(userId, accountId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/accounts/${accountId}`);\n\n // Validate response with Zod schema from Mini-Arc 1\n return AccountSchema.parse(response.data);\n },\n staleTime: 1000 * 60 * 5, // 5 minutes\n ...options,\n });\n}\n","/**\n * Query hook for fetching net worth summary for a user\n * Legacy API: GET /users/{userId}/networth\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { NetWorthResponseSchema, NetWorth } from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface UseNetWorthParams {\n userId: string;\n}\n\n/**\n * Fetch net worth summary for a user\n * Includes: assets, debts, history, and summary metadata\n * Uses Zod validation to ensure API response matches expected schema\n *\n * @param params - Query parameters\n * @param options - TanStack Query options\n * @returns Query result with validated net worth data\n *\n * @example\n * ```tsx\n * function NetWorthSummary() {\n * const { data, isLoading, error } = useNetWorth({ userId: 'user123' });\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * <h2>Net Worth: {data.meta.net_worth}</h2>\n * <p>Total Assets: {data.meta.total_assets}</p>\n * <p>Total Debts: {data.meta.total_debts}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useNetWorth(\n params: UseNetWorthParams,\n options?: Omit<\n UseQueryOptions<NetWorth>,\n 'queryKey' | 'queryFn'\n >\n) {\n const { userId } = params;\n\n return useQuery({\n queryKey: accountKeys.networthSummary(userId),\n queryFn: async () => {\n const response = await api.get(`/users/${userId}/networth`);\n\n // Validate response with Zod schema\n // This ensures type safety and catches API contract changes\n return NetWorthResponseSchema.parse(response.data);\n },\n staleTime: 1000 * 60 * 5, // 5 minutes - net worth doesn't change frequently\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n AccountCreateSchemaAdmin,\n AccountCreateSchemaUser,\n AccountSchema,\n useAppMode,\n type AccountCreate,\n type Account,\n} from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { accountKeys } from '../keys';\n\n/**\n * Parameters for useCreateAccount mutation\n */\nexport interface CreateAccountParams {\n userId: string;\n data: AccountCreate;\n}\n\n/**\n * Mutation hook for creating a new account\n *\n * Creates an account manually for testing purposes.\n * Uses mode switching for validation:\n * - Admin mode: Minimal validation for test data creation\n * - User mode: Full validation with business rules\n *\n * @example\n * ```tsx\n * const createAccount = useCreateAccount();\n *\n * createAccount.mutate({\n * userId: 'user123',\n * data: {\n * name: 'Test Checking',\n * balance: '1000.00',\n * account_type: 'checking',\n * state: 'active',\n * aggregation_type: 'partner',\n * include_in_expenses: true,\n * include_in_budget: true,\n * include_in_cashflow: true,\n * include_in_dashboard: true,\n * include_in_goals: false,\n * include_in_networth: true\n * }\n * });\n * ```\n */\nexport function useCreateAccount(\n options?: Omit<UseMutationOptions<Account, Error, CreateAccountParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateAccountParams) => {\n // Select schema based on mode\n const schema =\n mode === 'admin'\n ? AccountCreateSchemaAdmin\n : AccountCreateSchemaUser;\n\n // Validate account data\n const validated = schema.parse(data);\n\n // POST to create new account\n const response = await api.post(\n `/users/${userId}/accounts`,\n validated\n );\n\n // Return created account\n return AccountSchema.parse(response.data);\n },\n onSuccess: (newAccount, variables, context, mutation) => {\n // Update the cache directly with the new account\n queryClient.setQueryData(\n accountKeys.list(variables.userId),\n (oldData: any) => {\n if (!oldData?.accounts) return oldData;\n return {\n ...oldData,\n accounts: [...oldData.accounts, newAccount],\n };\n }\n );\n\n // Call user-provided onSuccess callback if provided\n options?.onSuccess?.(newAccount, variables, context, mutation);\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for updating an account\n * Legacy API: PUT /users/{userId}/accounts/{id}\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport {\n AccountUpdateSchema,\n AccountSchema,\n Account,\n AccountUpdate,\n} from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface UpdateAccountParams {\n userId: string;\n accountId: number;\n data: AccountUpdate;\n}\n\n/**\n * Update an existing account\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 AccountEditForm({ account }: { account: Account }) {\n * const updateAccount = useUpdateAccount();\n *\n * const handleSubmit = (formData) => {\n * updateAccount.mutate({\n * userId: 'user123',\n * accountId: account.id,\n * data: {\n * nickname: formData.nickname,\n * goal_amount: formData.goalAmount,\n * }\n * }, {\n * onSuccess: () => {\n * toast.success('Account updated!');\n * },\n * onError: (error) => {\n * toast.error(`Failed to update: ${error.message}`);\n * }\n * });\n * };\n *\n * return <form onSubmit={handleSubmit}>...</form>;\n * }\n * ```\n */\nexport function useUpdateAccount(\n options?: Omit<\n UseMutationOptions<Account, Error, UpdateAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, accountId, data }: UpdateAccountParams) => {\n // Validate input with Zod schema from Mini-Arc 1\n // This ensures type safety before sending to API\n const validated = AccountUpdateSchema.parse(data);\n\n const response = await api.put(\n `/users/${userId}/accounts/${accountId}`,\n validated\n );\n\n // Validate response\n return AccountSchema.parse(response.data);\n },\n onSuccess: (_, { userId, accountId }) => {\n // Invalidate account list query to refetch updated data\n queryClient.invalidateQueries({\n queryKey: accountKeys.list(userId),\n });\n\n // Invalidate specific account detail query\n queryClient.invalidateQueries({\n queryKey: accountKeys.detail(userId, accountId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for deleting an account\n * Legacy API: DELETE /users/{userId}/accounts/{id}\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { accountKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface DeleteAccountParams {\n userId: string;\n accountId: number;\n}\n\n/**\n * Delete an account\n * Removes account from user's account 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 AccountDeleteButton({ accountId }: { accountId: number }) {\n * const deleteAccount = useDeleteAccount();\n *\n * const handleDelete = () => {\n * if (confirm('Are you sure you want to delete this account?')) {\n * deleteAccount.mutate({\n * userId: 'user123',\n * accountId\n * }, {\n * onSuccess: () => {\n * toast.success('Account deleted successfully');\n * navigate('/accounts');\n * },\n * onError: (error) => {\n * toast.error(`Failed to delete: ${error.message}`);\n * }\n * });\n * }\n * };\n *\n * return (\n * <button onClick={handleDelete} disabled={deleteAccount.isPending}>\n * {deleteAccount.isPending ? 'Deleting...' : 'Delete Account'}\n * </button>\n * );\n * }\n * ```\n */\nexport function useDeleteAccount(\n options?: Omit<\n UseMutationOptions<void, Error, DeleteAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, accountId }: DeleteAccountParams) => {\n await api.delete(`/users/${userId}/accounts/${accountId}`);\n // DELETE returns 204 No Content - no response body to validate\n },\n onSuccess: (_, { userId, accountId }) => {\n // Invalidate account list to refetch without deleted account\n queryClient.invalidateQueries({\n queryKey: accountKeys.list(userId),\n });\n\n // Remove specific account from cache\n queryClient.removeQueries({\n queryKey: accountKeys.detail(userId, accountId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for archiving an account (soft delete)\n * Legacy API: PUT /users/{userId}/accounts/{id}/archive\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { AccountSchema, Account } from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { api } from '../client';\n\nexport interface ArchiveAccountParams {\n userId: string;\n accountId: number;\n}\n\n/**\n * Archive an account (soft delete)\n * Changes account state to 'archived' instead of permanently deleting\n * Invalidates related queries on success\n *\n * @param options - TanStack Mutation options\n * @returns Mutation result\n *\n * @example\n * ```tsx\n * function AccountArchiveButton({ accountId }: { accountId: number }) {\n * const archiveAccount = useArchiveAccount();\n *\n * const handleArchive = () => {\n * archiveAccount.mutate({\n * userId: 'user123',\n * accountId\n * }, {\n * onSuccess: (archivedAccount) => {\n * toast.success(`${archivedAccount.name} archived`);\n * },\n * onError: (error) => {\n * toast.error(`Failed to archive: ${error.message}`);\n * }\n * });\n * };\n *\n * return (\n * <button onClick={handleArchive} disabled={archiveAccount.isPending}>\n * {archiveAccount.isPending ? 'Archiving...' : 'Archive Account'}\n * </button>\n * );\n * }\n * ```\n */\nexport function useArchiveAccount(\n options?: Omit<\n UseMutationOptions<Account, Error, ArchiveAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, accountId }: ArchiveAccountParams) => {\n const response = await api.put(\n `/users/${userId}/accounts/${accountId}/archive`\n );\n\n // Validate response - returns updated account with state='archived'\n return AccountSchema.parse(response.data);\n },\n onSuccess: (_, { userId, accountId }) => {\n // Invalidate account list to refetch with updated states\n queryClient.invalidateQueries({\n queryKey: accountKeys.list(userId),\n });\n\n // Invalidate specific account detail\n queryClient.invalidateQueries({\n queryKey: accountKeys.detail(userId, accountId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for creating a manual net worth account\n * Legacy API: POST /users/{userId}/networth/accounts\n */\n\nimport {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NetWorthAccountCreateSchema,\n NetWorthAssetSchema,\n NetWorthDebtSchema,\n type NetWorthAccountCreate,\n type NetWorthAsset,\n type NetWorthDebt,\n} from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { accountKeys } from '../keys';\n\n/**\n * Parameters for useCreateNetWorthAccount mutation\n */\nexport interface CreateNetWorthAccountParams {\n userId: string;\n data: NetWorthAccountCreate;\n}\n\n/**\n * Mutation hook for creating a manual net worth account\n *\n * Creates a manual asset or debt account for net worth tracking.\n * Returns either an asset or debt object depending on account_type.\n *\n * @example\n * ```tsx\n * const createAccount = useCreateNetWorthAccount();\n *\n * // Create asset\n * createAccount.mutate({\n * userId: 'user123',\n * data: {\n * networth_account: {\n * account_type: 'asset',\n * balance: '250000.00',\n * name: 'My House'\n * }\n * }\n * });\n *\n * // Create debt\n * createAccount.mutate({\n * userId: 'user123',\n * data: {\n * networth_account: {\n * account_type: 'debt',\n * balance: '15000.00',\n * name: 'Car Loan'\n * }\n * }\n * });\n * ```\n */\nexport function useCreateNetWorthAccount(\n options?: Omit<\n UseMutationOptions<NetWorthAsset | NetWorthDebt, Error, CreateNetWorthAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNetWorthAccountParams) => {\n // Validate account data\n const validated = NetWorthAccountCreateSchema.parse(data);\n\n // POST to create new net worth account\n const response = await api.post(\n `/users/${userId}/networth/accounts`,\n validated\n );\n\n // Validate response based on account type\n const accountType = validated.networth_account.account_type;\n if (accountType === 'asset') {\n return NetWorthAssetSchema.parse(response.data);\n } else {\n return NetWorthDebtSchema.parse(response.data);\n }\n },\n onSuccess: (_, { userId }) => {\n // Invalidate net worth summary to refetch with new account\n queryClient.invalidateQueries({\n queryKey: accountKeys.networthSummary(userId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for updating a manual net worth account\n * Legacy API: PUT /users/{userId}/networth/accounts/{id}\n */\n\nimport {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n NetWorthAccountUpdateSchema,\n NetWorthAssetSchema,\n NetWorthDebtSchema,\n type NetWorthAccountUpdate,\n type NetWorthAsset,\n type NetWorthDebt,\n} from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { accountKeys } from '../keys';\n\n/**\n * Parameters for useUpdateNetWorthAccount mutation\n */\nexport interface UpdateNetWorthAccountParams {\n userId: string;\n accountId: number;\n data: NetWorthAccountUpdate;\n}\n\n/**\n * Mutation hook for updating a manual net worth account\n *\n * Updates name, balance, or account type for a manual net worth account.\n * All fields are optional - only provided fields will be updated.\n *\n * @example\n * ```tsx\n * const updateAccount = useUpdateNetWorthAccount();\n *\n * // Update only balance\n * updateAccount.mutate({\n * userId: 'user123',\n * accountId: 5,\n * data: {\n * networth_account: {\n * balance: '260000.00'\n * }\n * }\n * });\n *\n * // Update name and type\n * updateAccount.mutate({\n * userId: 'user123',\n * accountId: 5,\n * data: {\n * networth_account: {\n * name: 'Updated House Name',\n * account_type: 'debt'\n * }\n * }\n * });\n * ```\n */\nexport function useUpdateNetWorthAccount(\n options?: Omit<\n UseMutationOptions<NetWorthAsset | NetWorthDebt, Error, UpdateNetWorthAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, accountId, data }: UpdateNetWorthAccountParams) => {\n // Validate update data\n const validated = NetWorthAccountUpdateSchema.parse(data);\n\n // PUT to update net worth account\n const response = await api.put(\n `/users/${userId}/networth/accounts/${accountId}`,\n validated\n );\n\n // Validate response - could be asset or debt\n // Try asset first, fall back to debt\n try {\n return NetWorthAssetSchema.parse(response.data);\n } catch {\n return NetWorthDebtSchema.parse(response.data);\n }\n },\n onSuccess: (_, { userId }) => {\n // Invalidate net worth summary to refetch with updated account\n queryClient.invalidateQueries({\n queryKey: accountKeys.networthSummary(userId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for deleting a manual net worth account\n * Legacy API: DELETE /users/{userId}/networth/accounts/{id}\n */\n\nimport {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport { NetWorthAccountDeleteSchema } from '@pfm-platform/shared';\nimport { api } from '../client';\nimport { accountKeys } from '../keys';\n\n/**\n * Parameters for useDeleteNetWorthAccount mutation\n */\nexport interface DeleteNetWorthAccountParams {\n userId: string;\n accountId: number;\n}\n\n/**\n * Mutation hook for deleting a manual net worth account\n *\n * Permanently deletes a manual asset or debt account from net worth tracking.\n * This operation cannot be undone.\n *\n * @example\n * ```tsx\n * const deleteAccount = useDeleteNetWorthAccount();\n *\n * deleteAccount.mutate({\n * userId: 'user123',\n * accountId: 5\n * }, {\n * onSuccess: () => {\n * console.log('Net worth account deleted successfully');\n * }\n * });\n * ```\n */\nexport function useDeleteNetWorthAccount(\n options?: Omit<\n UseMutationOptions<void, Error, DeleteNetWorthAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, accountId }: DeleteNetWorthAccountParams) => {\n // Validate account ID\n NetWorthAccountDeleteSchema.parse({ id: accountId });\n\n // DELETE net worth account\n await api.delete(`/users/${userId}/networth/accounts/${accountId}`);\n },\n onSuccess: (_, { userId }) => {\n // Invalidate net worth summary to refetch without deleted account\n queryClient.invalidateQueries({\n queryKey: accountKeys.networthSummary(userId),\n });\n },\n ...options,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/keys.ts","../src/queries/useAccounts.ts","../src/queries/useAccount.ts","../src/queries/useNetWorth.ts","../src/mutations/useCreateAccount.ts","../src/mutations/useUpdateAccount.ts","../src/mutations/useDeleteAccount.ts","../src/mutations/useArchiveAccount.ts","../src/mutations/useCreateNetWorthAccount.ts","../src/mutations/useUpdateNetWorthAccount.ts","../src/mutations/useDeleteNetWorthAccount.ts"],"names":["useQuery","supabase","AccountsResponseSchema","AccountSchema","useQueryClient","useAppMode","useMutation","AccountCreateSchemaAdmin","AccountCreateSchemaUser","AccountUpdateSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Query key factory for Accounts domain\n * Following TanStack Query best practices for hierarchical cache keys\n *\n * Key structure:\n * - ['accounts'] - Root key for all account queries\n * - ['accounts', 'list', userId] - List of accounts for a user\n * - ['accounts', 'detail', userId, accountId] - Single account detail\n */\n\nexport const accountKeys = {\n all: ['accounts'] as const,\n\n lists: () => [...accountKeys.all, 'list'] as const,\n\n list: (userId: string) => [...accountKeys.lists(), userId] as const,\n\n details: () => [...accountKeys.all, 'detail'] as const,\n\n detail: (userId: string, accountId: string) =>\n [...accountKeys.details(), userId, accountId] as const,\n\n institutions: () => [...accountKeys.all, 'institutions'] as const,\n\n institution: (userId: string) =>\n [...accountKeys.institutions(), userId] as const,\n};\n","/**\n * Query hook for fetching all accounts for a user\n * Supabase: accounts table filtered by user_id\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { AccountsResponseSchema, type Account } from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface UseAccountsParams {\n userId: string;\n}\n\nexport interface AccountsData {\n accounts: Account[];\n}\n\n/**\n * Fetch all accounts for a user from Supabase\n *\n * Returns `{ accounts: Account[] }` to match the shape expected by\n * feature hooks (useAccountFilters, useAccountTypes, useAccountSummary).\n *\n * @example\n * ```tsx\n * const { data } = useAccounts({ userId });\n * // data.accounts is Account[]\n * ```\n */\nexport function useAccounts(\n params: UseAccountsParams,\n options?: Omit<UseQueryOptions<AccountsData>, 'queryKey' | 'queryFn'>\n) {\n const { userId } = params;\n\n return useQuery({\n queryKey: accountKeys.list(userId),\n queryFn: async (): Promise<AccountsData> => {\n const { data, error } = await supabase\n .from('accounts')\n .select('*')\n .eq('user_id', userId)\n .order('name');\n\n if (error) throw error;\n\n return { accounts: AccountsResponseSchema.parse(data) };\n },\n staleTime: 1000 * 60 * 5,\n ...options,\n });\n}\n","/**\n * Query hook for fetching a single account by ID\n * Supabase: accounts table filtered by id\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { AccountSchema, type Account } from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface UseAccountParams {\n userId: string;\n accountId: string;\n}\n\n/**\n * Fetch a single account by ID from Supabase\n *\n * @example\n * ```tsx\n * const { data } = useAccount({ userId, accountId });\n * // data is Account\n * ```\n */\nexport function useAccount(\n params: UseAccountParams,\n options?: Omit<UseQueryOptions<Account>, 'queryKey' | 'queryFn'>\n) {\n const { userId, accountId } = params;\n\n return useQuery({\n queryKey: accountKeys.detail(userId, accountId),\n queryFn: async () => {\n const { data, error } = await supabase\n .from('accounts')\n .select('*')\n .eq('id', accountId)\n .eq('user_id', userId)\n .single();\n\n if (error) throw error;\n\n return AccountSchema.parse(data);\n },\n staleTime: 1000 * 60 * 5,\n ...options,\n });\n}\n","/**\n * Query hook for fetching net worth data\n * TODO: Wire to Supabase networth_summary view + networth_accounts table\n */\n\nimport { useQuery, UseQueryOptions } from '@tanstack/react-query';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface NetWorthAccount {\n id: string;\n name: string;\n balance: string;\n account_type: 'asset' | 'debt';\n additional_networth_account: boolean;\n}\n\nexport interface NetWorthMeta {\n net_worth: string;\n net_worth_change: string;\n total_assets: string;\n total_debts: string;\n}\n\nexport interface NetWorthHistoryEntry {\n total: string;\n total_asset: string;\n total_debt: string;\n month: string;\n year: string;\n since_last_month: string;\n}\n\nexport interface NetWorthData {\n meta: NetWorthMeta;\n assets: NetWorthAccount[];\n debts: NetWorthAccount[];\n networth_histories: NetWorthHistoryEntry[];\n}\n\nexport interface UseNetWorthParams {\n userId: string;\n}\n\n/**\n * Fetch net worth summary with manual accounts\n * Combines networth_summary view + networth_accounts table\n */\nexport function useNetWorth(\n params: UseNetWorthParams,\n options?: Omit<UseQueryOptions<NetWorthData | null>, 'queryKey' | 'queryFn'>\n) {\n const { userId } = params;\n\n return useQuery({\n queryKey: [...accountKeys.all, 'networth', userId],\n queryFn: async (): Promise<NetWorthData | null> => {\n // Fetch manual networth accounts\n const { data: accounts, error: accountsError } = await supabase\n .from('networth_accounts')\n .select('*')\n .eq('user_id', userId);\n\n if (accountsError) throw accountsError;\n\n // Fetch networth history\n const { data: histories, error: historiesError } = await supabase\n .from('networth_history')\n .select('*')\n .eq('user_id', userId)\n .order('year', { ascending: true })\n .order('month', { ascending: true });\n\n if (historiesError) throw historiesError;\n\n const assets = (accounts || [])\n .filter((a) => a.account_type === 'asset')\n .map((a) => ({\n id: a.id,\n name: a.name,\n balance: String(a.balance),\n account_type: a.account_type as 'asset' | 'debt',\n additional_networth_account: a.additional_networth_account,\n }));\n\n const debts = (accounts || [])\n .filter((a) => a.account_type === 'debt')\n .map((a) => ({\n id: a.id,\n name: a.name,\n balance: String(a.balance),\n account_type: a.account_type as 'asset' | 'debt',\n additional_networth_account: a.additional_networth_account,\n }));\n\n const totalAssets = assets.reduce((sum, a) => sum + parseFloat(a.balance), 0);\n const totalDebts = debts.reduce((sum, d) => sum + parseFloat(d.balance), 0);\n\n const networthHistories: NetWorthHistoryEntry[] = (histories || []).map((h) => ({\n total: String(h.total),\n total_asset: String(h.total_asset),\n total_debt: String(h.total_debt),\n month: String(h.month).padStart(2, '0'),\n year: String(h.year),\n since_last_month: String(h.since_last_month),\n }));\n\n return {\n meta: {\n net_worth: String(totalAssets - totalDebts),\n net_worth_change: '0', // TODO: compute from networth_history\n total_assets: String(totalAssets),\n total_debts: String(totalDebts),\n },\n assets,\n debts,\n networth_histories: networthHistories,\n };\n },\n staleTime: 1000 * 60 * 5,\n ...options,\n });\n}\n","import {\n useMutation,\n useQueryClient,\n type UseMutationOptions,\n} from '@tanstack/react-query';\nimport {\n AccountCreateSchemaAdmin,\n AccountCreateSchemaUser,\n AccountSchema,\n useAppMode,\n type AccountCreate,\n type Account,\n} from '@pfm-platform/shared';\nimport { supabase } from '../client';\nimport { accountKeys } from '../keys';\nimport type { AccountsData } from '../queries/useAccounts';\n\nexport interface CreateAccountParams {\n userId: string;\n data: AccountCreate;\n}\n\n/**\n * Mutation hook for creating a new account in Supabase\n *\n * Uses mode switching for validation:\n * - Admin mode: Minimal validation for test data creation\n * - User mode: Full validation with business rules\n */\nexport function useCreateAccount(\n options?: Omit<UseMutationOptions<Account, Error, CreateAccountParams>, 'mutationFn'>\n) {\n const queryClient = useQueryClient();\n const { mode } = useAppMode();\n\n return useMutation({\n mutationFn: async ({ data }: CreateAccountParams) => {\n const schema =\n mode === 'admin'\n ? AccountCreateSchemaAdmin\n : AccountCreateSchemaUser;\n\n const validated = schema.parse(data);\n\n const { data: created, error } = await supabase\n .from('accounts')\n .insert(validated)\n .select()\n .single();\n\n if (error) throw error;\n\n return AccountSchema.parse(created);\n },\n onSuccess: (newAccount, variables, onMutateResult, context) => {\n queryClient.setQueryData(\n accountKeys.list(variables.userId),\n (oldData: AccountsData | undefined) => {\n if (!oldData) return { accounts: [newAccount] };\n return { accounts: [...oldData.accounts, newAccount] };\n }\n );\n\n options?.onSuccess?.(newAccount, variables, onMutateResult, context);\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for updating an account\n * Supabase: UPDATE accounts SET ... WHERE id = ...\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport {\n AccountUpdateSchema,\n AccountSchema,\n Account,\n AccountUpdate,\n} from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface UpdateAccountParams {\n userId: string;\n accountId: string;\n data: AccountUpdate;\n}\n\n/**\n * Update an existing account in Supabase\n */\nexport function useUpdateAccount(\n options?: Omit<\n UseMutationOptions<Account, Error, UpdateAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ accountId, data }: UpdateAccountParams) => {\n const validated = AccountUpdateSchema.parse(data);\n\n const { data: updated, error } = await supabase\n .from('accounts')\n .update(validated)\n .eq('id', accountId)\n .select()\n .single();\n\n if (error) throw error;\n\n return AccountSchema.parse(updated);\n },\n onSuccess: (_, { userId, accountId }) => {\n queryClient.invalidateQueries({\n queryKey: accountKeys.list(userId),\n });\n queryClient.invalidateQueries({\n queryKey: accountKeys.detail(userId, accountId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for deleting an account\n * Supabase: DELETE FROM accounts WHERE id = ...\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface DeleteAccountParams {\n userId: string;\n accountId: string;\n}\n\n/**\n * Delete an account from Supabase (hard delete)\n */\nexport function useDeleteAccount(\n options?: Omit<\n UseMutationOptions<void, Error, DeleteAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ accountId }: DeleteAccountParams) => {\n const { error } = await supabase\n .from('accounts')\n .delete()\n .eq('id', accountId);\n\n if (error) throw error;\n },\n onSuccess: (_, { userId, accountId }) => {\n queryClient.invalidateQueries({\n queryKey: accountKeys.list(userId),\n });\n queryClient.removeQueries({\n queryKey: accountKeys.detail(userId, accountId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for archiving an account (soft delete)\n * Supabase: UPDATE accounts SET is_active = false WHERE id = ...\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { AccountSchema, Account } from '@pfm-platform/shared';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface ArchiveAccountParams {\n userId: string;\n accountId: string;\n}\n\n/**\n * Archive an account (soft delete via is_active = false)\n */\nexport function useArchiveAccount(\n options?: Omit<\n UseMutationOptions<Account, Error, ArchiveAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ accountId }: ArchiveAccountParams) => {\n const { data, error } = await supabase\n .from('accounts')\n .update({ is_active: false })\n .eq('id', accountId)\n .select()\n .single();\n\n if (error) throw error;\n\n return AccountSchema.parse(data);\n },\n onSuccess: (_, { userId, accountId }) => {\n queryClient.invalidateQueries({\n queryKey: accountKeys.list(userId),\n });\n queryClient.invalidateQueries({\n queryKey: accountKeys.detail(userId, accountId),\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for creating a net worth account\n * Supabase: INSERT INTO networth_accounts ...\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface CreateNetWorthAccountParams {\n userId: string;\n data: {\n networth_account: {\n name: string;\n balance: string;\n account_type: string;\n };\n };\n}\n\n/**\n * Create a net worth account in Supabase\n */\nexport function useCreateNetWorthAccount(\n options?: Omit<\n UseMutationOptions<void, Error, CreateNetWorthAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ userId, data }: CreateNetWorthAccountParams) => {\n const { error } = await supabase.from('networth_accounts').insert({\n user_id: userId,\n name: data.networth_account.name,\n balance: parseFloat(data.networth_account.balance),\n account_type: data.networth_account.account_type,\n additional_networth_account: true,\n });\n\n if (error) throw error;\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: [...accountKeys.all, 'networth', userId],\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for updating a net worth account\n * Supabase: UPDATE networth_accounts SET ... WHERE id = ...\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface UpdateNetWorthAccountParams {\n userId: string;\n accountId: number | string;\n data: {\n networth_account: {\n name: string;\n balance: string;\n account_type: string;\n };\n };\n}\n\n/**\n * Update a net worth account in Supabase\n */\nexport function useUpdateNetWorthAccount(\n options?: Omit<\n UseMutationOptions<void, Error, UpdateNetWorthAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ accountId, data }: UpdateNetWorthAccountParams) => {\n const { error } = await supabase\n .from('networth_accounts')\n .update({\n name: data.networth_account.name,\n balance: parseFloat(data.networth_account.balance),\n account_type: data.networth_account.account_type,\n })\n .eq('id', String(accountId));\n\n if (error) throw error;\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: [...accountKeys.all, 'networth', userId],\n });\n },\n ...options,\n });\n}\n","/**\n * Mutation hook for deleting a net worth account\n * Supabase: DELETE FROM networth_accounts WHERE id = ...\n */\n\nimport {\n useMutation,\n UseMutationOptions,\n useQueryClient,\n} from '@tanstack/react-query';\nimport { accountKeys } from '../keys';\nimport { supabase } from '../client';\n\nexport interface DeleteNetWorthAccountParams {\n userId: string;\n accountId: number | string;\n}\n\n/**\n * Delete a net worth account from Supabase\n */\nexport function useDeleteNetWorthAccount(\n options?: Omit<\n UseMutationOptions<void, Error, DeleteNetWorthAccountParams>,\n 'mutationFn'\n >\n) {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ accountId }: DeleteNetWorthAccountParams) => {\n const { error } = await supabase\n .from('networth_accounts')\n .delete()\n .eq('id', String(accountId));\n\n if (error) throw error;\n },\n onSuccess: (_, { userId }) => {\n queryClient.invalidateQueries({\n queryKey: [...accountKeys.all, 'networth', userId],\n });\n },\n ...options,\n });\n}\n"]}
|