@pfm-platform/accounts-data-access 0.2.0

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 ADDED
@@ -0,0 +1,316 @@
1
+ 'use strict';
2
+
3
+ var reactQuery = require('@tanstack/react-query');
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
+
11
+ // src/queries/useAccounts.ts
12
+
13
+ // src/keys.ts
14
+ var accountKeys = {
15
+ /**
16
+ * Root key for all account-related queries
17
+ */
18
+ all: ["accounts"],
19
+ /**
20
+ * Key for all account list queries
21
+ */
22
+ lists: () => [...accountKeys.all, "list"],
23
+ /**
24
+ * Key for a specific user's account list
25
+ * @param userId - User ID
26
+ */
27
+ list: (userId) => [...accountKeys.lists(), userId],
28
+ /**
29
+ * Key for all account detail queries
30
+ */
31
+ details: () => [...accountKeys.all, "detail"],
32
+ /**
33
+ * Key for a specific account detail
34
+ * @param userId - User ID
35
+ * @param accountId - Account ID
36
+ */
37
+ detail: (userId, accountId) => [...accountKeys.details(), userId, accountId],
38
+ /**
39
+ * Key for all account investment queries
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]
78
+ };
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
+
112
+ // src/queries/useAccounts.ts
113
+ function useAccounts(params, options) {
114
+ const { userId } = params;
115
+ return reactQuery.useQuery({
116
+ queryKey: accountKeys.list(userId),
117
+ queryFn: async () => {
118
+ const response = await api.get(`/users/${userId}/accounts/all`);
119
+ return shared.AccountsResponseSchema.parse(response.data);
120
+ },
121
+ staleTime: 1e3 * 60 * 5,
122
+ // 5 minutes - accounts don't change frequently
123
+ ...options
124
+ });
125
+ }
126
+ function useAccount(params, options) {
127
+ const { userId, accountId } = params;
128
+ return reactQuery.useQuery({
129
+ queryKey: accountKeys.detail(userId, accountId),
130
+ queryFn: async () => {
131
+ const response = await api.get(`/users/${userId}/accounts/${accountId}`);
132
+ return shared.AccountSchema.parse(response.data);
133
+ },
134
+ staleTime: 1e3 * 60 * 5,
135
+ // 5 minutes
136
+ ...options
137
+ });
138
+ }
139
+ function useNetWorth(params, options) {
140
+ const { userId } = params;
141
+ return reactQuery.useQuery({
142
+ queryKey: accountKeys.networthSummary(userId),
143
+ queryFn: async () => {
144
+ const response = await api.get(`/users/${userId}/networth`);
145
+ return shared.NetWorthResponseSchema.parse(response.data);
146
+ },
147
+ staleTime: 1e3 * 60 * 5,
148
+ // 5 minutes - net worth doesn't change frequently
149
+ ...options
150
+ });
151
+ }
152
+ function useCreateAccount(options) {
153
+ const queryClient = reactQuery.useQueryClient();
154
+ const { mode } = shared.useAppMode();
155
+ return reactQuery.useMutation({
156
+ mutationFn: async ({ userId, data }) => {
157
+ const schema = mode === "admin" ? shared.AccountCreateSchemaAdmin : shared.AccountCreateSchemaUser;
158
+ const validated = schema.parse(data);
159
+ const response = await api.post(
160
+ `/users/${userId}/accounts`,
161
+ validated
162
+ );
163
+ return shared.AccountSchema.parse(response.data);
164
+ },
165
+ onSuccess: (newAccount, variables, context, mutation) => {
166
+ queryClient.setQueryData(
167
+ accountKeys.list(variables.userId),
168
+ (oldData) => {
169
+ if (!oldData?.accounts) return oldData;
170
+ return {
171
+ ...oldData,
172
+ accounts: [...oldData.accounts, newAccount]
173
+ };
174
+ }
175
+ );
176
+ options?.onSuccess?.(newAccount, variables, context, mutation);
177
+ },
178
+ ...options
179
+ });
180
+ }
181
+ function useUpdateAccount(options) {
182
+ const queryClient = reactQuery.useQueryClient();
183
+ return reactQuery.useMutation({
184
+ mutationFn: async ({ userId, accountId, data }) => {
185
+ const validated = shared.AccountUpdateSchema.parse(data);
186
+ const response = await api.put(
187
+ `/users/${userId}/accounts/${accountId}`,
188
+ validated
189
+ );
190
+ return shared.AccountSchema.parse(response.data);
191
+ },
192
+ onSuccess: (_, { userId, accountId }) => {
193
+ queryClient.invalidateQueries({
194
+ queryKey: accountKeys.list(userId)
195
+ });
196
+ queryClient.invalidateQueries({
197
+ queryKey: accountKeys.detail(userId, accountId)
198
+ });
199
+ },
200
+ ...options
201
+ });
202
+ }
203
+ function useDeleteAccount(options) {
204
+ const queryClient = reactQuery.useQueryClient();
205
+ return reactQuery.useMutation({
206
+ mutationFn: async ({ userId, accountId }) => {
207
+ await api.delete(`/users/${userId}/accounts/${accountId}`);
208
+ },
209
+ onSuccess: (_, { userId, accountId }) => {
210
+ queryClient.invalidateQueries({
211
+ queryKey: accountKeys.list(userId)
212
+ });
213
+ queryClient.removeQueries({
214
+ queryKey: accountKeys.detail(userId, accountId)
215
+ });
216
+ },
217
+ ...options
218
+ });
219
+ }
220
+ function useArchiveAccount(options) {
221
+ const queryClient = reactQuery.useQueryClient();
222
+ return reactQuery.useMutation({
223
+ mutationFn: async ({ userId, accountId }) => {
224
+ const response = await api.put(
225
+ `/users/${userId}/accounts/${accountId}/archive`
226
+ );
227
+ return shared.AccountSchema.parse(response.data);
228
+ },
229
+ onSuccess: (_, { userId, accountId }) => {
230
+ queryClient.invalidateQueries({
231
+ queryKey: accountKeys.list(userId)
232
+ });
233
+ queryClient.invalidateQueries({
234
+ queryKey: accountKeys.detail(userId, accountId)
235
+ });
236
+ },
237
+ ...options
238
+ });
239
+ }
240
+ function useCreateNetWorthAccount(options) {
241
+ const queryClient = reactQuery.useQueryClient();
242
+ return reactQuery.useMutation({
243
+ mutationFn: async ({ userId, data }) => {
244
+ const validated = shared.NetWorthAccountCreateSchema.parse(data);
245
+ const response = await api.post(
246
+ `/users/${userId}/networth/accounts`,
247
+ validated
248
+ );
249
+ const accountType = validated.networth_account.account_type;
250
+ if (accountType === "asset") {
251
+ return shared.NetWorthAssetSchema.parse(response.data);
252
+ } else {
253
+ return shared.NetWorthDebtSchema.parse(response.data);
254
+ }
255
+ },
256
+ onSuccess: (_, { userId }) => {
257
+ queryClient.invalidateQueries({
258
+ queryKey: accountKeys.networthSummary(userId)
259
+ });
260
+ },
261
+ ...options
262
+ });
263
+ }
264
+ function useUpdateNetWorthAccount(options) {
265
+ const queryClient = reactQuery.useQueryClient();
266
+ return reactQuery.useMutation({
267
+ mutationFn: async ({ userId, accountId, data }) => {
268
+ const validated = shared.NetWorthAccountUpdateSchema.parse(data);
269
+ const response = await api.put(
270
+ `/users/${userId}/networth/accounts/${accountId}`,
271
+ validated
272
+ );
273
+ try {
274
+ return shared.NetWorthAssetSchema.parse(response.data);
275
+ } catch {
276
+ return shared.NetWorthDebtSchema.parse(response.data);
277
+ }
278
+ },
279
+ onSuccess: (_, { userId }) => {
280
+ queryClient.invalidateQueries({
281
+ queryKey: accountKeys.networthSummary(userId)
282
+ });
283
+ },
284
+ ...options
285
+ });
286
+ }
287
+ function useDeleteNetWorthAccount(options) {
288
+ const queryClient = reactQuery.useQueryClient();
289
+ return reactQuery.useMutation({
290
+ mutationFn: async ({ userId, accountId }) => {
291
+ shared.NetWorthAccountDeleteSchema.parse({ id: accountId });
292
+ await api.delete(`/users/${userId}/networth/accounts/${accountId}`);
293
+ },
294
+ onSuccess: (_, { userId }) => {
295
+ queryClient.invalidateQueries({
296
+ queryKey: accountKeys.networthSummary(userId)
297
+ });
298
+ },
299
+ ...options
300
+ });
301
+ }
302
+
303
+ exports.accountKeys = accountKeys;
304
+ exports.api = api;
305
+ exports.useAccount = useAccount;
306
+ exports.useAccounts = useAccounts;
307
+ exports.useArchiveAccount = useArchiveAccount;
308
+ exports.useCreateAccount = useCreateAccount;
309
+ exports.useCreateNetWorthAccount = useCreateNetWorthAccount;
310
+ exports.useDeleteAccount = useDeleteAccount;
311
+ exports.useDeleteNetWorthAccount = useDeleteNetWorthAccount;
312
+ exports.useNetWorth = useNetWorth;
313
+ exports.useUpdateAccount = useUpdateAccount;
314
+ exports.useUpdateNetWorthAccount = useUpdateNetWorthAccount;
315
+ //# sourceMappingURL=index.cjs.map
316
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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"]}