@0xsequence/marketplace-sdk 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2OJB35FS.js → chunk-5NORRVPM.js} +5 -5
- package/dist/{chunk-2OJB35FS.js.map → chunk-5NORRVPM.js.map} +1 -1
- package/dist/{chunk-ATDCYXXV.js → chunk-6YHHCGGY.js} +2 -2
- package/dist/{chunk-WRMJ5FZM.js → chunk-HV2X2VZN.js} +874 -194
- package/dist/chunk-HV2X2VZN.js.map +1 -0
- package/dist/{chunk-AQT3BQ67.js → chunk-J2XJZ6SJ.js} +12 -5
- package/dist/chunk-J2XJZ6SJ.js.map +1 -0
- package/dist/{chunk-JEOUQFT3.js → chunk-LJAB3S6U.js} +4 -3
- package/dist/chunk-LJAB3S6U.js.map +1 -0
- package/dist/{chunk-7WCZP6FN.js → chunk-OUVFTA63.js} +649 -386
- package/dist/chunk-OUVFTA63.js.map +1 -0
- package/dist/{chunk-XXML5K3X.js → chunk-QTJF5GDQ.js} +2 -2
- package/dist/{chunk-LF44FCG5.js → chunk-TQWM4ER6.js} +2 -2
- package/dist/{chunk-LF44FCG5.js.map → chunk-TQWM4ER6.js.map} +1 -1
- package/dist/{chunk-6R4G7J6Q.js → chunk-WSCUPAGR.js} +33 -5
- package/dist/chunk-WSCUPAGR.js.map +1 -0
- package/dist/{create-config-D5WqfUft.d.ts → create-config-BXvwUh55.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-znEu4L0K.d.ts} +1 -1
- package/dist/{marketplace.gen-B8S8fflj.d.ts → marketplace.gen-CCJ-URn2.d.ts} +16 -4
- package/dist/react/_internal/api/index.d.ts +3 -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 +249 -74
- package/dist/react/hooks/index.js +18 -5
- 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 +22 -9
- package/dist/react/ssr/index.js +4 -0
- package/dist/react/ssr/index.js.map +1 -1
- 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 +8 -9
- package/dist/react/ui/icons/index.js +3 -3
- 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 +8 -9
- package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +3 -3
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +5 -5
- package/dist/{sdk-config-BXVH8PS2.d.ts → sdk-config-B32_2bG3.d.ts} +29 -7
- package/dist/{services-CdXAIjt1.d.ts → services-BRBVE0mm.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 +2 -2
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +1 -1
- package/dist/{types-eX4P9xju.d.ts → types-Yto6KrTN.d.ts} +2 -2
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +1 -1
- package/package.json +16 -16
- package/src/react/_internal/api/__mocks__/marketplace.msw.ts +4 -0
- package/src/react/_internal/api/marketplace.gen.ts +45 -7
- package/src/react/_internal/api/query-keys.ts +4 -0
- package/src/react/_internal/wallet/useWallet.ts +30 -46
- package/src/react/_internal/wallet/wallet.ts +52 -6
- package/src/react/hooks/index.ts +4 -0
- package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +10 -1
- package/src/react/hooks/useAutoSelectFeeOption.tsx +104 -0
- package/src/react/hooks/useCancelOrder.tsx +57 -1
- package/src/react/hooks/useCollectionBalanceDetails.tsx +87 -0
- 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 +35 -18
- 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/useBuyCollectable.ts +7 -4
- 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/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +5 -1
- 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
- /package/dist/{chunk-ATDCYXXV.js.map → chunk-6YHHCGGY.js.map} +0 -0
- /package/dist/{chunk-XXML5K3X.js.map → chunk-QTJF5GDQ.js.map} +0 -0
|
@@ -2,7 +2,6 @@ import { useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { Box, IconButton, Skeleton } from '@0xsequence/design-system';
|
|
4
4
|
import type { Hex } from 'viem';
|
|
5
|
-
import { useAccount } from 'wagmi';
|
|
6
5
|
import type {
|
|
7
6
|
ChainId,
|
|
8
7
|
CollectibleOrder,
|
|
@@ -10,7 +9,7 @@ import type {
|
|
|
10
9
|
Order,
|
|
11
10
|
OrderbookKind,
|
|
12
11
|
} from '../../../_internal';
|
|
13
|
-
import { useCurrency
|
|
12
|
+
import { useCurrency } from '../../../hooks';
|
|
14
13
|
import SvgDiamondEyeIcon from '../../icons/DiamondEye';
|
|
15
14
|
import ChessTileImage from '../../images/chess-tile.png';
|
|
16
15
|
import { ActionButton } from '../_internals/action-button/ActionButton';
|
|
@@ -63,6 +62,23 @@ type CollectibleCardProps = {
|
|
|
63
62
|
onOfferClick?: ({ order }: { order?: Order }) => void;
|
|
64
63
|
balance?: string;
|
|
65
64
|
cardLoading?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Callback function that is called when the user attempts to perform an action
|
|
67
|
+
* (such as buying or making an offer) that they are not permitted to do.
|
|
68
|
+
*
|
|
69
|
+
* This function is invoked in the following scenario:
|
|
70
|
+
*
|
|
71
|
+
* - When a disconnected user clicks on "Buy Now" and is prompted to connect
|
|
72
|
+
* their wallet. After connecting, if it is determined that the user is
|
|
73
|
+
* already the owner of the collectible, this callback is triggered to inform
|
|
74
|
+
* them that they cannot perform the action (e.g., buying their own collectible).
|
|
75
|
+
*
|
|
76
|
+
* @param action - The action that the user cannot perform, which can be either
|
|
77
|
+
* CollectibleCardAction.BUY or CollectibleCardAction.OFFER.
|
|
78
|
+
*/
|
|
79
|
+
onCannotPerformAction?: (
|
|
80
|
+
action: CollectibleCardAction.BUY | CollectibleCardAction.OFFER,
|
|
81
|
+
) => void;
|
|
66
82
|
};
|
|
67
83
|
|
|
68
84
|
export function CollectibleCard({
|
|
@@ -76,16 +92,11 @@ export function CollectibleCard({
|
|
|
76
92
|
onOfferClick,
|
|
77
93
|
balance,
|
|
78
94
|
cardLoading,
|
|
95
|
+
onCannotPerformAction,
|
|
79
96
|
}: CollectibleCardProps) {
|
|
80
|
-
const { address: accountAddress } = useAccount();
|
|
81
97
|
const collectibleMetadata = lowestListing?.metadata;
|
|
98
|
+
const highestOffer = lowestListing?.offer
|
|
82
99
|
const [imageLoadingError, setImageLoadingError] = useState(false);
|
|
83
|
-
const { data: highestOffer, isLoading: highestOfferLoading } =
|
|
84
|
-
useHighestOffer({
|
|
85
|
-
chainId: String(chainId),
|
|
86
|
-
collectionAddress,
|
|
87
|
-
tokenId: collectibleId,
|
|
88
|
-
});
|
|
89
100
|
|
|
90
101
|
const { data: lowestListingCurrency } = useCurrency({
|
|
91
102
|
chainId,
|
|
@@ -95,13 +106,13 @@ export function CollectibleCard({
|
|
|
95
106
|
enabled: !!lowestListing?.order?.priceCurrencyAddress,
|
|
96
107
|
},
|
|
97
108
|
});
|
|
98
|
-
if (
|
|
109
|
+
if (cardLoading) {
|
|
99
110
|
return <CollectibleSkeleton />;
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
const action = (
|
|
103
114
|
balance
|
|
104
|
-
? (highestOffer
|
|
115
|
+
? (highestOffer && CollectibleCardAction.SELL) ||
|
|
105
116
|
(!lowestListing?.order && CollectibleCardAction.LIST) ||
|
|
106
117
|
CollectibleCardAction.TRANSFER
|
|
107
118
|
: (lowestListing?.order && CollectibleCardAction.BUY) ||
|
|
@@ -118,6 +129,7 @@ export function CollectibleCard({
|
|
|
118
129
|
borderRadius="md"
|
|
119
130
|
overflow="hidden"
|
|
120
131
|
background="backgroundPrimary"
|
|
132
|
+
tabIndex={0}
|
|
121
133
|
>
|
|
122
134
|
<Box
|
|
123
135
|
display="flex"
|
|
@@ -134,11 +146,15 @@ export function CollectibleCard({
|
|
|
134
146
|
padding="0"
|
|
135
147
|
className={collectibleTileWrapper}
|
|
136
148
|
>
|
|
137
|
-
<article
|
|
149
|
+
<article
|
|
150
|
+
style={{ width: '100%', display: 'flex', flexDirection: 'column' }}
|
|
151
|
+
>
|
|
138
152
|
{externalUrl && (
|
|
139
153
|
<IconButton
|
|
140
154
|
as="a"
|
|
141
155
|
href={externalUrl}
|
|
156
|
+
target="_blank"
|
|
157
|
+
rel="noopener noreferrer"
|
|
142
158
|
size="sm"
|
|
143
159
|
backdropFilter="blur"
|
|
144
160
|
variant="glass"
|
|
@@ -146,6 +162,7 @@ export function CollectibleCard({
|
|
|
146
162
|
e.stopPropagation();
|
|
147
163
|
}}
|
|
148
164
|
position="absolute"
|
|
165
|
+
zIndex="20"
|
|
149
166
|
top="2"
|
|
150
167
|
left="2"
|
|
151
168
|
icon={SvgDiamondEyeIcon}
|
|
@@ -162,15 +179,14 @@ export function CollectibleCard({
|
|
|
162
179
|
<Footer
|
|
163
180
|
name={name || ''}
|
|
164
181
|
type={collectionType}
|
|
165
|
-
onOfferClick={() => onOfferClick?.({ order: highestOffer
|
|
166
|
-
highestOffer={highestOffer
|
|
182
|
+
onOfferClick={() => onOfferClick?.({ order: highestOffer })}
|
|
183
|
+
highestOffer={highestOffer}
|
|
167
184
|
lowestListingPriceAmount={lowestListing?.order?.priceAmount}
|
|
168
185
|
lowestListingCurrency={lowestListingCurrency}
|
|
169
186
|
balance={balance}
|
|
170
|
-
isAnimated={!!action}
|
|
171
187
|
/>
|
|
172
188
|
|
|
173
|
-
{
|
|
189
|
+
{(highestOffer || lowestListing) && (
|
|
174
190
|
<Box
|
|
175
191
|
display="flex"
|
|
176
192
|
alignItems="center"
|
|
@@ -184,9 +200,10 @@ export function CollectibleCard({
|
|
|
184
200
|
tokenId={collectibleId}
|
|
185
201
|
orderbookKind={orderbookKind}
|
|
186
202
|
action={action}
|
|
187
|
-
highestOffer={highestOffer
|
|
203
|
+
highestOffer={highestOffer}
|
|
188
204
|
lowestListing={lowestListing?.order}
|
|
189
|
-
|
|
205
|
+
owned={!!balance}
|
|
206
|
+
onCannotPerformAction={onCannotPerformAction}
|
|
190
207
|
/>
|
|
191
208
|
</Box>
|
|
192
209
|
)}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Box, IconButton, Image, Text } from '@0xsequence/design-system';
|
|
2
2
|
import { formatUnits } from 'viem';
|
|
3
|
-
import { useAccount } from 'wagmi';
|
|
4
3
|
import { ContractType, type Currency, type Order } from '../../../_internal';
|
|
5
4
|
import SvgBellIcon from '../../icons/Bell';
|
|
6
5
|
import { footer, offerBellButton } from './styles.css';
|
|
@@ -13,7 +12,6 @@ type FooterProps = {
|
|
|
13
12
|
lowestListingPriceAmount?: string;
|
|
14
13
|
lowestListingCurrency?: Currency;
|
|
15
14
|
balance?: string;
|
|
16
|
-
isAnimated?: boolean;
|
|
17
15
|
};
|
|
18
16
|
|
|
19
17
|
export const Footer = ({
|
|
@@ -24,9 +22,7 @@ export const Footer = ({
|
|
|
24
22
|
lowestListingPriceAmount,
|
|
25
23
|
lowestListingCurrency,
|
|
26
24
|
balance,
|
|
27
|
-
isAnimated,
|
|
28
25
|
}: FooterProps) => {
|
|
29
|
-
const { address } = useAccount();
|
|
30
26
|
const listed = !!lowestListingPriceAmount && !!lowestListingCurrency;
|
|
31
27
|
|
|
32
28
|
if (name.length > 15 && highestOffer) {
|
|
@@ -45,7 +41,7 @@ export const Footer = ({
|
|
|
45
41
|
padding="4"
|
|
46
42
|
whiteSpace="nowrap"
|
|
47
43
|
position="relative"
|
|
48
|
-
className={
|
|
44
|
+
className={footer}
|
|
49
45
|
>
|
|
50
46
|
<Box
|
|
51
47
|
display="flex"
|
|
@@ -60,8 +56,9 @@ export const Footer = ({
|
|
|
60
56
|
fontWeight="bold"
|
|
61
57
|
textAlign="left"
|
|
62
58
|
fontFamily="body"
|
|
59
|
+
visibility={name ? 'visible' : 'hidden'}
|
|
63
60
|
>
|
|
64
|
-
{name}
|
|
61
|
+
{name || 'Untitled'}
|
|
65
62
|
</Text>
|
|
66
63
|
|
|
67
64
|
{highestOffer && onOfferClick && (
|
|
@@ -82,8 +79,8 @@ export const Footer = ({
|
|
|
82
79
|
</Box>
|
|
83
80
|
|
|
84
81
|
<Box display="flex" alignItems="center" gap="1">
|
|
85
|
-
{listed && (
|
|
86
|
-
<Image src={lowestListingCurrency
|
|
82
|
+
{listed && lowestListingCurrency.imageUrl && (
|
|
83
|
+
<Image src={lowestListingCurrency.imageUrl} width="3" height="3" />
|
|
87
84
|
)}
|
|
88
85
|
|
|
89
86
|
<Text
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { atoms } from '@0xsequence/design-system';
|
|
2
|
-
import { style
|
|
2
|
+
import { style } from '@vanilla-extract/css';
|
|
3
3
|
|
|
4
4
|
export const collectibleCard = style([
|
|
5
5
|
{
|
|
6
6
|
width: '175px',
|
|
7
7
|
border: '1px solid hsla(0, 0%, 31%, 1)',
|
|
8
|
+
':active': {
|
|
9
|
+
border: '1px solid hsla(247, 100%, 75%, 1)',
|
|
10
|
+
boxShadow: '0px 0px 0px 1px hsla(247, 100%, 75%, 1)',
|
|
11
|
+
},
|
|
12
|
+
':focus-visible': {
|
|
13
|
+
border: '1px solid hsla(247, 100%, 75%, 1)',
|
|
14
|
+
boxShadow: '0px 0px 0px 2px hsla(247, 100%, 75%, 1)',
|
|
15
|
+
outline: '4px solid hsla(254, 100%, 57%, 1)',
|
|
16
|
+
outlineOffset: '2px',
|
|
17
|
+
},
|
|
8
18
|
},
|
|
9
19
|
]);
|
|
10
20
|
|
|
11
|
-
export const collectibleImage = style({
|
|
12
|
-
width: '175px',
|
|
13
|
-
height: '175px',
|
|
14
|
-
objectFit: 'cover',
|
|
15
|
-
});
|
|
16
|
-
|
|
17
21
|
export const collectibleTileWrapper = style({
|
|
18
22
|
padding: 0,
|
|
19
23
|
border: 'none',
|
|
@@ -24,6 +28,24 @@ export const collectibleTileWrapper = style({
|
|
|
24
28
|
'&:focus': {
|
|
25
29
|
outline: 'none',
|
|
26
30
|
},
|
|
31
|
+
|
|
32
|
+
[`${collectibleCard}:focus &`]: {
|
|
33
|
+
outline: '3px solid black',
|
|
34
|
+
outlineOffset: '-3px',
|
|
35
|
+
borderRadius: 10,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const collectibleImage = style({
|
|
41
|
+
width: '175px',
|
|
42
|
+
height: '175px',
|
|
43
|
+
objectFit: 'cover',
|
|
44
|
+
transition: 'transform 0.2s ease-in-out',
|
|
45
|
+
selectors: {
|
|
46
|
+
[`${collectibleTileWrapper}:hover &`]: {
|
|
47
|
+
transform: 'scale(1.165)',
|
|
48
|
+
},
|
|
27
49
|
},
|
|
28
50
|
});
|
|
29
51
|
|
|
@@ -32,31 +54,22 @@ export const offerBellButton = style({
|
|
|
32
54
|
height: '22px',
|
|
33
55
|
});
|
|
34
56
|
|
|
35
|
-
const
|
|
57
|
+
export const footer = style([atoms({ background: 'backgroundPrimary' })]);
|
|
36
58
|
|
|
37
|
-
export const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
59
|
+
export const actionWrapper = style([
|
|
60
|
+
atoms({
|
|
61
|
+
backdropFilter: 'blur',
|
|
62
|
+
}),
|
|
63
|
+
{
|
|
64
|
+
background: 'hsla(0, 0%, 100%, 0.1)',
|
|
65
|
+
transition: 'transform 0.2s ease-in-out',
|
|
66
|
+
position: 'absolute',
|
|
67
|
+
width: '100%',
|
|
68
|
+
bottom: -44,
|
|
69
|
+
selectors: {
|
|
70
|
+
[`${collectibleTileWrapper}:hover &`]: {
|
|
71
|
+
transform: 'translateY(-44px)',
|
|
46
72
|
},
|
|
47
73
|
},
|
|
48
|
-
],
|
|
49
|
-
static: [footerBase],
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
export const actionWrapper = style({
|
|
53
|
-
transition: 'transform 0.2s ease-in-out',
|
|
54
|
-
position: 'absolute',
|
|
55
|
-
width: '100%',
|
|
56
|
-
bottom: -36,
|
|
57
|
-
selectors: {
|
|
58
|
-
[`${collectibleTileWrapper}:hover &`]: {
|
|
59
|
-
transform: 'translateY(-36px)',
|
|
60
|
-
},
|
|
61
74
|
},
|
|
62
|
-
|
|
75
|
+
]);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Box, type IconProps } from '@0xsequence/design-system';
|
|
2
|
+
import { iconVariants } from './styles.css';
|
|
3
|
+
|
|
4
|
+
const Svg = () => (
|
|
5
|
+
<svg
|
|
6
|
+
width="20"
|
|
7
|
+
height="20"
|
|
8
|
+
viewBox="0 0 20 20"
|
|
9
|
+
fill="none"
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
role="img"
|
|
12
|
+
aria-labelledby="cart-title"
|
|
13
|
+
>
|
|
14
|
+
<title id="cart-title">Cart Icon</title>
|
|
15
|
+
<path
|
|
16
|
+
fillRule="evenodd"
|
|
17
|
+
clipRule="evenodd"
|
|
18
|
+
d="M2.5 3.46836C2.5 3.20969 2.72366 3 2.99955 3H5.16925C5.88938 3 6.5077 3.48022 6.64172 4.14359L8.33188 12.5093C8.37655 12.7304 8.58266 12.8905 8.8227 12.8905H16.987C17.2629 12.8905 17.4866 13.1002 17.4866 13.3589C17.4866 13.6175 17.2629 13.8272 16.987 13.8272H8.8227C8.10257 13.8272 7.48425 13.347 7.35023 12.6836L5.66007 4.31793C5.6154 4.0968 5.40929 3.93673 5.16925 3.93673H2.99955C2.72366 3.93673 2.5 3.72704 2.5 3.46836Z"
|
|
19
|
+
fill="white"
|
|
20
|
+
/>
|
|
21
|
+
<path
|
|
22
|
+
d="M18.0003 5.34182H6.40946L7.49564 10.8234H17.0736C17.3133 10.8234 17.5193 10.6637 17.5643 10.443L18.491 5.89813C18.5498 5.60942 18.3138 5.34182 18.0003 5.34182Z"
|
|
23
|
+
fill="white"
|
|
24
|
+
/>
|
|
25
|
+
<path
|
|
26
|
+
d="M10.0889 15.8559C10.0889 16.4878 9.54259 17 8.86866 17C8.19473 17 7.64841 16.4878 7.64841 15.8559C7.64841 15.2241 8.19473 14.7119 8.86866 14.7119C9.54259 14.7119 10.0889 15.2241 10.0889 15.8559Z"
|
|
27
|
+
fill="white"
|
|
28
|
+
/>
|
|
29
|
+
<path
|
|
30
|
+
d="M16.6268 15.8559C16.6268 16.4878 16.0804 17 15.4065 17C14.7326 17 14.1863 16.4878 14.1863 15.8559C14.1863 15.2241 14.7326 14.7119 15.4065 14.7119C16.0804 14.7119 16.6268 15.2241 16.6268 15.8559Z"
|
|
31
|
+
fill="white"
|
|
32
|
+
/>
|
|
33
|
+
</svg>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const SvgCartIcon = ({ size = 'sm', ...props }: IconProps) => (
|
|
37
|
+
<Box
|
|
38
|
+
as={Svg}
|
|
39
|
+
className={iconVariants({
|
|
40
|
+
size,
|
|
41
|
+
})}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export default SvgCartIcon;
|
|
@@ -24,7 +24,6 @@ const BuyModalContent = () => {
|
|
|
24
24
|
buyModal$.state.order.collectionContractAddress,
|
|
25
25
|
) as Hex;
|
|
26
26
|
const collectibleId = use$(buyModal$.state.order.tokenId);
|
|
27
|
-
const modalId = use$(buyModal$.state.modalId);
|
|
28
27
|
const callbacks = use$(buyModal$.callbacks);
|
|
29
28
|
const order = use$(buyModal$.state.order);
|
|
30
29
|
const isOpen = use$(buyModal$.isOpen);
|
|
@@ -94,7 +93,6 @@ const BuyModalContent = () => {
|
|
|
94
93
|
|
|
95
94
|
return collection.type === ContractType.ERC721 ? (
|
|
96
95
|
<CheckoutModal
|
|
97
|
-
key={modalId}
|
|
98
96
|
buy={buyAction}
|
|
99
97
|
collectable={collectable as TokenMetadata}
|
|
100
98
|
order={order}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import {
|
|
3
|
+
render,
|
|
4
|
+
screen,
|
|
5
|
+
cleanup,
|
|
6
|
+
waitFor,
|
|
7
|
+
} from '../../../../_internal/test-utils';
|
|
8
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
9
|
+
import { BuyModal } from '../Modal';
|
|
10
|
+
import { buyModal$ } from '../store';
|
|
11
|
+
import { useLoadData } from '../hooks/useLoadData';
|
|
12
|
+
import { useBuyCollectable } from '../hooks/useBuyCollectable';
|
|
13
|
+
import type { Mock } from 'vitest';
|
|
14
|
+
import type { Order } from '../../../../_internal';
|
|
15
|
+
import { MarketplaceKind } from '../../../../_internal';
|
|
16
|
+
import { ContractType } from '../../../../_internal';
|
|
17
|
+
|
|
18
|
+
const mockOrder = {
|
|
19
|
+
orderId: '1',
|
|
20
|
+
priceAmount: '1000000000000000000',
|
|
21
|
+
priceCurrencyAddress: '0x0',
|
|
22
|
+
quantityRemaining: '1',
|
|
23
|
+
createdAt: new Date().toISOString(),
|
|
24
|
+
marketplace: MarketplaceKind.sequence_marketplace_v2,
|
|
25
|
+
} as Order;
|
|
26
|
+
|
|
27
|
+
vi.mock('../hooks/useLoadData', () => ({
|
|
28
|
+
useLoadData: vi.fn(),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
vi.mock('../hooks/useBuyCollectable', () => ({
|
|
32
|
+
useBuyCollectable: vi.fn(),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
describe('BuyModal', () => {
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
vi.clearAllMocks();
|
|
38
|
+
|
|
39
|
+
(useLoadData as Mock).mockReturnValue({
|
|
40
|
+
collection: null,
|
|
41
|
+
collectable: null,
|
|
42
|
+
checkoutOptions: null,
|
|
43
|
+
isLoading: false,
|
|
44
|
+
isError: false,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
(useBuyCollectable as Mock).mockReturnValue({
|
|
48
|
+
buy: vi.fn(),
|
|
49
|
+
isLoading: false,
|
|
50
|
+
isError: false,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
buyModal$.close();
|
|
54
|
+
|
|
55
|
+
cleanup();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should not render when isOpen is false', () => {
|
|
59
|
+
render(<BuyModal />);
|
|
60
|
+
|
|
61
|
+
expect(screen.queryByText('Loading Sequence Pay')).not.toBeInTheDocument();
|
|
62
|
+
expect(screen.queryByText('Checkout')).not.toBeInTheDocument();
|
|
63
|
+
expect(screen.queryByText('Select Quantity')).not.toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should render error modal when there is an error', async () => {
|
|
67
|
+
const mockOrderBasic = {
|
|
68
|
+
...mockOrder,
|
|
69
|
+
marketplace: MarketplaceKind.sequence_marketplace_v2,
|
|
70
|
+
collectionContractAddress: '0x123',
|
|
71
|
+
tokenId: '1',
|
|
72
|
+
quantityRemaining: '1',
|
|
73
|
+
priceCurrencyAddress: '0x0',
|
|
74
|
+
chainId: 1,
|
|
75
|
+
priceAmount: '1000000000000000000',
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Test loading error
|
|
79
|
+
(useLoadData as Mock).mockReturnValue({
|
|
80
|
+
collection: { type: ContractType.ERC721 },
|
|
81
|
+
collectable: { decimals: 0 },
|
|
82
|
+
checkoutOptions: { someOption: true },
|
|
83
|
+
isLoading: false,
|
|
84
|
+
isError: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
buyModal$.open({
|
|
88
|
+
order: mockOrderBasic,
|
|
89
|
+
callbacks: {},
|
|
90
|
+
chainId: '1',
|
|
91
|
+
collectionAddress: '0x123',
|
|
92
|
+
tokenId: '1',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
render(<BuyModal />);
|
|
96
|
+
|
|
97
|
+
// Should show error modal
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
expect(screen.getByTestId('error-modal')).toBeInTheDocument();
|
|
100
|
+
expect(
|
|
101
|
+
screen.getByText('Error loading item details'),
|
|
102
|
+
).toBeInTheDocument();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Cleanup
|
|
106
|
+
cleanup();
|
|
107
|
+
|
|
108
|
+
// Test buy error
|
|
109
|
+
(useLoadData as Mock).mockReturnValue({
|
|
110
|
+
collection: { type: ContractType.ERC721 },
|
|
111
|
+
collectable: { decimals: 0 },
|
|
112
|
+
checkoutOptions: { someOption: true },
|
|
113
|
+
isLoading: false,
|
|
114
|
+
isError: false,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
(useBuyCollectable as Mock).mockReturnValue({
|
|
118
|
+
buy: vi.fn(),
|
|
119
|
+
isLoading: false,
|
|
120
|
+
isError: true,
|
|
121
|
+
status: 'error',
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
buyModal$.open({
|
|
125
|
+
order: mockOrderBasic,
|
|
126
|
+
callbacks: {},
|
|
127
|
+
chainId: '1',
|
|
128
|
+
collectionAddress: '0x123',
|
|
129
|
+
tokenId: '1',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
render(<BuyModal />);
|
|
133
|
+
|
|
134
|
+
// Should show error modal for buy error too
|
|
135
|
+
expect(screen.getByText('Error')).toBeInTheDocument();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should render ERC1155QuantityModal when contract type is ERC1155', async () => {
|
|
139
|
+
const mockOrderERC1155 = {
|
|
140
|
+
...mockOrder,
|
|
141
|
+
marketplace: MarketplaceKind.sequence_marketplace_v2,
|
|
142
|
+
collectionContractAddress: '0x123',
|
|
143
|
+
tokenId: '1',
|
|
144
|
+
quantityRemaining: '10',
|
|
145
|
+
priceCurrencyAddress: '0x0',
|
|
146
|
+
chainId: 1,
|
|
147
|
+
quantityDecimals: 0,
|
|
148
|
+
priceAmount: '1000000000000000000',
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
(useLoadData as Mock).mockReturnValue({
|
|
152
|
+
collection: { type: ContractType.ERC1155 },
|
|
153
|
+
collectable: { decimals: 0 },
|
|
154
|
+
checkoutOptions: { someOption: true },
|
|
155
|
+
isLoading: false,
|
|
156
|
+
isError: false,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
(useBuyCollectable as Mock).mockReturnValue({
|
|
160
|
+
buy: vi.fn(),
|
|
161
|
+
isLoading: false,
|
|
162
|
+
isError: false,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
buyModal$.open({
|
|
166
|
+
order: mockOrderERC1155,
|
|
167
|
+
callbacks: {},
|
|
168
|
+
chainId: '1',
|
|
169
|
+
collectionAddress: '0x123',
|
|
170
|
+
tokenId: '1',
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Initialize quantity state
|
|
174
|
+
buyModal$.state.quantity.set('1');
|
|
175
|
+
buyModal$.state.checkoutModalLoaded.set(false);
|
|
176
|
+
buyModal$.state.checkoutModalIsLoading.set(false);
|
|
177
|
+
|
|
178
|
+
render(<BuyModal />);
|
|
179
|
+
|
|
180
|
+
await waitFor(() => {
|
|
181
|
+
expect(screen.getByText('Select Quantity')).toBeInTheDocument();
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should not render ERC1155QuantityModal when contract type is ERC721', async () => {
|
|
186
|
+
const mockBuy = vi.fn();
|
|
187
|
+
const mockOrderERC721 = {
|
|
188
|
+
...mockOrder,
|
|
189
|
+
marketplace: MarketplaceKind.sequence_marketplace_v2,
|
|
190
|
+
collectionContractAddress: '0x123',
|
|
191
|
+
tokenId: '1',
|
|
192
|
+
quantityRemaining: '1',
|
|
193
|
+
priceCurrencyAddress: '0x0',
|
|
194
|
+
chainId: 1,
|
|
195
|
+
priceAmount: '1000000000000000000',
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// First, mock loading state
|
|
199
|
+
(useLoadData as Mock).mockReturnValue({
|
|
200
|
+
collection: null,
|
|
201
|
+
collectable: null,
|
|
202
|
+
checkoutOptions: null,
|
|
203
|
+
isLoading: true,
|
|
204
|
+
isError: false,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
(useBuyCollectable as Mock).mockReturnValue({
|
|
208
|
+
buy: mockBuy,
|
|
209
|
+
isLoading: false,
|
|
210
|
+
isError: false,
|
|
211
|
+
status: 'ready',
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
buyModal$.open({
|
|
215
|
+
order: mockOrderERC721,
|
|
216
|
+
callbacks: {},
|
|
217
|
+
chainId: '1',
|
|
218
|
+
collectionAddress: '0x123',
|
|
219
|
+
tokenId: '1',
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const { rerender } = render(<BuyModal />);
|
|
223
|
+
|
|
224
|
+
// Verify loading modal is shown
|
|
225
|
+
expect(screen.getByText('Loading Sequence Pay')).toBeInTheDocument();
|
|
226
|
+
|
|
227
|
+
// Then update the mock to simulate data loaded
|
|
228
|
+
(useLoadData as Mock).mockReturnValue({
|
|
229
|
+
collection: { type: ContractType.ERC721 },
|
|
230
|
+
collectable: { decimals: 0 },
|
|
231
|
+
checkoutOptions: { someOption: true },
|
|
232
|
+
isLoading: false,
|
|
233
|
+
isError: false,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Force a re-render with the new mock values
|
|
237
|
+
rerender(<BuyModal />);
|
|
238
|
+
|
|
239
|
+
// Wait for loading to complete and verify the rest of the flow
|
|
240
|
+
await waitFor(() => {
|
|
241
|
+
expect(mockBuy).toHaveBeenCalledWith({
|
|
242
|
+
orderId: mockOrderERC721.orderId,
|
|
243
|
+
collectableDecimals: 0,
|
|
244
|
+
quantity: '1',
|
|
245
|
+
marketplace: mockOrderERC721.marketplace,
|
|
246
|
+
checkoutOptions: { someOption: true },
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
expect(screen.queryByText('Loading Sequence Pay')).not.toBeInTheDocument();
|
|
251
|
+
expect(screen.queryByText('Select Quantity')).not.toBeInTheDocument();
|
|
252
|
+
});
|
|
253
|
+
});
|