@0xsequence/marketplace-sdk 0.8.3 → 0.8.5

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.
Files changed (97) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/dist/{chunk-25CAMYCG.js → chunk-BB2PTJHI.js} +22 -20
  3. package/dist/chunk-BB2PTJHI.js.map +1 -0
  4. package/dist/{chunk-5ATGT5S4.js → chunk-EZFCQZHU.js} +14 -6
  5. package/dist/chunk-EZFCQZHU.js.map +1 -0
  6. package/dist/{chunk-DFI52A2E.js → chunk-KCLMSSPS.js} +364 -242
  7. package/dist/chunk-KCLMSSPS.js.map +1 -0
  8. package/dist/{chunk-XUNDLCEH.js → chunk-LDZZUYG7.js} +2 -2
  9. package/dist/{chunk-QTV77W42.js → chunk-SFSFIGHM.js} +45 -35
  10. package/dist/chunk-SFSFIGHM.js.map +1 -0
  11. package/dist/{chunk-FSJKN4YN.js → chunk-ZSCZLHKX.js} +194 -2
  12. package/dist/chunk-ZSCZLHKX.js.map +1 -0
  13. package/dist/{chunk-FH4TZRDV.js → chunk-ZVTG6US2.js} +2 -2
  14. package/dist/index.css +4 -4
  15. package/dist/index.css.map +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/{lowestListing-DUZ_nYml.d.ts → lowestListing-W7P4EkC3.d.ts} +34 -11
  18. package/dist/react/_internal/databeat/index.js +5 -5
  19. package/dist/react/_internal/index.d.ts +1 -1
  20. package/dist/react/_internal/index.js +3 -1
  21. package/dist/react/_internal/wagmi/index.d.ts +3 -2
  22. package/dist/react/_internal/wagmi/index.js +3 -1
  23. package/dist/react/hooks/index.d.ts +8 -5
  24. package/dist/react/hooks/index.js +6 -4
  25. package/dist/react/hooks/options/index.js +2 -2
  26. package/dist/react/index.d.ts +2 -2
  27. package/dist/react/index.js +9 -7
  28. package/dist/react/queries/index.d.ts +1 -1
  29. package/dist/react/queries/index.js +6 -2
  30. package/dist/react/ssr/index.js +1 -1
  31. package/dist/react/ui/components/collectible-card/index.d.ts +3 -2
  32. package/dist/react/ui/components/collectible-card/index.js +7 -7
  33. package/dist/react/ui/icons/index.js +1 -1
  34. package/dist/react/ui/index.js +7 -7
  35. package/dist/react/ui/modals/_internal/components/actionModal/index.js +5 -5
  36. package/dist/types/index.js +1 -1
  37. package/dist/utils/index.js +1 -1
  38. package/package.json +19 -19
  39. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +35 -21
  40. package/src/react/_internal/wagmi/__tests__/create-config.test.ts +1 -11
  41. package/src/react/_internal/wagmi/get-connectors.ts +27 -24
  42. package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +4 -9
  43. package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +5 -4
  44. package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +14 -10
  45. package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +115 -65
  46. package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +10 -7
  47. package/src/react/hooks/__tests__/useInventory.test.tsx +294 -0
  48. package/src/react/hooks/index.ts +1 -0
  49. package/src/react/hooks/useAutoSelectFeeOption.tsx +10 -3
  50. package/src/react/hooks/useCancelOrder.tsx +1 -0
  51. package/src/react/hooks/useCancelTransactionSteps.tsx +18 -4
  52. package/src/react/hooks/useGenerateOfferTransaction.tsx +11 -1
  53. package/src/react/hooks/useInventory.tsx +15 -0
  54. package/src/react/hooks/util/optimisticCancelUpdates.ts +115 -0
  55. package/src/react/queries/index.ts +1 -0
  56. package/src/react/queries/inventory.ts +303 -0
  57. package/src/react/queries/listBalances.ts +1 -8
  58. package/src/react/queries/listCollectibles.ts +12 -3
  59. package/src/react/ui/components/_internals/action-button/__tests__/ActionButtonBody.test.tsx +27 -94
  60. package/src/react/ui/components/_internals/action-button/__tests__/NonOwnerActions.test.tsx +59 -0
  61. package/src/react/ui/components/_internals/action-button/__tests__/OwnerActions.test.tsx +73 -0
  62. package/src/react/ui/components/_internals/action-button/__tests__/useActionButtonLogic.test.tsx +77 -0
  63. package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +3 -2
  64. package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +4 -3
  65. package/src/react/ui/components/collectible-card/CollectibleAsset.tsx +1 -0
  66. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +18 -12
  67. package/src/react/ui/components/collectible-card/__tests__/CollectibleAsset.test.tsx +200 -0
  68. package/src/react/ui/components/collectible-card/__tests__/CollectibleCard.test.tsx +92 -123
  69. package/src/react/ui/components/collectible-card/__tests__/Footer.test.tsx +136 -0
  70. package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +2 -8
  71. package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +74 -104
  72. package/src/react/ui/modals/MakeOfferModal/__tests__/Modal.test.tsx +108 -78
  73. package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +72 -135
  74. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.test.tsx +286 -0
  75. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +16 -4
  76. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +35 -132
  77. package/src/react/ui/modals/_internal/components/floorPriceText/__tests__/FloorPriceText.test.tsx +199 -0
  78. package/src/react/ui/modals/_internal/components/priceInput/__tests__/PriceInput.test.tsx +55 -0
  79. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +1 -1
  80. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/ActionButtons.test.tsx +72 -0
  81. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/BalanceIndicator.test.tsx +50 -0
  82. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/SelectWaasFeeOptions.test.tsx +193 -0
  83. package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +2 -2
  84. package/test/const.ts +24 -0
  85. package/test/test-utils.tsx +85 -47
  86. package/.changeset/flat-parks-clean.md +0 -8
  87. package/.changeset/red-buckets-deny.md +0 -6
  88. package/.changeset/seven-doors-taste.md +0 -5
  89. package/dist/chunk-25CAMYCG.js.map +0 -1
  90. package/dist/chunk-5ATGT5S4.js.map +0 -1
  91. package/dist/chunk-DFI52A2E.js.map +0 -1
  92. package/dist/chunk-FSJKN4YN.js.map +0 -1
  93. package/dist/chunk-QTV77W42.js.map +0 -1
  94. package/src/react/ui/components/_internals/action-button/__tests__/ActionButton.test.tsx +0 -107
  95. package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +0 -164
  96. /package/dist/{chunk-XUNDLCEH.js.map → chunk-LDZZUYG7.js.map} +0 -0
  97. /package/dist/{chunk-FH4TZRDV.js.map → chunk-ZVTG6US2.js.map} +0 -0
