@0xsequence/marketplace-sdk 0.4.0 → 0.4.1

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 (133) hide show
  1. package/dist/{chunk-P3EQRM7K.js → chunk-5GDO4ZBC.js} +5 -4
  2. package/dist/{chunk-P3EQRM7K.js.map → chunk-5GDO4ZBC.js.map} +1 -1
  3. package/dist/{chunk-QTQH5I2E.js → chunk-EVRILXOH.js} +2 -2
  4. package/dist/chunk-EVRILXOH.js.map +1 -0
  5. package/dist/{chunk-GVDLVCR5.js → chunk-GSDUAHL3.js} +1 -1
  6. package/dist/chunk-GSDUAHL3.js.map +1 -0
  7. package/dist/{chunk-6HEMV2OR.js → chunk-IOTKCWOB.js} +890 -644
  8. package/dist/chunk-IOTKCWOB.js.map +1 -0
  9. package/dist/{chunk-AY2MZHZN.js → chunk-KNX2LER4.js} +5 -6
  10. package/dist/{chunk-PAHT6PTD.js.map → chunk-KNX2LER4.js.map} +1 -1
  11. package/dist/{chunk-SBVLWSRZ.js → chunk-LF44FCG5.js} +2 -2
  12. package/dist/{chunk-SBVLWSRZ.js.map → chunk-LF44FCG5.js.map} +1 -1
  13. package/dist/{chunk-PAHT6PTD.js → chunk-LSMQVX77.js} +5 -6
  14. package/dist/{chunk-AY2MZHZN.js.map → chunk-LSMQVX77.js.map} +1 -1
  15. package/dist/{chunk-6AYHE7ZA.js → chunk-MIYMMP2K.js} +79 -33
  16. package/dist/chunk-MIYMMP2K.js.map +1 -0
  17. package/dist/{chunk-EK5ZSW4M.js → chunk-QMO2CUNM.js} +2 -2
  18. package/dist/{chunk-L6GSYPCR.js → chunk-RZSZNVEH.js} +5 -5
  19. package/dist/{chunk-L6GSYPCR.js.map → chunk-RZSZNVEH.js.map} +1 -1
  20. package/dist/chunk-T5T6JNB2.js +171 -0
  21. package/dist/chunk-T5T6JNB2.js.map +1 -0
  22. package/dist/chunk-UPLTM63S.js +435 -0
  23. package/dist/chunk-UPLTM63S.js.map +1 -0
  24. package/dist/{chunk-Y7YO5TLE.js → chunk-XXML5K3X.js} +5 -2
  25. package/dist/chunk-XXML5K3X.js.map +1 -0
  26. package/dist/{create-config-CgtmCzvb.d.ts → create-config-8sffBvlt.d.ts} +1 -1
  27. package/dist/index.js +4 -4
  28. package/dist/react/_internal/api/index.js +2 -2
  29. package/dist/react/_internal/index.d.ts +1 -1
  30. package/dist/react/_internal/index.js +3 -3
  31. package/dist/react/_internal/wagmi/index.d.ts +1 -1
  32. package/dist/react/_internal/wagmi/index.js +2 -2
  33. package/dist/react/hooks/index.d.ts +663 -74
  34. package/dist/react/hooks/index.js +7 -7
  35. package/dist/react/index.css +17 -0
  36. package/dist/react/index.css.map +1 -1
  37. package/dist/react/index.d.ts +1 -1
  38. package/dist/react/index.js +11 -11
  39. package/dist/react/ssr/index.js +1 -1
  40. package/dist/react/ssr/index.js.map +1 -1
  41. package/dist/react/ui/components/index.css +17 -0
  42. package/dist/react/ui/components/index.css.map +1 -1
  43. package/dist/react/ui/components/index.js +11 -11
  44. package/dist/react/ui/icons/index.js +4 -4
  45. package/dist/react/ui/icons/index.js.map +1 -1
  46. package/dist/react/ui/index.css +17 -0
  47. package/dist/react/ui/index.css.map +1 -1
  48. package/dist/react/ui/index.js +11 -11
  49. package/dist/react/ui/modals/_internal/components/actionModal/index.css +22 -0
  50. package/dist/react/ui/modals/_internal/components/actionModal/index.css.map +1 -1
  51. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +17 -9
  52. package/dist/react/ui/modals/_internal/components/actionModal/index.js +8 -4
  53. package/dist/react/ui/styles/index.d.ts +1 -1
  54. package/dist/styles/index.d.ts +1 -1
  55. package/dist/styles/index.js +2 -2
  56. package/dist/types/index.js +3 -3
  57. package/dist/utils/index.js +2 -2
  58. package/package.json +25 -25
  59. package/src/react/_internal/api/marketplace-api.ts +3 -2
  60. package/src/react/_internal/transaction-machine/execute-transaction.ts +28 -12
  61. package/src/react/_internal/transaction-machine/useTransactionMachine.ts +43 -8
  62. package/src/react/hooks/useBuyCollectable.tsx +13 -6
  63. package/src/react/hooks/useCancelOrder.tsx +14 -7
  64. package/src/react/hooks/useCreateListing.tsx +74 -10
  65. package/src/react/hooks/useCurrencies.tsx +1 -1
  66. package/src/react/hooks/useCurrencyBalance.tsx +1 -1
  67. package/src/react/hooks/useCurrencyOptions.tsx +1 -1
  68. package/src/react/hooks/useMakeOffer.tsx +73 -11
  69. package/src/react/hooks/useSell.tsx +72 -11
  70. package/src/react/ui/components/_internals/action-button/ActionButton.tsx +1 -7
  71. package/src/react/ui/components/_internals/action-button/types.ts +7 -0
  72. package/src/react/ui/components/_internals/custom-select/CustomSelect.tsx +18 -15
  73. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +5 -7
  74. package/src/react/ui/components/collectible-card/Footer.tsx +5 -7
  75. package/src/react/ui/components/collectible-card/styles.css.ts +1 -1
  76. package/src/react/ui/icons/ArrowUp.tsx +3 -0
  77. package/src/react/ui/icons/Bell.tsx +3 -0
  78. package/src/react/ui/icons/CalendarIcon.tsx +3 -0
  79. package/src/react/ui/icons/DiamondEye.tsx +3 -0
  80. package/src/react/ui/icons/InfoIcon.tsx +3 -0
  81. package/src/react/ui/icons/InventoryIcon.tsx +3 -0
  82. package/src/react/ui/icons/MinusIcon.tsx +3 -0
  83. package/src/react/ui/icons/PlusIcon.tsx +3 -0
  84. package/src/react/ui/icons/PositiveCircleIcon.tsx +3 -0
  85. package/src/react/ui/modals/BuyModal/index.tsx +25 -8
  86. package/src/react/ui/modals/CreateListingModal/_store.ts +5 -2
  87. package/src/react/ui/modals/CreateListingModal/index.tsx +62 -23
  88. package/src/react/ui/modals/MakeOfferModal/_store.ts +5 -2
  89. package/src/react/ui/modals/MakeOfferModal/index.tsx +83 -65
  90. package/src/react/ui/modals/SellModal/index.tsx +107 -57
  91. package/src/react/ui/modals/TransferModal/_store.ts +1 -1
  92. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/index.tsx +4 -2
  93. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +5 -5
  94. package/src/react/ui/modals/TransferModal/index.tsx +1 -1
  95. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +29 -8
  96. package/src/react/ui/modals/_internal/components/actionModal/ErrorModal.tsx +15 -5
  97. package/src/react/ui/modals/_internal/components/actionModal/LoadingModal.tsx +15 -5
  98. package/src/react/ui/modals/_internal/components/actionModal/store.ts +6 -0
  99. package/src/react/ui/modals/_internal/components/calendar/index.tsx +1 -1
  100. package/src/react/ui/modals/_internal/components/currencyImage/index.tsx +3 -3
  101. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +11 -10
  102. package/src/react/ui/modals/_internal/components/expirationDateSelect/index.tsx +14 -19
  103. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +34 -12
  104. package/src/react/ui/modals/_internal/components/quantityInput/index.tsx +3 -3
  105. package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +7 -4
  106. package/src/react/ui/modals/_internal/components/tokenPreview/index.tsx +1 -0
  107. package/src/react/ui/modals/_internal/components/transaction-footer/index.tsx +3 -3
  108. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +9 -5
  109. package/src/react/ui/modals/_internal/components/transactionPreview/index.tsx +4 -4
  110. package/src/react/ui/modals/_internal/components/transactionPreview/useTransactionPreviewTitle.tsx +1 -1
  111. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +51 -29
  112. package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +2 -2
  113. package/src/react/ui/modals/_internal/components/transactionStatusModal/util/getFormattedType.ts +1 -1
  114. package/src/react/ui/modals/_internal/components/transactionStatusModal/util/getMessage.ts +2 -2
  115. package/src/react/ui/modals/_internal/components/transactionStatusModal/util/getTitle.ts +6 -3
  116. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/index.tsx +146 -0
  117. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/store.ts +12 -0
  118. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/styles.css.ts +53 -0
  119. package/src/react/ui/modals/_internal/components/waasFeeOptionsSelect/WaasFeeOptionsSelect.tsx +117 -0
  120. package/src/utils/_internal/error/transaction.ts +2 -2
  121. package/src/utils/price.ts +3 -4
  122. package/tsconfig.json +1 -21
  123. package/tsconfig.tsbuildinfo +1 -1
  124. package/dist/chunk-6AYHE7ZA.js.map +0 -1
  125. package/dist/chunk-6HEMV2OR.js.map +0 -1
  126. package/dist/chunk-FFCNYF3S.js +0 -153
  127. package/dist/chunk-FFCNYF3S.js.map +0 -1
  128. package/dist/chunk-GVDLVCR5.js.map +0 -1
  129. package/dist/chunk-NMCGA2TB.js +0 -98
  130. package/dist/chunk-NMCGA2TB.js.map +0 -1
  131. package/dist/chunk-QTQH5I2E.js.map +0 -1
  132. package/dist/chunk-Y7YO5TLE.js.map +0 -1
  133. /package/dist/{chunk-EK5ZSW4M.js.map → chunk-QMO2CUNM.js.map} +0 -0
