@tapcart/mobile-components 0.8.62 → 0.8.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/hooks/use-infinite-scroll.d.ts +7 -6
- package/dist/components/hooks/use-infinite-scroll.d.ts.map +1 -1
- package/dist/components/hooks/use-infinite-scroll.js +80 -18
- package/dist/components/hooks/use-mock-cart.js +1 -1
- package/dist/components/hooks/use-products.d.ts.map +1 -1
- package/dist/components/hooks/use-products.js +20 -21
- package/dist/components/hooks/use-sort-filter.d.ts +3 -2
- package/dist/components/hooks/use-sort-filter.d.ts.map +1 -1
- package/dist/components/hooks/use-sort-filter.js +36 -6
- package/dist/components/libs/cache/ProductsLocalStorage.d.ts.map +1 -1
- package/dist/components/libs/cache/ProductsLocalStorage.js +8 -4
- package/dist/components/ui/button.js +4 -3
- package/dist/components/ui/quantity-pickerNEW.d.ts +1 -0
- package/dist/components/ui/quantity-pickerNEW.d.ts.map +1 -1
- package/dist/components/ui/quantity-pickerNEW.js +30 -36
- package/dist/styles.css +15 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReadonlyURLSearchParams } from "next/navigation";
|
|
2
|
-
import { Product } from "app-studio-types";
|
|
2
|
+
import { Product, BaseSearchClient } from "app-studio-types";
|
|
3
3
|
interface PageData {
|
|
4
4
|
products: Product[];
|
|
5
5
|
cursorBlob?: string;
|
|
@@ -10,10 +10,11 @@ interface PageData {
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
interface UseInfiniteScrollProps {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
searchClient?: BaseSearchClient<Product>;
|
|
14
|
+
initialData?: PageData;
|
|
15
|
+
queryVariables?: Record<string, any>;
|
|
16
|
+
direction?: "vertical" | "horizontal";
|
|
17
|
+
productLimit?: number;
|
|
17
18
|
threshold?: number;
|
|
18
19
|
interval?: number;
|
|
19
20
|
customFetcher?: (...args: any[]) => Promise<any>;
|
|
@@ -33,6 +34,6 @@ interface UseInfiniteScrollReturn {
|
|
|
33
34
|
}
|
|
34
35
|
export declare const formatSearchParamsAsNextQueryVariables: (searchParams: ReadonlyURLSearchParams) => {};
|
|
35
36
|
declare const constructURL: (apiURL: string) => string;
|
|
36
|
-
declare const useInfiniteScroll: ({ initialData, queryVariables: queryVariableProps, direction, productLimit, threshold, interval, customFetcher, customGetKey, }: UseInfiniteScrollProps) => UseInfiniteScrollReturn;
|
|
37
|
+
declare const useInfiniteScroll: ({ searchClient, initialData, queryVariables: queryVariableProps, direction, productLimit, threshold, interval, customFetcher, customGetKey, }: UseInfiniteScrollProps) => UseInfiniteScrollReturn;
|
|
37
38
|
export { useInfiniteScroll, constructURL };
|
|
38
39
|
//# sourceMappingURL=use-infinite-scroll.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-infinite-scroll.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-infinite-scroll.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAmB,MAAM,iBAAiB,CAAA;AAE1E,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"use-infinite-scroll.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-infinite-scroll.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAmB,MAAM,iBAAiB,CAAA;AAE1E,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAE5D,UAAU,QAAQ;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,GAAG,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAA;CACxC;AAED,UAAU,sBAAsB;IAE9B,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAGxC,WAAW,CAAC,EAAE,QAAQ,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAGpC,SAAS,CAAC,EAAE,UAAU,GAAG,YAAY,CAAA;IACrC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAChD,YAAY,CAAC,EAAE,CACb,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,GAAG,GAAG,IAAI,EAC5B,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,GAAG,CAAA;CACT;AAED,UAAU,uBAAuB;IAC/B,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAA;IAC5B,KAAK,EAAE,GAAG,CAAA;IACV,oBAAoB,EAAE,OAAO,CAAA;IAC7B,aAAa,EAAE,OAAO,GAAG,SAAS,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;IACtB,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,CAAA;IAChD,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,OAAO,CAAA;CACtB;AAED,eAAO,MAAM,sCAAsC,iBACnC,uBAAuB,OAsBtC,CAAA;AAED,QAAA,MAAM,YAAY,WAAY,MAAM,WAGnC,CAAA;AAED,QAAA,MAAM,iBAAiB,kJAepB,sBAAsB,KAAG,uBA+L3B,CAAA;AAED,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -41,7 +41,13 @@ const constructURL = (apiURL) => {
|
|
|
41
41
|
const url = new URL(apiURL);
|
|
42
42
|
return url.toString();
|
|
43
43
|
};
|
|
44
|
-
const useInfiniteScroll = ({
|
|
44
|
+
const useInfiniteScroll = ({
|
|
45
|
+
// Search client props
|
|
46
|
+
searchClient,
|
|
47
|
+
// API props (backwards compatibility)
|
|
48
|
+
initialData, queryVariables: queryVariableProps,
|
|
49
|
+
// Common props
|
|
50
|
+
direction = "vertical", productLimit = Infinity, threshold = 0.01, interval = 33, // ~2 frames
|
|
45
51
|
customFetcher, customGetKey, }) => {
|
|
46
52
|
var _a, _b, _c, _d, _e;
|
|
47
53
|
const searchParams = useSearchParams();
|
|
@@ -50,11 +56,19 @@ customFetcher, customGetKey, }) => {
|
|
|
50
56
|
rootMargin: direction === "vertical" ? "600px" : "0px 420px 0px 0px",
|
|
51
57
|
threshold: threshold,
|
|
52
58
|
});
|
|
59
|
+
// When searchClient is provided, use search client approach
|
|
60
|
+
const usingSearchClient = Boolean(searchClient);
|
|
61
|
+
// Search client approach - getKey and fetcher
|
|
62
|
+
const searchClientGetKey = useMemo(() => customGetKey || (searchClient === null || searchClient === void 0 ? void 0 : searchClient.getKey), [customGetKey, searchClient === null || searchClient === void 0 ? void 0 : searchClient.getKey]);
|
|
63
|
+
const searchClientFetcher = useMemo(() => customFetcher || (searchClient === null || searchClient === void 0 ? void 0 : searchClient.fetcher), [customFetcher, searchClient === null || searchClient === void 0 ? void 0 : searchClient.fetcher]);
|
|
64
|
+
// API approach - query variables and fetcher
|
|
53
65
|
const queryVariables = useMemo(() => {
|
|
66
|
+
if (usingSearchClient)
|
|
67
|
+
return null;
|
|
54
68
|
const formattedParams = formatSearchParamsAsNextQueryVariables(searchParams);
|
|
55
69
|
return Object.assign(Object.assign({}, queryVariableProps), { searchParams: formattedParams });
|
|
56
|
-
}, [queryVariableProps, searchParams]);
|
|
57
|
-
|
|
70
|
+
}, [queryVariableProps, searchParams, usingSearchClient]);
|
|
71
|
+
const apiGetKey = (pageIndex, previousPageData, queryVariables) => {
|
|
58
72
|
var _a;
|
|
59
73
|
if (pageIndex === 0) {
|
|
60
74
|
return Object.assign({}, queryVariables);
|
|
@@ -63,11 +77,11 @@ customFetcher, customGetKey, }) => {
|
|
|
63
77
|
return null;
|
|
64
78
|
return Object.assign(Object.assign({}, queryVariables), { cursorBlob: previousPageData.pageData.cursorBlob });
|
|
65
79
|
};
|
|
66
|
-
|
|
67
|
-
getKey = customGetKey;
|
|
68
|
-
}
|
|
69
|
-
let fetcher = (body) => __awaiter(void 0, void 0, void 0, function* () {
|
|
80
|
+
const apiFetcher = (body) => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
81
|
var _f, _g;
|
|
82
|
+
if (!(initialData === null || initialData === void 0 ? void 0 : initialData.apiURL)) {
|
|
83
|
+
throw new Error("initialData.apiURL is required for API mode");
|
|
84
|
+
}
|
|
71
85
|
const res = yield fetch(constructURL(initialData.apiURL), {
|
|
72
86
|
method: "POST",
|
|
73
87
|
body: JSON.stringify(body),
|
|
@@ -76,10 +90,25 @@ customFetcher, customGetKey, }) => {
|
|
|
76
90
|
productCount.current += (_g = (_f = data === null || data === void 0 ? void 0 : data.products) === null || _f === void 0 ? void 0 : _f.length) !== null && _g !== void 0 ? _g : 0;
|
|
77
91
|
return data;
|
|
78
92
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
// Determine which approach to use
|
|
94
|
+
const getKey = usingSearchClient
|
|
95
|
+
? (pageIndex, previousPageData) => {
|
|
96
|
+
if (!searchClientGetKey)
|
|
97
|
+
return null;
|
|
98
|
+
return searchClientGetKey(pageIndex, previousPageData);
|
|
99
|
+
}
|
|
100
|
+
: (pageIndex, previousPageData) => (customGetKey || apiGetKey)(pageIndex, previousPageData, queryVariables !== null && queryVariables !== void 0 ? queryVariables : {});
|
|
101
|
+
const fetcher = usingSearchClient
|
|
102
|
+
? (...args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
+
var _h, _j;
|
|
104
|
+
if (!searchClientFetcher)
|
|
105
|
+
return null;
|
|
106
|
+
const result = yield searchClientFetcher(...args);
|
|
107
|
+
productCount.current += (_j = (_h = result === null || result === void 0 ? void 0 : result.products) === null || _h === void 0 ? void 0 : _h.length) !== null && _j !== void 0 ? _j : 0;
|
|
108
|
+
return result;
|
|
109
|
+
})
|
|
110
|
+
: customFetcher || apiFetcher;
|
|
111
|
+
const { data, error, size, setSize, isLoading, isValidating, mutate, } = useSWRInfinite(getKey, fetcher, {
|
|
83
112
|
revalidateFirstPage: false,
|
|
84
113
|
initialSize: 1,
|
|
85
114
|
});
|
|
@@ -87,8 +116,16 @@ customFetcher, customGetKey, }) => {
|
|
|
87
116
|
const isLoadingMore = isLoadingInitialData ||
|
|
88
117
|
(size > 0 && data && typeof data[size - 1] === "undefined");
|
|
89
118
|
const isEmpty = ((_c = (_b = (_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.products) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) === 0;
|
|
90
|
-
|
|
91
|
-
|
|
119
|
+
let isEndPointer;
|
|
120
|
+
if (!data) {
|
|
121
|
+
isEndPointer = true;
|
|
122
|
+
}
|
|
123
|
+
else if (usingSearchClient) {
|
|
124
|
+
isEndPointer = !(searchClient === null || searchClient === void 0 ? void 0 : searchClient.getHasMore());
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
isEndPointer = !((_e = (_d = data[data.length - 1]) === null || _d === void 0 ? void 0 : _d.pageData) === null || _e === void 0 ? void 0 : _e.cursorBlob);
|
|
128
|
+
}
|
|
92
129
|
const isReachingEnd = isEmpty || isEndPointer;
|
|
93
130
|
const isRefreshing = isValidating && data && data.length === size;
|
|
94
131
|
const loadMore = useCallback(() => {
|
|
@@ -104,6 +141,7 @@ customFetcher, customGetKey, }) => {
|
|
|
104
141
|
isRefreshing,
|
|
105
142
|
productLimit,
|
|
106
143
|
setSize,
|
|
144
|
+
size,
|
|
107
145
|
]);
|
|
108
146
|
const throttleLoadMore = useMemo(() => throttle(loadMore, interval), [loadMore, interval]);
|
|
109
147
|
useEffect(() => {
|
|
@@ -111,7 +149,22 @@ customFetcher, customGetKey, }) => {
|
|
|
111
149
|
throttleLoadMore();
|
|
112
150
|
}
|
|
113
151
|
}, [inView, throttleLoadMore]);
|
|
114
|
-
|
|
152
|
+
// Search client state change listener (only for search client approach)
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (!usingSearchClient || !searchClient)
|
|
155
|
+
return;
|
|
156
|
+
const unsubscribeAllChanges = searchClient.onSearchStateChange(() => {
|
|
157
|
+
productCount.current = 0;
|
|
158
|
+
mutate(undefined, { revalidate: true });
|
|
159
|
+
});
|
|
160
|
+
return unsubscribeAllChanges;
|
|
161
|
+
}, [searchClient, mutate, usingSearchClient]);
|
|
162
|
+
const products = useMemo(() => {
|
|
163
|
+
return data
|
|
164
|
+
? data === null || data === void 0 ? void 0 : data.flatMap((page) => page === null || page === void 0 ? void 0 : page.products).slice(0, productLimit)
|
|
165
|
+
: [];
|
|
166
|
+
}, [data, productLimit]);
|
|
167
|
+
return useMemo(() => ({
|
|
115
168
|
data,
|
|
116
169
|
error,
|
|
117
170
|
isLoadingInitialData,
|
|
@@ -119,11 +172,20 @@ customFetcher, customGetKey, }) => {
|
|
|
119
172
|
isEmpty,
|
|
120
173
|
isReachingEnd,
|
|
121
174
|
ref,
|
|
122
|
-
products
|
|
123
|
-
? data === null || data === void 0 ? void 0 : data.flatMap((page) => page === null || page === void 0 ? void 0 : page.products).slice(0, productLimit)
|
|
124
|
-
: [],
|
|
175
|
+
products,
|
|
125
176
|
isLoading,
|
|
126
177
|
isValidating,
|
|
127
|
-
}
|
|
178
|
+
}), [
|
|
179
|
+
data,
|
|
180
|
+
error,
|
|
181
|
+
isLoadingInitialData,
|
|
182
|
+
isLoadingMore,
|
|
183
|
+
isEmpty,
|
|
184
|
+
isReachingEnd,
|
|
185
|
+
ref,
|
|
186
|
+
products,
|
|
187
|
+
isLoading,
|
|
188
|
+
isValidating,
|
|
189
|
+
]);
|
|
128
190
|
};
|
|
129
191
|
export { useInfiniteScroll, constructURL };
|
|
@@ -359,7 +359,7 @@ const transformCart = ({ products, cartOrigin = cartMock, }) => {
|
|
|
359
359
|
totalDutyAmount: null,
|
|
360
360
|
} });
|
|
361
361
|
};
|
|
362
|
-
export const useMockCart = ({ apiUrl, appId, enabled = true, limit =
|
|
362
|
+
export const useMockCart = ({ apiUrl, appId, enabled = true, limit = 4, }) => {
|
|
363
363
|
const [isLoading, setIsLoading] = useState(true);
|
|
364
364
|
const [initialLoadHappened, setInitialLoadHappened] = useState(false);
|
|
365
365
|
const { products, error: productsError, isRefreshing: productsLoading, } = useProducts({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-products.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-products.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"use-products.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-products.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAK1C,KAAK,GAAG,GAAG,MAAM,CAAA;AACjB,KAAK,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AACxD,KAAK,gBAAgB,GAAG;IACtB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IACjC,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,OAAO,EAAE,GAAG,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAC1E,UAAU,CAAC,EAAE,cAAc,EAAE,CAAA;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC,CAAA;AACD,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,KAAK,EAAE,GAAG,CAAA;IACV,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,OAAO,CAAA;IACrB,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAC3B;QACE,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;KACf,GACD,SAAS,CAAA;CACd,CAAA;AAgCD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,iBAAiB,CA8I7E"}
|
|
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
import useSWR from "swr";
|
|
12
12
|
import { getProductGidsFromIds, getVariantGidsFromIds } from "../../lib/utils";
|
|
13
|
-
import { useCollection } from "./use-collection";
|
|
14
13
|
import React from "react";
|
|
15
14
|
import ProductsLocalStorage from "../libs/cache/ProductsLocalStorage";
|
|
16
15
|
const isUseProductsProps = (props) => {
|
|
@@ -31,28 +30,21 @@ const formatProductData = ({ data, onlyAvailableProducts = false, }) => {
|
|
|
31
30
|
};
|
|
32
31
|
const productsLocalStorage = new ProductsLocalStorage();
|
|
33
32
|
export function useProducts(props) {
|
|
34
|
-
var _a
|
|
33
|
+
var _a;
|
|
35
34
|
let url = null;
|
|
36
35
|
let body = null;
|
|
37
36
|
const shouldMockProducts = Boolean(props === null || props === void 0 ? void 0 : props.mock);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
appId: ((_a = props === null || props === void 0 ? void 0 : props.queryVariables) === null || _a === void 0 ? void 0 : _a.appId) || "",
|
|
41
|
-
language: ((_b = props === null || props === void 0 ? void 0 : props.queryVariables) === null || _b === void 0 ? void 0 : _b.language) || "en",
|
|
42
|
-
collectionId: undefined,
|
|
43
|
-
getCollections: shouldMockProducts,
|
|
44
|
-
limit: 1,
|
|
45
|
-
});
|
|
46
|
-
const [cachedProducts, setCachedProducts] = React.useState(productsLocalStorage.getCacheItems({
|
|
37
|
+
// No collection logic needed for mock mode - we use direct product fetching
|
|
38
|
+
const [productResponse, setProductResponse] = React.useState(() => productsLocalStorage.getCacheItems({
|
|
47
39
|
productIds: props === null || props === void 0 ? void 0 : props.productIds,
|
|
48
40
|
productHandles: props === null || props === void 0 ? void 0 : props.productHandles,
|
|
49
41
|
}));
|
|
50
42
|
if (isUseProductsProps(props)) {
|
|
51
43
|
let { baseURL, productIds, variantIds, productHandles, metafields, collection, queryVariables, } = props;
|
|
52
44
|
if (shouldMockProducts) {
|
|
53
|
-
|
|
54
|
-
queryVariables = Object.assign(
|
|
55
|
-
collection
|
|
45
|
+
// In mock mode, always use direct product fetching without collections
|
|
46
|
+
queryVariables = Object.assign({}, queryVariables);
|
|
47
|
+
// Don't set collection to enable direct product fetching
|
|
56
48
|
}
|
|
57
49
|
let queryParams = new URLSearchParams();
|
|
58
50
|
if ((productIds === null || productIds === void 0 ? void 0 : productIds.length) > 0) {
|
|
@@ -79,9 +71,18 @@ export function useProducts(props) {
|
|
|
79
71
|
if (queryVariables === null || queryVariables === void 0 ? void 0 : queryVariables.language) {
|
|
80
72
|
queryParams.set("language", queryVariables.language);
|
|
81
73
|
}
|
|
82
|
-
queryParams.set("mediaLimit", (
|
|
74
|
+
queryParams.set("mediaLimit", (_a = queryVariables === null || queryVariables === void 0 ? void 0 : queryVariables.mediaLimit) !== null && _a !== void 0 ? _a : 10);
|
|
83
75
|
url = `${baseURL}/products/by-ids?${queryParams.toString()}`;
|
|
84
76
|
}
|
|
77
|
+
// Handle collection-free product fetching when in mock mode
|
|
78
|
+
if (shouldMockProducts &&
|
|
79
|
+
!collection &&
|
|
80
|
+
!(productIds === null || productIds === void 0 ? void 0 : productIds.length) &&
|
|
81
|
+
!(productHandles === null || productHandles === void 0 ? void 0 : productHandles.length) &&
|
|
82
|
+
!(variantIds === null || variantIds === void 0 ? void 0 : variantIds.length)) {
|
|
83
|
+
url = `${baseURL}/products/by-page?${queryParams.toString()}`;
|
|
84
|
+
body = queryVariables || {};
|
|
85
|
+
}
|
|
85
86
|
}
|
|
86
87
|
const defaultFetcher = (url, body) => fetch(url, {
|
|
87
88
|
method: body ? "POST" : "GET",
|
|
@@ -110,23 +111,21 @@ export function useProducts(props) {
|
|
|
110
111
|
};
|
|
111
112
|
// set local state when when SWR data is updated
|
|
112
113
|
React.useEffect(() => {
|
|
113
|
-
if (!data)
|
|
114
|
-
setCachedProducts([]);
|
|
114
|
+
if (!data)
|
|
115
115
|
return;
|
|
116
|
-
}
|
|
117
116
|
// Determine the products array from data
|
|
118
117
|
const productsArray = Array.isArray(data) ? data : data.products || [];
|
|
119
118
|
if (!productsArray.length)
|
|
120
119
|
return;
|
|
121
|
-
|
|
120
|
+
setProductResponse(productsArray);
|
|
122
121
|
}, [data]);
|
|
123
122
|
return {
|
|
124
123
|
products: formatProductData({
|
|
125
|
-
data:
|
|
124
|
+
data: productResponse,
|
|
126
125
|
onlyAvailableProducts: (props === null || props === void 0 ? void 0 : props.mock) && (props === null || props === void 0 ? void 0 : props.onlyAvailableProducts),
|
|
127
126
|
}),
|
|
128
127
|
error,
|
|
129
|
-
isLoading: !
|
|
128
|
+
isLoading: !productResponse.length && isLoading,
|
|
130
129
|
isRefreshing: isLoading,
|
|
131
130
|
cacheProduct,
|
|
132
131
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Collection } from "app-studio-types";
|
|
1
|
+
import { Collection, Product, BaseSearchClient } from "app-studio-types";
|
|
2
2
|
import { FilterCategory, FiltersAndRelatedCategories, Integration, IntegrationSortItem } from "../libs/sort-filter/search-integration";
|
|
3
3
|
interface UseSortFilterProps {
|
|
4
4
|
initialData: PageData;
|
|
5
5
|
queryVariables: Record<string, any>;
|
|
6
6
|
dynamicKey?: (queryVariables: any) => () => any;
|
|
7
|
+
searchClient?: BaseSearchClient<Product>;
|
|
7
8
|
}
|
|
8
9
|
interface PageData {
|
|
9
10
|
filtersURL: string;
|
|
@@ -27,6 +28,6 @@ interface SortFilterData {
|
|
|
27
28
|
dynamicFiltersEnabled: boolean;
|
|
28
29
|
integrations: Integration[];
|
|
29
30
|
}
|
|
30
|
-
declare const useSortFilter: ({ initialData, queryVariables, dynamicKey, }: UseSortFilterProps) => UseSortFilterReturn;
|
|
31
|
+
declare const useSortFilter: ({ initialData, queryVariables, dynamicKey, searchClient, }: UseSortFilterProps) => UseSortFilterReturn;
|
|
31
32
|
export { useSortFilter };
|
|
32
33
|
//# sourceMappingURL=use-sort-filter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-sort-filter.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-sort-filter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"use-sort-filter.d.ts","sourceRoot":"","sources":["../../../components/hooks/use-sort-filter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExE,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,WAAW,EACX,mBAAmB,EACpB,MAAM,wCAAwC,CAAA;AAI/C,UAAU,kBAAkB;IAC1B,WAAW,EAAE,QAAQ,CAAA;IACrB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,UAAU,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,KAAK,MAAM,GAAG,CAAA;IAC/C,YAAY,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;CACzC;AAED,UAAU,QAAQ;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,cAAc,EAAE,CAAA;IAC/B,cAAc,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAA;CACxC;AAED,UAAU,mBAAmB;IAC3B,cAAc,EAAE,cAAc,CAAA;IAC9B,IAAI,EAAE,GAAG,EAAE,CAAA;IACX,MAAM,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,eAAe,EAAE,OAAO,CAAA;CACzB;AAED,UAAU,cAAc;IACtB,UAAU,EAAE,UAAU,CAAA;IACtB,2BAA2B,EAAE,2BAA2B,CAAA;IACxD,WAAW,EAAE,mBAAmB,EAAE,CAAA;IAClC,qBAAqB,EAAE,OAAO,CAAA;IAC9B,YAAY,EAAE,WAAW,EAAE,CAAA;CAC5B;AAeD,QAAA,MAAM,aAAa,+DAKhB,kBAAkB,KAAG,mBA2EvB,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
import useSWRInfinite from "swr/infinite";
|
|
3
12
|
import useSWR from "swr";
|
|
4
13
|
import { useCallback, useMemo } from "react";
|
|
@@ -12,26 +21,28 @@ const fetcher = ({ apiURL, body }) => fetch(constructURL(apiURL), {
|
|
|
12
21
|
})
|
|
13
22
|
.then((res) => res.json())
|
|
14
23
|
.catch((error) => console.error(error));
|
|
15
|
-
const useSortFilter = ({ initialData, queryVariables, dynamicKey, }) => {
|
|
16
|
-
const shouldFetch = queryVariables && Object.keys(queryVariables).length > 0;
|
|
24
|
+
const useSortFilter = ({ initialData, queryVariables, dynamicKey, searchClient, }) => {
|
|
25
|
+
const shouldFetch = queryVariables && Object.keys(queryVariables).length > 0 && !searchClient;
|
|
17
26
|
const { data: sortFilterData, isLoading } = useSWR(shouldFetch
|
|
18
27
|
? { apiUrl: initialData.sortFilterURL, body: Object.assign({}, queryVariables) }
|
|
19
28
|
: null, ({ apiUrl, body }) => fetcher({ apiURL: apiUrl, body }), { revalidateOnFocus: false });
|
|
20
29
|
const getKey = () => {
|
|
21
|
-
if (!sortFilterData ||
|
|
30
|
+
if (!sortFilterData ||
|
|
31
|
+
!sortFilterData.dynamicFiltersEnabled ||
|
|
32
|
+
searchClient)
|
|
22
33
|
return null;
|
|
23
34
|
return Object.assign(Object.assign({}, sortFilterData.queryVariables), (initialData.uiFilterState && {
|
|
24
35
|
filterCategories: initialData.uiFilterState,
|
|
25
36
|
}));
|
|
26
37
|
};
|
|
27
38
|
const memoizedDynamicKey = useCallback(() => {
|
|
28
|
-
if (dynamicKey) {
|
|
29
|
-
return dynamicKey(sortFilterData.queryVariables);
|
|
39
|
+
if (dynamicKey && !searchClient) {
|
|
40
|
+
return dynamicKey(sortFilterData === null || sortFilterData === void 0 ? void 0 : sortFilterData.queryVariables);
|
|
30
41
|
}
|
|
31
42
|
else {
|
|
32
43
|
return null;
|
|
33
44
|
}
|
|
34
|
-
}, [dynamicKey, sortFilterData === null || sortFilterData === void 0 ? void 0 : sortFilterData.queryVariables]);
|
|
45
|
+
}, [dynamicKey, sortFilterData === null || sortFilterData === void 0 ? void 0 : sortFilterData.queryVariables, searchClient]);
|
|
35
46
|
const memoizedFetch = useMemo(() => {
|
|
36
47
|
return (body) => fetcher({ apiURL: initialData.filtersURL, body });
|
|
37
48
|
}, [initialData.filtersURL]);
|
|
@@ -40,6 +51,25 @@ const useSortFilter = ({ initialData, queryVariables, dynamicKey, }) => {
|
|
|
40
51
|
revalidateOnFocus: false,
|
|
41
52
|
initialSize: 1,
|
|
42
53
|
});
|
|
54
|
+
// If searchClient is provided, return default values
|
|
55
|
+
if (searchClient) {
|
|
56
|
+
return {
|
|
57
|
+
sortFilterData: {
|
|
58
|
+
collection: {},
|
|
59
|
+
filtersAndRelatedCategories: {
|
|
60
|
+
filterCategories: [],
|
|
61
|
+
relatedCategories: [],
|
|
62
|
+
},
|
|
63
|
+
sortOptions: [],
|
|
64
|
+
dynamicFiltersEnabled: false,
|
|
65
|
+
integrations: [],
|
|
66
|
+
},
|
|
67
|
+
data: [],
|
|
68
|
+
mutate: () => __awaiter(void 0, void 0, void 0, function* () { return ({}); }),
|
|
69
|
+
isLoading: false,
|
|
70
|
+
isFilterLoading: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
43
73
|
return {
|
|
44
74
|
sortFilterData,
|
|
45
75
|
data: data !== null && data !== void 0 ? data : [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductsLocalStorage.d.ts","sourceRoot":"","sources":["../../../../components/libs/cache/ProductsLocalStorage.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"ProductsLocalStorage.d.ts","sourceRoot":"","sources":["../../../../components/libs/cache/ProductsLocalStorage.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAG7C,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,CAAA;IACV,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,cAAc;IAC9D,OAAO,EAAE,MAAM,CAA2B;IAC1C,WAAW,EAAE,MAAM,CAAe;IAElC,aAAa,CAAC,EAAE,EAAE,MAAM;IAIxB,iBAAiB,CAAC,MAAM,EAAE,MAAM;;IAShC,QAAQ,IAAI,aAAa,EAAE;IAiB3B,YAAY,CAAC,EACX,EAAE,EACF,MAAM,GACP,EAAE;QACD,EAAE,CAAC,EAAE,MAAM,CAAA;QACX,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GAAG,MAAM,GAAG,IAAI;IAgBjB,aAAa,CAAC,QAAQ,EAAE;QACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;QACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;KAC1B,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAYrB,YAAY,CACV,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EACvC,KAAK,CAAC,EAAE,aAAa,EAAE,EACvB,YAAY,GAAE,OAAc;gBAFT,MAAM;YAAM,MAAM;;IAiEvC,aAAa,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE;;;;IASrD,eAAe,CAAC,WAAW,GAAE,MAAU;IAWvC,UAAU;IAQV,eAAe,CAAC,CAAC,EAAE,GAAG;CASvB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import AppStudioCache from "./AppStudioCache";
|
|
2
|
+
import { getProductGidsFromIds } from "../../../lib/utils";
|
|
2
3
|
export default class ProductsLocalStorage extends AppStudioCache {
|
|
3
4
|
getIdCacheKey(id) {
|
|
4
5
|
return `${this.cachePrefix}-data-${id}`;
|
|
@@ -31,8 +32,11 @@ export default class ProductsLocalStorage extends AppStudioCache {
|
|
|
31
32
|
getCacheItem({ id, handle, }) {
|
|
32
33
|
if (!(id === null || id === void 0 ? void 0 : id.length) && !(handle === null || handle === void 0 ? void 0 : handle.length))
|
|
33
34
|
return null;
|
|
34
|
-
let objectId =
|
|
35
|
-
if (
|
|
35
|
+
let objectId = null;
|
|
36
|
+
if (id === null || id === void 0 ? void 0 : id.length) {
|
|
37
|
+
objectId = getProductGidsFromIds([id])[0];
|
|
38
|
+
}
|
|
39
|
+
else if (handle === null || handle === void 0 ? void 0 : handle.length) {
|
|
36
40
|
objectId = localStorage.getItem(this.getHandleCacheKey(handle));
|
|
37
41
|
}
|
|
38
42
|
if (!(objectId === null || objectId === void 0 ? void 0 : objectId.length))
|
|
@@ -45,11 +49,11 @@ export default class ProductsLocalStorage extends AppStudioCache {
|
|
|
45
49
|
getCacheItems(products) {
|
|
46
50
|
var _a, _b;
|
|
47
51
|
const returnProducts = ((_a = products === null || products === void 0 ? void 0 : products.productIds) === null || _a === void 0 ? void 0 : _a.length)
|
|
48
|
-
? products.productIds.map((id) => this.getCacheItem({ id }))
|
|
52
|
+
? products.productIds.map((id) => this.getCacheItem({ id: getProductGidsFromIds([id])[0] }))
|
|
49
53
|
: ((_b = products === null || products === void 0 ? void 0 : products.productHandles) === null || _b === void 0 ? void 0 : _b.length)
|
|
50
54
|
? products.productHandles.map((handle) => this.getCacheItem({ handle }))
|
|
51
55
|
: [];
|
|
52
|
-
return returnProducts;
|
|
56
|
+
return returnProducts.filter((product) => product !== null);
|
|
53
57
|
}
|
|
54
58
|
setCacheItem(product, cache, shouldExpire = true) {
|
|
55
59
|
var _a, _b;
|
|
@@ -83,7 +83,7 @@ const labelVariants = cva("truncate", {
|
|
|
83
83
|
});
|
|
84
84
|
const Button = (_a) => {
|
|
85
85
|
var { className, labelClassName, labelStyle, variant, size, asChild = false, loading, icon, iconColor, iconStrokeColor, iconPosition, iconSize, iconUrl, iconClassName, onClick, type, disableHaptic = false } = _a, props = __rest(_a, ["className", "labelClassName", "labelStyle", "variant", "size", "asChild", "loading", "icon", "iconColor", "iconStrokeColor", "iconPosition", "iconSize", "iconUrl", "iconClassName", "onClick", "type", "disableHaptic"]);
|
|
86
|
-
const
|
|
86
|
+
const webbridgeActions = useActions();
|
|
87
87
|
const Comp = asChild
|
|
88
88
|
? Slot
|
|
89
89
|
: (onClick || type ? "button" : "div");
|
|
@@ -96,11 +96,12 @@ const Button = (_a) => {
|
|
|
96
96
|
const LoadingButton = () => (_jsx("div", Object.assign({ className: cn("flex items-center justify-center", size === "icon" ? "h-5" : "h-6") }, { children: _jsx(Icon, { className: cn(iconVariants({ variant }), "h-5 w-5 animate-spin"), name: "loader", style: { color: iconColor } }) })));
|
|
97
97
|
const handleClick = Comp === "button" && onClick
|
|
98
98
|
? (e) => {
|
|
99
|
+
var _a;
|
|
99
100
|
try {
|
|
100
|
-
onClick(e);
|
|
101
101
|
if (!disableHaptic) {
|
|
102
|
-
action("trigger/haptic");
|
|
102
|
+
(_a = webbridgeActions.action) === null || _a === void 0 ? void 0 : _a.call(webbridgeActions, "trigger/haptic");
|
|
103
103
|
}
|
|
104
|
+
onClick(e);
|
|
104
105
|
}
|
|
105
106
|
catch (error) {
|
|
106
107
|
console.error(error);
|
|
@@ -19,6 +19,7 @@ export interface QuantityPickerNEWProps extends React.HTMLAttributes<HTMLDivElem
|
|
|
19
19
|
buttonCornerRadius?: number;
|
|
20
20
|
debounceTime?: number;
|
|
21
21
|
max?: number;
|
|
22
|
+
parentRef?: React.RefObject<HTMLDivElement>;
|
|
22
23
|
}
|
|
23
24
|
declare const QuantityPickerNEW: React.ForwardRefExoticComponent<QuantityPickerNEWProps & React.RefAttributes<HTMLDivElement>>;
|
|
24
25
|
export { QuantityPickerNEW };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quantity-pickerNEW.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-pickerNEW.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,MAAM,WAAW,sBACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"quantity-pickerNEW.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-pickerNEW.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,MAAM,WAAW,sBACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;CAC5C;AAwED,QAAA,MAAM,iBAAiB,+FA0KtB,CAAA;AAID,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -15,7 +15,6 @@ import * as React from "react";
|
|
|
15
15
|
import { cn } from "../../lib/utils";
|
|
16
16
|
import { Icon } from "./icon";
|
|
17
17
|
import { LoadingDots } from "./loading-dots";
|
|
18
|
-
import debounce from "lodash/debounce";
|
|
19
18
|
const IconButton = ({ iconUrl, iconColor, handler, className, style, disabled }) => {
|
|
20
19
|
const [isButtonPressed, setIsButtonPressed] = React.useState(false);
|
|
21
20
|
// Handle press state manually for the invisible button
|
|
@@ -40,23 +39,14 @@ const IconButton = ({ iconUrl, iconColor, handler, className, style, disabled })
|
|
|
40
39
|
}, disabled: disabled, "aria-label": "Quantity button" })] })));
|
|
41
40
|
};
|
|
42
41
|
const QuantityPickerNEW = React.forwardRef((_a, ref) => {
|
|
43
|
-
var { className, decreaseIconUrl, increaseIconUrl, deleteIconUrl, isDeleteOnly = false, iconColor, onDecreaseClick, onIncreaseClick, isDecreaseDisabled, isIncreaseDisabled, value, onValueSet, onAdjustQuantity, inputStyle, buttonStyle, buttonCornerRadius = 4, max = 99, loading = false, debounceTime = 300 } = _a, props = __rest(_a, ["className", "decreaseIconUrl", "increaseIconUrl", "deleteIconUrl", "isDeleteOnly", "iconColor", "onDecreaseClick", "onIncreaseClick", "isDecreaseDisabled", "isIncreaseDisabled", "value", "onValueSet", "onAdjustQuantity", "inputStyle", "buttonStyle", "buttonCornerRadius", "max", "loading", "debounceTime"]);
|
|
42
|
+
var { className, decreaseIconUrl, increaseIconUrl, deleteIconUrl, isDeleteOnly = false, iconColor, onDecreaseClick, onIncreaseClick, isDecreaseDisabled, isIncreaseDisabled, value, onValueSet, onAdjustQuantity, inputStyle, buttonStyle, buttonCornerRadius = 4, max = 99, loading = false, debounceTime = 300, parentRef } = _a, props = __rest(_a, ["className", "decreaseIconUrl", "increaseIconUrl", "deleteIconUrl", "isDeleteOnly", "iconColor", "onDecreaseClick", "onIncreaseClick", "isDecreaseDisabled", "isIncreaseDisabled", "value", "onValueSet", "onAdjustQuantity", "inputStyle", "buttonStyle", "buttonCornerRadius", "max", "loading", "debounceTime", "parentRef"]);
|
|
43
|
+
const inputRef = React.useRef(null);
|
|
44
44
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
45
|
-
const pendingQuantityAdjustment = React.useRef(0);
|
|
46
45
|
const [localInputValue, setLocalInputValue] = React.useState(value);
|
|
47
46
|
// Update local state when external value changes
|
|
48
47
|
React.useEffect(() => {
|
|
49
|
-
|
|
50
|
-
setLocalInputValue(value);
|
|
51
|
-
}
|
|
48
|
+
setLocalInputValue(value);
|
|
52
49
|
}, [value]);
|
|
53
|
-
// Create debounced function for applying changes
|
|
54
|
-
const debouncedApplyChanges = React.useMemo(() => debounce(() => {
|
|
55
|
-
if (pendingQuantityAdjustment.current !== 0) {
|
|
56
|
-
onAdjustQuantity(pendingQuantityAdjustment.current);
|
|
57
|
-
pendingQuantityAdjustment.current = 0;
|
|
58
|
-
}
|
|
59
|
-
}, debounceTime), [debounceTime, onAdjustQuantity]);
|
|
60
50
|
const leftButtonStyle = Object.assign(Object.assign({}, buttonStyle), { borderTopLeftRadius: buttonCornerRadius
|
|
61
51
|
? `${buttonCornerRadius}px`
|
|
62
52
|
: undefined, borderBottomLeftRadius: buttonCornerRadius
|
|
@@ -68,56 +58,60 @@ const QuantityPickerNEW = React.forwardRef((_a, ref) => {
|
|
|
68
58
|
? `${buttonCornerRadius}px`
|
|
69
59
|
: undefined });
|
|
70
60
|
const singleButtonStyle = Object.assign(Object.assign({}, buttonStyle), { borderRadius: buttonCornerRadius ? `${buttonCornerRadius}px` : undefined });
|
|
71
|
-
const adjustQuantity = (amount) => {
|
|
72
|
-
const newAmount = localInputValue + amount;
|
|
73
|
-
const clampedNewAmount = Math.min(Math.max(newAmount, 0), max);
|
|
74
|
-
// Update local value immediately
|
|
75
|
-
setLocalInputValue(clampedNewAmount);
|
|
76
|
-
// Track pending change for batched update
|
|
77
|
-
pendingQuantityAdjustment.current += amount;
|
|
78
|
-
// Trigger debounced API update
|
|
79
|
-
debouncedApplyChanges();
|
|
80
|
-
};
|
|
81
61
|
const handleDecreaseClick = (e) => {
|
|
82
62
|
e.preventDefault();
|
|
83
63
|
e.stopPropagation();
|
|
84
|
-
|
|
64
|
+
onAdjustQuantity(-1);
|
|
85
65
|
onDecreaseClick(e);
|
|
86
66
|
};
|
|
87
67
|
const handleIncreaseClick = (e) => {
|
|
88
68
|
e.preventDefault();
|
|
89
69
|
e.stopPropagation();
|
|
90
|
-
|
|
70
|
+
onAdjustQuantity(1);
|
|
91
71
|
onIncreaseClick(e);
|
|
92
72
|
};
|
|
93
|
-
return (_jsxs("div", Object.assign({ className: cn("flex relative", className), ref: ref }, props, { children: [isDeleteOnly ? (_jsx(IconButton, { handler: handleDecreaseClick, iconUrl: deleteIconUrl, iconColor: iconColor, style: singleButtonStyle })) : (_jsxs(_Fragment, { children: [_jsx(IconButton, { handler: handleDecreaseClick, iconUrl:
|
|
73
|
+
return (_jsxs("div", Object.assign({ className: cn("flex relative", className), ref: ref }, props, { children: [isDeleteOnly ? (_jsx(IconButton, { handler: handleDecreaseClick, iconUrl: deleteIconUrl, iconColor: iconColor, style: singleButtonStyle })) : (_jsxs(_Fragment, { children: [_jsx(IconButton, { handler: handleDecreaseClick, iconUrl: value <= 1 ? deleteIconUrl : decreaseIconUrl, iconColor: iconColor, style: leftButtonStyle, disabled: isDecreaseDisabled || loading }), _jsx("input", { type: "number", step: 1, enterKeyHint: "done", ref: inputRef, disabled: loading, max: max, value: localInputValue, onBlur: (e) => {
|
|
94
74
|
setIsFocused(false);
|
|
75
|
+
if (e.target.value === "") {
|
|
76
|
+
setLocalInputValue(value);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
95
79
|
const parsedValue = parseInt(e.target.value) || 0;
|
|
96
80
|
const clampedValue = Math.min(parsedValue, max);
|
|
97
|
-
// Cancel any pending debounced operations
|
|
98
|
-
debouncedApplyChanges.cancel();
|
|
99
|
-
// Update and apply changes
|
|
100
|
-
const delta = clampedValue - value;
|
|
101
|
-
pendingQuantityAdjustment.current = delta;
|
|
102
|
-
setLocalInputValue(clampedValue);
|
|
103
81
|
onValueSet(clampedValue);
|
|
104
|
-
}, onFocus: () => {
|
|
82
|
+
}, onFocus: (e) => {
|
|
83
|
+
setLocalInputValue("");
|
|
105
84
|
setIsFocused(true);
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
var _a;
|
|
87
|
+
(_a = parentRef === null || parentRef === void 0 ? void 0 : parentRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({
|
|
88
|
+
block: "start",
|
|
89
|
+
inline: "nearest",
|
|
90
|
+
behavior: "smooth",
|
|
91
|
+
});
|
|
92
|
+
}, 250);
|
|
106
93
|
}, onChange: (e) => {
|
|
107
94
|
const inputValue = e.target.value;
|
|
108
95
|
if (inputValue === "") {
|
|
109
|
-
setLocalInputValue(
|
|
96
|
+
setLocalInputValue("");
|
|
110
97
|
}
|
|
111
98
|
else {
|
|
112
|
-
const parsedValue = parseInt(inputValue);
|
|
99
|
+
const parsedValue = parseInt(inputValue, 10);
|
|
113
100
|
if (!isNaN(parsedValue)) {
|
|
114
101
|
const clampedValue = Math.min(parsedValue, max);
|
|
115
102
|
setLocalInputValue(clampedValue);
|
|
116
103
|
}
|
|
117
104
|
}
|
|
105
|
+
}, onKeyDown: (e) => {
|
|
106
|
+
var _a;
|
|
107
|
+
if (e.key === "Enter") {
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
e.stopPropagation();
|
|
110
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
|
|
111
|
+
}
|
|
118
112
|
}, className: "w-8 h-7 focus-visible:outline-no ne text-center bg-coreColors-inputBackground text-textColors-primaryColor border-t border-b border-coreColors-dividingLines", style: Object.assign(Object.assign({}, inputStyle), { borderRadius: (inputStyle === null || inputStyle === void 0 ? void 0 : inputStyle.borderRadius)
|
|
119
113
|
? `${inputStyle.borderRadius}px`
|
|
120
|
-
: 0 }), inputMode: "numeric" }), _jsx(IconButton, { handler: handleIncreaseClick, iconUrl: increaseIconUrl, iconColor: iconColor, style: rightButtonStyle, disabled: isIncreaseDisabled || loading ||
|
|
114
|
+
: 0 }), inputMode: "numeric" }), _jsx(IconButton, { handler: handleIncreaseClick, iconUrl: increaseIconUrl, iconColor: iconColor, style: rightButtonStyle, disabled: isIncreaseDisabled || loading || value >= max })] })), _jsx(LoadingDots, { show: loading, size: 1, iconColor: iconColor })] })));
|
|
121
115
|
});
|
|
122
116
|
QuantityPickerNEW.displayName = "QuantityPickerNEW";
|
|
123
117
|
export { QuantityPickerNEW };
|
package/dist/styles.css
CHANGED
|
@@ -823,6 +823,10 @@ video {
|
|
|
823
823
|
.m-auto {
|
|
824
824
|
margin: auto;
|
|
825
825
|
}
|
|
826
|
+
.-mx-4 {
|
|
827
|
+
margin-left: -1rem;
|
|
828
|
+
margin-right: -1rem;
|
|
829
|
+
}
|
|
826
830
|
.mx-1 {
|
|
827
831
|
margin-left: 0.25rem;
|
|
828
832
|
margin-right: 0.25rem;
|
|
@@ -1072,6 +1076,9 @@ video {
|
|
|
1072
1076
|
.h-full {
|
|
1073
1077
|
height: 100%;
|
|
1074
1078
|
}
|
|
1079
|
+
.h-px {
|
|
1080
|
+
height: 1px;
|
|
1081
|
+
}
|
|
1075
1082
|
.h-screen {
|
|
1076
1083
|
height: 100vh;
|
|
1077
1084
|
}
|
|
@@ -2016,6 +2023,10 @@ video {
|
|
|
2016
2023
|
.text-\[23px\] {
|
|
2017
2024
|
font-size: 23px;
|
|
2018
2025
|
}
|
|
2026
|
+
.text-base {
|
|
2027
|
+
font-size: 1rem;
|
|
2028
|
+
line-height: 1.5rem;
|
|
2029
|
+
}
|
|
2019
2030
|
.text-lg {
|
|
2020
2031
|
font-size: 1.125rem;
|
|
2021
2032
|
line-height: 1.75rem;
|
|
@@ -2619,6 +2630,10 @@ body::-webkit-scrollbar {
|
|
|
2619
2630
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
|
|
2620
2631
|
}
|
|
2621
2632
|
|
|
2633
|
+
.hover\:no-underline:hover {
|
|
2634
|
+
text-decoration-line: none;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2622
2637
|
.hover\:opacity-90:hover {
|
|
2623
2638
|
opacity: 0.9;
|
|
2624
2639
|
}
|