@@ -0,0 +1,294 @@
1
+ import { renderHook, server, waitFor } from '@test';
2
+ import { http, HttpResponse } from 'msw';
3
+ import { zeroAddress } from 'viem';
4
+ import { beforeEach, describe, expect, it } from 'vitest';
5
+ import {
6
+ mockIndexerEndpoint,
7
+ mockTokenBalance,
8
+ } from '../../_internal/api/__mocks__/indexer.msw';
9
+ import {
10
+ mockCollectibleOrder,
11
+ mockMarketplaceEndpoint,
12
+ } from '../../_internal/api/__mocks__/marketplace.msw';
13
+ import type { UseInventoryArgs } from '../../queries/inventory';
14
+ import { mockConfig } from '../options/__mocks__/marketplaceConfig.msw';
15
+ import { useInventory } from '../useInventory';
16
+
17
+ // Make sure mockCollectibleOrder has a tokenId of "1" for tests
18
+ mockCollectibleOrder.metadata.tokenId = '1';
19
+
20
+ describe('useInventory', () => {
21
+ const defaultArgs: UseInventoryArgs = {
22
+ accountAddress:
23
+ '0x1234567890123456789012345678901234567890' as `0x${string}`,
24
+ chainId: 1,
25
+ collectionAddress: zeroAddress,
26
+ };
27
+
28
+ beforeEach(() => {
29
+ // Reset MSW handlers before each test to ensure a clean state
30
+ server.resetHandlers();
31
+ });
32
+
33
+ it('should fetch inventory data successfully', async () => {
34
+ const { result } = renderHook(() => useInventory(defaultArgs));
35
+
36
+ // Initially loading
37
+ expect(result.current.isLoading).toBe(true);
38
+ expect(result.current.data).toBeUndefined();
39
+
40
+ // Wait for data to be loaded
41
+ await waitFor(() => {
42
+ expect(result.current.isLoading).toBe(false);
43
+ });
44
+
45
+ // Verify the data is defined and has pages
46
+ expect(result.current.data).toBeDefined();
47
+ expect(result.current.data?.pages).toBeDefined();
48
+ expect(result.current.error).toBeNull();
49
+ });
50
+
51
+ it('should handle error gracefully', async () => {
52
+ // Mock both API endpoints to return errors
53
+ server.use(
54
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
55
+ return new HttpResponse(null, { status: 500 });
56
+ }),
57
+ http.post(mockIndexerEndpoint('GetTokenBalances'), () => {
58
+ return new HttpResponse(null, { status: 500 });
59
+ }),
60
+ );
61
+
62
+ const { result } = renderHook(() =>
63
+ useInventory({
64
+ ...defaultArgs,
65
+ // Add a unique key to avoid caching
66
+ collectionAddress:
67
+ '0xdeadbeef0000000000000000000000000000dead' as `0x${string}`,
68
+ }),
69
+ );
70
+
71
+ // Wait for the query to finish loading and show error
72
+ await waitFor(
73
+ () => {
74
+ expect(result.current.isLoading).toBe(false);
75
+ },
76
+ { timeout: 3000 },
77
+ );
78
+
79
+ // Verify error state
80
+ expect(result.current.status).toBe('error');
81
+ expect(result.current.isError).toBe(true);
82
+ expect(result.current.error).not.toBeNull();
83
+ });
84
+
85
+ it('should refetch when args change', async () => {
86
+ const { result, rerender } = renderHook(() => useInventory(defaultArgs));
87
+
88
+ // Wait for initial data
89
+ await waitFor(() => {
90
+ expect(result.current.isLoading).toBe(false);
91
+ });
92
+
93
+ // Change args and rerender with a new hook
94
+ const newArgs = {
95
+ ...defaultArgs,
96
+ collectionAddress:
97
+ '0x1234567890123456789012345678901234567890' as `0x${string}`,
98
+ };
99
+
100
+ rerender(() => useInventory(newArgs));
101
+
102
+ // Wait for new data
103
+ await waitFor(() => {
104
+ expect(result.current.data).toBeDefined();
105
+ });
106
+
107
+ // Verify that the query was refetched with new args
108
+ expect(result.current.data).toBeDefined();
109
+ expect(result.current.isSuccess).toBe(true);
110
+ });
111
+
112
+ it('should handle disabled queries', async () => {
113
+ const disabledArgs: UseInventoryArgs = {
114
+ ...defaultArgs,
115
+ query: {
116
+ enabled: false,
117
+ },
118
+ };
119
+
120
+ const { result } = renderHook(() => useInventory(disabledArgs));
121
+
122
+ // Should not be loading or have data
123
+ expect(result.current.isLoading).toBe(false);
124
+ expect(result.current.data).toBeUndefined();
125
+ expect(result.current.isFetched).toBe(false);
126
+ });
127
+
128
+ it('should use isLaos721 flag from marketplaceConfig', async () => {
129
+ // Setup config with LAOS collection
130
+ const laosCollectionAddress = '0x1234567890123456789012345678901234567890';
131
+ server.use(
132
+ http.get('*/marketplace/*/settings.json', () => {
133
+ const configWithLaos = {
134
+ ...mockConfig,
135
+ collections: [
136
+ {
137
+ ...mockConfig.collections[0],
138
+ address: laosCollectionAddress,
139
+ isLAOSERC721: true,
140
+ },
141
+ ],
142
+ };
143
+ return HttpResponse.json(configWithLaos);
144
+ }),
145
+ );
146
+
147
+ const laosArgs: UseInventoryArgs = {
148
+ ...defaultArgs,
149
+ collectionAddress: laosCollectionAddress as `0x${string}`,
150
+ };
151
+
152
+ const { result } = renderHook(() => useInventory(laosArgs));
153
+
154
+ await waitFor(() => {
155
+ expect(result.current.isLoading).toBe(false);
156
+ });
157
+
158
+ expect(result.current.data).toBeDefined();
159
+ expect(result.current.isSuccess).toBe(true);
160
+ });
161
+
162
+ it('should fetch data from indexer when marketplace API has no more results', async () => {
163
+ // Mock marketplace API with empty results
164
+ server.use(
165
+ http.post(mockMarketplaceEndpoint('ListCollectibles'), () => {
166
+ return HttpResponse.json({
167
+ collectibles: [],
168
+ page: {
169
+ page: 1,
170
+ pageSize: 50,
171
+ more: false,
172
+ },
173
+ });
174
+ }),
175
+ // Mock indexer with data
176
+ http.post(mockIndexerEndpoint('GetTokenBalances'), () => {
177
+ return HttpResponse.json({
178
+ balances: [mockTokenBalance],
179
+ page: {
180
+ page: 1,
181
+ pageSize: 50,
182
+ more: false,
183
+ },
184
+ });
185
+ }),
186
+ );
187
+
188
+ const { result } = renderHook(() => useInventory(defaultArgs));
189
+
190
+ await waitFor(() => {
191
+ expect(result.current.isLoading).toBe(false);
192
+ });
193
+
194
+ expect(result.current.data).toBeDefined();
195
+ expect(result.current.data?.pages[0].collectibles).toBeDefined();
196
+ expect(result.current.isSuccess).toBe(true);
197
+ });
198
+
199
+ it('should support pagination with fetchNextPage', async () => {
200
+ // Simplified test for pagination
201
+ // Set up mock data for first and second pages
202
+ const page1Data = {
203
+ collectibles: [
204
+ {
205
+ ...mockCollectibleOrder,
206
+ metadata: {
207
+ ...mockCollectibleOrder.metadata,
208
+ tokenId: '1',
209
+ name: 'Token 1',
210
+ },
211
+ },
212
+ ],
213
+ page: {
214
+ page: 1,
215
+ pageSize: 10,
216
+ more: true, // indicate there's a next page
217
+ },
218
+ };
219
+
220
+ // Mock API to return data for the first page
221
+ server.use(
222
+ http.post(
223
+ mockMarketplaceEndpoint('ListCollectibles'),
224
+ async ({ request }) => {
225
+ const body = (await request.json()) as { page?: number };
226
+ const pageNumber = body?.page || 1;
227
+
228
+ // Return first page data
229
+ if (pageNumber === 1) {
230
+ return HttpResponse.json(page1Data);
231
+ }
232
+
233
+ // For second page, return empty collectibles but with more=false
234
+ return HttpResponse.json({
235
+ collectibles: [],
236
+ page: {
237
+ page: 2,
238
+ pageSize: 10,
239
+ more: false,
240
+ },
241
+ });
242
+ },
243
+ ),
244
+ );
245
+
246
+ // Use unique test args to avoid caching issues
247
+ const testArgs = {
248
+ ...defaultArgs,
249
+ accountAddress:
250
+ '0xabcdef1234567890abcdef1234567890abcdef12' as `0x${string}`,
251
+ collectionAddress:
252
+ '0xabcdef1234567890abcdef1234567890abcdef12' as `0x${string}`,
253
+ };
254
+
255
+ const { result } = renderHook(() => useInventory(testArgs));
256
+
257
+ // Wait for the first page to load
258
+ await waitFor(
259
+ () => {
260
+ expect(result.current.isLoading).toBe(false);
261
+ expect(result.current.data?.pages).toBeDefined();
262
+ },
263
+ { timeout: 5000 },
264
+ );
265
+
266
+ // Verify first page data loaded correctly
267
+ expect(result.current.data?.pages[0].collectibles).toBeDefined();
268
+ expect(result.current.data?.pages[0].collectibles.length).toBeGreaterThan(
269
+ 0,
270
+ );
271
+ // Check that at least one item has the expected tokenId
272
+ expect(
273
+ result.current.data?.pages[0].collectibles.some(
274
+ (c) => c.metadata.tokenId === '1',
275
+ ),
276
+ ).toBe(true);
277
+ expect(result.current.hasNextPage).toBe(true);
278
+
279
+ // Fetch the next page
280
+ await result.current.fetchNextPage();
281
+
282
+ // Wait for second page to load
283
+ await waitFor(
284
+ () => {
285
+ expect(result.current.data?.pages.length).toBe(2);
286
+ },
287
+ { timeout: 5000 },
288
+ );
289
+
290
+ // For an empty second page we just verify it exists
291
+ expect(result.current.data?.pages[1]).toBeDefined();
292
+ expect(result.current.hasNextPage).toBe(false); // No more pages
293
+ });
294
+ });
@@ -12,6 +12,7 @@ export * from './useCurrency';
12
12
  export * from './useFilters';
