@diffsome/react 1.1.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/README.md +353 -0
- package/dist/index.d.mts +546 -0
- package/dist/index.d.ts +546 -0
- package/dist/index.js +2340 -0
- package/dist/index.mjs +2255 -0
- package/package.json +50 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2255 @@
|
|
|
1
|
+
// src/context/DiffsomeContext.tsx
|
|
2
|
+
import { createContext, useContext, useState, useEffect, useMemo } from "react";
|
|
3
|
+
import { Diffsome } from "@diffsome/sdk";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
var DiffsomeContext = createContext(null);
|
|
6
|
+
function DiffsomeProvider({ children, config }) {
|
|
7
|
+
const [isReady, setIsReady] = useState(false);
|
|
8
|
+
const client = useMemo(() => {
|
|
9
|
+
return new Diffsome({
|
|
10
|
+
...config,
|
|
11
|
+
persistToken: config.persistToken ?? true,
|
|
12
|
+
storageType: config.storageType ?? "localStorage"
|
|
13
|
+
});
|
|
14
|
+
}, [config.tenantId, config.baseUrl, config.apiKey]);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setIsReady(true);
|
|
17
|
+
}, []);
|
|
18
|
+
const value = useMemo(() => ({
|
|
19
|
+
client,
|
|
20
|
+
isReady
|
|
21
|
+
}), [client, isReady]);
|
|
22
|
+
return /* @__PURE__ */ jsx(DiffsomeContext.Provider, { value, children });
|
|
23
|
+
}
|
|
24
|
+
function useDiffsome() {
|
|
25
|
+
const context = useContext(DiffsomeContext);
|
|
26
|
+
if (!context) {
|
|
27
|
+
throw new Error("useDiffsome must be used within DiffsomeProvider");
|
|
28
|
+
}
|
|
29
|
+
return context;
|
|
30
|
+
}
|
|
31
|
+
function useClient() {
|
|
32
|
+
const { client } = useDiffsome();
|
|
33
|
+
return client;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/hooks/useAuth.ts
|
|
37
|
+
import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
|
|
38
|
+
function useAuth() {
|
|
39
|
+
const client = useClient();
|
|
40
|
+
const [user, setUser] = useState2(null);
|
|
41
|
+
const [loading, setLoading] = useState2(true);
|
|
42
|
+
const [error, setError] = useState2(null);
|
|
43
|
+
const isAuthenticated = !!user && client.isAuthenticated();
|
|
44
|
+
const fetchProfile = useCallback2(async () => {
|
|
45
|
+
if (!client.isAuthenticated()) {
|
|
46
|
+
setUser(null);
|
|
47
|
+
setLoading(false);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const profile = await client.auth.me();
|
|
52
|
+
setUser(profile);
|
|
53
|
+
setError(null);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
setUser(null);
|
|
56
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch profile"));
|
|
57
|
+
} finally {
|
|
58
|
+
setLoading(false);
|
|
59
|
+
}
|
|
60
|
+
}, [client]);
|
|
61
|
+
useEffect2(() => {
|
|
62
|
+
fetchProfile();
|
|
63
|
+
}, [fetchProfile]);
|
|
64
|
+
const login = useCallback2(async (credentials) => {
|
|
65
|
+
setLoading(true);
|
|
66
|
+
setError(null);
|
|
67
|
+
try {
|
|
68
|
+
const response = await client.auth.login(credentials);
|
|
69
|
+
setUser(response.user);
|
|
70
|
+
return response;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
const error2 = err instanceof Error ? err : new Error("Login failed");
|
|
73
|
+
setError(error2);
|
|
74
|
+
throw error2;
|
|
75
|
+
} finally {
|
|
76
|
+
setLoading(false);
|
|
77
|
+
}
|
|
78
|
+
}, [client]);
|
|
79
|
+
const register = useCallback2(async (data) => {
|
|
80
|
+
setLoading(true);
|
|
81
|
+
setError(null);
|
|
82
|
+
try {
|
|
83
|
+
const response = await client.auth.register(data);
|
|
84
|
+
setUser(response.user);
|
|
85
|
+
return response;
|
|
86
|
+
} catch (err) {
|
|
87
|
+
const error2 = err instanceof Error ? err : new Error("Registration failed");
|
|
88
|
+
setError(error2);
|
|
89
|
+
throw error2;
|
|
90
|
+
} finally {
|
|
91
|
+
setLoading(false);
|
|
92
|
+
}
|
|
93
|
+
}, [client]);
|
|
94
|
+
const logout = useCallback2(async () => {
|
|
95
|
+
setLoading(true);
|
|
96
|
+
try {
|
|
97
|
+
await client.auth.logout();
|
|
98
|
+
} finally {
|
|
99
|
+
setUser(null);
|
|
100
|
+
setLoading(false);
|
|
101
|
+
}
|
|
102
|
+
}, [client]);
|
|
103
|
+
const getProfile = useCallback2(async () => {
|
|
104
|
+
const profile = await client.auth.me();
|
|
105
|
+
setUser(profile);
|
|
106
|
+
return profile;
|
|
107
|
+
}, [client]);
|
|
108
|
+
const updateProfile = useCallback2(async (data) => {
|
|
109
|
+
const profile = await client.auth.updateProfile(data);
|
|
110
|
+
setUser(profile);
|
|
111
|
+
return profile;
|
|
112
|
+
}, [client]);
|
|
113
|
+
const forgotPassword = useCallback2(async (email) => {
|
|
114
|
+
return await client.auth.forgotPassword({ email });
|
|
115
|
+
}, [client]);
|
|
116
|
+
const resetPassword = useCallback2(async (data) => {
|
|
117
|
+
return await client.auth.resetPassword(data);
|
|
118
|
+
}, [client]);
|
|
119
|
+
const refresh = useCallback2(async () => {
|
|
120
|
+
await fetchProfile();
|
|
121
|
+
}, [fetchProfile]);
|
|
122
|
+
return {
|
|
123
|
+
user,
|
|
124
|
+
isAuthenticated,
|
|
125
|
+
loading,
|
|
126
|
+
error,
|
|
127
|
+
login,
|
|
128
|
+
register,
|
|
129
|
+
logout,
|
|
130
|
+
getProfile,
|
|
131
|
+
updateProfile,
|
|
132
|
+
forgotPassword,
|
|
133
|
+
resetPassword,
|
|
134
|
+
refresh
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/hooks/useSocialAuth.ts
|
|
139
|
+
import { useState as useState3, useEffect as useEffect3, useCallback as useCallback3 } from "react";
|
|
140
|
+
function useSocialAuth() {
|
|
141
|
+
const client = useClient();
|
|
142
|
+
const [providers, setProviders] = useState3([]);
|
|
143
|
+
const [loading, setLoading] = useState3(true);
|
|
144
|
+
const [error, setError] = useState3(null);
|
|
145
|
+
const fetchProviders = useCallback3(async () => {
|
|
146
|
+
setLoading(true);
|
|
147
|
+
setError(null);
|
|
148
|
+
try {
|
|
149
|
+
const data = await client.auth.getSocialProviders();
|
|
150
|
+
setProviders(data);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch providers"));
|
|
153
|
+
} finally {
|
|
154
|
+
setLoading(false);
|
|
155
|
+
}
|
|
156
|
+
}, [client]);
|
|
157
|
+
useEffect3(() => {
|
|
158
|
+
fetchProviders();
|
|
159
|
+
}, [fetchProviders]);
|
|
160
|
+
const getAuthUrl = useCallback3(async (provider) => {
|
|
161
|
+
const result = await client.auth.getSocialAuthUrl(provider);
|
|
162
|
+
return result.url;
|
|
163
|
+
}, [client]);
|
|
164
|
+
const handleCallback = useCallback3(async (provider, code) => {
|
|
165
|
+
return await client.auth.socialCallback(provider, code);
|
|
166
|
+
}, [client]);
|
|
167
|
+
return {
|
|
168
|
+
providers,
|
|
169
|
+
loading,
|
|
170
|
+
error,
|
|
171
|
+
getAuthUrl,
|
|
172
|
+
handleCallback,
|
|
173
|
+
refresh: fetchProviders
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/hooks/useCart.ts
|
|
178
|
+
import { useState as useState4, useEffect as useEffect4, useCallback as useCallback4 } from "react";
|
|
179
|
+
function useCart() {
|
|
180
|
+
const client = useClient();
|
|
181
|
+
const [cart, setCart] = useState4(null);
|
|
182
|
+
const [loading, setLoading] = useState4(true);
|
|
183
|
+
const [error, setError] = useState4(null);
|
|
184
|
+
const fetchCart = useCallback4(async () => {
|
|
185
|
+
try {
|
|
186
|
+
const cartData = await client.shop.getCart();
|
|
187
|
+
setCart(cartData);
|
|
188
|
+
setError(null);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
setCart(null);
|
|
191
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch cart"));
|
|
192
|
+
} finally {
|
|
193
|
+
setLoading(false);
|
|
194
|
+
}
|
|
195
|
+
}, [client]);
|
|
196
|
+
useEffect4(() => {
|
|
197
|
+
fetchCart();
|
|
198
|
+
}, [fetchCart]);
|
|
199
|
+
const addToCart = useCallback4(async (productId, quantity = 1, variantId, options) => {
|
|
200
|
+
const data = {
|
|
201
|
+
product_id: productId,
|
|
202
|
+
quantity,
|
|
203
|
+
variant_id: variantId,
|
|
204
|
+
options
|
|
205
|
+
};
|
|
206
|
+
const updatedCart = await client.shop.addToCart(data);
|
|
207
|
+
setCart(updatedCart);
|
|
208
|
+
return updatedCart;
|
|
209
|
+
}, [client]);
|
|
210
|
+
const updateItem = useCallback4(async (itemId, quantity) => {
|
|
211
|
+
const updatedCart = await client.shop.updateCartItem(itemId, { quantity });
|
|
212
|
+
setCart(updatedCart);
|
|
213
|
+
return updatedCart;
|
|
214
|
+
}, [client]);
|
|
215
|
+
const removeItem = useCallback4(async (itemId) => {
|
|
216
|
+
const updatedCart = await client.shop.removeFromCart(itemId);
|
|
217
|
+
setCart(updatedCart);
|
|
218
|
+
return updatedCart;
|
|
219
|
+
}, [client]);
|
|
220
|
+
const clearCart = useCallback4(async () => {
|
|
221
|
+
await client.shop.clearCart();
|
|
222
|
+
setCart(null);
|
|
223
|
+
}, [client]);
|
|
224
|
+
const refresh = useCallback4(async () => {
|
|
225
|
+
setLoading(true);
|
|
226
|
+
await fetchCart();
|
|
227
|
+
}, [fetchCart]);
|
|
228
|
+
const isInCart = useCallback4((productId, variantId) => {
|
|
229
|
+
if (!cart?.items) return false;
|
|
230
|
+
return cart.items.some(
|
|
231
|
+
(item) => item.product_id === productId && (variantId === void 0 || item.variant_id === variantId)
|
|
232
|
+
);
|
|
233
|
+
}, [cart]);
|
|
234
|
+
const getItemQuantity = useCallback4((productId, variantId) => {
|
|
235
|
+
if (!cart?.items) return 0;
|
|
236
|
+
const item = cart.items.find(
|
|
237
|
+
(item2) => item2.product_id === productId && (variantId === void 0 || item2.variant_id === variantId)
|
|
238
|
+
);
|
|
239
|
+
return item?.quantity ?? 0;
|
|
240
|
+
}, [cart]);
|
|
241
|
+
return {
|
|
242
|
+
cart,
|
|
243
|
+
items: cart?.items ?? [],
|
|
244
|
+
itemCount: cart?.item_count ?? 0,
|
|
245
|
+
totalQuantity: cart?.total_quantity ?? 0,
|
|
246
|
+
subtotal: cart?.subtotal ?? 0,
|
|
247
|
+
shippingFee: cart?.shipping_fee ?? 0,
|
|
248
|
+
total: cart?.total ?? 0,
|
|
249
|
+
loading,
|
|
250
|
+
error,
|
|
251
|
+
addToCart,
|
|
252
|
+
updateItem,
|
|
253
|
+
removeItem,
|
|
254
|
+
clearCart,
|
|
255
|
+
refresh,
|
|
256
|
+
isInCart,
|
|
257
|
+
getItemQuantity
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/hooks/useWishlist.ts
|
|
262
|
+
import { useState as useState5, useEffect as useEffect5, useCallback as useCallback5 } from "react";
|
|
263
|
+
function useWishlist() {
|
|
264
|
+
const client = useClient();
|
|
265
|
+
const [items, setItems] = useState5([]);
|
|
266
|
+
const [loading, setLoading] = useState5(true);
|
|
267
|
+
const [error, setError] = useState5(null);
|
|
268
|
+
const [wishlistMap, setWishlistMap] = useState5({});
|
|
269
|
+
const fetchWishlist = useCallback5(async () => {
|
|
270
|
+
if (!client.isAuthenticated()) {
|
|
271
|
+
setItems([]);
|
|
272
|
+
setWishlistMap({});
|
|
273
|
+
setLoading(false);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
const response = await client.shop.getWishlist({ per_page: 100 });
|
|
278
|
+
setItems(response.data);
|
|
279
|
+
const map = {};
|
|
280
|
+
response.data.forEach((item) => {
|
|
281
|
+
const key = item.variant_id ? `${item.product_id}_${item.variant_id}` : String(item.product_id);
|
|
282
|
+
map[key] = true;
|
|
283
|
+
});
|
|
284
|
+
setWishlistMap(map);
|
|
285
|
+
setError(null);
|
|
286
|
+
} catch (err) {
|
|
287
|
+
setItems([]);
|
|
288
|
+
setWishlistMap({});
|
|
289
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch wishlist"));
|
|
290
|
+
} finally {
|
|
291
|
+
setLoading(false);
|
|
292
|
+
}
|
|
293
|
+
}, [client]);
|
|
294
|
+
useEffect5(() => {
|
|
295
|
+
fetchWishlist();
|
|
296
|
+
}, [fetchWishlist]);
|
|
297
|
+
const isInWishlist = useCallback5((productId, variantId) => {
|
|
298
|
+
const key = variantId ? `${productId}_${variantId}` : String(productId);
|
|
299
|
+
return wishlistMap[key] || false;
|
|
300
|
+
}, [wishlistMap]);
|
|
301
|
+
const toggleWishlist = useCallback5(async (productId, variantId) => {
|
|
302
|
+
const result = await client.shop.toggleWishlist(productId, variantId);
|
|
303
|
+
const key = variantId ? `${productId}_${variantId}` : String(productId);
|
|
304
|
+
setWishlistMap((prev) => ({
|
|
305
|
+
...prev,
|
|
306
|
+
[key]: result.in_wishlist
|
|
307
|
+
}));
|
|
308
|
+
if (result.action === "added") {
|
|
309
|
+
await fetchWishlist();
|
|
310
|
+
} else {
|
|
311
|
+
setItems((prev) => prev.filter(
|
|
312
|
+
(item) => !(item.product_id === productId && item.variant_id === variantId)
|
|
313
|
+
));
|
|
314
|
+
}
|
|
315
|
+
return result;
|
|
316
|
+
}, [client, fetchWishlist]);
|
|
317
|
+
const addToWishlist = useCallback5(async (productId, variantId, note) => {
|
|
318
|
+
const item = await client.shop.addToWishlist({
|
|
319
|
+
product_id: productId,
|
|
320
|
+
variant_id: variantId,
|
|
321
|
+
note
|
|
322
|
+
});
|
|
323
|
+
await fetchWishlist();
|
|
324
|
+
return item;
|
|
325
|
+
}, [client, fetchWishlist]);
|
|
326
|
+
const removeFromWishlist = useCallback5(async (wishlistId) => {
|
|
327
|
+
const item = items.find((i) => i.id === wishlistId);
|
|
328
|
+
await client.shop.removeFromWishlist(wishlistId);
|
|
329
|
+
if (item) {
|
|
330
|
+
const key = item.variant_id ? `${item.product_id}_${item.variant_id}` : String(item.product_id);
|
|
331
|
+
setWishlistMap((prev) => {
|
|
332
|
+
const next = { ...prev };
|
|
333
|
+
delete next[key];
|
|
334
|
+
return next;
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
setItems((prev) => prev.filter((i) => i.id !== wishlistId));
|
|
338
|
+
}, [client, items]);
|
|
339
|
+
const moveToCart = useCallback5(async (wishlistIds) => {
|
|
340
|
+
const result = await client.shop.moveWishlistToCart(wishlistIds);
|
|
341
|
+
await fetchWishlist();
|
|
342
|
+
return result;
|
|
343
|
+
}, [client, fetchWishlist]);
|
|
344
|
+
const updateNote = useCallback5(async (wishlistId, note) => {
|
|
345
|
+
const item = await client.shop.updateWishlistNote(wishlistId, note);
|
|
346
|
+
setItems((prev) => prev.map((i) => i.id === wishlistId ? item : i));
|
|
347
|
+
return item;
|
|
348
|
+
}, [client]);
|
|
349
|
+
const getProductWishlistCount = useCallback5(async (productSlug) => {
|
|
350
|
+
return await client.shop.getProductWishlistCount(productSlug);
|
|
351
|
+
}, [client]);
|
|
352
|
+
const refresh = useCallback5(async () => {
|
|
353
|
+
setLoading(true);
|
|
354
|
+
await fetchWishlist();
|
|
355
|
+
}, [fetchWishlist]);
|
|
356
|
+
return {
|
|
357
|
+
items,
|
|
358
|
+
count: items.length,
|
|
359
|
+
loading,
|
|
360
|
+
error,
|
|
361
|
+
isInWishlist,
|
|
362
|
+
toggleWishlist,
|
|
363
|
+
addToWishlist,
|
|
364
|
+
removeFromWishlist,
|
|
365
|
+
moveToCart,
|
|
366
|
+
updateNote,
|
|
367
|
+
getProductWishlistCount,
|
|
368
|
+
refresh
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/hooks/useProducts.ts
|
|
373
|
+
import { useState as useState6, useEffect as useEffect6, useCallback as useCallback6 } from "react";
|
|
374
|
+
function useProducts(options = {}) {
|
|
375
|
+
const { autoFetch = true, ...params } = options;
|
|
376
|
+
const client = useClient();
|
|
377
|
+
const [products, setProducts] = useState6([]);
|
|
378
|
+
const [meta, setMeta] = useState6(null);
|
|
379
|
+
const [loading, setLoading] = useState6(autoFetch);
|
|
380
|
+
const [error, setError] = useState6(null);
|
|
381
|
+
const [currentParams, setCurrentParams] = useState6(params);
|
|
382
|
+
const fetchProducts = useCallback6(async (fetchParams, append = false) => {
|
|
383
|
+
setLoading(true);
|
|
384
|
+
setError(null);
|
|
385
|
+
try {
|
|
386
|
+
const response = await client.shop.listProducts(fetchParams);
|
|
387
|
+
if (append) {
|
|
388
|
+
setProducts((prev) => [...prev, ...response.data]);
|
|
389
|
+
} else {
|
|
390
|
+
setProducts(response.data);
|
|
391
|
+
}
|
|
392
|
+
setMeta(response.meta);
|
|
393
|
+
} catch (err) {
|
|
394
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch products"));
|
|
395
|
+
} finally {
|
|
396
|
+
setLoading(false);
|
|
397
|
+
}
|
|
398
|
+
}, [client]);
|
|
399
|
+
useEffect6(() => {
|
|
400
|
+
if (autoFetch) {
|
|
401
|
+
fetchProducts(params);
|
|
402
|
+
}
|
|
403
|
+
}, []);
|
|
404
|
+
const hasMore = meta ? meta.current_page < meta.last_page : false;
|
|
405
|
+
const loadMore = useCallback6(async () => {
|
|
406
|
+
if (!hasMore || loading) return;
|
|
407
|
+
const nextPage = (meta?.current_page ?? 0) + 1;
|
|
408
|
+
await fetchProducts({ ...currentParams, page: nextPage }, true);
|
|
409
|
+
}, [hasMore, loading, meta, currentParams, fetchProducts]);
|
|
410
|
+
const refresh = useCallback6(async () => {
|
|
411
|
+
setCurrentParams(params);
|
|
412
|
+
await fetchProducts(params);
|
|
413
|
+
}, [params, fetchProducts]);
|
|
414
|
+
const search = useCallback6(async (query) => {
|
|
415
|
+
const searchParams = { ...params, search: query, page: 1 };
|
|
416
|
+
setCurrentParams(searchParams);
|
|
417
|
+
await fetchProducts(searchParams);
|
|
418
|
+
}, [params, fetchProducts]);
|
|
419
|
+
return {
|
|
420
|
+
products,
|
|
421
|
+
meta,
|
|
422
|
+
loading,
|
|
423
|
+
error,
|
|
424
|
+
hasMore,
|
|
425
|
+
loadMore,
|
|
426
|
+
refresh,
|
|
427
|
+
search
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function useProduct(idOrSlug) {
|
|
431
|
+
const client = useClient();
|
|
432
|
+
const [product, setProduct] = useState6(null);
|
|
433
|
+
const [loading, setLoading] = useState6(true);
|
|
434
|
+
const [error, setError] = useState6(null);
|
|
435
|
+
const fetchProduct = useCallback6(async () => {
|
|
436
|
+
setLoading(true);
|
|
437
|
+
setError(null);
|
|
438
|
+
try {
|
|
439
|
+
const data = await client.shop.getProduct(idOrSlug);
|
|
440
|
+
setProduct(data);
|
|
441
|
+
} catch (err) {
|
|
442
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch product"));
|
|
443
|
+
} finally {
|
|
444
|
+
setLoading(false);
|
|
445
|
+
}
|
|
446
|
+
}, [client, idOrSlug]);
|
|
447
|
+
useEffect6(() => {
|
|
448
|
+
fetchProduct();
|
|
449
|
+
}, [fetchProduct]);
|
|
450
|
+
return {
|
|
451
|
+
product,
|
|
452
|
+
loading,
|
|
453
|
+
error,
|
|
454
|
+
refresh: fetchProduct
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
function useCategories() {
|
|
458
|
+
const client = useClient();
|
|
459
|
+
const [categories, setCategories] = useState6([]);
|
|
460
|
+
const [loading, setLoading] = useState6(true);
|
|
461
|
+
const [error, setError] = useState6(null);
|
|
462
|
+
const fetchCategories = useCallback6(async () => {
|
|
463
|
+
setLoading(true);
|
|
464
|
+
setError(null);
|
|
465
|
+
try {
|
|
466
|
+
const response = await client.shop.listCategories();
|
|
467
|
+
setCategories(response.data);
|
|
468
|
+
} catch (err) {
|
|
469
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch categories"));
|
|
470
|
+
} finally {
|
|
471
|
+
setLoading(false);
|
|
472
|
+
}
|
|
473
|
+
}, [client]);
|
|
474
|
+
useEffect6(() => {
|
|
475
|
+
fetchCategories();
|
|
476
|
+
}, [fetchCategories]);
|
|
477
|
+
return {
|
|
478
|
+
categories,
|
|
479
|
+
loading,
|
|
480
|
+
error,
|
|
481
|
+
refresh: fetchCategories
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function useFeaturedProducts(limit = 8) {
|
|
485
|
+
const client = useClient();
|
|
486
|
+
const [products, setProducts] = useState6([]);
|
|
487
|
+
const [loading, setLoading] = useState6(true);
|
|
488
|
+
const [error, setError] = useState6(null);
|
|
489
|
+
const fetchProducts = useCallback6(async () => {
|
|
490
|
+
setLoading(true);
|
|
491
|
+
setError(null);
|
|
492
|
+
try {
|
|
493
|
+
const data = await client.shop.featuredProducts(limit);
|
|
494
|
+
setProducts(data);
|
|
495
|
+
} catch (err) {
|
|
496
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch featured products"));
|
|
497
|
+
} finally {
|
|
498
|
+
setLoading(false);
|
|
499
|
+
}
|
|
500
|
+
}, [client, limit]);
|
|
501
|
+
useEffect6(() => {
|
|
502
|
+
fetchProducts();
|
|
503
|
+
}, [fetchProducts]);
|
|
504
|
+
return {
|
|
505
|
+
products,
|
|
506
|
+
loading,
|
|
507
|
+
error,
|
|
508
|
+
refresh: fetchProducts
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function useProductsByType(type, params) {
|
|
512
|
+
const client = useClient();
|
|
513
|
+
const [products, setProducts] = useState6([]);
|
|
514
|
+
const [meta, setMeta] = useState6(null);
|
|
515
|
+
const [loading, setLoading] = useState6(true);
|
|
516
|
+
const [error, setError] = useState6(null);
|
|
517
|
+
const fetchProducts = useCallback6(async () => {
|
|
518
|
+
setLoading(true);
|
|
519
|
+
setError(null);
|
|
520
|
+
try {
|
|
521
|
+
const response = await client.shop.listProductsByType(type, params);
|
|
522
|
+
setProducts(response.data);
|
|
523
|
+
setMeta(response.meta);
|
|
524
|
+
} catch (err) {
|
|
525
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch products"));
|
|
526
|
+
} finally {
|
|
527
|
+
setLoading(false);
|
|
528
|
+
}
|
|
529
|
+
}, [client, type, params]);
|
|
530
|
+
useEffect6(() => {
|
|
531
|
+
fetchProducts();
|
|
532
|
+
}, [fetchProducts]);
|
|
533
|
+
return {
|
|
534
|
+
products,
|
|
535
|
+
meta,
|
|
536
|
+
loading,
|
|
537
|
+
error,
|
|
538
|
+
refresh: fetchProducts
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function useDigitalProducts(params) {
|
|
542
|
+
return useProductsByType("digital", params);
|
|
543
|
+
}
|
|
544
|
+
function useSubscriptionProducts(params) {
|
|
545
|
+
return useProductsByType("subscription", params);
|
|
546
|
+
}
|
|
547
|
+
function useBundleProducts(params) {
|
|
548
|
+
return useProductsByType("bundle", params);
|
|
549
|
+
}
|
|
550
|
+
function useBundleItems(productSlug) {
|
|
551
|
+
const client = useClient();
|
|
552
|
+
const [bundle, setBundle] = useState6(null);
|
|
553
|
+
const [loading, setLoading] = useState6(true);
|
|
554
|
+
const [error, setError] = useState6(null);
|
|
555
|
+
const fetchBundle = useCallback6(async () => {
|
|
556
|
+
setLoading(true);
|
|
557
|
+
setError(null);
|
|
558
|
+
try {
|
|
559
|
+
const data = await client.shop.getBundleItems(productSlug);
|
|
560
|
+
setBundle(data);
|
|
561
|
+
} catch (err) {
|
|
562
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch bundle items"));
|
|
563
|
+
} finally {
|
|
564
|
+
setLoading(false);
|
|
565
|
+
}
|
|
566
|
+
}, [client, productSlug]);
|
|
567
|
+
useEffect6(() => {
|
|
568
|
+
fetchBundle();
|
|
569
|
+
}, [fetchBundle]);
|
|
570
|
+
return {
|
|
571
|
+
bundle,
|
|
572
|
+
loading,
|
|
573
|
+
error,
|
|
574
|
+
refresh: fetchBundle
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// src/hooks/useOrders.ts
|
|
579
|
+
import { useState as useState7, useEffect as useEffect7, useCallback as useCallback7 } from "react";
|
|
580
|
+
function useOrders(params) {
|
|
581
|
+
const client = useClient();
|
|
582
|
+
const [orders, setOrders] = useState7([]);
|
|
583
|
+
const [meta, setMeta] = useState7(null);
|
|
584
|
+
const [loading, setLoading] = useState7(true);
|
|
585
|
+
const [error, setError] = useState7(null);
|
|
586
|
+
const fetchOrders = useCallback7(async (fetchParams, append = false) => {
|
|
587
|
+
if (!client.isAuthenticated()) {
|
|
588
|
+
setOrders([]);
|
|
589
|
+
setLoading(false);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
setLoading(true);
|
|
593
|
+
setError(null);
|
|
594
|
+
try {
|
|
595
|
+
const response = await client.shop.listOrders(fetchParams);
|
|
596
|
+
if (append) {
|
|
597
|
+
setOrders((prev) => [...prev, ...response.data]);
|
|
598
|
+
} else {
|
|
599
|
+
setOrders(response.data);
|
|
600
|
+
}
|
|
601
|
+
setMeta(response.meta);
|
|
602
|
+
} catch (err) {
|
|
603
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch orders"));
|
|
604
|
+
} finally {
|
|
605
|
+
setLoading(false);
|
|
606
|
+
}
|
|
607
|
+
}, [client]);
|
|
608
|
+
useEffect7(() => {
|
|
609
|
+
fetchOrders(params);
|
|
610
|
+
}, []);
|
|
611
|
+
const hasMore = meta ? meta.current_page < meta.last_page : false;
|
|
612
|
+
const loadMore = useCallback7(async () => {
|
|
613
|
+
if (!hasMore || loading) return;
|
|
614
|
+
const nextPage = (meta?.current_page ?? 0) + 1;
|
|
615
|
+
await fetchOrders({ ...params, page: nextPage }, true);
|
|
616
|
+
}, [hasMore, loading, meta, params, fetchOrders]);
|
|
617
|
+
const refresh = useCallback7(async () => {
|
|
618
|
+
await fetchOrders(params);
|
|
619
|
+
}, [params, fetchOrders]);
|
|
620
|
+
return {
|
|
621
|
+
orders,
|
|
622
|
+
meta,
|
|
623
|
+
loading,
|
|
624
|
+
error,
|
|
625
|
+
hasMore,
|
|
626
|
+
loadMore,
|
|
627
|
+
refresh
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function useOrder(idOrNumber) {
|
|
631
|
+
const client = useClient();
|
|
632
|
+
const [order, setOrder] = useState7(null);
|
|
633
|
+
const [loading, setLoading] = useState7(true);
|
|
634
|
+
const [error, setError] = useState7(null);
|
|
635
|
+
const fetchOrder = useCallback7(async () => {
|
|
636
|
+
setLoading(true);
|
|
637
|
+
setError(null);
|
|
638
|
+
try {
|
|
639
|
+
const data = await client.shop.getOrder(idOrNumber);
|
|
640
|
+
setOrder(data);
|
|
641
|
+
} catch (err) {
|
|
642
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch order"));
|
|
643
|
+
} finally {
|
|
644
|
+
setLoading(false);
|
|
645
|
+
}
|
|
646
|
+
}, [client, idOrNumber]);
|
|
647
|
+
useEffect7(() => {
|
|
648
|
+
fetchOrder();
|
|
649
|
+
}, [fetchOrder]);
|
|
650
|
+
const cancel = useCallback7(async () => {
|
|
651
|
+
if (!order) throw new Error("Order not loaded");
|
|
652
|
+
const cancelled = await client.shop.cancelOrder(order.id);
|
|
653
|
+
setOrder(cancelled);
|
|
654
|
+
return cancelled;
|
|
655
|
+
}, [client, order]);
|
|
656
|
+
return {
|
|
657
|
+
order,
|
|
658
|
+
loading,
|
|
659
|
+
error,
|
|
660
|
+
cancel,
|
|
661
|
+
refresh: fetchOrder
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
function useCreateOrder() {
|
|
665
|
+
const client = useClient();
|
|
666
|
+
const [loading, setLoading] = useState7(false);
|
|
667
|
+
const [error, setError] = useState7(null);
|
|
668
|
+
const createOrder = useCallback7(async (data) => {
|
|
669
|
+
setLoading(true);
|
|
670
|
+
setError(null);
|
|
671
|
+
try {
|
|
672
|
+
return await client.shop.createOrder(data);
|
|
673
|
+
} catch (err) {
|
|
674
|
+
const error2 = err instanceof Error ? err : new Error("Failed to create order");
|
|
675
|
+
setError(error2);
|
|
676
|
+
throw error2;
|
|
677
|
+
} finally {
|
|
678
|
+
setLoading(false);
|
|
679
|
+
}
|
|
680
|
+
}, [client]);
|
|
681
|
+
return {
|
|
682
|
+
createOrder,
|
|
683
|
+
loading,
|
|
684
|
+
error
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// src/hooks/usePayment.ts
|
|
689
|
+
import { useState as useState8, useCallback as useCallback8 } from "react";
|
|
690
|
+
function usePaymentStatus() {
|
|
691
|
+
const client = useClient();
|
|
692
|
+
const [status, setStatus] = useState8(null);
|
|
693
|
+
const [loading, setLoading] = useState8(true);
|
|
694
|
+
const [error, setError] = useState8(null);
|
|
695
|
+
const fetchStatus = useCallback8(async () => {
|
|
696
|
+
setLoading(true);
|
|
697
|
+
setError(null);
|
|
698
|
+
try {
|
|
699
|
+
const data = await client.shop.getPaymentStatus();
|
|
700
|
+
setStatus(data);
|
|
701
|
+
} catch (err) {
|
|
702
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch payment status"));
|
|
703
|
+
} finally {
|
|
704
|
+
setLoading(false);
|
|
705
|
+
}
|
|
706
|
+
}, [client]);
|
|
707
|
+
return {
|
|
708
|
+
status,
|
|
709
|
+
loading,
|
|
710
|
+
error,
|
|
711
|
+
refresh: fetchStatus,
|
|
712
|
+
isTossAvailable: status?.toss?.available ?? false,
|
|
713
|
+
isStripeAvailable: status?.stripe?.available ?? false,
|
|
714
|
+
stripePublishableKey: status?.stripe?.publishable_key ?? null
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function useTossPayment() {
|
|
718
|
+
const client = useClient();
|
|
719
|
+
const [loading, setLoading] = useState8(false);
|
|
720
|
+
const [error, setError] = useState8(null);
|
|
721
|
+
const preparePayment = useCallback8(async (orderNumber, successUrl, failUrl) => {
|
|
722
|
+
setLoading(true);
|
|
723
|
+
setError(null);
|
|
724
|
+
try {
|
|
725
|
+
return await client.shop.tossPaymentReady({
|
|
726
|
+
order_number: orderNumber,
|
|
727
|
+
success_url: successUrl,
|
|
728
|
+
fail_url: failUrl
|
|
729
|
+
});
|
|
730
|
+
} catch (err) {
|
|
731
|
+
const error2 = err instanceof Error ? err : new Error("Failed to prepare payment");
|
|
732
|
+
setError(error2);
|
|
733
|
+
throw error2;
|
|
734
|
+
} finally {
|
|
735
|
+
setLoading(false);
|
|
736
|
+
}
|
|
737
|
+
}, [client]);
|
|
738
|
+
const confirmPayment = useCallback8(async (paymentKey, orderId, amount) => {
|
|
739
|
+
setLoading(true);
|
|
740
|
+
setError(null);
|
|
741
|
+
try {
|
|
742
|
+
return await client.shop.tossPaymentConfirm({
|
|
743
|
+
payment_key: paymentKey,
|
|
744
|
+
order_id: orderId,
|
|
745
|
+
amount
|
|
746
|
+
});
|
|
747
|
+
} catch (err) {
|
|
748
|
+
const error2 = err instanceof Error ? err : new Error("Failed to confirm payment");
|
|
749
|
+
setError(error2);
|
|
750
|
+
throw error2;
|
|
751
|
+
} finally {
|
|
752
|
+
setLoading(false);
|
|
753
|
+
}
|
|
754
|
+
}, [client]);
|
|
755
|
+
const cancelPayment = useCallback8(async (orderNumber, reason, amount) => {
|
|
756
|
+
setLoading(true);
|
|
757
|
+
setError(null);
|
|
758
|
+
try {
|
|
759
|
+
await client.shop.tossPaymentCancel(orderNumber, reason, amount);
|
|
760
|
+
} catch (err) {
|
|
761
|
+
const error2 = err instanceof Error ? err : new Error("Failed to cancel payment");
|
|
762
|
+
setError(error2);
|
|
763
|
+
throw error2;
|
|
764
|
+
} finally {
|
|
765
|
+
setLoading(false);
|
|
766
|
+
}
|
|
767
|
+
}, [client]);
|
|
768
|
+
return {
|
|
769
|
+
preparePayment,
|
|
770
|
+
confirmPayment,
|
|
771
|
+
cancelPayment,
|
|
772
|
+
loading,
|
|
773
|
+
error
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function useStripePayment() {
|
|
777
|
+
const client = useClient();
|
|
778
|
+
const [loading, setLoading] = useState8(false);
|
|
779
|
+
const [error, setError] = useState8(null);
|
|
780
|
+
const createCheckout = useCallback8(async (orderNumber, successUrl, cancelUrl) => {
|
|
781
|
+
setLoading(true);
|
|
782
|
+
setError(null);
|
|
783
|
+
try {
|
|
784
|
+
return await client.shop.stripeCheckout({
|
|
785
|
+
order_number: orderNumber,
|
|
786
|
+
success_url: successUrl,
|
|
787
|
+
cancel_url: cancelUrl
|
|
788
|
+
});
|
|
789
|
+
} catch (err) {
|
|
790
|
+
const error2 = err instanceof Error ? err : new Error("Failed to create checkout");
|
|
791
|
+
setError(error2);
|
|
792
|
+
throw error2;
|
|
793
|
+
} finally {
|
|
794
|
+
setLoading(false);
|
|
795
|
+
}
|
|
796
|
+
}, [client]);
|
|
797
|
+
const verifyPayment = useCallback8(async (sessionId) => {
|
|
798
|
+
setLoading(true);
|
|
799
|
+
setError(null);
|
|
800
|
+
try {
|
|
801
|
+
return await client.shop.stripeVerify({ session_id: sessionId });
|
|
802
|
+
} catch (err) {
|
|
803
|
+
const error2 = err instanceof Error ? err : new Error("Failed to verify payment");
|
|
804
|
+
setError(error2);
|
|
805
|
+
throw error2;
|
|
806
|
+
} finally {
|
|
807
|
+
setLoading(false);
|
|
808
|
+
}
|
|
809
|
+
}, [client]);
|
|
810
|
+
const refund = useCallback8(async (orderNumber, reason, amount) => {
|
|
811
|
+
setLoading(true);
|
|
812
|
+
setError(null);
|
|
813
|
+
try {
|
|
814
|
+
await client.shop.stripeRefund(orderNumber, reason, amount);
|
|
815
|
+
} catch (err) {
|
|
816
|
+
const error2 = err instanceof Error ? err : new Error("Failed to refund");
|
|
817
|
+
setError(error2);
|
|
818
|
+
throw error2;
|
|
819
|
+
} finally {
|
|
820
|
+
setLoading(false);
|
|
821
|
+
}
|
|
822
|
+
}, [client]);
|
|
823
|
+
return {
|
|
824
|
+
createCheckout,
|
|
825
|
+
verifyPayment,
|
|
826
|
+
refund,
|
|
827
|
+
loading,
|
|
828
|
+
error
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// src/hooks/useCoupons.ts
|
|
833
|
+
import { useState as useState9, useEffect as useEffect8, useCallback as useCallback9 } from "react";
|
|
834
|
+
function useCoupons() {
|
|
835
|
+
const client = useClient();
|
|
836
|
+
const [coupons, setCoupons] = useState9([]);
|
|
837
|
+
const [loading, setLoading] = useState9(true);
|
|
838
|
+
const [error, setError] = useState9(null);
|
|
839
|
+
const fetchCoupons = useCallback9(async () => {
|
|
840
|
+
if (!client.isAuthenticated()) {
|
|
841
|
+
setCoupons([]);
|
|
842
|
+
setLoading(false);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
setLoading(true);
|
|
846
|
+
setError(null);
|
|
847
|
+
try {
|
|
848
|
+
const data = await client.shop.myCoupons();
|
|
849
|
+
setCoupons(data);
|
|
850
|
+
} catch (err) {
|
|
851
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch coupons"));
|
|
852
|
+
} finally {
|
|
853
|
+
setLoading(false);
|
|
854
|
+
}
|
|
855
|
+
}, [client]);
|
|
856
|
+
useEffect8(() => {
|
|
857
|
+
fetchCoupons();
|
|
858
|
+
}, [fetchCoupons]);
|
|
859
|
+
return {
|
|
860
|
+
coupons,
|
|
861
|
+
loading,
|
|
862
|
+
error,
|
|
863
|
+
refresh: fetchCoupons
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
function useValidateCoupon() {
|
|
867
|
+
const client = useClient();
|
|
868
|
+
const [validation, setValidation] = useState9(null);
|
|
869
|
+
const [loading, setLoading] = useState9(false);
|
|
870
|
+
const [error, setError] = useState9(null);
|
|
871
|
+
const validate = useCallback9(async (code, orderAmount) => {
|
|
872
|
+
setLoading(true);
|
|
873
|
+
setError(null);
|
|
874
|
+
try {
|
|
875
|
+
const result = await client.shop.validateCoupon(code, orderAmount);
|
|
876
|
+
setValidation(result);
|
|
877
|
+
return result;
|
|
878
|
+
} catch (err) {
|
|
879
|
+
const error2 = err instanceof Error ? err : new Error("Failed to validate coupon");
|
|
880
|
+
setError(error2);
|
|
881
|
+
setValidation({ valid: false, message: error2.message });
|
|
882
|
+
throw error2;
|
|
883
|
+
} finally {
|
|
884
|
+
setLoading(false);
|
|
885
|
+
}
|
|
886
|
+
}, [client]);
|
|
887
|
+
const reset = useCallback9(() => {
|
|
888
|
+
setValidation(null);
|
|
889
|
+
setError(null);
|
|
890
|
+
}, []);
|
|
891
|
+
return {
|
|
892
|
+
validate,
|
|
893
|
+
validation,
|
|
894
|
+
loading,
|
|
895
|
+
error,
|
|
896
|
+
reset
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// src/hooks/useSubscriptions.ts
|
|
901
|
+
import { useState as useState10, useEffect as useEffect9, useCallback as useCallback10 } from "react";
|
|
902
|
+
function useSubscriptions() {
|
|
903
|
+
const client = useClient();
|
|
904
|
+
const [subscriptions, setSubscriptions] = useState10([]);
|
|
905
|
+
const [loading, setLoading] = useState10(true);
|
|
906
|
+
const [error, setError] = useState10(null);
|
|
907
|
+
const fetchSubscriptions = useCallback10(async () => {
|
|
908
|
+
if (!client.isAuthenticated()) {
|
|
909
|
+
setSubscriptions([]);
|
|
910
|
+
setLoading(false);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
setLoading(true);
|
|
914
|
+
setError(null);
|
|
915
|
+
try {
|
|
916
|
+
const data = await client.shop.getSubscriptions();
|
|
917
|
+
setSubscriptions(data);
|
|
918
|
+
} catch (err) {
|
|
919
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch subscriptions"));
|
|
920
|
+
} finally {
|
|
921
|
+
setLoading(false);
|
|
922
|
+
}
|
|
923
|
+
}, [client]);
|
|
924
|
+
useEffect9(() => {
|
|
925
|
+
fetchSubscriptions();
|
|
926
|
+
}, [fetchSubscriptions]);
|
|
927
|
+
const activeSubscription = subscriptions.find((s) => s.is_active) ?? null;
|
|
928
|
+
const hasActiveSubscription = !!activeSubscription;
|
|
929
|
+
return {
|
|
930
|
+
subscriptions,
|
|
931
|
+
loading,
|
|
932
|
+
error,
|
|
933
|
+
activeSubscription,
|
|
934
|
+
hasActiveSubscription,
|
|
935
|
+
refresh: fetchSubscriptions
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
function useSubscription(id) {
|
|
939
|
+
const client = useClient();
|
|
940
|
+
const [subscription, setSubscription] = useState10(null);
|
|
941
|
+
const [loading, setLoading] = useState10(true);
|
|
942
|
+
const [error, setError] = useState10(null);
|
|
943
|
+
const fetchSubscription = useCallback10(async () => {
|
|
944
|
+
setLoading(true);
|
|
945
|
+
setError(null);
|
|
946
|
+
try {
|
|
947
|
+
const data = await client.shop.getSubscription(id);
|
|
948
|
+
setSubscription(data);
|
|
949
|
+
} catch (err) {
|
|
950
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch subscription"));
|
|
951
|
+
} finally {
|
|
952
|
+
setLoading(false);
|
|
953
|
+
}
|
|
954
|
+
}, [client, id]);
|
|
955
|
+
useEffect9(() => {
|
|
956
|
+
fetchSubscription();
|
|
957
|
+
}, [fetchSubscription]);
|
|
958
|
+
const cancel = useCallback10(async (immediately = false) => {
|
|
959
|
+
const updated = await client.shop.cancelSubscription(id, immediately);
|
|
960
|
+
setSubscription(updated);
|
|
961
|
+
return updated;
|
|
962
|
+
}, [client, id]);
|
|
963
|
+
const pause = useCallback10(async () => {
|
|
964
|
+
const updated = await client.shop.pauseSubscription(id);
|
|
965
|
+
setSubscription(updated);
|
|
966
|
+
return updated;
|
|
967
|
+
}, [client, id]);
|
|
968
|
+
const resume = useCallback10(async () => {
|
|
969
|
+
const updated = await client.shop.resumeSubscription(id);
|
|
970
|
+
setSubscription(updated);
|
|
971
|
+
return updated;
|
|
972
|
+
}, [client, id]);
|
|
973
|
+
return {
|
|
974
|
+
subscription,
|
|
975
|
+
loading,
|
|
976
|
+
error,
|
|
977
|
+
cancel,
|
|
978
|
+
pause,
|
|
979
|
+
resume,
|
|
980
|
+
refresh: fetchSubscription
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
function useCreateSubscription() {
|
|
984
|
+
const client = useClient();
|
|
985
|
+
const [loading, setLoading] = useState10(false);
|
|
986
|
+
const [error, setError] = useState10(null);
|
|
987
|
+
const createCheckout = useCallback10(async (planId, successUrl, cancelUrl) => {
|
|
988
|
+
setLoading(true);
|
|
989
|
+
setError(null);
|
|
990
|
+
try {
|
|
991
|
+
return await client.shop.createSubscriptionCheckout({
|
|
992
|
+
plan_id: planId,
|
|
993
|
+
success_url: successUrl,
|
|
994
|
+
cancel_url: cancelUrl
|
|
995
|
+
});
|
|
996
|
+
} catch (err) {
|
|
997
|
+
const error2 = err instanceof Error ? err : new Error("Failed to create checkout");
|
|
998
|
+
setError(error2);
|
|
999
|
+
throw error2;
|
|
1000
|
+
} finally {
|
|
1001
|
+
setLoading(false);
|
|
1002
|
+
}
|
|
1003
|
+
}, [client]);
|
|
1004
|
+
const verifyCheckout = useCallback10(async (sessionId) => {
|
|
1005
|
+
setLoading(true);
|
|
1006
|
+
setError(null);
|
|
1007
|
+
try {
|
|
1008
|
+
const result = await client.shop.verifySubscriptionCheckout(sessionId);
|
|
1009
|
+
return result.subscription;
|
|
1010
|
+
} catch (err) {
|
|
1011
|
+
const error2 = err instanceof Error ? err : new Error("Failed to verify checkout");
|
|
1012
|
+
setError(error2);
|
|
1013
|
+
throw error2;
|
|
1014
|
+
} finally {
|
|
1015
|
+
setLoading(false);
|
|
1016
|
+
}
|
|
1017
|
+
}, [client]);
|
|
1018
|
+
const createSetupIntent = useCallback10(async () => {
|
|
1019
|
+
setLoading(true);
|
|
1020
|
+
setError(null);
|
|
1021
|
+
try {
|
|
1022
|
+
const result = await client.shop.createSetupIntent();
|
|
1023
|
+
return result.client_secret;
|
|
1024
|
+
} catch (err) {
|
|
1025
|
+
const error2 = err instanceof Error ? err : new Error("Failed to create setup intent");
|
|
1026
|
+
setError(error2);
|
|
1027
|
+
throw error2;
|
|
1028
|
+
} finally {
|
|
1029
|
+
setLoading(false);
|
|
1030
|
+
}
|
|
1031
|
+
}, [client]);
|
|
1032
|
+
return {
|
|
1033
|
+
createCheckout,
|
|
1034
|
+
verifyCheckout,
|
|
1035
|
+
createSetupIntent,
|
|
1036
|
+
loading,
|
|
1037
|
+
error
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// src/hooks/useDownloads.ts
|
|
1042
|
+
import { useState as useState11, useEffect as useEffect10, useCallback as useCallback11 } from "react";
|
|
1043
|
+
function useDownloads() {
|
|
1044
|
+
const client = useClient();
|
|
1045
|
+
const [downloads, setDownloads] = useState11([]);
|
|
1046
|
+
const [loading, setLoading] = useState11(true);
|
|
1047
|
+
const [error, setError] = useState11(null);
|
|
1048
|
+
const fetchDownloads = useCallback11(async () => {
|
|
1049
|
+
if (!client.isAuthenticated()) {
|
|
1050
|
+
setDownloads([]);
|
|
1051
|
+
setLoading(false);
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
setLoading(true);
|
|
1055
|
+
setError(null);
|
|
1056
|
+
try {
|
|
1057
|
+
const data = await client.shop.getMyDownloads();
|
|
1058
|
+
setDownloads(data);
|
|
1059
|
+
} catch (err) {
|
|
1060
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch downloads"));
|
|
1061
|
+
} finally {
|
|
1062
|
+
setLoading(false);
|
|
1063
|
+
}
|
|
1064
|
+
}, [client]);
|
|
1065
|
+
useEffect10(() => {
|
|
1066
|
+
fetchDownloads();
|
|
1067
|
+
}, [fetchDownloads]);
|
|
1068
|
+
const getDownloadUrl = useCallback11((token) => {
|
|
1069
|
+
return client.shop.getDownloadUrl(token);
|
|
1070
|
+
}, [client]);
|
|
1071
|
+
const getDownloadInfo = useCallback11(async (token) => {
|
|
1072
|
+
return await client.shop.getDownloadInfo(token);
|
|
1073
|
+
}, [client]);
|
|
1074
|
+
return {
|
|
1075
|
+
downloads,
|
|
1076
|
+
loading,
|
|
1077
|
+
error,
|
|
1078
|
+
getDownloadUrl,
|
|
1079
|
+
getDownloadInfo,
|
|
1080
|
+
refresh: fetchDownloads
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
function useOrderDownloads(orderNumber) {
|
|
1084
|
+
const client = useClient();
|
|
1085
|
+
const [downloads, setDownloads] = useState11([]);
|
|
1086
|
+
const [loading, setLoading] = useState11(true);
|
|
1087
|
+
const [error, setError] = useState11(null);
|
|
1088
|
+
const fetchDownloads = useCallback11(async () => {
|
|
1089
|
+
if (!client.isAuthenticated()) {
|
|
1090
|
+
setDownloads([]);
|
|
1091
|
+
setLoading(false);
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
setLoading(true);
|
|
1095
|
+
setError(null);
|
|
1096
|
+
try {
|
|
1097
|
+
const data = await client.shop.getOrderDownloads(orderNumber);
|
|
1098
|
+
setDownloads(data);
|
|
1099
|
+
} catch (err) {
|
|
1100
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch downloads"));
|
|
1101
|
+
} finally {
|
|
1102
|
+
setLoading(false);
|
|
1103
|
+
}
|
|
1104
|
+
}, [client, orderNumber]);
|
|
1105
|
+
useEffect10(() => {
|
|
1106
|
+
fetchDownloads();
|
|
1107
|
+
}, [fetchDownloads]);
|
|
1108
|
+
const getDownloadUrl = useCallback11((token) => {
|
|
1109
|
+
return client.shop.getDownloadUrl(token);
|
|
1110
|
+
}, [client]);
|
|
1111
|
+
const getDownloadInfo = useCallback11(async (token) => {
|
|
1112
|
+
return await client.shop.getDownloadInfo(token);
|
|
1113
|
+
}, [client]);
|
|
1114
|
+
return {
|
|
1115
|
+
downloads,
|
|
1116
|
+
loading,
|
|
1117
|
+
error,
|
|
1118
|
+
getDownloadUrl,
|
|
1119
|
+
getDownloadInfo,
|
|
1120
|
+
refresh: fetchDownloads
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// src/hooks/useReviews.ts
|
|
1125
|
+
import { useState as useState12, useEffect as useEffect11, useCallback as useCallback12 } from "react";
|
|
1126
|
+
function useProductReviews(productSlug, params) {
|
|
1127
|
+
const client = useClient();
|
|
1128
|
+
const [reviews, setReviews] = useState12([]);
|
|
1129
|
+
const [stats, setStats] = useState12(null);
|
|
1130
|
+
const [meta, setMeta] = useState12(null);
|
|
1131
|
+
const [loading, setLoading] = useState12(true);
|
|
1132
|
+
const [error, setError] = useState12(null);
|
|
1133
|
+
const fetchReviews = useCallback12(async () => {
|
|
1134
|
+
setLoading(true);
|
|
1135
|
+
setError(null);
|
|
1136
|
+
try {
|
|
1137
|
+
const response = await client.shop.getProductReviews(productSlug, params);
|
|
1138
|
+
setReviews(response.data);
|
|
1139
|
+
setStats(response.stats);
|
|
1140
|
+
setMeta(response.meta);
|
|
1141
|
+
} catch (err) {
|
|
1142
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch reviews"));
|
|
1143
|
+
} finally {
|
|
1144
|
+
setLoading(false);
|
|
1145
|
+
}
|
|
1146
|
+
}, [client, productSlug, params]);
|
|
1147
|
+
useEffect11(() => {
|
|
1148
|
+
fetchReviews();
|
|
1149
|
+
}, [fetchReviews]);
|
|
1150
|
+
return {
|
|
1151
|
+
reviews,
|
|
1152
|
+
stats,
|
|
1153
|
+
meta,
|
|
1154
|
+
loading,
|
|
1155
|
+
error,
|
|
1156
|
+
refresh: fetchReviews
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
function useCanReview(productSlug) {
|
|
1160
|
+
const client = useClient();
|
|
1161
|
+
const [canReview, setCanReview] = useState12(false);
|
|
1162
|
+
const [reason, setReason] = useState12(null);
|
|
1163
|
+
const [loading, setLoading] = useState12(true);
|
|
1164
|
+
const [error, setError] = useState12(null);
|
|
1165
|
+
const check = useCallback12(async () => {
|
|
1166
|
+
setLoading(true);
|
|
1167
|
+
setError(null);
|
|
1168
|
+
try {
|
|
1169
|
+
const response = await client.shop.canReviewProduct(productSlug);
|
|
1170
|
+
setCanReview(response.can_review);
|
|
1171
|
+
setReason(response.reason ?? null);
|
|
1172
|
+
return response;
|
|
1173
|
+
} catch (err) {
|
|
1174
|
+
setError(err instanceof Error ? err : new Error("Failed to check review eligibility"));
|
|
1175
|
+
return { can_review: false, reason: "not_logged_in" };
|
|
1176
|
+
} finally {
|
|
1177
|
+
setLoading(false);
|
|
1178
|
+
}
|
|
1179
|
+
}, [client, productSlug]);
|
|
1180
|
+
useEffect11(() => {
|
|
1181
|
+
if (client.isAuthenticated()) {
|
|
1182
|
+
check();
|
|
1183
|
+
} else {
|
|
1184
|
+
setCanReview(false);
|
|
1185
|
+
setReason("not_logged_in");
|
|
1186
|
+
setLoading(false);
|
|
1187
|
+
}
|
|
1188
|
+
}, [check, client]);
|
|
1189
|
+
return {
|
|
1190
|
+
canReview,
|
|
1191
|
+
reason,
|
|
1192
|
+
loading,
|
|
1193
|
+
error,
|
|
1194
|
+
check
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
function useCreateReview() {
|
|
1198
|
+
const client = useClient();
|
|
1199
|
+
const [loading, setLoading] = useState12(false);
|
|
1200
|
+
const [error, setError] = useState12(null);
|
|
1201
|
+
const createReview = useCallback12(async (productSlug, data) => {
|
|
1202
|
+
setLoading(true);
|
|
1203
|
+
setError(null);
|
|
1204
|
+
try {
|
|
1205
|
+
return await client.shop.createReview(productSlug, data);
|
|
1206
|
+
} catch (err) {
|
|
1207
|
+
const error2 = err instanceof Error ? err : new Error("Failed to create review");
|
|
1208
|
+
setError(error2);
|
|
1209
|
+
throw error2;
|
|
1210
|
+
} finally {
|
|
1211
|
+
setLoading(false);
|
|
1212
|
+
}
|
|
1213
|
+
}, [client]);
|
|
1214
|
+
return {
|
|
1215
|
+
createReview,
|
|
1216
|
+
loading,
|
|
1217
|
+
error
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
function useMyReviews(params) {
|
|
1221
|
+
const client = useClient();
|
|
1222
|
+
const [reviews, setReviews] = useState12([]);
|
|
1223
|
+
const [meta, setMeta] = useState12(null);
|
|
1224
|
+
const [loading, setLoading] = useState12(true);
|
|
1225
|
+
const [error, setError] = useState12(null);
|
|
1226
|
+
const fetchReviews = useCallback12(async () => {
|
|
1227
|
+
if (!client.isAuthenticated()) {
|
|
1228
|
+
setReviews([]);
|
|
1229
|
+
setLoading(false);
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
setLoading(true);
|
|
1233
|
+
setError(null);
|
|
1234
|
+
try {
|
|
1235
|
+
const response = await client.shop.myReviews(params);
|
|
1236
|
+
setReviews(response.data);
|
|
1237
|
+
setMeta(response.meta);
|
|
1238
|
+
} catch (err) {
|
|
1239
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch reviews"));
|
|
1240
|
+
} finally {
|
|
1241
|
+
setLoading(false);
|
|
1242
|
+
}
|
|
1243
|
+
}, [client, params]);
|
|
1244
|
+
useEffect11(() => {
|
|
1245
|
+
fetchReviews();
|
|
1246
|
+
}, [fetchReviews]);
|
|
1247
|
+
const deleteReview = useCallback12(async (reviewId) => {
|
|
1248
|
+
await client.shop.deleteReview(reviewId);
|
|
1249
|
+
setReviews((prev) => prev.filter((r) => r.id !== reviewId));
|
|
1250
|
+
}, [client]);
|
|
1251
|
+
const updateReview = useCallback12(async (reviewId, data) => {
|
|
1252
|
+
const updated = await client.shop.updateReview(reviewId, data);
|
|
1253
|
+
setReviews((prev) => prev.map((r) => r.id === reviewId ? updated : r));
|
|
1254
|
+
return updated;
|
|
1255
|
+
}, [client]);
|
|
1256
|
+
return {
|
|
1257
|
+
reviews,
|
|
1258
|
+
meta,
|
|
1259
|
+
loading,
|
|
1260
|
+
error,
|
|
1261
|
+
refresh: fetchReviews,
|
|
1262
|
+
deleteReview,
|
|
1263
|
+
updateReview
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// src/hooks/useBlog.ts
|
|
1268
|
+
import { useState as useState13, useEffect as useEffect12, useCallback as useCallback13 } from "react";
|
|
1269
|
+
function useBlog(options = {}) {
|
|
1270
|
+
const { autoFetch = true, ...params } = options;
|
|
1271
|
+
const client = useClient();
|
|
1272
|
+
const [posts, setPosts] = useState13([]);
|
|
1273
|
+
const [meta, setMeta] = useState13(null);
|
|
1274
|
+
const [loading, setLoading] = useState13(autoFetch);
|
|
1275
|
+
const [error, setError] = useState13(null);
|
|
1276
|
+
const [currentParams, setCurrentParams] = useState13(params);
|
|
1277
|
+
const fetchPosts = useCallback13(async (fetchParams, append = false) => {
|
|
1278
|
+
setLoading(true);
|
|
1279
|
+
setError(null);
|
|
1280
|
+
try {
|
|
1281
|
+
const response = await client.blog.list(fetchParams);
|
|
1282
|
+
if (append) {
|
|
1283
|
+
setPosts((prev) => [...prev, ...response.data]);
|
|
1284
|
+
} else {
|
|
1285
|
+
setPosts(response.data);
|
|
1286
|
+
}
|
|
1287
|
+
setMeta(response.meta);
|
|
1288
|
+
} catch (err) {
|
|
1289
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch blog posts"));
|
|
1290
|
+
} finally {
|
|
1291
|
+
setLoading(false);
|
|
1292
|
+
}
|
|
1293
|
+
}, [client]);
|
|
1294
|
+
useEffect12(() => {
|
|
1295
|
+
if (autoFetch) {
|
|
1296
|
+
fetchPosts(params);
|
|
1297
|
+
}
|
|
1298
|
+
}, []);
|
|
1299
|
+
const hasMore = meta ? meta.current_page < meta.last_page : false;
|
|
1300
|
+
const loadMore = useCallback13(async () => {
|
|
1301
|
+
if (!hasMore || loading) return;
|
|
1302
|
+
const nextPage = (meta?.current_page ?? 0) + 1;
|
|
1303
|
+
await fetchPosts({ ...currentParams, page: nextPage }, true);
|
|
1304
|
+
}, [hasMore, loading, meta, currentParams, fetchPosts]);
|
|
1305
|
+
const refresh = useCallback13(async () => {
|
|
1306
|
+
setCurrentParams(params);
|
|
1307
|
+
await fetchPosts(params);
|
|
1308
|
+
}, [params, fetchPosts]);
|
|
1309
|
+
return {
|
|
1310
|
+
posts,
|
|
1311
|
+
meta,
|
|
1312
|
+
loading,
|
|
1313
|
+
error,
|
|
1314
|
+
hasMore,
|
|
1315
|
+
loadMore,
|
|
1316
|
+
refresh
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
function useBlogPost(slug) {
|
|
1320
|
+
const client = useClient();
|
|
1321
|
+
const [post, setPost] = useState13(null);
|
|
1322
|
+
const [loading, setLoading] = useState13(true);
|
|
1323
|
+
const [error, setError] = useState13(null);
|
|
1324
|
+
const fetchPost = useCallback13(async () => {
|
|
1325
|
+
setLoading(true);
|
|
1326
|
+
setError(null);
|
|
1327
|
+
try {
|
|
1328
|
+
const data = await client.blog.get(slug);
|
|
1329
|
+
setPost(data);
|
|
1330
|
+
} catch (err) {
|
|
1331
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch blog post"));
|
|
1332
|
+
} finally {
|
|
1333
|
+
setLoading(false);
|
|
1334
|
+
}
|
|
1335
|
+
}, [client, slug]);
|
|
1336
|
+
useEffect12(() => {
|
|
1337
|
+
fetchPost();
|
|
1338
|
+
}, [fetchPost]);
|
|
1339
|
+
return {
|
|
1340
|
+
post,
|
|
1341
|
+
loading,
|
|
1342
|
+
error,
|
|
1343
|
+
refresh: fetchPost
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
function useBlogCategories() {
|
|
1347
|
+
const client = useClient();
|
|
1348
|
+
const [categories, setCategories] = useState13([]);
|
|
1349
|
+
const [loading, setLoading] = useState13(true);
|
|
1350
|
+
const [error, setError] = useState13(null);
|
|
1351
|
+
const fetchCategories = useCallback13(async () => {
|
|
1352
|
+
setLoading(true);
|
|
1353
|
+
setError(null);
|
|
1354
|
+
try {
|
|
1355
|
+
const data = await client.blog.categories();
|
|
1356
|
+
setCategories(data);
|
|
1357
|
+
} catch (err) {
|
|
1358
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch blog categories"));
|
|
1359
|
+
} finally {
|
|
1360
|
+
setLoading(false);
|
|
1361
|
+
}
|
|
1362
|
+
}, [client]);
|
|
1363
|
+
useEffect12(() => {
|
|
1364
|
+
fetchCategories();
|
|
1365
|
+
}, [fetchCategories]);
|
|
1366
|
+
return {
|
|
1367
|
+
categories,
|
|
1368
|
+
loading,
|
|
1369
|
+
error,
|
|
1370
|
+
refresh: fetchCategories
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
function useBlogTags() {
|
|
1374
|
+
const client = useClient();
|
|
1375
|
+
const [tags, setTags] = useState13([]);
|
|
1376
|
+
const [loading, setLoading] = useState13(true);
|
|
1377
|
+
const [error, setError] = useState13(null);
|
|
1378
|
+
const fetchTags = useCallback13(async () => {
|
|
1379
|
+
setLoading(true);
|
|
1380
|
+
setError(null);
|
|
1381
|
+
try {
|
|
1382
|
+
const data = await client.blog.tags();
|
|
1383
|
+
setTags(data);
|
|
1384
|
+
} catch (err) {
|
|
1385
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch blog tags"));
|
|
1386
|
+
} finally {
|
|
1387
|
+
setLoading(false);
|
|
1388
|
+
}
|
|
1389
|
+
}, [client]);
|
|
1390
|
+
useEffect12(() => {
|
|
1391
|
+
fetchTags();
|
|
1392
|
+
}, [fetchTags]);
|
|
1393
|
+
return {
|
|
1394
|
+
tags,
|
|
1395
|
+
loading,
|
|
1396
|
+
error,
|
|
1397
|
+
refresh: fetchTags
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
function useFeaturedBlog(limit = 5) {
|
|
1401
|
+
const client = useClient();
|
|
1402
|
+
const [posts, setPosts] = useState13([]);
|
|
1403
|
+
const [loading, setLoading] = useState13(true);
|
|
1404
|
+
const [error, setError] = useState13(null);
|
|
1405
|
+
const fetchPosts = useCallback13(async () => {
|
|
1406
|
+
setLoading(true);
|
|
1407
|
+
setError(null);
|
|
1408
|
+
try {
|
|
1409
|
+
const data = await client.blog.featured(limit);
|
|
1410
|
+
setPosts(data);
|
|
1411
|
+
} catch (err) {
|
|
1412
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch featured posts"));
|
|
1413
|
+
} finally {
|
|
1414
|
+
setLoading(false);
|
|
1415
|
+
}
|
|
1416
|
+
}, [client, limit]);
|
|
1417
|
+
useEffect12(() => {
|
|
1418
|
+
fetchPosts();
|
|
1419
|
+
}, [fetchPosts]);
|
|
1420
|
+
return {
|
|
1421
|
+
posts,
|
|
1422
|
+
loading,
|
|
1423
|
+
error,
|
|
1424
|
+
refresh: fetchPosts
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
function useBlogSearch() {
|
|
1428
|
+
const client = useClient();
|
|
1429
|
+
const [posts, setPosts] = useState13([]);
|
|
1430
|
+
const [meta, setMeta] = useState13(null);
|
|
1431
|
+
const [loading, setLoading] = useState13(false);
|
|
1432
|
+
const [error, setError] = useState13(null);
|
|
1433
|
+
const search = useCallback13(async (query) => {
|
|
1434
|
+
setLoading(true);
|
|
1435
|
+
setError(null);
|
|
1436
|
+
try {
|
|
1437
|
+
const response = await client.blog.search(query);
|
|
1438
|
+
setPosts(response.data);
|
|
1439
|
+
setMeta(response.meta);
|
|
1440
|
+
} catch (err) {
|
|
1441
|
+
setError(err instanceof Error ? err : new Error("Failed to search posts"));
|
|
1442
|
+
} finally {
|
|
1443
|
+
setLoading(false);
|
|
1444
|
+
}
|
|
1445
|
+
}, [client]);
|
|
1446
|
+
return {
|
|
1447
|
+
posts,
|
|
1448
|
+
meta,
|
|
1449
|
+
loading,
|
|
1450
|
+
error,
|
|
1451
|
+
search
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// src/hooks/useBoards.ts
|
|
1456
|
+
import { useState as useState14, useEffect as useEffect13, useCallback as useCallback14 } from "react";
|
|
1457
|
+
function useBoards(params) {
|
|
1458
|
+
const client = useClient();
|
|
1459
|
+
const [boards, setBoards] = useState14([]);
|
|
1460
|
+
const [loading, setLoading] = useState14(true);
|
|
1461
|
+
const [error, setError] = useState14(null);
|
|
1462
|
+
const fetchBoards = useCallback14(async () => {
|
|
1463
|
+
setLoading(true);
|
|
1464
|
+
setError(null);
|
|
1465
|
+
try {
|
|
1466
|
+
const response = await client.boards.list(params);
|
|
1467
|
+
setBoards(response.data);
|
|
1468
|
+
} catch (err) {
|
|
1469
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch boards"));
|
|
1470
|
+
} finally {
|
|
1471
|
+
setLoading(false);
|
|
1472
|
+
}
|
|
1473
|
+
}, [client, params]);
|
|
1474
|
+
useEffect13(() => {
|
|
1475
|
+
fetchBoards();
|
|
1476
|
+
}, [fetchBoards]);
|
|
1477
|
+
return {
|
|
1478
|
+
boards,
|
|
1479
|
+
loading,
|
|
1480
|
+
error,
|
|
1481
|
+
refresh: fetchBoards
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
function useBoard(slug) {
|
|
1485
|
+
const client = useClient();
|
|
1486
|
+
const [board, setBoard] = useState14(null);
|
|
1487
|
+
const [loading, setLoading] = useState14(true);
|
|
1488
|
+
const [error, setError] = useState14(null);
|
|
1489
|
+
const fetchBoard = useCallback14(async () => {
|
|
1490
|
+
setLoading(true);
|
|
1491
|
+
setError(null);
|
|
1492
|
+
try {
|
|
1493
|
+
const data = await client.boards.get(slug);
|
|
1494
|
+
setBoard(data);
|
|
1495
|
+
} catch (err) {
|
|
1496
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch board"));
|
|
1497
|
+
} finally {
|
|
1498
|
+
setLoading(false);
|
|
1499
|
+
}
|
|
1500
|
+
}, [client, slug]);
|
|
1501
|
+
useEffect13(() => {
|
|
1502
|
+
fetchBoard();
|
|
1503
|
+
}, [fetchBoard]);
|
|
1504
|
+
return {
|
|
1505
|
+
board,
|
|
1506
|
+
loading,
|
|
1507
|
+
error,
|
|
1508
|
+
refresh: fetchBoard
|
|
1509
|
+
};
|
|
1510
|
+
}
|
|
1511
|
+
function useBoardPosts(boardSlug, params) {
|
|
1512
|
+
const client = useClient();
|
|
1513
|
+
const [posts, setPosts] = useState14([]);
|
|
1514
|
+
const [meta, setMeta] = useState14(null);
|
|
1515
|
+
const [loading, setLoading] = useState14(true);
|
|
1516
|
+
const [error, setError] = useState14(null);
|
|
1517
|
+
const [currentParams, setCurrentParams] = useState14(params);
|
|
1518
|
+
const fetchPosts = useCallback14(async (fetchParams, append = false) => {
|
|
1519
|
+
setLoading(true);
|
|
1520
|
+
setError(null);
|
|
1521
|
+
try {
|
|
1522
|
+
const response = await client.boards.listPosts(boardSlug, fetchParams);
|
|
1523
|
+
if (append) {
|
|
1524
|
+
setPosts((prev) => [...prev, ...response.data]);
|
|
1525
|
+
} else {
|
|
1526
|
+
setPosts(response.data);
|
|
1527
|
+
}
|
|
1528
|
+
setMeta(response.meta);
|
|
1529
|
+
} catch (err) {
|
|
1530
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch posts"));
|
|
1531
|
+
} finally {
|
|
1532
|
+
setLoading(false);
|
|
1533
|
+
}
|
|
1534
|
+
}, [client, boardSlug]);
|
|
1535
|
+
useEffect13(() => {
|
|
1536
|
+
fetchPosts(params);
|
|
1537
|
+
}, []);
|
|
1538
|
+
const hasMore = meta ? meta.current_page < meta.last_page : false;
|
|
1539
|
+
const loadMore = useCallback14(async () => {
|
|
1540
|
+
if (!hasMore || loading) return;
|
|
1541
|
+
const nextPage = (meta?.current_page ?? 0) + 1;
|
|
1542
|
+
await fetchPosts({ ...currentParams, page: nextPage }, true);
|
|
1543
|
+
}, [hasMore, loading, meta, currentParams, fetchPosts]);
|
|
1544
|
+
const refresh = useCallback14(async () => {
|
|
1545
|
+
setCurrentParams(params);
|
|
1546
|
+
await fetchPosts(params);
|
|
1547
|
+
}, [params, fetchPosts]);
|
|
1548
|
+
return {
|
|
1549
|
+
posts,
|
|
1550
|
+
meta,
|
|
1551
|
+
loading,
|
|
1552
|
+
error,
|
|
1553
|
+
hasMore,
|
|
1554
|
+
loadMore,
|
|
1555
|
+
refresh
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
function useBoardPost(postId) {
|
|
1559
|
+
const client = useClient();
|
|
1560
|
+
const [post, setPost] = useState14(null);
|
|
1561
|
+
const [loading, setLoading] = useState14(true);
|
|
1562
|
+
const [error, setError] = useState14(null);
|
|
1563
|
+
const fetchPost = useCallback14(async () => {
|
|
1564
|
+
setLoading(true);
|
|
1565
|
+
setError(null);
|
|
1566
|
+
try {
|
|
1567
|
+
const data = await client.boards.getPost(postId);
|
|
1568
|
+
setPost(data);
|
|
1569
|
+
} catch (err) {
|
|
1570
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch post"));
|
|
1571
|
+
} finally {
|
|
1572
|
+
setLoading(false);
|
|
1573
|
+
}
|
|
1574
|
+
}, [client, postId]);
|
|
1575
|
+
useEffect13(() => {
|
|
1576
|
+
fetchPost();
|
|
1577
|
+
}, [fetchPost]);
|
|
1578
|
+
return {
|
|
1579
|
+
post,
|
|
1580
|
+
loading,
|
|
1581
|
+
error,
|
|
1582
|
+
refresh: fetchPost
|
|
1583
|
+
};
|
|
1584
|
+
}
|
|
1585
|
+
function useCreateBoardPost() {
|
|
1586
|
+
const client = useClient();
|
|
1587
|
+
const [loading, setLoading] = useState14(false);
|
|
1588
|
+
const [error, setError] = useState14(null);
|
|
1589
|
+
const createPost = useCallback14(async (data) => {
|
|
1590
|
+
setLoading(true);
|
|
1591
|
+
setError(null);
|
|
1592
|
+
try {
|
|
1593
|
+
return await client.boards.createPost(data);
|
|
1594
|
+
} catch (err) {
|
|
1595
|
+
const error2 = err instanceof Error ? err : new Error("Failed to create post");
|
|
1596
|
+
setError(error2);
|
|
1597
|
+
throw error2;
|
|
1598
|
+
} finally {
|
|
1599
|
+
setLoading(false);
|
|
1600
|
+
}
|
|
1601
|
+
}, [client]);
|
|
1602
|
+
return {
|
|
1603
|
+
createPost,
|
|
1604
|
+
loading,
|
|
1605
|
+
error
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
// src/hooks/useComments.ts
|
|
1610
|
+
import { useState as useState15, useEffect as useEffect14, useCallback as useCallback15 } from "react";
|
|
1611
|
+
function useComments(options) {
|
|
1612
|
+
const { type, target, page, per_page } = options;
|
|
1613
|
+
const client = useClient();
|
|
1614
|
+
const [comments, setComments] = useState15([]);
|
|
1615
|
+
const [meta, setMeta] = useState15(null);
|
|
1616
|
+
const [loading, setLoading] = useState15(true);
|
|
1617
|
+
const [error, setError] = useState15(null);
|
|
1618
|
+
const fetchComments = useCallback15(async () => {
|
|
1619
|
+
setLoading(true);
|
|
1620
|
+
setError(null);
|
|
1621
|
+
try {
|
|
1622
|
+
let response;
|
|
1623
|
+
const params = { page, per_page };
|
|
1624
|
+
switch (type) {
|
|
1625
|
+
case "board":
|
|
1626
|
+
response = await client.comments.boardPost(target, params);
|
|
1627
|
+
break;
|
|
1628
|
+
case "blog":
|
|
1629
|
+
response = await client.comments.blogPost(target, params);
|
|
1630
|
+
break;
|
|
1631
|
+
case "standalone":
|
|
1632
|
+
response = await client.comments.standalone(target, params);
|
|
1633
|
+
break;
|
|
1634
|
+
}
|
|
1635
|
+
setComments(response.data);
|
|
1636
|
+
setMeta(response.meta);
|
|
1637
|
+
} catch (err) {
|
|
1638
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch comments"));
|
|
1639
|
+
} finally {
|
|
1640
|
+
setLoading(false);
|
|
1641
|
+
}
|
|
1642
|
+
}, [client, type, target, page, per_page]);
|
|
1643
|
+
useEffect14(() => {
|
|
1644
|
+
fetchComments();
|
|
1645
|
+
}, [fetchComments]);
|
|
1646
|
+
const createComment = useCallback15(async (data) => {
|
|
1647
|
+
let response;
|
|
1648
|
+
switch (type) {
|
|
1649
|
+
case "board":
|
|
1650
|
+
response = await client.comments.createBoardPost(target, data);
|
|
1651
|
+
break;
|
|
1652
|
+
case "blog":
|
|
1653
|
+
response = await client.comments.createBlogPost(target, data);
|
|
1654
|
+
break;
|
|
1655
|
+
case "standalone":
|
|
1656
|
+
response = await client.comments.createStandalone(target, data);
|
|
1657
|
+
break;
|
|
1658
|
+
}
|
|
1659
|
+
await fetchComments();
|
|
1660
|
+
return response.data;
|
|
1661
|
+
}, [client, type, target, fetchComments]);
|
|
1662
|
+
const updateComment = useCallback15(async (commentId, content) => {
|
|
1663
|
+
const response = await client.comments.update(commentId, { content });
|
|
1664
|
+
setComments((prev) => prev.map((c) => c.id === commentId ? response.data : c));
|
|
1665
|
+
return response.data;
|
|
1666
|
+
}, [client]);
|
|
1667
|
+
const deleteComment = useCallback15(async (commentId, password) => {
|
|
1668
|
+
await client.comments.delete(commentId, password ? { password } : void 0);
|
|
1669
|
+
setComments((prev) => prev.filter((c) => c.id !== commentId));
|
|
1670
|
+
}, [client]);
|
|
1671
|
+
const likeComment = useCallback15(async (commentId) => {
|
|
1672
|
+
const response = await client.comments.like(commentId);
|
|
1673
|
+
setComments((prev) => prev.map(
|
|
1674
|
+
(c) => c.id === commentId ? { ...c, likes: response.data.likes } : c
|
|
1675
|
+
));
|
|
1676
|
+
return response.data.likes;
|
|
1677
|
+
}, [client]);
|
|
1678
|
+
return {
|
|
1679
|
+
comments,
|
|
1680
|
+
meta,
|
|
1681
|
+
loading,
|
|
1682
|
+
error,
|
|
1683
|
+
createComment,
|
|
1684
|
+
updateComment,
|
|
1685
|
+
deleteComment,
|
|
1686
|
+
likeComment,
|
|
1687
|
+
refresh: fetchComments
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
// src/hooks/useForms.ts
|
|
1692
|
+
import { useState as useState16, useEffect as useEffect15, useCallback as useCallback16 } from "react";
|
|
1693
|
+
function useForm(formSlug) {
|
|
1694
|
+
const client = useClient();
|
|
1695
|
+
const [form, setForm] = useState16(null);
|
|
1696
|
+
const [loading, setLoading] = useState16(true);
|
|
1697
|
+
const [error, setError] = useState16(null);
|
|
1698
|
+
const [submitting, setSubmitting] = useState16(false);
|
|
1699
|
+
const [submitted, setSubmitted] = useState16(false);
|
|
1700
|
+
const fetchForm = useCallback16(async () => {
|
|
1701
|
+
setLoading(true);
|
|
1702
|
+
setError(null);
|
|
1703
|
+
try {
|
|
1704
|
+
const data = await client.forms.get(formSlug);
|
|
1705
|
+
setForm(data);
|
|
1706
|
+
} catch (err) {
|
|
1707
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch form"));
|
|
1708
|
+
} finally {
|
|
1709
|
+
setLoading(false);
|
|
1710
|
+
}
|
|
1711
|
+
}, [client, formSlug]);
|
|
1712
|
+
useEffect15(() => {
|
|
1713
|
+
fetchForm();
|
|
1714
|
+
}, [fetchForm]);
|
|
1715
|
+
const submit = useCallback16(async (data) => {
|
|
1716
|
+
setSubmitting(true);
|
|
1717
|
+
setError(null);
|
|
1718
|
+
try {
|
|
1719
|
+
const submission = await client.forms.submit(formSlug, data);
|
|
1720
|
+
setSubmitted(true);
|
|
1721
|
+
return submission;
|
|
1722
|
+
} catch (err) {
|
|
1723
|
+
const error2 = err instanceof Error ? err : new Error("Failed to submit form");
|
|
1724
|
+
setError(error2);
|
|
1725
|
+
throw error2;
|
|
1726
|
+
} finally {
|
|
1727
|
+
setSubmitting(false);
|
|
1728
|
+
}
|
|
1729
|
+
}, [client, formSlug]);
|
|
1730
|
+
const reset = useCallback16(() => {
|
|
1731
|
+
setSubmitted(false);
|
|
1732
|
+
setError(null);
|
|
1733
|
+
}, []);
|
|
1734
|
+
return {
|
|
1735
|
+
form,
|
|
1736
|
+
loading,
|
|
1737
|
+
error,
|
|
1738
|
+
submit,
|
|
1739
|
+
submitting,
|
|
1740
|
+
submitted,
|
|
1741
|
+
reset
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
// src/hooks/useReservation.ts
|
|
1746
|
+
import { useState as useState17, useEffect as useEffect16, useCallback as useCallback17 } from "react";
|
|
1747
|
+
function useReservationServices() {
|
|
1748
|
+
const client = useClient();
|
|
1749
|
+
const [services, setServices] = useState17([]);
|
|
1750
|
+
const [loading, setLoading] = useState17(true);
|
|
1751
|
+
const [error, setError] = useState17(null);
|
|
1752
|
+
const fetchServices = useCallback17(async () => {
|
|
1753
|
+
setLoading(true);
|
|
1754
|
+
setError(null);
|
|
1755
|
+
try {
|
|
1756
|
+
const data = await client.reservation.listServices();
|
|
1757
|
+
setServices(data);
|
|
1758
|
+
} catch (err) {
|
|
1759
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch services"));
|
|
1760
|
+
} finally {
|
|
1761
|
+
setLoading(false);
|
|
1762
|
+
}
|
|
1763
|
+
}, [client]);
|
|
1764
|
+
useEffect16(() => {
|
|
1765
|
+
fetchServices();
|
|
1766
|
+
}, [fetchServices]);
|
|
1767
|
+
return {
|
|
1768
|
+
services,
|
|
1769
|
+
loading,
|
|
1770
|
+
error,
|
|
1771
|
+
refresh: fetchServices
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
function useReservationStaffs() {
|
|
1775
|
+
const client = useClient();
|
|
1776
|
+
const [staffs, setStaffs] = useState17([]);
|
|
1777
|
+
const [loading, setLoading] = useState17(true);
|
|
1778
|
+
const [error, setError] = useState17(null);
|
|
1779
|
+
const fetchStaffs = useCallback17(async () => {
|
|
1780
|
+
setLoading(true);
|
|
1781
|
+
setError(null);
|
|
1782
|
+
try {
|
|
1783
|
+
const data = await client.reservation.listStaff();
|
|
1784
|
+
setStaffs(data);
|
|
1785
|
+
} catch (err) {
|
|
1786
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch staffs"));
|
|
1787
|
+
} finally {
|
|
1788
|
+
setLoading(false);
|
|
1789
|
+
}
|
|
1790
|
+
}, [client]);
|
|
1791
|
+
useEffect16(() => {
|
|
1792
|
+
fetchStaffs();
|
|
1793
|
+
}, [fetchStaffs]);
|
|
1794
|
+
return {
|
|
1795
|
+
staffs,
|
|
1796
|
+
loading,
|
|
1797
|
+
error,
|
|
1798
|
+
refresh: fetchStaffs
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
function useAvailableSlots(serviceId, date, staffId) {
|
|
1802
|
+
const client = useClient();
|
|
1803
|
+
const [slots, setSlots] = useState17([]);
|
|
1804
|
+
const [loading, setLoading] = useState17(true);
|
|
1805
|
+
const [error, setError] = useState17(null);
|
|
1806
|
+
const fetchSlots = useCallback17(async () => {
|
|
1807
|
+
if (!serviceId || !date) {
|
|
1808
|
+
setSlots([]);
|
|
1809
|
+
setLoading(false);
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
setLoading(true);
|
|
1813
|
+
setError(null);
|
|
1814
|
+
try {
|
|
1815
|
+
const data = await client.reservation.getAvailableSlots({
|
|
1816
|
+
service_id: serviceId,
|
|
1817
|
+
date,
|
|
1818
|
+
staff_id: staffId
|
|
1819
|
+
});
|
|
1820
|
+
setSlots(data);
|
|
1821
|
+
} catch (err) {
|
|
1822
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch slots"));
|
|
1823
|
+
} finally {
|
|
1824
|
+
setLoading(false);
|
|
1825
|
+
}
|
|
1826
|
+
}, [client, serviceId, date, staffId]);
|
|
1827
|
+
useEffect16(() => {
|
|
1828
|
+
fetchSlots();
|
|
1829
|
+
}, [fetchSlots]);
|
|
1830
|
+
return {
|
|
1831
|
+
slots,
|
|
1832
|
+
loading,
|
|
1833
|
+
error,
|
|
1834
|
+
refresh: fetchSlots
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
function useMyReservations(params) {
|
|
1838
|
+
const client = useClient();
|
|
1839
|
+
const [reservations, setReservations] = useState17([]);
|
|
1840
|
+
const [meta, setMeta] = useState17(null);
|
|
1841
|
+
const [loading, setLoading] = useState17(true);
|
|
1842
|
+
const [error, setError] = useState17(null);
|
|
1843
|
+
const fetchReservations = useCallback17(async () => {
|
|
1844
|
+
if (!client.isAuthenticated()) {
|
|
1845
|
+
setReservations([]);
|
|
1846
|
+
setLoading(false);
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
setLoading(true);
|
|
1850
|
+
setError(null);
|
|
1851
|
+
try {
|
|
1852
|
+
const response = await client.reservation.list(params);
|
|
1853
|
+
setReservations(response.data);
|
|
1854
|
+
setMeta(response.meta);
|
|
1855
|
+
} catch (err) {
|
|
1856
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch reservations"));
|
|
1857
|
+
} finally {
|
|
1858
|
+
setLoading(false);
|
|
1859
|
+
}
|
|
1860
|
+
}, [client, params]);
|
|
1861
|
+
useEffect16(() => {
|
|
1862
|
+
fetchReservations();
|
|
1863
|
+
}, [fetchReservations]);
|
|
1864
|
+
return {
|
|
1865
|
+
reservations,
|
|
1866
|
+
meta,
|
|
1867
|
+
loading,
|
|
1868
|
+
error,
|
|
1869
|
+
refresh: fetchReservations
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
function useCreateReservation() {
|
|
1873
|
+
const client = useClient();
|
|
1874
|
+
const [loading, setLoading] = useState17(false);
|
|
1875
|
+
const [error, setError] = useState17(null);
|
|
1876
|
+
const createReservation = useCallback17(async (data) => {
|
|
1877
|
+
setLoading(true);
|
|
1878
|
+
setError(null);
|
|
1879
|
+
try {
|
|
1880
|
+
const result = await client.reservation.create(data);
|
|
1881
|
+
return result.reservation;
|
|
1882
|
+
} catch (err) {
|
|
1883
|
+
const error2 = err instanceof Error ? err : new Error("Failed to create reservation");
|
|
1884
|
+
setError(error2);
|
|
1885
|
+
throw error2;
|
|
1886
|
+
} finally {
|
|
1887
|
+
setLoading(false);
|
|
1888
|
+
}
|
|
1889
|
+
}, [client]);
|
|
1890
|
+
return {
|
|
1891
|
+
createReservation,
|
|
1892
|
+
loading,
|
|
1893
|
+
error
|
|
1894
|
+
};
|
|
1895
|
+
}
|
|
1896
|
+
function useReservationSettings() {
|
|
1897
|
+
const client = useClient();
|
|
1898
|
+
const [settings, setSettings] = useState17(null);
|
|
1899
|
+
const [loading, setLoading] = useState17(true);
|
|
1900
|
+
const [error, setError] = useState17(null);
|
|
1901
|
+
const fetchSettings = useCallback17(async () => {
|
|
1902
|
+
setLoading(true);
|
|
1903
|
+
setError(null);
|
|
1904
|
+
try {
|
|
1905
|
+
const data = await client.reservation.getSettings();
|
|
1906
|
+
setSettings(data);
|
|
1907
|
+
} catch (err) {
|
|
1908
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch settings"));
|
|
1909
|
+
} finally {
|
|
1910
|
+
setLoading(false);
|
|
1911
|
+
}
|
|
1912
|
+
}, [client]);
|
|
1913
|
+
useEffect16(() => {
|
|
1914
|
+
fetchSettings();
|
|
1915
|
+
}, [fetchSettings]);
|
|
1916
|
+
return {
|
|
1917
|
+
settings,
|
|
1918
|
+
loading,
|
|
1919
|
+
error,
|
|
1920
|
+
refresh: fetchSettings
|
|
1921
|
+
};
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
// src/hooks/useMedia.ts
|
|
1925
|
+
import { useState as useState18, useEffect as useEffect17, useCallback as useCallback18 } from "react";
|
|
1926
|
+
function useMedia(options = {}) {
|
|
1927
|
+
const { type, page, per_page, autoFetch = true } = options;
|
|
1928
|
+
const client = useClient();
|
|
1929
|
+
const [files, setFiles] = useState18([]);
|
|
1930
|
+
const [meta, setMeta] = useState18(null);
|
|
1931
|
+
const [loading, setLoading] = useState18(autoFetch);
|
|
1932
|
+
const [error, setError] = useState18(null);
|
|
1933
|
+
const [uploading, setUploading] = useState18(false);
|
|
1934
|
+
const [uploadProgress, setUploadProgress] = useState18(0);
|
|
1935
|
+
const fetchMedia = useCallback18(async () => {
|
|
1936
|
+
if (!client.isAuthenticated()) {
|
|
1937
|
+
setFiles([]);
|
|
1938
|
+
setLoading(false);
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
setLoading(true);
|
|
1942
|
+
setError(null);
|
|
1943
|
+
try {
|
|
1944
|
+
const response = await client.media.list({ type, page, per_page });
|
|
1945
|
+
setFiles(response.data);
|
|
1946
|
+
setMeta(response.meta);
|
|
1947
|
+
} catch (err) {
|
|
1948
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch media"));
|
|
1949
|
+
} finally {
|
|
1950
|
+
setLoading(false);
|
|
1951
|
+
}
|
|
1952
|
+
}, [client, type, page, per_page]);
|
|
1953
|
+
useEffect17(() => {
|
|
1954
|
+
if (autoFetch) {
|
|
1955
|
+
fetchMedia();
|
|
1956
|
+
}
|
|
1957
|
+
}, [autoFetch, fetchMedia]);
|
|
1958
|
+
const upload = useCallback18(async (file) => {
|
|
1959
|
+
setUploading(true);
|
|
1960
|
+
setUploadProgress(0);
|
|
1961
|
+
setError(null);
|
|
1962
|
+
try {
|
|
1963
|
+
const media = await client.media.upload(file);
|
|
1964
|
+
setFiles((prev) => [media, ...prev]);
|
|
1965
|
+
setUploadProgress(100);
|
|
1966
|
+
return media;
|
|
1967
|
+
} catch (err) {
|
|
1968
|
+
const error2 = err instanceof Error ? err : new Error("Failed to upload file");
|
|
1969
|
+
setError(error2);
|
|
1970
|
+
throw error2;
|
|
1971
|
+
} finally {
|
|
1972
|
+
setUploading(false);
|
|
1973
|
+
}
|
|
1974
|
+
}, [client]);
|
|
1975
|
+
const uploadMultiple = useCallback18(async (filesToUpload) => {
|
|
1976
|
+
setUploading(true);
|
|
1977
|
+
setUploadProgress(0);
|
|
1978
|
+
setError(null);
|
|
1979
|
+
try {
|
|
1980
|
+
const results = [];
|
|
1981
|
+
for (let i = 0; i < filesToUpload.length; i++) {
|
|
1982
|
+
const media = await client.media.upload(filesToUpload[i]);
|
|
1983
|
+
results.push(media);
|
|
1984
|
+
setUploadProgress(Math.round((i + 1) / filesToUpload.length * 100));
|
|
1985
|
+
}
|
|
1986
|
+
setFiles((prev) => [...results, ...prev]);
|
|
1987
|
+
return results;
|
|
1988
|
+
} catch (err) {
|
|
1989
|
+
const error2 = err instanceof Error ? err : new Error("Failed to upload files");
|
|
1990
|
+
setError(error2);
|
|
1991
|
+
throw error2;
|
|
1992
|
+
} finally {
|
|
1993
|
+
setUploading(false);
|
|
1994
|
+
}
|
|
1995
|
+
}, [client]);
|
|
1996
|
+
const deleteFile = useCallback18(async (mediaId) => {
|
|
1997
|
+
await client.media.delete(mediaId);
|
|
1998
|
+
setFiles((prev) => prev.filter((f) => f.id !== mediaId));
|
|
1999
|
+
}, [client]);
|
|
2000
|
+
return {
|
|
2001
|
+
files,
|
|
2002
|
+
meta,
|
|
2003
|
+
loading,
|
|
2004
|
+
error,
|
|
2005
|
+
upload,
|
|
2006
|
+
uploadMultiple,
|
|
2007
|
+
deleteFile,
|
|
2008
|
+
refresh: fetchMedia,
|
|
2009
|
+
uploading,
|
|
2010
|
+
uploadProgress
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
// src/hooks/useEntities.ts
|
|
2015
|
+
import { useState as useState19, useEffect as useEffect18, useCallback as useCallback19, useMemo as useMemo2 } from "react";
|
|
2016
|
+
function useEntities() {
|
|
2017
|
+
const client = useClient();
|
|
2018
|
+
const [entities, setEntities] = useState19([]);
|
|
2019
|
+
const [loading, setLoading] = useState19(true);
|
|
2020
|
+
const [error, setError] = useState19(null);
|
|
2021
|
+
const fetchEntities = useCallback19(async () => {
|
|
2022
|
+
setLoading(true);
|
|
2023
|
+
setError(null);
|
|
2024
|
+
try {
|
|
2025
|
+
const data = await client.entities.list();
|
|
2026
|
+
setEntities(data);
|
|
2027
|
+
} catch (err) {
|
|
2028
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch entities"));
|
|
2029
|
+
} finally {
|
|
2030
|
+
setLoading(false);
|
|
2031
|
+
}
|
|
2032
|
+
}, [client]);
|
|
2033
|
+
useEffect18(() => {
|
|
2034
|
+
fetchEntities();
|
|
2035
|
+
}, [fetchEntities]);
|
|
2036
|
+
return {
|
|
2037
|
+
entities,
|
|
2038
|
+
loading,
|
|
2039
|
+
error,
|
|
2040
|
+
refresh: fetchEntities
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
function useEntity(slug) {
|
|
2044
|
+
const client = useClient();
|
|
2045
|
+
const [entity, setEntity] = useState19(null);
|
|
2046
|
+
const [loading, setLoading] = useState19(true);
|
|
2047
|
+
const [error, setError] = useState19(null);
|
|
2048
|
+
const fetchEntity = useCallback19(async () => {
|
|
2049
|
+
setLoading(true);
|
|
2050
|
+
setError(null);
|
|
2051
|
+
try {
|
|
2052
|
+
const data = await client.entities.get(slug);
|
|
2053
|
+
setEntity(data);
|
|
2054
|
+
} catch (err) {
|
|
2055
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch entity"));
|
|
2056
|
+
} finally {
|
|
2057
|
+
setLoading(false);
|
|
2058
|
+
}
|
|
2059
|
+
}, [client, slug]);
|
|
2060
|
+
useEffect18(() => {
|
|
2061
|
+
fetchEntity();
|
|
2062
|
+
}, [fetchEntity]);
|
|
2063
|
+
return {
|
|
2064
|
+
entity,
|
|
2065
|
+
loading,
|
|
2066
|
+
error,
|
|
2067
|
+
refresh: fetchEntity
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
function useEntityRecords(slug, params) {
|
|
2071
|
+
const client = useClient();
|
|
2072
|
+
const [records, setRecords] = useState19([]);
|
|
2073
|
+
const [meta, setMeta] = useState19(null);
|
|
2074
|
+
const [loading, setLoading] = useState19(true);
|
|
2075
|
+
const [error, setError] = useState19(null);
|
|
2076
|
+
const [currentParams, setCurrentParams] = useState19(params);
|
|
2077
|
+
const fetchRecords = useCallback19(async (fetchParams, append = false) => {
|
|
2078
|
+
setLoading(true);
|
|
2079
|
+
setError(null);
|
|
2080
|
+
try {
|
|
2081
|
+
const response = await client.entities.listRecords(slug, fetchParams);
|
|
2082
|
+
if (append) {
|
|
2083
|
+
setRecords((prev) => [...prev, ...response.data]);
|
|
2084
|
+
} else {
|
|
2085
|
+
setRecords(response.data);
|
|
2086
|
+
}
|
|
2087
|
+
setMeta(response.meta);
|
|
2088
|
+
} catch (err) {
|
|
2089
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch records"));
|
|
2090
|
+
} finally {
|
|
2091
|
+
setLoading(false);
|
|
2092
|
+
}
|
|
2093
|
+
}, [client, slug]);
|
|
2094
|
+
useEffect18(() => {
|
|
2095
|
+
fetchRecords(params);
|
|
2096
|
+
}, []);
|
|
2097
|
+
const hasMore = meta ? meta.current_page < meta.last_page : false;
|
|
2098
|
+
const loadMore = useCallback19(async () => {
|
|
2099
|
+
if (!hasMore || loading) return;
|
|
2100
|
+
const nextPage = (meta?.current_page ?? 0) + 1;
|
|
2101
|
+
await fetchRecords({ ...currentParams, page: nextPage }, true);
|
|
2102
|
+
}, [hasMore, loading, meta, currentParams, fetchRecords]);
|
|
2103
|
+
const createRecord = useCallback19(async (data) => {
|
|
2104
|
+
const record = await client.entities.createRecord(slug, data);
|
|
2105
|
+
setRecords((prev) => [record, ...prev]);
|
|
2106
|
+
return record;
|
|
2107
|
+
}, [client, slug]);
|
|
2108
|
+
const updateRecord = useCallback19(async (id, data) => {
|
|
2109
|
+
const record = await client.entities.updateRecord(slug, id, data);
|
|
2110
|
+
setRecords((prev) => prev.map((r) => r.id === id ? record : r));
|
|
2111
|
+
return record;
|
|
2112
|
+
}, [client, slug]);
|
|
2113
|
+
const deleteRecord = useCallback19(async (id) => {
|
|
2114
|
+
await client.entities.deleteRecord(slug, id);
|
|
2115
|
+
setRecords((prev) => prev.filter((r) => r.id !== id));
|
|
2116
|
+
}, [client, slug]);
|
|
2117
|
+
const refresh = useCallback19(async () => {
|
|
2118
|
+
setCurrentParams(params);
|
|
2119
|
+
await fetchRecords(params);
|
|
2120
|
+
}, [params, fetchRecords]);
|
|
2121
|
+
return {
|
|
2122
|
+
records,
|
|
2123
|
+
meta,
|
|
2124
|
+
loading,
|
|
2125
|
+
error,
|
|
2126
|
+
hasMore,
|
|
2127
|
+
loadMore,
|
|
2128
|
+
createRecord,
|
|
2129
|
+
updateRecord,
|
|
2130
|
+
deleteRecord,
|
|
2131
|
+
refresh
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
function useEntityRecord(slug, id) {
|
|
2135
|
+
const client = useClient();
|
|
2136
|
+
const [record, setRecord] = useState19(null);
|
|
2137
|
+
const [loading, setLoading] = useState19(true);
|
|
2138
|
+
const [error, setError] = useState19(null);
|
|
2139
|
+
const fetchRecord = useCallback19(async () => {
|
|
2140
|
+
setLoading(true);
|
|
2141
|
+
setError(null);
|
|
2142
|
+
try {
|
|
2143
|
+
const data = await client.entities.getRecord(slug, id);
|
|
2144
|
+
setRecord(data);
|
|
2145
|
+
} catch (err) {
|
|
2146
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch record"));
|
|
2147
|
+
} finally {
|
|
2148
|
+
setLoading(false);
|
|
2149
|
+
}
|
|
2150
|
+
}, [client, slug, id]);
|
|
2151
|
+
useEffect18(() => {
|
|
2152
|
+
fetchRecord();
|
|
2153
|
+
}, [fetchRecord]);
|
|
2154
|
+
const update = useCallback19(async (data) => {
|
|
2155
|
+
const updated = await client.entities.updateRecord(slug, id, data);
|
|
2156
|
+
setRecord(updated);
|
|
2157
|
+
return updated;
|
|
2158
|
+
}, [client, slug, id]);
|
|
2159
|
+
return {
|
|
2160
|
+
record,
|
|
2161
|
+
loading,
|
|
2162
|
+
error,
|
|
2163
|
+
update,
|
|
2164
|
+
refresh: fetchRecord
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
function useTypedEntity(slug) {
|
|
2168
|
+
const client = useClient();
|
|
2169
|
+
return useMemo2(() => ({
|
|
2170
|
+
useRecords: (params) => {
|
|
2171
|
+
const result = useEntityRecords(slug, params);
|
|
2172
|
+
return {
|
|
2173
|
+
...result,
|
|
2174
|
+
records: result.records
|
|
2175
|
+
};
|
|
2176
|
+
},
|
|
2177
|
+
useRecord: (id) => {
|
|
2178
|
+
const result = useEntityRecord(slug, id);
|
|
2179
|
+
return {
|
|
2180
|
+
...result,
|
|
2181
|
+
record: result.record
|
|
2182
|
+
};
|
|
2183
|
+
},
|
|
2184
|
+
create: async (data) => {
|
|
2185
|
+
const record = await client.entities.createRecord(slug, data);
|
|
2186
|
+
return record;
|
|
2187
|
+
},
|
|
2188
|
+
update: async (id, data) => {
|
|
2189
|
+
const record = await client.entities.updateRecord(slug, id, data);
|
|
2190
|
+
return record;
|
|
2191
|
+
},
|
|
2192
|
+
delete: (id) => client.entities.deleteRecord(slug, id)
|
|
2193
|
+
}), [client, slug]);
|
|
2194
|
+
}
|
|
2195
|
+
export {
|
|
2196
|
+
DiffsomeContext,
|
|
2197
|
+
DiffsomeProvider,
|
|
2198
|
+
useAuth,
|
|
2199
|
+
useAvailableSlots,
|
|
2200
|
+
useBlog,
|
|
2201
|
+
useBlogCategories,
|
|
2202
|
+
useBlogPost,
|
|
2203
|
+
useBlogSearch,
|
|
2204
|
+
useBlogTags,
|
|
2205
|
+
useBoard,
|
|
2206
|
+
useBoardPost,
|
|
2207
|
+
useBoardPosts,
|
|
2208
|
+
useBoards,
|
|
2209
|
+
useBundleItems,
|
|
2210
|
+
useBundleProducts,
|
|
2211
|
+
useCanReview,
|
|
2212
|
+
useCart,
|
|
2213
|
+
useCategories,
|
|
2214
|
+
useClient,
|
|
2215
|
+
useComments,
|
|
2216
|
+
useCoupons,
|
|
2217
|
+
useCreateBoardPost,
|
|
2218
|
+
useCreateOrder,
|
|
2219
|
+
useCreateReservation,
|
|
2220
|
+
useCreateReview,
|
|
2221
|
+
useCreateSubscription,
|
|
2222
|
+
useDiffsome,
|
|
2223
|
+
useDigitalProducts,
|
|
2224
|
+
useDownloads,
|
|
2225
|
+
useEntities,
|
|
2226
|
+
useEntity,
|
|
2227
|
+
useEntityRecord,
|
|
2228
|
+
useEntityRecords,
|
|
2229
|
+
useFeaturedBlog,
|
|
2230
|
+
useFeaturedProducts,
|
|
2231
|
+
useForm,
|
|
2232
|
+
useMedia,
|
|
2233
|
+
useMyReservations,
|
|
2234
|
+
useMyReviews,
|
|
2235
|
+
useOrder,
|
|
2236
|
+
useOrderDownloads,
|
|
2237
|
+
useOrders,
|
|
2238
|
+
usePaymentStatus,
|
|
2239
|
+
useProduct,
|
|
2240
|
+
useProductReviews,
|
|
2241
|
+
useProducts,
|
|
2242
|
+
useProductsByType,
|
|
2243
|
+
useReservationServices,
|
|
2244
|
+
useReservationSettings,
|
|
2245
|
+
useReservationStaffs,
|
|
2246
|
+
useSocialAuth,
|
|
2247
|
+
useStripePayment,
|
|
2248
|
+
useSubscription,
|
|
2249
|
+
useSubscriptionProducts,
|
|
2250
|
+
useSubscriptions,
|
|
2251
|
+
useTossPayment,
|
|
2252
|
+
useTypedEntity,
|
|
2253
|
+
useValidateCoupon,
|
|
2254
|
+
useWishlist
|
|
2255
|
+
};
|