@0xsequence/marketplace-sdk 0.4.8 → 0.4.9
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/{chunk-6R4G7J6Q.js → chunk-7HWJ4DUX.js} +29 -5
- package/dist/chunk-7HWJ4DUX.js.map +1 -0
- package/dist/{chunk-7WCZP6FN.js → chunk-BJLOO4NP.js} +628 -369
- package/dist/chunk-BJLOO4NP.js.map +1 -0
- package/dist/{chunk-2OJB35FS.js → chunk-BMWCIHCB.js} +5 -5
- package/dist/{chunk-2OJB35FS.js.map → chunk-BMWCIHCB.js.map} +1 -1
- package/dist/{chunk-WRMJ5FZM.js → chunk-CUA4SGWT.js} +524 -18
- package/dist/chunk-CUA4SGWT.js.map +1 -0
- package/dist/{chunk-JEOUQFT3.js → chunk-TFCSNRD5.js} +4 -3
- package/dist/chunk-TFCSNRD5.js.map +1 -0
- package/dist/{chunk-AQT3BQ67.js → chunk-Y3KINNAU.js} +12 -5
- package/dist/chunk-Y3KINNAU.js.map +1 -0
- package/dist/{create-config-D5WqfUft.d.ts → create-config-CgYQDyMD.d.ts} +2 -2
- package/dist/index.css +31 -17
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/{marketplace-config-C_fDWzz0.d.ts → marketplace-config-BP5-XnFG.d.ts} +1 -1
- package/dist/{marketplace.gen-B8S8fflj.d.ts → marketplace.gen-BzmWLP9L.d.ts} +14 -4
- package/dist/react/_internal/api/index.d.ts +2 -2
- package/dist/react/_internal/api/index.js +3 -1
- package/dist/react/_internal/index.d.ts +5 -5
- package/dist/react/_internal/index.js +3 -1
- package/dist/react/_internal/wagmi/index.d.ts +3 -3
- package/dist/react/hooks/index.d.ts +46 -5
- package/dist/react/hooks/index.js +10 -3
- package/dist/react/index.css +37 -17
- package/dist/react/index.css.map +1 -1
- package/dist/react/index.d.ts +6 -6
- package/dist/react/index.js +13 -6
- package/dist/react/ui/components/collectible-card/index.css +37 -17
- package/dist/react/ui/components/collectible-card/index.css.map +1 -1
- package/dist/react/ui/components/collectible-card/index.d.ts +27 -4
- package/dist/react/ui/components/collectible-card/index.js +5 -6
- package/dist/react/ui/index.css +37 -17
- package/dist/react/ui/index.css.map +1 -1
- package/dist/react/ui/index.d.ts +3 -3
- package/dist/react/ui/index.js +5 -6
- package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +3 -3
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +3 -3
- package/dist/{sdk-config-BXVH8PS2.d.ts → sdk-config-LbbmA85k.d.ts} +27 -7
- package/dist/{services-CdXAIjt1.d.ts → services-DW26ougH.d.ts} +1 -1
- package/dist/styles/index.css +31 -17
- package/dist/styles/index.css.map +1 -1
- package/dist/styles/index.d.ts +2 -2
- package/dist/styles/index.js +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +1 -1
- package/dist/{types-eX4P9xju.d.ts → types-DhTZWw1U.d.ts} +2 -2
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
- package/src/react/_internal/api/__mocks__/marketplace.msw.ts +4 -0
- package/src/react/_internal/api/marketplace.gen.ts +42 -7
- package/src/react/_internal/wallet/useWallet.ts +30 -46
- package/src/react/_internal/wallet/wallet.ts +52 -6
- package/src/react/hooks/index.ts +2 -0
- package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +10 -1
- package/src/react/hooks/useCollectionDetails.tsx +35 -0
- package/src/react/hooks/useCollectionDetailsPolling.tsx +60 -0
- package/src/react/ui/components/_internals/action-button/ActionButton.tsx +36 -118
- package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +52 -0
- package/src/react/ui/components/_internals/action-button/components/NonOwnerActions.tsx +72 -0
- package/src/react/ui/components/_internals/action-button/components/OwnerActions.tsx +81 -0
- package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +93 -0
- package/src/react/ui/components/_internals/action-button/store.ts +47 -0
- package/src/react/ui/components/_internals/action-button/styles.css.ts +8 -0
- package/src/react/ui/components/collectible-card/CollectibleCard.tsx +25 -6
- package/src/react/ui/components/collectible-card/Footer.tsx +5 -8
- package/src/react/ui/components/collectible-card/styles.css.ts +44 -31
- package/src/react/ui/icons/CartIcon.tsx +46 -0
- package/src/react/ui/modals/BuyModal/Modal.tsx +0 -2
- package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +253 -0
- package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +100 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useBuyCollectable.test.tsx +402 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +267 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useFees.test.tsx +166 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useLoadData.test.tsx +209 -0
- package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +19 -17
- package/src/react/ui/modals/BuyModal/hooks/useLoadData.ts +9 -7
- package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +36 -18
- package/src/react/ui/modals/BuyModal/modals/__tests__/CheckoutModal.test.tsx +162 -0
- package/src/react/ui/modals/BuyModal/modals/__tests__/Modal1155.test.tsx +243 -0
- package/src/react/ui/modals/BuyModal/store.ts +11 -10
- package/src/react/ui/modals/CreateListingModal/Modal.tsx +26 -3
- package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +141 -29
- package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +20 -11
- package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +13 -58
- package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +2 -0
- package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +18 -19
- package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/utils.test.ts +2 -0
- package/src/react/ui/modals/_internal/components/transactionStatusModal/hooks/useTransactionStatus.ts +62 -0
- package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +53 -100
- package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +2 -10
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/chunk-6R4G7J6Q.js.map +0 -1
- package/dist/chunk-7WCZP6FN.js.map +0 -1
- package/dist/chunk-AQT3BQ67.js.map +0 -1
- package/dist/chunk-FWN2MCLI.js +0 -425
- package/dist/chunk-FWN2MCLI.js.map +0 -1
- package/dist/chunk-JEOUQFT3.js.map +0 -1
- package/dist/chunk-WRMJ5FZM.js.map +0 -1
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import {
|
|
3
|
+
render,
|
|
4
|
+
screen,
|
|
5
|
+
waitFor,
|
|
6
|
+
within,
|
|
7
|
+
fireEvent,
|
|
8
|
+
act,
|
|
9
|
+
cleanup,
|
|
10
|
+
} from '../../../../../_internal/test-utils';
|
|
11
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
12
|
+
import { ERC1155QuantityModal } from '../Modal1155';
|
|
13
|
+
import { buyModal$ } from '../../store';
|
|
14
|
+
import { MarketplaceKind } from '../../../../../_internal';
|
|
15
|
+
import type { Order, TokenMetadata } from '../../../../../_internal';
|
|
16
|
+
|
|
17
|
+
describe('ERC1155QuantityModal', () => {
|
|
18
|
+
const mockOrder = {
|
|
19
|
+
orderId: '1',
|
|
20
|
+
priceAmount: '1000000000000000000', // 1 ETH in wei
|
|
21
|
+
priceCurrencyAddress: '0x0',
|
|
22
|
+
quantityRemaining: '10',
|
|
23
|
+
quantityDecimals: 0,
|
|
24
|
+
chainId: 1,
|
|
25
|
+
marketplace: MarketplaceKind.sequence_marketplace_v2,
|
|
26
|
+
createdAt: new Date().toISOString(),
|
|
27
|
+
quantityAvailableFormatted: '1',
|
|
28
|
+
} as Order;
|
|
29
|
+
|
|
30
|
+
const mockCollectable: TokenMetadata = {
|
|
31
|
+
decimals: 0,
|
|
32
|
+
tokenId: '1',
|
|
33
|
+
name: 'Test Token',
|
|
34
|
+
description: 'Test Description',
|
|
35
|
+
image: 'https://example.com/image.png',
|
|
36
|
+
attributes: [],
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const mockBuy = vi.fn();
|
|
40
|
+
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
vi.clearAllMocks();
|
|
43
|
+
|
|
44
|
+
// Reset the modal state
|
|
45
|
+
buyModal$.close();
|
|
46
|
+
buyModal$.state.checkoutModalLoaded.set(false);
|
|
47
|
+
buyModal$.state.checkoutModalIsLoading.set(false);
|
|
48
|
+
buyModal$.state.invalidQuantity.set(false);
|
|
49
|
+
buyModal$.state.quantity.set('1');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
buyModal$.close();
|
|
54
|
+
cleanup();
|
|
55
|
+
vi.clearAllMocks();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should render quantity input correctly', async () => {
|
|
59
|
+
// Open the modal with initial state
|
|
60
|
+
buyModal$.open({
|
|
61
|
+
order: mockOrder,
|
|
62
|
+
callbacks: {},
|
|
63
|
+
chainId: '1',
|
|
64
|
+
collectionAddress: '0x123',
|
|
65
|
+
tokenId: '1',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
render(
|
|
69
|
+
<ERC1155QuantityModal
|
|
70
|
+
buy={mockBuy}
|
|
71
|
+
collectable={mockCollectable}
|
|
72
|
+
order={mockOrder}
|
|
73
|
+
chainId="1"
|
|
74
|
+
collectionAddress="0x123"
|
|
75
|
+
collectibleId="1"
|
|
76
|
+
/>,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Verify modal title
|
|
80
|
+
expect(screen.getByText('Select Quantity')).toBeInTheDocument();
|
|
81
|
+
|
|
82
|
+
// Verify quantity input is present with initial value
|
|
83
|
+
const quantityInput = screen.getByRole('textbox', {
|
|
84
|
+
name: /enter quantity/i,
|
|
85
|
+
});
|
|
86
|
+
expect(quantityInput).toBeInTheDocument();
|
|
87
|
+
expect(quantityInput).toHaveValue('1');
|
|
88
|
+
|
|
89
|
+
// Verify total price calculation (1 ETH)
|
|
90
|
+
const priceLabels = screen.getAllByText('Total Price');
|
|
91
|
+
const priceContainer = priceLabels[0].parentElement;
|
|
92
|
+
if (!priceContainer) throw new Error('Price container not found');
|
|
93
|
+
expect(within(priceContainer).getByText('1')).toBeInTheDocument();
|
|
94
|
+
expect(within(priceContainer).getByText('ETH')).toBeInTheDocument();
|
|
95
|
+
|
|
96
|
+
// Verify buy button
|
|
97
|
+
const buyButton = screen.getByRole('button', { name: /buy now/i });
|
|
98
|
+
expect(buyButton).toBeInTheDocument();
|
|
99
|
+
expect(buyButton).not.toBeDisabled();
|
|
100
|
+
|
|
101
|
+
// Verify token image
|
|
102
|
+
const tokenImage = screen.getByRole('img', { name: '' });
|
|
103
|
+
expect(tokenImage).toBeInTheDocument();
|
|
104
|
+
expect(tokenImage).toHaveAttribute('src', 'https://example.com/eth.png');
|
|
105
|
+
|
|
106
|
+
// Ensure loading state is false and button is enabled before clicking
|
|
107
|
+
buyModal$.state.checkoutModalIsLoading.set(false);
|
|
108
|
+
buyModal$.state.invalidQuantity.set(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should update total price when quantity changes', async () => {
|
|
112
|
+
buyModal$.open({
|
|
113
|
+
order: mockOrder,
|
|
114
|
+
callbacks: {},
|
|
115
|
+
chainId: '1',
|
|
116
|
+
collectionAddress: '0x123',
|
|
117
|
+
tokenId: '1',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
render(
|
|
121
|
+
<ERC1155QuantityModal
|
|
122
|
+
buy={mockBuy}
|
|
123
|
+
collectable={mockCollectable}
|
|
124
|
+
order={mockOrder}
|
|
125
|
+
chainId="1"
|
|
126
|
+
collectionAddress="0x123"
|
|
127
|
+
collectibleId="1"
|
|
128
|
+
/>,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const quantityInput = screen.getByRole('textbox', {
|
|
132
|
+
name: /enter quantity/i,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Change quantity to 2
|
|
136
|
+
await act(async () => {
|
|
137
|
+
fireEvent.change(quantityInput, { target: { value: '2' } });
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Verify total price updates to 2 ETH
|
|
141
|
+
const priceLabels = screen.getAllByText('Total Price');
|
|
142
|
+
const priceContainer = priceLabels[0].parentElement;
|
|
143
|
+
if (!priceContainer) throw new Error('Price container not found');
|
|
144
|
+
|
|
145
|
+
await waitFor(() => {
|
|
146
|
+
expect(within(priceContainer).getByText('2')).toBeInTheDocument();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should disable buy button when quantity is invalid', async () => {
|
|
151
|
+
buyModal$.open({
|
|
152
|
+
order: mockOrder,
|
|
153
|
+
callbacks: {},
|
|
154
|
+
chainId: '1',
|
|
155
|
+
collectionAddress: '0x123',
|
|
156
|
+
tokenId: '1',
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Set invalid quantity and loading state
|
|
160
|
+
buyModal$.state.invalidQuantity.set(true);
|
|
161
|
+
buyModal$.state.checkoutModalIsLoading.set(true);
|
|
162
|
+
|
|
163
|
+
render(
|
|
164
|
+
<ERC1155QuantityModal
|
|
165
|
+
buy={mockBuy}
|
|
166
|
+
collectable={mockCollectable}
|
|
167
|
+
order={mockOrder}
|
|
168
|
+
chainId="1"
|
|
169
|
+
collectionAddress="0x123"
|
|
170
|
+
collectibleId="1"
|
|
171
|
+
/>,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const buyButton = screen.getByRole('button', { name: /buy now/i });
|
|
175
|
+
|
|
176
|
+
// Wait for the button to be disabled
|
|
177
|
+
await waitFor(() => {
|
|
178
|
+
expect(buyButton).toBeDisabled();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Click should not trigger buy function
|
|
182
|
+
fireEvent.click(buyButton);
|
|
183
|
+
expect(mockBuy).not.toHaveBeenCalled();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should calculate total price correctly', async () => {
|
|
187
|
+
// Open the modal with initial state
|
|
188
|
+
buyModal$.open({
|
|
189
|
+
order: mockOrder,
|
|
190
|
+
callbacks: {},
|
|
191
|
+
chainId: '1',
|
|
192
|
+
collectionAddress: '0x123',
|
|
193
|
+
tokenId: '1',
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
render(
|
|
197
|
+
<ERC1155QuantityModal
|
|
198
|
+
buy={mockBuy}
|
|
199
|
+
collectable={mockCollectable}
|
|
200
|
+
order={mockOrder}
|
|
201
|
+
chainId="1"
|
|
202
|
+
collectionAddress="0x123"
|
|
203
|
+
collectibleId="1"
|
|
204
|
+
/>,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Wait for modal content to be fully loaded
|
|
208
|
+
await waitFor(() => {
|
|
209
|
+
expect(screen.getByText('Select Quantity')).toBeInTheDocument();
|
|
210
|
+
expect(
|
|
211
|
+
screen.getByRole('textbox', { name: /enter quantity/i }),
|
|
212
|
+
).toBeInTheDocument();
|
|
213
|
+
expect(screen.getAllByText('Total Price')[0]).toBeInTheDocument();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Verify initial total price (1 ETH)
|
|
217
|
+
const priceLabels = screen.getAllByText('Total Price');
|
|
218
|
+
const priceContainer = priceLabels[0].parentElement;
|
|
219
|
+
if (!priceContainer) throw new Error('Price container not found');
|
|
220
|
+
|
|
221
|
+
await waitFor(() => {
|
|
222
|
+
expect(within(priceContainer).getByText('1')).toBeInTheDocument();
|
|
223
|
+
expect(within(priceContainer).getByText('ETH')).toBeInTheDocument();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Change quantity to 3
|
|
227
|
+
const quantityInput = screen.getByRole('textbox', {
|
|
228
|
+
name: /enter quantity/i,
|
|
229
|
+
});
|
|
230
|
+
await act(async () => {
|
|
231
|
+
fireEvent.change(quantityInput, { target: { value: '3' } });
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Verify total price updates to 3 ETH
|
|
235
|
+
await waitFor(() => {
|
|
236
|
+
expect(within(priceContainer).getByText('3')).toBeInTheDocument();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Verify modal is in a valid state
|
|
240
|
+
expect(buyModal$.state.checkoutModalIsLoading.get()).toBe(false);
|
|
241
|
+
expect(buyModal$.state.invalidQuantity.get()).toBe(false);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
@@ -3,6 +3,14 @@ import type { ShowBuyModalArgs } from '.';
|
|
|
3
3
|
import type { Order } from '../../../_internal';
|
|
4
4
|
import type { ModalCallbacks } from '../_internal/types';
|
|
5
5
|
|
|
6
|
+
const buyState = {
|
|
7
|
+
order: undefined as unknown as Order,
|
|
8
|
+
quantity: '1',
|
|
9
|
+
invalidQuantity: false,
|
|
10
|
+
checkoutModalIsLoading: false,
|
|
11
|
+
checkoutModalLoaded: false,
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
6
14
|
export interface BuyModalState {
|
|
7
15
|
isOpen: boolean;
|
|
8
16
|
open: (
|
|
@@ -15,7 +23,6 @@ export interface BuyModalState {
|
|
|
15
23
|
state: {
|
|
16
24
|
order: Order;
|
|
17
25
|
quantity: string;
|
|
18
|
-
modalId: number;
|
|
19
26
|
invalidQuantity: boolean;
|
|
20
27
|
checkoutModalIsLoading: boolean;
|
|
21
28
|
checkoutModalLoaded: boolean;
|
|
@@ -38,7 +45,6 @@ export const initialState: BuyModalState = {
|
|
|
38
45
|
buyModal$.state.set({
|
|
39
46
|
quantity: args.order.quantityAvailableFormatted,
|
|
40
47
|
order: args.order,
|
|
41
|
-
modalId: buyModal$.state.modalId.get() + 1,
|
|
42
48
|
invalidQuantity: false,
|
|
43
49
|
checkoutModalIsLoading: false,
|
|
44
50
|
checkoutModalLoaded: false,
|
|
@@ -48,15 +54,10 @@ export const initialState: BuyModalState = {
|
|
|
48
54
|
},
|
|
49
55
|
close: () => {
|
|
50
56
|
buyModal$.isOpen.set(false);
|
|
57
|
+
buyModal$.callbacks.set(undefined);
|
|
58
|
+
buyModal$.state.set(buyState);
|
|
51
59
|
},
|
|
52
|
-
state:
|
|
53
|
-
order: undefined as unknown as Order,
|
|
54
|
-
quantity: '1',
|
|
55
|
-
modalId: 0,
|
|
56
|
-
invalidQuantity: false,
|
|
57
|
-
checkoutModalIsLoading: false,
|
|
58
|
-
checkoutModalLoaded: false,
|
|
59
|
-
},
|
|
60
|
+
state: buyState,
|
|
60
61
|
setCheckoutModalIsLoading: (isLoading: boolean) => {
|
|
61
62
|
buyModal$.state.checkoutModalIsLoading.set(isLoading);
|
|
62
63
|
},
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
useBalanceOfCollectible,
|
|
8
8
|
useCollectible,
|
|
9
9
|
useCollection,
|
|
10
|
+
useCurrencies,
|
|
11
|
+
useCurrencyOptions,
|
|
10
12
|
} from '../../../hooks';
|
|
11
13
|
import {
|
|
12
14
|
ActionModal,
|
|
@@ -49,7 +51,16 @@ const Modal = observer(() => {
|
|
|
49
51
|
collectionAddress,
|
|
50
52
|
collectibleId,
|
|
51
53
|
});
|
|
52
|
-
|
|
54
|
+
const currencyOptions = useCurrencyOptions({ collectionAddress });
|
|
55
|
+
const {
|
|
56
|
+
data: currencies,
|
|
57
|
+
isLoading: currenciesLoading,
|
|
58
|
+
isError: currenciesIsError,
|
|
59
|
+
} = useCurrencies({
|
|
60
|
+
chainId,
|
|
61
|
+
currencyOptions,
|
|
62
|
+
includeNativeCurrency: true,
|
|
63
|
+
});
|
|
53
64
|
const {
|
|
54
65
|
data: collection,
|
|
55
66
|
isLoading: collectionIsLoading,
|
|
@@ -91,7 +102,7 @@ const Modal = observer(() => {
|
|
|
91
102
|
steps$: steps$,
|
|
92
103
|
});
|
|
93
104
|
|
|
94
|
-
if (collectableIsLoading || collectionIsLoading) {
|
|
105
|
+
if (collectableIsLoading || collectionIsLoading || currenciesLoading) {
|
|
95
106
|
return (
|
|
96
107
|
<LoadingModal
|
|
97
108
|
isOpen={createListingModal$.isOpen.get()}
|
|
@@ -102,13 +113,25 @@ const Modal = observer(() => {
|
|
|
102
113
|
);
|
|
103
114
|
}
|
|
104
115
|
|
|
105
|
-
if (collectableIsError || collectionIsError) {
|
|
116
|
+
if (collectableIsError || collectionIsError || currenciesIsError) {
|
|
117
|
+
return (
|
|
118
|
+
<ErrorModal
|
|
119
|
+
isOpen={createListingModal$.isOpen.get()}
|
|
120
|
+
chainId={Number(chainId)}
|
|
121
|
+
onClose={createListingModal$.close}
|
|
122
|
+
title="List item for sale"
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!currencies || currencies.length === 0) {
|
|
106
128
|
return (
|
|
107
129
|
<ErrorModal
|
|
108
130
|
isOpen={createListingModal$.isOpen.get()}
|
|
109
131
|
chainId={Number(chainId)}
|
|
110
132
|
onClose={createListingModal$.close}
|
|
111
133
|
title="List item for sale"
|
|
134
|
+
message="No currencies are configured for the marketplace, contact the marketplace owners"
|
|
112
135
|
/>
|
|
113
136
|
);
|
|
114
137
|
}
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
useCollectible,
|
|
14
14
|
useCollection,
|
|
15
15
|
useBalanceOfCollectible,
|
|
16
|
+
useCurrencies,
|
|
17
|
+
useCurrencyOptions,
|
|
16
18
|
} from '../../../../hooks';
|
|
17
19
|
import { useCreateListing } from '../hooks/useCreateListing';
|
|
18
20
|
import { useWallet } from '../../../../_internal/wallet/useWallet';
|
|
@@ -27,6 +29,11 @@ vi.mock('../../../../hooks', () => ({
|
|
|
27
29
|
isLoading: false,
|
|
28
30
|
isError: false,
|
|
29
31
|
}),
|
|
32
|
+
useCurrencyOptions: vi.fn().mockReturnValue({
|
|
33
|
+
data: ['0x123'],
|
|
34
|
+
isLoading: false,
|
|
35
|
+
isError: false,
|
|
36
|
+
}),
|
|
30
37
|
useMarketplaceConfig: vi.fn().mockReturnValue({
|
|
31
38
|
data: {
|
|
32
39
|
collections: [
|
|
@@ -107,39 +114,29 @@ describe('CreateListingModal', () => {
|
|
|
107
114
|
expect(screen.queryByText('List item for sale')).toBeNull();
|
|
108
115
|
});
|
|
109
116
|
|
|
110
|
-
it('should render
|
|
117
|
+
it('should render main form when data is loaded', () => {
|
|
118
|
+
// Mock successful states for all required hooks
|
|
111
119
|
(useCollectible as any).mockReturnValue({
|
|
112
|
-
|
|
120
|
+
data: { decimals: 18, name: 'Test NFT' },
|
|
121
|
+
isLoading: false,
|
|
122
|
+
isError: false,
|
|
113
123
|
});
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
collectibleId: '1',
|
|
124
|
+
(useCollection as any).mockReturnValue({
|
|
125
|
+
data: { type: 'ERC721', name: 'Test Collection' },
|
|
126
|
+
isLoading: false,
|
|
127
|
+
isError: false,
|
|
119
128
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should render error state', () => {
|
|
127
|
-
(useCollectible as any).mockReturnValue({
|
|
128
|
-
isError: true,
|
|
129
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
130
|
+
data: ['0x123'],
|
|
131
|
+
isLoading: false,
|
|
132
|
+
isError: false,
|
|
129
133
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
collectibleId: '1',
|
|
134
|
+
(useCurrencies as any).mockReturnValue({
|
|
135
|
+
data: [{ address: '0x123', symbol: 'TEST', decimals: 18 }],
|
|
136
|
+
isLoading: false,
|
|
137
|
+
isError: false,
|
|
135
138
|
});
|
|
136
139
|
|
|
137
|
-
render(<CreateListingModal />);
|
|
138
|
-
const errorModal = screen.getByTestId('error-modal');
|
|
139
|
-
expect(errorModal).toBeVisible();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should render main form when data is loaded', () => {
|
|
143
140
|
createListingModal$.open({
|
|
144
141
|
collectionAddress: '0x123',
|
|
145
142
|
chainId: '1',
|
|
@@ -148,6 +145,9 @@ describe('CreateListingModal', () => {
|
|
|
148
145
|
|
|
149
146
|
render(<CreateListingModal />);
|
|
150
147
|
|
|
148
|
+
// Check for the modal title using a more specific selector
|
|
149
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
150
|
+
// Check for the collection name in the token preview
|
|
151
151
|
expect(screen.getByText('Test Collection')).toBeInTheDocument();
|
|
152
152
|
});
|
|
153
153
|
|
|
@@ -183,6 +183,28 @@ describe('CreateListingModal', () => {
|
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
it('should update state based on price input', async () => {
|
|
186
|
+
// Mock successful states for all required hooks
|
|
187
|
+
(useCollectible as any).mockReturnValue({
|
|
188
|
+
data: { decimals: 18, name: 'Test NFT' },
|
|
189
|
+
isLoading: false,
|
|
190
|
+
isError: false,
|
|
191
|
+
});
|
|
192
|
+
(useCollection as any).mockReturnValue({
|
|
193
|
+
data: { type: 'ERC721', name: 'Test Collection' },
|
|
194
|
+
isLoading: false,
|
|
195
|
+
isError: false,
|
|
196
|
+
});
|
|
197
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
198
|
+
data: ['0x123'],
|
|
199
|
+
isLoading: false,
|
|
200
|
+
isError: false,
|
|
201
|
+
});
|
|
202
|
+
(useCurrencies as any).mockReturnValue({
|
|
203
|
+
data: [{ address: '0x123', symbol: 'TEST', decimals: 18 }],
|
|
204
|
+
isLoading: false,
|
|
205
|
+
isError: false,
|
|
206
|
+
});
|
|
207
|
+
|
|
186
208
|
createListingModal$.open({
|
|
187
209
|
collectionAddress: '0x123',
|
|
188
210
|
chainId: '1',
|
|
@@ -194,8 +216,8 @@ describe('CreateListingModal', () => {
|
|
|
194
216
|
// Initial price should be 0
|
|
195
217
|
expect(createListingModal$.listingPrice.amountRaw.get()).toBe('0');
|
|
196
218
|
|
|
197
|
-
// Find and interact with price input
|
|
198
|
-
const priceInput = screen.getByRole('textbox', { name:
|
|
219
|
+
// Find and interact with price input using id
|
|
220
|
+
const priceInput = screen.getByRole('textbox', { name: /enter price/i });
|
|
199
221
|
expect(priceInput).toBeInTheDocument();
|
|
200
222
|
|
|
201
223
|
fireEvent.change(priceInput, { target: { value: '1.5' } });
|
|
@@ -205,4 +227,94 @@ describe('CreateListingModal', () => {
|
|
|
205
227
|
expect(createListingModal$.listingPrice.amountRaw.get()).not.toBe('0');
|
|
206
228
|
});
|
|
207
229
|
});
|
|
230
|
+
|
|
231
|
+
it('should show loading modal when data is being fetched', () => {
|
|
232
|
+
// Mock loading states for all required hooks
|
|
233
|
+
(useCollectible as any).mockReturnValue({
|
|
234
|
+
isLoading: true,
|
|
235
|
+
isError: false,
|
|
236
|
+
});
|
|
237
|
+
(useCollection as any).mockReturnValue({
|
|
238
|
+
isLoading: true,
|
|
239
|
+
isError: false,
|
|
240
|
+
});
|
|
241
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
242
|
+
isLoading: true,
|
|
243
|
+
isError: false,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
createListingModal$.open({
|
|
247
|
+
collectionAddress: '0x123',
|
|
248
|
+
chainId: '1',
|
|
249
|
+
collectibleId: '1',
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
render(<CreateListingModal />);
|
|
253
|
+
|
|
254
|
+
expect(screen.getByTestId('loading-modal')).toBeInTheDocument();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should show error modal when there is an error fetching data', () => {
|
|
258
|
+
// Mock error states for required hooks
|
|
259
|
+
(useCollectible as any).mockReturnValue({
|
|
260
|
+
isLoading: false,
|
|
261
|
+
isError: true,
|
|
262
|
+
});
|
|
263
|
+
(useCollection as any).mockReturnValue({
|
|
264
|
+
isLoading: false,
|
|
265
|
+
isError: false,
|
|
266
|
+
});
|
|
267
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
268
|
+
isLoading: false,
|
|
269
|
+
isError: false,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
createListingModal$.open({
|
|
273
|
+
collectionAddress: '0x123',
|
|
274
|
+
chainId: '1',
|
|
275
|
+
collectibleId: '1',
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
render(<CreateListingModal />);
|
|
279
|
+
|
|
280
|
+
expect(screen.getByText('Error loading item details')).toBeInTheDocument();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should show no ERC20 configured modal when currencies array is empty', () => {
|
|
284
|
+
// Reset all hooks to success state
|
|
285
|
+
(useCollectible as any).mockReturnValue({
|
|
286
|
+
data: { decimals: 18, name: 'Test NFT' },
|
|
287
|
+
isLoading: false,
|
|
288
|
+
isError: false,
|
|
289
|
+
});
|
|
290
|
+
(useCollection as any).mockReturnValue({
|
|
291
|
+
data: { type: 'ERC721', name: 'Test Collection' },
|
|
292
|
+
isLoading: false,
|
|
293
|
+
isError: false,
|
|
294
|
+
});
|
|
295
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
296
|
+
data: [],
|
|
297
|
+
isLoading: false,
|
|
298
|
+
isError: false,
|
|
299
|
+
});
|
|
300
|
+
(useCurrencies as any).mockReturnValue({
|
|
301
|
+
data: [],
|
|
302
|
+
isLoading: false,
|
|
303
|
+
isError: false,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
createListingModal$.open({
|
|
307
|
+
collectionAddress: '0x123',
|
|
308
|
+
chainId: '1',
|
|
309
|
+
collectibleId: '1',
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
render(<CreateListingModal />);
|
|
313
|
+
|
|
314
|
+
expect(
|
|
315
|
+
screen.getByText(
|
|
316
|
+
'No currencies are configured for the marketplace, contact the marketplace owners',
|
|
317
|
+
),
|
|
318
|
+
).toBeInTheDocument();
|
|
319
|
+
});
|
|
208
320
|
});
|
|
@@ -12,7 +12,14 @@ import {
|
|
|
12
12
|
Text,
|
|
13
13
|
} from '@0xsequence/design-system';
|
|
14
14
|
import { observer } from '@legendapp/state/react';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
Close,
|
|
17
|
+
Content,
|
|
18
|
+
Overlay,
|
|
19
|
+
Portal,
|
|
20
|
+
Root,
|
|
21
|
+
Title,
|
|
22
|
+
} from '@radix-ui/react-dialog';
|
|
16
23
|
import { getProviderEl } from '../../../../../_internal';
|
|
17
24
|
import {
|
|
18
25
|
closeButton,
|
|
@@ -77,16 +84,18 @@ export const ActionModal = observer(
|
|
|
77
84
|
gap="4"
|
|
78
85
|
position={'relative'}
|
|
79
86
|
>
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
<Title asChild>
|
|
88
|
+
<Text
|
|
89
|
+
fontSize="medium"
|
|
90
|
+
fontWeight="bold"
|
|
91
|
+
textAlign="center"
|
|
92
|
+
width="full"
|
|
93
|
+
color="text100"
|
|
94
|
+
fontFamily="body"
|
|
95
|
+
>
|
|
96
|
+
{title}
|
|
97
|
+
</Text>
|
|
98
|
+
</Title>
|
|
90
99
|
|
|
91
100
|
{children}
|
|
92
101
|
|