13
13
  export * from './useFloorOrder';
14
14
  export * from './useHighestOffer';
15
+ export * from './useInventory';
15
16
  export * from './useListBalances';
16
17
  export * from './useListCollectibleActivities';
17
18
  export * from './useListCollectibles';
@@ -1,7 +1,7 @@
1
1
  import { type Address, zeroAddress } from 'viem';
2
2
 
3
3
  import { useChain } from '@0xsequence/connect';
4
- import { useCallback } from 'react';
4
+ import { useCallback, useEffect } from 'react';
5
5
  import { useAccount } from 'wagmi';
6
6
  import type { FeeOption } from '../../types/waas-types';
7
7
  import { useCollectionBalanceDetails } from './useCollectionBalanceDetails';
@@ -19,6 +19,7 @@ type UseAutoSelectFeeOptionArgs = {
19
19
  options: FeeOption[] | undefined;
20
20
  chainId: number;
21
21
  };
22
+ enabled?: boolean;
22
23
  };
23
24
 
24
25
  /**
@@ -87,6 +88,7 @@ type UseAutoSelectFeeOptionArgs = {
87
88
  */
88
89
  export function useAutoSelectFeeOption({
89
90
  pendingFeeOptionConfirmation,
91
+ enabled,
90
92
  }: UseAutoSelectFeeOptionArgs) {
91
93
  const { address: userAddress } = useAccount();
92
94
 
@@ -110,7 +112,8 @@ export function useAutoSelectFeeOption({
110
112
  omitNativeBalances: false,
111
113
  },
112
114
  query: {
113
- enabled: !!pendingFeeOptionConfirmation.options && !!userAddress,
115
+ enabled:
116
+ !!pendingFeeOptionConfirmation.options && !!userAddress && enabled,
114
117
  },
115
118
  });