@@ -16,23 +16,30 @@ interface UseBuyOrderArgs
16
16
  onSuccess?: (hash: Hash) => void;
17
17
  onError?: (error: UseBuyOrderError) => void;
18
18
  onTransactionSent?: (hash?: Hex) => void;
19
+ onSwitchChainRefused: () => void;
20
+ enabled: boolean;
19
21
  }
20
22
 
21
23
  export const useBuyCollectable = ({
22
24
  onSuccess,
23
25
  onError,
24
26
  onTransactionSent,
27
+ onSwitchChainRefused,
28
+ enabled,
25
29
  ...config
26
30
  }: UseBuyOrderArgs) => {
27
- const { machine, error, isLoading } = useTransactionMachine(
28
- {
29
- ...config,
30
- type: TransactionType.BUY,
31
- },
31
+ const machineConfig = {
32
+ ...config,
33
+ type: TransactionType.BUY,
34
+ };
35
+ const { machine, error, isLoading } = useTransactionMachine({
36
+ config: machineConfig,
37
+ enabled,
38
+ onSwitchChainRefused,
32
39
  onSuccess,
33
40
  onError,
34
41
  onTransactionSent,
35
- );
42
+ });
36
43
 
37
44
  return {
38
45
  buy: (props: BuyInput) => {
@@ -1,4 +1,4 @@
1
- import { Hex } from 'viem';
1
+ import type { Hex } from 'viem';
2
2
  import {
3
3
  type CancelInput,
4
4
  TransactionType,
@@ -13,23 +13,30 @@ interface UseCancelOrderArgs
13
13
  onSuccess?: (hash: string) => void;
14
14
  onError?: (error: Error) => void;
15
15
  onTransactionSent?: (hash?: Hex) => void;
16
+ onSwitchChainRefused: () => void;
17
+ enabled: boolean;
16
18
  }
17
19
 
18
20
  export const useCancelOrder = ({
19
21
  onSuccess,
20
22
  onError,
21
23
  onTransactionSent,
24
+ onSwitchChainRefused,
25
+ enabled,
22
26
  ...config
23
27
  }: UseCancelOrderArgs) => {
24
- const { machine, isLoading } = useTransactionMachine(
25
- {
26
- ...config,
27
- type: TransactionType.CANCEL,
28
- },
28
+ const machineConfig = {
29
+ ...config,
30
+ type: TransactionType.CANCEL,
31
+ };
32
+ const { machine, isLoading } = useTransactionMachine({
33
+ config: machineConfig,
34
+ enabled,
35
+ onSwitchChainRefused,
29
36
  onSuccess,
30
37
  onError,
31
38
  onTransactionSent,
32
- );
39
+ });
33
40
 
34
41
  return {
35
42
  cancel: (props: CancelInput) => machine?.start(props),
@@ -16,26 +16,48 @@ interface UseCreateListingArgs
16
16
  onSuccess?: (hash: Hash) => void;
17
17
  onError?: (error: TransactionError) => void;
18
18
  onTransactionSent?: (hash?: Hash, orderId?: string) => void;
19
+ onApprovalSuccess?: (hash: Hash) => void;
20
+ onSwitchChainRefused: () => void;
21
+ enabled: boolean;
19
22
  }
20
23
 
24
+ type ExecutionState = 'approval' | 'listing' | null;
25
+
21
26
  export const useCreateListing = ({
22
27
  onSuccess,
23
28
  onError,
24
29
  onTransactionSent,
30
+ onApprovalSuccess,
31
+ onSwitchChainRefused,
32
+ enabled,
25
33
  ...config
26
34
  }: UseCreateListingArgs) => {
27
35
  const [isLoading, setIsLoading] = useState(false);
28
36
  const [steps, setSteps] = useState<TransactionSteps | null>(null);
37
+ const [executionState, setExecutionState] = useState<ExecutionState>(null);
38
+ const machineConfig = {
39
+ ...config,
40
+ type: TransactionType.LISTING,
41
+ };
29
42
 
30
- const { machine, isLoading: isMachineLoading } = useTransactionMachine(
31
- {
32
- ...config,
33
- type: TransactionType.LISTING,
43
+ const { machine, isLoading: isMachineLoading } = useTransactionMachine({
44
+ config: machineConfig,
45
+ enabled,
46
+ onSuccess: (hash) => {
47
+ setExecutionState(null);
48
+ onSuccess?.(hash);
49
+ },
50
+ onError: (error) => {
51
+ setExecutionState(null);
52
+ onError?.(error);
34
53
  },
35
- onSuccess,
36
- onError,
37
54
  onTransactionSent,
38
- );
55
+ onApprovalSuccess: (hash) => {
56
+ setExecutionState(null);
57
+ onApprovalSuccess?.(hash);
58
+ },
59
+ onSwitchChainRefused,
60
+ });
39
61
 
40
62
  const loadSteps = useCallback(
41
63
  async (props: ListingInput) => {
@@ -46,17 +68,59 @@ export const useCreateListing = ({
46
68
  setIsLoading(false);
47
69
  return;
48
70
  }
49
- setSteps(generatedSteps);
71
+ setSteps({
72
+ ...generatedSteps,
73
+ approval: {
74
+ ...generatedSteps.approval,
75
+ isExecuting: executionState === 'approval',
76
+ },
77
+ transaction: {
78
+ ...generatedSteps.transaction,
79
+ isExecuting: executionState === 'listing',
80
+ },
81
+ });
50
82
  setIsLoading(false);
51
83
  },
52
- [machine, onError],
84
+ [machine, executionState],
85
+ );
86
+
87
+ const handleStepExecution = useCallback(
88
+ async (type: ExecutionState, execute: () => Promise<any> | undefined) => {
89
+ if (!type) return;
90
+ setExecutionState(type);
91
+ try {
92
+ await execute();
93
+ } catch (error) {
94
+ setExecutionState(null);
95
+ throw error;
96
+ }
97
+ },
98
+ [],
53
99
  );
54
100
 
55
101
  return {
56
102
  createListing: (props: ListingInput) => machine?.start(props),
57
103
  getListingSteps: (props: ListingInput) => ({
58
104
  isLoading,
59
- steps,
105
+ steps: steps
106
+ ? {
107
+ ...steps,
108
+ approval: {
109
+ ...steps.approval,
110
+ isExecuting: executionState === 'approval',
111
+ execute: () =>
112
+ handleStepExecution('approval', () => steps.approval.execute()),
113
+ },
114
+ transaction: {
115
+ ...steps.transaction,
116
+ isExecuting: executionState === 'listing',
117
+ execute: () =>
118
+ handleStepExecution('listing', () =>
119
+ steps.transaction.execute(),
120
+ ),
121
+ },
122
+ }
123
+ : null,
60
124
  refreshSteps: () => loadSteps(props),
61
125
  }),
62
126
  isLoading: isMachineLoading,
@@ -1,4 +1,5 @@
1
1
  import { queryOptions, useQuery } from '@tanstack/react-query';
2
+ import { toHex, zeroAddress } from 'viem';
2
3
  import { z } from 'zod';
3
4
  import type { SdkConfig } from '../../types';
4
5
  import { InvalidCurrencyOptionsError } from '../../utils/_internal/error/transaction';
@@ -12,7 +13,6 @@ import {
12
13
  getMarketplaceClient,
13
14
  } from '../_internal';
14
15
  import { useConfig } from './useConfig';
15
- import { toHex, zeroAddress } from 'viem';
16
16
 
17
17
  const ChainIdCoerce = ChainIdSchema.transform((val) => val.toString());
18
18
 
@@ -1,5 +1,5 @@
1
1
  import { useQuery } from '@tanstack/react-query';
2
- import { Address, erc20Abi, formatUnits, zeroAddress } from 'viem';
2
+ import { type Address, erc20Abi, formatUnits, zeroAddress } from 'viem';
3
3
  import { getPublicRpcClient } from '../../utils';
4
4
 
5
5
  export function useCurrencyBalance({
@@ -1,4 +1,4 @@
1
- import { Address } from 'viem';
1
+ import type { Address } from 'viem';
2
2
  import { useMarketplaceConfig } from './useMarketplaceConfig';
3
3
 
4
4
  export const useCurrencyOptions = ({
@@ -15,26 +15,48 @@ interface UseMakeOfferArgs extends Omit<UseTransactionMachineConfig, 'type'> {
15
15
  onSuccess?: (hash: Hash) => void;
16
16
  onError?: (error: TransactionError) => void;
17
17
  onTransactionSent?: (hash?: Hash, orderId?: string) => void;
18
+ onApprovalSuccess?: (hash: Hash) => void;
19
+ onSwitchChainRefused: () => void;
20
+ enabled: boolean;
18
21
  }
19
22
 
23
+ type ExecutionState = 'approval' | 'offer' | null;
24
+
20
25
  export const useMakeOffer = ({
21
26
  onSuccess,
22
27
  onError,
23
28
  onTransactionSent,
29
+ onApprovalSuccess,
30
+ onSwitchChainRefused,
31
+ enabled,
24
32
  ...config
25
33
  }: UseMakeOfferArgs) => {
26
34
  const [isLoading, setIsLoading] = useState(false);
27
35
  const [steps, setSteps] = useState<TransactionSteps | null>(null);
36
+ const [executionState, setExecutionState] = useState<ExecutionState>(null);
37
+ const machineConfig = {
38
+ ...config,
39
+ type: TransactionType.OFFER,
40
+ };
28
41
 
29
- const { machine, isLoading: isMachineLoading } = useTransactionMachine(
30
- {
31
- ...config,
32
- type: TransactionType.OFFER,
42
+ const { machine, isLoading: isMachineLoading } = useTransactionMachine({
43
+ config: machineConfig,
44
+ enabled,
45
+ onSuccess: (hash) => {
46
+ setExecutionState(null);
47
+ onSuccess?.(hash);
48
+ },
49
+ onError: (error) => {
50
+ setExecutionState(null);
51
+ onError?.(error);
33
52
  },
34
- onSuccess,
35
- onError,
36
53
  onTransactionSent,
37
- );
54
+ onApprovalSuccess: (hash) => {
55
+ setExecutionState(null);
56
+ onApprovalSuccess?.(hash);
57
+ },
58
+ onSwitchChainRefused,
59
+ });
38
60
 
39
61
  const loadSteps = useCallback(
40
62
  async (props: OfferInput) => {
@@ -45,17 +67,57 @@ export const useMakeOffer = ({
45
67
  setIsLoading(false);
46
68
  return;
47
69
  }
48
- setSteps(generatedSteps);
70
+ setSteps({
71
+ ...generatedSteps,
72
+ approval: {
73
+ ...generatedSteps.approval,
74
+ isExecuting: executionState === 'approval',
75
+ },
76
+ transaction: {
77
+ ...generatedSteps.transaction,
78
+ isExecuting: executionState === 'offer',
79
+ },
80
+ });
49
81
  setIsLoading(false);
50
82
  },
51
- [machine, onError],
83
+ [machine, executionState],
84
+ );
85
+
86
+ const handleStepExecution = useCallback(
87
+ async (type: ExecutionState, execute: () => Promise<any> | undefined) => {
88
+ if (!type) return;
89
+ setExecutionState(type);
90
+ try {
91
+ await execute();
92
+ } catch (error) {
93
+ setExecutionState(null);
94
+ throw error;
95
+ }
96
+ },
97
+ [],
52
98
  );
53
99
 
54
100
  return {
55
101
  makeOffer: (props: OfferInput) => machine?.start(props),
56
102
  getMakeOfferSteps: (props: OfferInput) => ({
57
- isLoading: isLoading,
58
- steps,
103
+ isLoading,
104
+ steps: steps
105
+ ? {
106
+ ...steps,
107
+ approval: {
108
+ ...steps.approval,
109
+ isExecuting: executionState === 'approval',
110
+ execute: () =>
111
+ handleStepExecution('approval', () => steps.approval.execute()),
112
+ },
113
+ transaction: {
114
+ ...steps.transaction,
115
+ isExecuting: executionState === 'offer',
116
+ execute: () =>
117
+ handleStepExecution('offer', () => steps.transaction.execute()),
118
+ },
119
+ }
120
+ : null,
59
121
  refreshSteps: () => loadSteps(props),
60
122
  }),
61
123
  isLoading: isMachineLoading,
@@ -10,31 +10,52 @@ import {
10
10
  useTransactionMachine,
11
11
  } from '../_internal/transaction-machine/useTransactionMachine';
12
12
 
13
+ type ExecutionState = 'approval' | 'sell' | null;
13
14
  interface UseSellArgs
14
15
  extends Omit<UseTransactionMachineConfig, 'type' | 'orderbookKind'> {
15
16
  onSuccess?: (hash: Hash) => void;
16
17
  onError?: (error: Error) => void;
17
18
  onTransactionSent?: (hash?: Hash) => void;
19
+ onApprovalSuccess?: (hash: Hash) => void;
20
+ onSwitchChainRefused: () => void;
21
+ enabled: boolean;
18
22
  }
19
23
 
20
24
  export const useSell = ({
21
25
  onSuccess,
22
26
  onError,
23
27
  onTransactionSent,
28
+ onApprovalSuccess,
29
+ onSwitchChainRefused,
30
+ enabled,
24
31
  ...config
25
32
  }: UseSellArgs) => {
26
33
  const [isLoading, setIsLoading] = useState(false);
27
34
  const [steps, setSteps] = useState<TransactionSteps | null>(null);
35
+ const [executionState, setExecutionState] = useState<ExecutionState>(null);
36
+ const machineConfig = {
37
+ ...config,
38
+ type: TransactionType.SELL,
39
+ };
28
40
 
29
- const { machine, isLoading: isMachineLoading } = useTransactionMachine(
30
- {
31
- ...config,
32
- type: TransactionType.SELL,
41
+ const { machine, isLoading: isMachineLoading } = useTransactionMachine({
42
+ config: machineConfig,
43
+ enabled,
44
+ onSwitchChainRefused,
45
+ onSuccess: (hash) => {
46
+ setExecutionState(null);
47
+ onSuccess?.(hash);
48
+ },
49
+ onError: (error) => {
50
+ setExecutionState(null);
51
+ onError?.(error);
33
52
  },
34
- onSuccess,
35
- onError,
36
53
  onTransactionSent,
37
- );
54
+ onApprovalSuccess: (hash) => {
55
+ setExecutionState(null);
56
+ onApprovalSuccess?.(hash);
57
+ },
58
+ });
38
59
 
39
60
  const loadSteps = useCallback(
40
61
  async (props: SellInput) => {
@@ -45,17 +66,57 @@ export const useSell = ({
45
66
  setIsLoading(false);
46
67
  return;
47
68
  }
48
- setSteps(generatedSteps);
69
+ setSteps({
70
+ ...generatedSteps,
71
+ approval: {
72
+ ...generatedSteps.approval,
73
+ isExecuting: executionState === 'approval',
74
+ },
75
+ transaction: {
76
+ ...generatedSteps.transaction,
77
+ isExecuting: executionState === 'sell',
78
+ },
79
+ });
49
80
  setIsLoading(false);
50
81
  },
51
- [machine, onError],
82
+ [machine, executionState],
83
+ );
84
+
85
+ const handleStepExecution = useCallback(
86
+ async (type: ExecutionState, execute: () => Promise<any> | undefined) => {
87
+ if (!type) return;
88
+ setExecutionState(type);
89
+ try {
90
+ await execute();
91
+ } catch (error) {
92
+ setExecutionState(null);
93
+ throw error;
94
+ }
95
+ },
96
+ [],
52
97
  );
53
98
 
54
99
  return {
55
100
  sell: (props: SellInput) => machine?.start(props),
56
101
  getSellSteps: (props: SellInput) => ({
57
- isLoading: isLoading,
58
- steps,
102
+ isLoading,
103
+ steps: steps
104
+ ? {
105
+ ...steps,
106
+ approval: {
107
+ ...steps.approval,
108
+ isExecuting: executionState === 'approval',
109
+ execute: () =>
110
+ handleStepExecution('approval', () => steps.approval.execute()),
111
+ },
112
+ transaction: {
113
+ ...steps.transaction,
114
+ isExecuting: executionState === 'sell',
115
+ execute: () =>
116
+ handleStepExecution('sell', () => steps.transaction.execute()),
117
+ },
118
+ }
119
+ : null,
59
120
  refreshSteps: () => loadSteps(props),
60
121
  }),
61
122
  isLoading: isMachineLoading,
@@ -11,13 +11,7 @@ import { useMakeOfferModal } from '../../../modals/MakeOfferModal';
11
11
  import { useSellModal } from '../../../modals/SellModal';
12
12
  import { useTransferModal } from '../../../modals/TransferModal';
13
13
 
14
- export enum CollectibleCardAction {
15
- BUY = 'Buy',
16
- SELL = 'Sell',
17
- LIST = 'Create listing',
18
- OFFER = 'Make an offer',
19
- TRANSFER = 'Transfer',
20
- }
14
+ import { CollectibleCardAction } from './types';
21
15
 
22
16
  type ActionButtonProps = {
23
17
  chainId: string;
@@ -0,0 +1,7 @@
1
+ export enum CollectibleCardAction {
2
+ BUY = 'Buy',
3
+ SELL = 'Sell',
4
+ LIST = 'Create listing',
5
+ OFFER = 'Make an offer',
6
+ TRANSFER = 'Transfer',
7
+ }
@@ -1,22 +1,23 @@
1
1
  import { CheckmarkIcon, ChevronDownIcon } from '@0xsequence/design-system';
2
2
  import * as Select from '@radix-ui/react-select';
3
- import React from 'react';
3
+ import React, { type ReactNode } from 'react';
4
4
  import { content, item, itemIndicator, trigger } from './styles.css';
5
5
 
6
- interface CustomSelectProps {
7
- items: Array<{
8
- value: string;
9
- label: string;
10
- disabled?: boolean;
11
- }>;
6
+ export interface SelectItem {
12
7
  value: string;
8
+ content: ReactNode;
9
+ disabled?: boolean;
10
+ }
11
+
12
+ interface CustomSelectProps {
13
+ items: SelectItem[];
13
14
  onValueChange?: (value: string) => void;
14
- defaultValue?: string;
15
+ defaultValue?: SelectItem;
15
16
  }
16
17
 
17
18
  const CustomSelectItem = React.forwardRef<
18
19
  HTMLDivElement,
19
- Select.SelectItemProps
20
+ Select.SelectItemProps & { children: ReactNode }
20
21
  >(({ children, ...props }, forwardedRef) => {
21
22
  return (
22
23
  <Select.Item className={item} {...props} ref={forwardedRef}>
@@ -30,13 +31,15 @@ const CustomSelectItem = React.forwardRef<
30
31
 
31
32
  export const CustomSelect: React.FC<CustomSelectProps> = ({
32
33
  items,
33
- value,
34
34
  onValueChange,
35
35
  defaultValue,
36
36
  }) => {
37
37
  return (
38
- <Select.Root onValueChange={onValueChange} defaultValue={defaultValue}>
39
- <Select.Trigger className={trigger} value={value}>
38
+ <Select.Root
39
+ onValueChange={onValueChange}
40
+ defaultValue={defaultValue?.value}
41
+ >
42
+ <Select.Trigger className={trigger}>
40
43
  <Select.Value />
41
44
  <Select.Icon>
42
45
  <ChevronDownIcon size="xs" />
@@ -46,13 +49,13 @@ export const CustomSelect: React.FC<CustomSelectProps> = ({
46
49
  <Select.Portal>
47
50
  <Select.Content className={content}>
48
51
  <Select.Viewport>
49
- {items.map((item, index) => (
52
+ {items.map((item) => (
50
53
  <CustomSelectItem
51
- key={index}
54
+ key={item.value}
52
55
  value={item.value}
53
56
  disabled={item.disabled}
54
57
  >
55
- {item.label}
58
+ {item.content}
56
59
  </CustomSelectItem>
57
60
  ))}
58
61
  </Select.Viewport>
@@ -11,12 +11,11 @@ import type {
11
11
  OrderbookKind,
12
12
  } from '../../../_internal';
13
13
  import { useCurrencies, useHighestOffer } from '../../../hooks';
14
+ import { useCurrencyOptions } from '../../../hooks/useCurrencyOptions';
14
15
  import SvgDiamondEyeIcon from '../../icons/DiamondEye';
15
16
  import ChessTileImage from '../../images/chess-tile.png';
16
- import {
17
- ActionButton,
18
- CollectibleCardAction,
19
- } from '../_internals/action-button/ActionButton';
17
+ import { ActionButton } from '../_internals/action-button/ActionButton';
18
+ import { CollectibleCardAction } from '../_internals/action-button/types';
20
19
  import { Footer } from './Footer';
21
20
  import {
22
21
  actionWrapper,
@@ -24,7 +23,6 @@ import {
24
23
  collectibleImage,
25
24
  collectibleTileWrapper,
26
25
  } from './styles.css';
27
- import { useCurrencyOptions } from '../../../hooks/useCurrencyOptions';
28
26
 
29
27
  function CollectibleSkeleton() {
30
28
  return (
@@ -101,7 +99,7 @@ export function CollectibleCard({
101
99
  }
102
100
 
103
101
  const action = (
104
- !!balance
102
+ balance
105
103
  ? (highestOffer?.order && CollectibleCardAction.SELL) ||
106
104
  (!lowestListing?.order && CollectibleCardAction.LIST) ||
107
105
  CollectibleCardAction.TRANSFER
@@ -161,7 +159,7 @@ export function CollectibleCard({
161
159
  />
162
160
 
163
161
  <Footer
164
- name={name!}
162
+ name={name || ''}
165
163
  type={collectionType}
166
164
  onOfferClick={() => onOfferClick?.({ order: highestOffer?.order })}
167
165
  highestOffer={highestOffer?.order}
@@ -30,10 +30,10 @@ export const Footer = ({
30
30
  const listed = !!lowestListingPriceAmount && !!lowestListingCurrency;
31
31
 
32
32
  if (name.length > 15 && highestOffer) {
33
- name = name.substring(0, 13) + '...';
33
+ name = `${name.substring(0, 13)}...`;
34
34
  }
35
35
  if (name.length > 17 && !highestOffer) {
36
- name = name.substring(0, 17) + '...';
36
+ name = `${name.substring(0, 17)}...`;
37
37
  }
38
38
 
39
39
  return (
@@ -94,12 +94,10 @@ export const Footer = ({
94
94
  fontFamily="body"
95
95
  >
96
96
  {listed &&
97
- formatUnits(
97
+ `${formatUnits(
98
98
  BigInt(lowestListingPriceAmount),
99
99
  lowestListingCurrency.decimals,
100
- ) +
101
- ' ' +
102
- lowestListingCurrency.symbol}
100
+ )} ${lowestListingCurrency.symbol}`}
103
101
 
104
102
  {!listed && 'Not listed yet'}
105
103
  </Text>
@@ -116,7 +114,7 @@ const TokenTypeBalancePill = ({
116
114
  }: { balance?: string; type: ContractType }) => {
117
115
  const displayText =
118
116
  type === ContractType.ERC1155
119
- ? !!balance
117
+ ? balance
120
118
  ? `Owned: ${balance}`
121
119
  : 'ERC-1155'
122
120
  : 'ERC-721';
@@ -21,7 +21,7 @@ export const collectibleTileWrapper = style({
21
21
  background: 'none',
22
22
  position: 'relative',
23
23
  selectors: {
24
- [`&:focus`]: {
24
+ '&:focus': {
25
25
  outline: 'none',
26
26
  },
27
27
  },
@@ -8,7 +8,10 @@ const Svg = () => (
8
8
  viewBox="0 0 12 12"
9
9
  fill="none"
10
10
  xmlns="http://www.w3.org/2000/svg"
11
+ role="img"
12
+ aria-label="Arrow up"
11
13
  >
14
+ <title>Arrow up icon</title>
12
15
  <path
13
16
  d="M8.65039 6.03638L9.28679 5.39999L5.96859 2.08179L2.65039 5.39999L3.28679 6.03638L5.51859 3.80458V9.91822H6.41859V3.80458L8.65039 6.03638Z"
14
17
  fill="#D1D1D1"
@@ -8,7 +8,10 @@ const Svg = () => (
8
8
  viewBox="0 0 17 17"
9
9
  fill="none"
10
10
  xmlns="http://www.w3.org/2000/svg"
11
+ role="img"
12
+ aria-labelledby="bell-title"
11
13
  >
14
+ <title id="bell-title">Notification Bell</title>
12
15
  <path
13
16
  fillRule="evenodd"
14
17
  clipRule="evenodd"