@decocms/apps 1.7.0 → 1.8.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/package.json
CHANGED
|
@@ -37,25 +37,41 @@ export type CartFragment = {
|
|
|
37
37
|
|
|
38
38
|
// Mutation types
|
|
39
39
|
export type AddItemToCartMutation = { cart?: CartFragment | null };
|
|
40
|
-
export type AddItemToCartMutationVariables = { cartId: string; lines:
|
|
40
|
+
export type AddItemToCartMutationVariables = { cartId: string; lines: unknown };
|
|
41
41
|
export type UpdateItemsMutation = { cart?: CartFragment | null };
|
|
42
|
-
export type UpdateItemsMutationVariables = { cartId: string; lines:
|
|
42
|
+
export type UpdateItemsMutationVariables = { cartId: string; lines: unknown };
|
|
43
43
|
export type AddCouponMutation = { cart?: CartFragment | null };
|
|
44
44
|
export type AddCouponMutationVariables = { cartId: string; discountCodes: string[] };
|
|
45
45
|
|
|
46
|
-
// Product types
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
export type
|
|
51
|
-
export type
|
|
46
|
+
// Product types — these are intentionally loose stubs because the
|
|
47
|
+
// real Shopify Storefront API GraphQL types are huge and only a tiny
|
|
48
|
+
// subset is consumed. `unknown` keeps consumers honest (forces a cast
|
|
49
|
+
// at the boundary) without exploding the type surface.
|
|
50
|
+
export type ProductFragment = unknown;
|
|
51
|
+
export type ProductVariantFragment = unknown;
|
|
52
|
+
export type GetProductQuery = { product?: unknown };
|
|
53
|
+
export type GetProductQueryVariables = { handle?: string; identifiers?: unknown[] };
|
|
54
|
+
export type ProductRecommendationsQuery = { productRecommendations?: unknown[] };
|
|
52
55
|
export type ProductRecommendationsQueryVariables = { productId: string };
|
|
53
56
|
|
|
54
57
|
// Search/Collection types
|
|
55
58
|
export type InputMaybe<T> = T | null | undefined;
|
|
56
59
|
export type ProductCollectionSortKeys = string;
|
|
57
60
|
export type SearchSortKeys = string;
|
|
58
|
-
|
|
61
|
+
// Loose shape derived from the only consumers in
|
|
62
|
+
// `shopify/utils/utils.ts` (filterToObject + getFiltersByUrl). Keeps
|
|
63
|
+
// the types honest without depending on Shopify's full GraphQL schema.
|
|
64
|
+
export type ProductFilter = {
|
|
65
|
+
tag?: string;
|
|
66
|
+
productType?: string;
|
|
67
|
+
productVendor?: string;
|
|
68
|
+
available?: boolean;
|
|
69
|
+
price?: { min?: number; max?: number };
|
|
70
|
+
variantOption?: { name: string; value: string };
|
|
71
|
+
productMetafield?: { namespace: string; key: string; value: string };
|
|
72
|
+
taxonomyMetafield?: { namespace: string; key: string; value: string };
|
|
73
|
+
category?: { id: string };
|
|
74
|
+
};
|
|
59
75
|
|
|
60
76
|
// Customer types
|
|
61
77
|
export type Customer = {
|
|
@@ -65,9 +81,9 @@ export type Customer = {
|
|
|
65
81
|
email?: string | null;
|
|
66
82
|
phone?: string | null;
|
|
67
83
|
acceptsMarketing?: boolean;
|
|
68
|
-
defaultAddress?:
|
|
69
|
-
addresses?: { nodes:
|
|
70
|
-
orders?: { nodes:
|
|
84
|
+
defaultAddress?: unknown;
|
|
85
|
+
addresses?: { nodes: unknown[] };
|
|
86
|
+
orders?: { nodes: unknown[] };
|
|
71
87
|
};
|
|
72
88
|
|
|
73
89
|
export type CustomerAccessTokenCreateInput = {
|
|
@@ -31,9 +31,7 @@ import type { OrderForm, OrderFormItem } from "../types";
|
|
|
31
31
|
export interface CreateUseCartInvoke {
|
|
32
32
|
vtex: {
|
|
33
33
|
actions: {
|
|
34
|
-
getOrCreateCart: (args: {
|
|
35
|
-
data: { orderFormId?: string };
|
|
36
|
-
}) => Promise<OrderForm>;
|
|
34
|
+
getOrCreateCart: (args: { data: { orderFormId?: string } }) => Promise<OrderForm>;
|
|
37
35
|
addItemsToCart: (args: {
|
|
38
36
|
data: {
|
|
39
37
|
orderFormId: string;
|
|
@@ -130,10 +128,7 @@ export function createUseCart(opts: CreateUseCartOptions) {
|
|
|
130
128
|
return of.orderFormId;
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
function itemToAnalyticsItem(
|
|
134
|
-
item: OrderFormItem & { coupon?: string },
|
|
135
|
-
index: number,
|
|
136
|
-
) {
|
|
131
|
+
function itemToAnalyticsItem(item: OrderFormItem & { coupon?: string }, index: number) {
|
|
137
132
|
return {
|
|
138
133
|
item_id: item.productId,
|
|
139
134
|
item_group_id: item.productId,
|
|
@@ -217,11 +212,7 @@ export function createUseCart(opts: CreateUseCartOptions) {
|
|
|
217
212
|
},
|
|
218
213
|
},
|
|
219
214
|
|
|
220
|
-
addItem: async (params: {
|
|
221
|
-
id: string;
|
|
222
|
-
seller: string;
|
|
223
|
-
quantity?: number;
|
|
224
|
-
}) => {
|
|
215
|
+
addItem: async (params: { id: string; seller: string; quantity?: number }) => {
|
|
225
216
|
setLoading(true);
|
|
226
217
|
try {
|
|
227
218
|
const ofId = await ensureOrderForm();
|
|
@@ -266,9 +257,7 @@ export function createUseCart(opts: CreateUseCartOptions) {
|
|
|
266
257
|
}
|
|
267
258
|
},
|
|
268
259
|
|
|
269
|
-
updateItems: async (params: {
|
|
270
|
-
orderItems: Array<{ index: number; quantity: number }>;
|
|
271
|
-
}) => {
|
|
260
|
+
updateItems: async (params: { orderItems: Array<{ index: number; quantity: number }> }) => {
|
|
272
261
|
const ofId = _orderForm?.orderFormId || getOrderFormIdFromCookie();
|
|
273
262
|
if (!ofId) return;
|
|
274
263
|
setLoading(true);
|
|
@@ -319,10 +308,7 @@ export function createUseCart(opts: CreateUseCartOptions) {
|
|
|
319
308
|
}
|
|
320
309
|
},
|
|
321
310
|
|
|
322
|
-
sendAttachment: async (params: {
|
|
323
|
-
attachment: string;
|
|
324
|
-
body: Record<string, unknown>;
|
|
325
|
-
}) => {
|
|
311
|
+
sendAttachment: async (params: { attachment: string; body: Record<string, unknown> }) => {
|
|
326
312
|
const ofId = _orderForm?.orderFormId || getOrderFormIdFromCookie();
|
|
327
313
|
if (!ofId) return;
|
|
328
314
|
setLoading(true);
|
|
@@ -361,9 +347,7 @@ export function createUseCart(opts: CreateUseCartOptions) {
|
|
|
361
347
|
},
|
|
362
348
|
|
|
363
349
|
mapItemsToAnalyticsItems: (orderForm: OrderForm | null) => {
|
|
364
|
-
return (orderForm?.items || []).map((item, index) =>
|
|
365
|
-
itemToAnalyticsItem(item, index),
|
|
366
|
-
);
|
|
350
|
+
return (orderForm?.items || []).map((item, index) => itemToAnalyticsItem(item, index));
|
|
367
351
|
},
|
|
368
352
|
};
|
|
369
353
|
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory for the legacy invoke-based `useUser` hook.
|
|
3
|
+
*
|
|
4
|
+
* This is the API shape that migrated Fresh sites depend on:
|
|
5
|
+
* - module-level singleton state (no QueryClient required)
|
|
6
|
+
* - listener-based re-render (`forceRender` on a useState counter)
|
|
7
|
+
* - signal-shaped accessors (`user.value`, `loading.value`)
|
|
8
|
+
* - awaitable refresh (`await refresh()`)
|
|
9
|
+
*
|
|
10
|
+
* It is intentionally separate from the canonical `useUser` in
|
|
11
|
+
* `vtex/hooks/useUser.ts`, which is built on TanStack Query and exposes
|
|
12
|
+
* `{ user, isLoggedIn, isLoading, refetch }`. Both can coexist in a single site.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // src/hooks/useUser.ts
|
|
17
|
+
* import { createUseUser } from "@decocms/apps/vtex/hooks/createUseUser";
|
|
18
|
+
* import { invoke } from "~/server/invoke";
|
|
19
|
+
*
|
|
20
|
+
* export const { useUser, resetUser } = createUseUser({ invoke });
|
|
21
|
+
* export type { Person } from "@decocms/apps/vtex/loaders/user";
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { useEffect, useState } from "react";
|
|
26
|
+
import type { Person } from "../loaders/user";
|
|
27
|
+
|
|
28
|
+
/** Minimal structural shape of the invoke proxy this hook needs. */
|
|
29
|
+
export interface CreateUseUserInvoke {
|
|
30
|
+
vtex: {
|
|
31
|
+
loaders: {
|
|
32
|
+
user: () => Promise<Person | null>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface CreateUseUserOptions {
|
|
38
|
+
invoke: CreateUseUserInvoke;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Build a per-site `useUser` plus its companions. */
|
|
42
|
+
export function createUseUser(opts: CreateUseUserOptions) {
|
|
43
|
+
const { invoke } = opts;
|
|
44
|
+
|
|
45
|
+
let _user: Person | null = null;
|
|
46
|
+
let _loading = false;
|
|
47
|
+
let _initStarted = false;
|
|
48
|
+
let _initFailed = false;
|
|
49
|
+
const _listeners = new Set<() => void>();
|
|
50
|
+
|
|
51
|
+
function notify() {
|
|
52
|
+
for (const fn of _listeners) fn();
|
|
53
|
+
}
|
|
54
|
+
function setUser(u: Person | null) {
|
|
55
|
+
_user = u;
|
|
56
|
+
notify();
|
|
57
|
+
}
|
|
58
|
+
function setLoading(v: boolean) {
|
|
59
|
+
_loading = v;
|
|
60
|
+
notify();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function refresh(): Promise<Person | null> {
|
|
64
|
+
setLoading(true);
|
|
65
|
+
try {
|
|
66
|
+
const u = await invoke.vtex.loaders.user();
|
|
67
|
+
setUser(u);
|
|
68
|
+
_initFailed = false;
|
|
69
|
+
return u;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.error("[useUser] refresh failed:", err);
|
|
72
|
+
_initFailed = true;
|
|
73
|
+
notify();
|
|
74
|
+
return null;
|
|
75
|
+
} finally {
|
|
76
|
+
setLoading(false);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Reset module-level user state so the next useUser() re-fetches. */
|
|
81
|
+
function resetUser() {
|
|
82
|
+
_user = null;
|
|
83
|
+
_loading = false;
|
|
84
|
+
_initStarted = false;
|
|
85
|
+
_initFailed = false;
|
|
86
|
+
notify();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function useUser() {
|
|
90
|
+
const [, forceRender] = useState(0);
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const listener = () => forceRender((n) => n + 1);
|
|
94
|
+
_listeners.add(listener);
|
|
95
|
+
|
|
96
|
+
if (!_user && !_initStarted) {
|
|
97
|
+
_initStarted = true;
|
|
98
|
+
setLoading(true);
|
|
99
|
+
invoke.vtex.loaders
|
|
100
|
+
.user()
|
|
101
|
+
.then((u) => {
|
|
102
|
+
setUser(u);
|
|
103
|
+
})
|
|
104
|
+
.catch((err: unknown) => {
|
|
105
|
+
console.error("[useUser] init failed:", err);
|
|
106
|
+
_initFailed = true;
|
|
107
|
+
notify();
|
|
108
|
+
})
|
|
109
|
+
.finally(() => setLoading(false));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return () => {
|
|
113
|
+
_listeners.delete(listener);
|
|
114
|
+
};
|
|
115
|
+
}, []);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
user: {
|
|
119
|
+
get value() {
|
|
120
|
+
return _user;
|
|
121
|
+
},
|
|
122
|
+
set value(v: Person | null) {
|
|
123
|
+
setUser(v);
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
loading: {
|
|
128
|
+
get value() {
|
|
129
|
+
return _loading;
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
isLoggedIn: {
|
|
134
|
+
get value() {
|
|
135
|
+
return !!_user?.email;
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
initFailed: {
|
|
140
|
+
get value() {
|
|
141
|
+
return _initFailed;
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
refresh,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
useUser,
|
|
151
|
+
resetUser,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory for the legacy invoke-based `useWishlist` hook.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the deco-cx/apps signal-based wishlist API used by migrated
|
|
5
|
+
* Fresh sites: `wishlist.addItem(productId, productGroupId)`,
|
|
6
|
+
* `removeItem(productId)`, `getItem(productId): boolean`.
|
|
7
|
+
*
|
|
8
|
+
* It is intentionally separate from the canonical `useWishlist` in
|
|
9
|
+
* `vtex/hooks/useWishlist.ts`, which is built on TanStack Query and exposes
|
|
10
|
+
* `{ items, isInWishlist, toggle, add, remove }`. Both can coexist.
|
|
11
|
+
*
|
|
12
|
+
* ## VTEX wishlist arg conventions
|
|
13
|
+
*
|
|
14
|
+
* The legacy hook's `addItem(productId, productGroupId)` argument names
|
|
15
|
+
* are misleading because they were originally derived from analytics
|
|
16
|
+
* `item_id` / `item_group_id`:
|
|
17
|
+
*
|
|
18
|
+
* - `productId` arg → analytics `item_id` → VTEX `sku` field on the wishlist
|
|
19
|
+
* - `productGroupId` arg → analytics `item_group_id` → VTEX `productId`
|
|
20
|
+
*
|
|
21
|
+
* The factory swaps them on the wire so the canonical
|
|
22
|
+
* `vtex/actions/wishlist.addItem` gets the right shape.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* // src/hooks/useWishlist.ts
|
|
27
|
+
* import { createUseWishlist } from "@decocms/apps/vtex/hooks/createUseWishlist";
|
|
28
|
+
* import { invoke } from "~/server/invoke";
|
|
29
|
+
*
|
|
30
|
+
* export const { useWishlist, resetWishlist } = createUseWishlist({ invoke });
|
|
31
|
+
* export type { WishlistItem } from "@decocms/apps/vtex/loaders/wishlist";
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { useEffect, useState } from "react";
|
|
36
|
+
import type { WishlistItem } from "../loaders/wishlist";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pure helper: find a wishlist entry by either the SKU id (legacy
|
|
40
|
+
* `productId` arg) or the VTEX productId. Exported for unit testability.
|
|
41
|
+
*/
|
|
42
|
+
export function findWishlistEntry(
|
|
43
|
+
items: readonly WishlistItem[],
|
|
44
|
+
productId: string,
|
|
45
|
+
): WishlistItem | undefined {
|
|
46
|
+
return items.find((it) => it.sku === productId || it.productId === productId);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pure helper: convert legacy `addItem(productId, productGroupId)` args
|
|
51
|
+
* into the canonical `{ productId, sku }` shape expected by
|
|
52
|
+
* `vtex/actions/wishlist.addItem`. Exported for unit testability.
|
|
53
|
+
*/
|
|
54
|
+
export function legacyAddArgsToCanonical(
|
|
55
|
+
legacyProductId: string,
|
|
56
|
+
legacyProductGroupId: string,
|
|
57
|
+
): { productId: string; sku: string } {
|
|
58
|
+
// See arg conventions in the file header. The legacy `productId` is
|
|
59
|
+
// the SKU; the legacy `productGroupId` is the VTEX productId.
|
|
60
|
+
return {
|
|
61
|
+
productId: legacyProductGroupId,
|
|
62
|
+
sku: legacyProductId,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Minimal structural shape of the invoke proxy this hook needs. */
|
|
67
|
+
export interface CreateUseWishlistInvoke {
|
|
68
|
+
vtex: {
|
|
69
|
+
loaders: {
|
|
70
|
+
wishlist: () => Promise<WishlistItem[]>;
|
|
71
|
+
};
|
|
72
|
+
actions: {
|
|
73
|
+
addToWishlist: (args: {
|
|
74
|
+
data: { productId: string; sku: string; title?: string };
|
|
75
|
+
}) => Promise<WishlistItem[]>;
|
|
76
|
+
removeFromWishlist: (args: { data: { id: string } }) => Promise<WishlistItem[]>;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface CreateUseWishlistOptions {
|
|
82
|
+
invoke: CreateUseWishlistInvoke;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Build a per-site `useWishlist` plus its companions. */
|
|
86
|
+
export function createUseWishlist(opts: CreateUseWishlistOptions) {
|
|
87
|
+
const { invoke } = opts;
|
|
88
|
+
|
|
89
|
+
let _items: WishlistItem[] = [];
|
|
90
|
+
let _loading = false;
|
|
91
|
+
let _initStarted = false;
|
|
92
|
+
let _initFailed = false;
|
|
93
|
+
const _listeners = new Set<() => void>();
|
|
94
|
+
|
|
95
|
+
function notify() {
|
|
96
|
+
for (const fn of _listeners) fn();
|
|
97
|
+
}
|
|
98
|
+
function setItems(items: WishlistItem[]) {
|
|
99
|
+
_items = items;
|
|
100
|
+
notify();
|
|
101
|
+
}
|
|
102
|
+
function setLoading(v: boolean) {
|
|
103
|
+
_loading = v;
|
|
104
|
+
notify();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getItem(productId: string): boolean {
|
|
108
|
+
return !!findWishlistEntry(_items, productId);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function addItem(productId: string, productGroupId: string): Promise<void> {
|
|
112
|
+
setLoading(true);
|
|
113
|
+
try {
|
|
114
|
+
const updated = await invoke.vtex.actions.addToWishlist({
|
|
115
|
+
data: legacyAddArgsToCanonical(productId, productGroupId),
|
|
116
|
+
});
|
|
117
|
+
setItems(updated);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
console.error("[useWishlist] addItem failed:", err);
|
|
120
|
+
throw err;
|
|
121
|
+
} finally {
|
|
122
|
+
setLoading(false);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function removeItem(productId: string): Promise<void> {
|
|
127
|
+
const entry = findWishlistEntry(_items, productId);
|
|
128
|
+
if (!entry?.id) {
|
|
129
|
+
// Either the wishlist hasn't loaded yet or the item isn't there.
|
|
130
|
+
// Either way, nothing to remove.
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
setLoading(true);
|
|
134
|
+
try {
|
|
135
|
+
const updated = await invoke.vtex.actions.removeFromWishlist({
|
|
136
|
+
data: { id: entry.id },
|
|
137
|
+
});
|
|
138
|
+
setItems(updated);
|
|
139
|
+
} catch (err) {
|
|
140
|
+
console.error("[useWishlist] removeItem failed:", err);
|
|
141
|
+
throw err;
|
|
142
|
+
} finally {
|
|
143
|
+
setLoading(false);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function refresh(): Promise<WishlistItem[]> {
|
|
148
|
+
setLoading(true);
|
|
149
|
+
try {
|
|
150
|
+
const items = await invoke.vtex.loaders.wishlist();
|
|
151
|
+
setItems(items);
|
|
152
|
+
_initFailed = false;
|
|
153
|
+
return items;
|
|
154
|
+
} catch (err) {
|
|
155
|
+
console.error("[useWishlist] refresh failed:", err);
|
|
156
|
+
_initFailed = true;
|
|
157
|
+
notify();
|
|
158
|
+
return [];
|
|
159
|
+
} finally {
|
|
160
|
+
setLoading(false);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Reset module-level wishlist state so the next useWishlist() re-fetches. */
|
|
165
|
+
function resetWishlist() {
|
|
166
|
+
_items = [];
|
|
167
|
+
_loading = false;
|
|
168
|
+
_initStarted = false;
|
|
169
|
+
_initFailed = false;
|
|
170
|
+
notify();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function useWishlist() {
|
|
174
|
+
const [, forceRender] = useState(0);
|
|
175
|
+
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
const listener = () => forceRender((n) => n + 1);
|
|
178
|
+
_listeners.add(listener);
|
|
179
|
+
|
|
180
|
+
if (_items.length === 0 && !_initStarted) {
|
|
181
|
+
_initStarted = true;
|
|
182
|
+
setLoading(true);
|
|
183
|
+
invoke.vtex.loaders
|
|
184
|
+
.wishlist()
|
|
185
|
+
.then((items) => {
|
|
186
|
+
setItems(items);
|
|
187
|
+
})
|
|
188
|
+
.catch((err: unknown) => {
|
|
189
|
+
// 401 / unauthenticated is normal — user just isn't logged in.
|
|
190
|
+
// Real errors get logged.
|
|
191
|
+
console.error("[useWishlist] init failed:", err);
|
|
192
|
+
_initFailed = true;
|
|
193
|
+
notify();
|
|
194
|
+
})
|
|
195
|
+
.finally(() => setLoading(false));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return () => {
|
|
199
|
+
_listeners.delete(listener);
|
|
200
|
+
};
|
|
201
|
+
}, []);
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
items: {
|
|
205
|
+
get value() {
|
|
206
|
+
return _items;
|
|
207
|
+
},
|
|
208
|
+
set value(v: WishlistItem[]) {
|
|
209
|
+
setItems(v);
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
loading: {
|
|
214
|
+
get value() {
|
|
215
|
+
return _loading;
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
initFailed: {
|
|
220
|
+
get value() {
|
|
221
|
+
return _initFailed;
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
count: {
|
|
226
|
+
get value() {
|
|
227
|
+
return _items.length;
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
addItem,
|
|
232
|
+
removeItem,
|
|
233
|
+
getItem,
|
|
234
|
+
refresh,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
useWishlist,
|
|
240
|
+
resetWishlist,
|
|
241
|
+
};
|
|
242
|
+
}
|
package/vtex/hooks/index.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
export { type UseAutocompleteOptions, useAutocomplete } from "./useAutocomplete";
|
|
2
|
-
export { type CartItem, type OrderForm, type UseCartOptions, useCart } from "./useCart";
|
|
3
1
|
export {
|
|
4
2
|
type CreateUseCartInvoke,
|
|
5
3
|
type CreateUseCartOptions,
|
|
6
4
|
createUseCart,
|
|
7
5
|
} from "./createUseCart";
|
|
6
|
+
export {
|
|
7
|
+
type CreateUseUserInvoke,
|
|
8
|
+
type CreateUseUserOptions,
|
|
9
|
+
createUseUser,
|
|
10
|
+
} from "./createUseUser";
|
|
11
|
+
export {
|
|
12
|
+
type CreateUseWishlistInvoke,
|
|
13
|
+
type CreateUseWishlistOptions,
|
|
14
|
+
createUseWishlist,
|
|
15
|
+
} from "./createUseWishlist";
|
|
16
|
+
export { type UseAutocompleteOptions, useAutocomplete } from "./useAutocomplete";
|
|
17
|
+
export { type CartItem, type OrderForm, type UseCartOptions, useCart } from "./useCart";
|
|
8
18
|
export { type UseUserOptions, useUser, type VtexUser } from "./useUser";
|
|
9
19
|
export { type UseWishlistOptions, useWishlist, type WishlistItem } from "./useWishlist";
|