116
119
  const chain = useChain(pendingFeeOptionConfirmation.chainId);
@@ -131,7 +134,11 @@ export function useAutoSelectFeeOption({
131
134
  })),
132
135
  ];
133
136
 
134
- console.debug('currency balances', combinedBalances);
137
+ useEffect(() => {
138
+ if (combinedBalances) {
139
+ console.debug('currency balances', combinedBalances);
140
+ }
141
+ }, [combinedBalances]);
135
142
 
136
143
  const autoSelectedOption = useCallback(async () => {
137
144
  if (!userAddress) {
@@ -54,6 +54,7 @@ export const useCancelOrder = ({
54
54
  options: undefined,
55
55
  chainId,
56
56
  },
57
+ enabled: !!pendingFeeOptionConfirmation,
57
58
  });
58
59
 
59
60
  useEffect(() => {
@@ -20,6 +20,10 @@ import type { ModalCallbacks } from '../ui/modals/_internal/types';
20
20
  import type { TransactionStep } from './useCancelOrder';
21
21
  import { useConfig } from './useConfig';
22
22
  import { useGenerateCancelTransaction } from './useGenerateCancelTransaction';
23
+ import {
24
+ invalidateQueriesOnCancel,
25
+ updateQueriesOnCancel,
26
+ } from './util/optimisticCancelUpdates';
23
27
 
24
28
  interface UseCancelTransactionStepsArgs {
25
29
  collectionAddress: string;
@@ -156,9 +160,12 @@ export const useCancelTransactionSteps = ({
156
160
 
157
161
  if (onSuccess && typeof onSuccess === 'function') {
158
162
  onSuccess({ hash });
159
- }
160
163
 
161
- queryClient.invalidateQueries();
164
+ updateQueriesOnCancel({
165
+ orderId,
166
+ queryClient,
167
+ });
168
+ }
162
169
 
163
170
  setSteps((prev) => ({
164
171
  ...prev,
@@ -172,9 +179,12 @@ export const useCancelTransactionSteps = ({
172
179
 
173
180
  if (onSuccess && typeof onSuccess === 'function') {
174
181
  onSuccess({ orderId: reservoirOrderId });
175
- }
176
182
 
177
- queryClient.invalidateQueries();
183
+ updateQueriesOnCancel({
184
+ orderId: reservoirOrderId,
185
+ queryClient,
186
+ });
187
+ }
178
188
 
179
189
  setSteps((prev) => ({
180
190
  ...prev,
@@ -182,6 +192,10 @@ export const useCancelTransactionSteps = ({
182
192
  }));
183
193
  }
184
194
  } catch (error) {
195
+ invalidateQueriesOnCancel({
196
+ queryClient,
197
+ });
198
+
185
199
  setSteps((prev) => ({
186
200
  ...prev,
187
201
  isExecuting: false,
@@ -5,8 +5,10 @@ import {
5
5
  type CreateReq,
6
6
  type GenerateOfferTransactionArgs,
7
7
  type Step,
8
+ type WalletKind,
8
9
  getMarketplaceClient,
9
10
  } from '../_internal';
11
+ import { useWallet } from '../_internal/wallet/useWallet';
10
12
  import { useConfig } from './useConfig';
11
13
 
12
14
  export type UseGenerateOfferTransactionArgs = {
@@ -29,10 +31,12 @@ export const generateOfferTransaction = async (
29
31
  params: GenerateOfferTransactionProps,
30
32
  config: SdkConfig,
31
33
  chainId: number,
34
+ walletKind?: WalletKind,
32
35
  ) => {
33
36
  const args = {
34
37
  ...params,
35
38
  offer: { ...params.offer, expiry: dateToUnixTime(params.offer.expiry) },
39
+ walletType: walletKind,
36
40
  } satisfies GenerateOfferTransactionArgs;
37
41
  const marketplaceClient = getMarketplaceClient(chainId, config);
38
42
  return (await marketplaceClient.generateOfferTransaction(args)).steps;
@@ -42,11 +46,17 @@ export const useGenerateOfferTransaction = (
42
46
  params: UseGenerateOfferTransactionArgs,
43
47
  ) => {
44
48
  const config = useConfig();
49
+ const { wallet } = useWallet();
45
50
 
46
51
  const { mutate, mutateAsync, ...result } = useMutation({
47
52
  onSuccess: params.onSuccess,
48
53
  mutationFn: (args: GenerateOfferTransactionProps) =>
49
- generateOfferTransaction(args, config, params.chainId),
54
+ generateOfferTransaction(
55
+ args,
56
+ config,
57
+ params.chainId,
58
+ wallet?.walletKind,
59
+ ),
50
60
  });
51
61
 
52
62
  return {
@@ -0,0 +1,15 @@
1
+ import { useInfiniteQuery } from '@tanstack/react-query';
2
+ import { type UseInventoryArgs, inventoryOptions } from '../queries/inventory';
3
+ import { useConfig } from './useConfig';
4
+ import { useMarketplaceConfig } from './useMarketplaceConfig';
5
+
6
+ export function useInventory(args: UseInventoryArgs) {
7
+ const config = useConfig();
8
+ const marketplaceConfig = useMarketplaceConfig();
9
+ const isLaos721 =
10
+ marketplaceConfig.data?.collections.find(
11
+ (c) => c.address === args.collectionAddress,
12
+ )?.isLAOSERC721 ?? false;
13
+
14
+ return useInfiniteQuery(inventoryOptions({ ...args, isLaos721 }, config));
15
+ }
@@ -0,0 +1,115 @@
1
+ import type { QueryClient } from '@tanstack/react-query';
2
+ import {
3
+ type GetCountOfListingsForCollectibleReturn,
4
+ type GetCountOfOffersForCollectibleReturn,
5
+ type ListListingsForCollectibleReturn,
6
+ type ListOffersForCollectibleReturn,
7
+ collectableKeys,
8
+ } from '../../_internal';
9
+
10
+ const SECOND = 1000;
11
+
12
+ interface OptimisticCancelUpdatesParams {
13
+ orderId: string;
14
+ queryClient: QueryClient;
15
+ }
16
+
17
+ export const updateQueriesOnCancel = ({
18
+ orderId,
19
+ queryClient,
20
+ }: OptimisticCancelUpdatesParams) => {
21
+ queryClient.setQueriesData(
22
+ { queryKey: collectableKeys.offersCount, exact: false },
23
+ (oldData: GetCountOfOffersForCollectibleReturn | undefined) => {
24
+ if (!oldData) return { count: 0 };
25
+ return { count: Math.max(0, oldData.count - 1) };
26
+ },
27
+ );
28
+
29
+ console.log('query client ', queryClient, 'orderId', orderId);
30
+
31
+ // remove the offer with matching orderId
32
+ queryClient.setQueriesData(
33
+ { queryKey: collectableKeys.offers, exact: false },
34
+ (oldData: ListOffersForCollectibleReturn | undefined) => {
35
+ if (!oldData || !oldData.offers) return oldData;
36
+ return {
37
+ ...oldData,
38
+ offers: oldData.offers.filter((offer) => offer.orderId !== orderId),
39
+ };
40
+ },
41
+ );
42
+
43
+ // 2 seconds is enough time for new data to be fetched
44
+ setTimeout(() => {
45
+ queryClient.invalidateQueries({
46
+ queryKey: collectableKeys.highestOffers,
47
+ exact: false,
48
+ });
49
+ }, 2 * SECOND);
50
+
51
+ queryClient.setQueriesData(
52
+ { queryKey: collectableKeys.listingsCount, exact: false },
53
+ (oldData: GetCountOfListingsForCollectibleReturn | undefined) => {
54
+ if (!oldData) return { count: 0 };
55
+ return { count: Math.max(0, oldData.count - 1) };
56
+ },
57
+ );
58
+
59
+ queryClient.setQueriesData(
60
+ { queryKey: collectableKeys.listings, exact: false },
61
+ (oldData: ListListingsForCollectibleReturn | undefined) => {
62
+ if (!oldData || !oldData.listings) return oldData;
63
+ return {
64
+ ...oldData,
65
+ listings: oldData.listings.filter(
66
+ (listing) => listing.orderId !== orderId,
67
+ ),
68
+ };
69
+ },
70
+ );
71
+
72
+ // 2 seconds is enough time for new data to be fetched
73
+ setTimeout(() => {
74
+ queryClient.invalidateQueries({
75
+ queryKey: collectableKeys.lowestListings,
76
+ exact: false,
77
+ });
78
+ }, 2 * SECOND);
79
+ };
80
+
81
+ export const invalidateQueriesOnCancel = ({
82
+ queryClient,
83
+ }: {
84
+ queryClient: QueryClient;
85
+ }) => {
86
+ queryClient.invalidateQueries({
87
+ queryKey: collectableKeys.offers,
88
+ exact: false,
89
+ });
90
+
91
+ queryClient.invalidateQueries({
92
+ queryKey: collectableKeys.offersCount,
93
+ exact: false,
94
+ });
95
+
96
+ queryClient.invalidateQueries({
97
+ queryKey: collectableKeys.listings,
98
+ exact: false,
99
+ });
100
+
101
+ queryClient.invalidateQueries({
102
+ queryKey: collectableKeys.listingsCount,
103
+ exact: false,
104
+ });
105
+
106
+ queryClient.invalidateQueries({
107
+ queryKey: collectableKeys.highestOffers,
108
+ exact: false,
109
+ });
110
+
111
+ queryClient.invalidateQueries({
112
+ queryKey: collectableKeys.lowestListings,
113
+ exact: false,
114
+ });
115
+ };
@@ -1,5 +1,6 @@
1
1
  export * from './balanceOfCollectible';
2
2
  export * from './getTokenSupplies';
3
+ export * from './inventory';
3
4
  export * from './listCollectibles';
4
5
  export * from './highestOffer';
5
6
  export * from './listBalances';