@0xsequence/marketplace-sdk 0.4.0 → 0.4.2

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 (152) hide show
  1. package/dist/{chunk-L6GSYPCR.js → chunk-2OJB35FS.js} +11 -11
  2. package/dist/{chunk-L6GSYPCR.js.map → chunk-2OJB35FS.js.map} +1 -1
  3. package/dist/{chunk-EK5ZSW4M.js → chunk-4RKM3VUV.js} +2 -2
  4. package/dist/{chunk-7NJETFMF.js → chunk-FI723DGL.js} +3 -3
  5. package/dist/{chunk-7NJETFMF.js.map → chunk-FI723DGL.js.map} +1 -1
  6. package/dist/{chunk-GVDLVCR5.js → chunk-GSDUAHL3.js} +1 -1
  7. package/dist/chunk-GSDUAHL3.js.map +1 -0
  8. package/dist/{chunk-SBVLWSRZ.js → chunk-LF44FCG5.js} +2 -2
  9. package/dist/{chunk-SBVLWSRZ.js.map → chunk-LF44FCG5.js.map} +1 -1
  10. package/dist/{chunk-PAHT6PTD.js → chunk-LSMQVX77.js} +5 -6
  11. package/dist/{chunk-PAHT6PTD.js.map → chunk-LSMQVX77.js.map} +1 -1
  12. package/dist/chunk-MQ5WSFDH.js +435 -0
  13. package/dist/chunk-MQ5WSFDH.js.map +1 -0
  14. package/dist/{chunk-6HEMV2OR.js → chunk-MTFS5SED.js} +1426 -1179
  15. package/dist/chunk-MTFS5SED.js.map +1 -0
  16. package/dist/{chunk-4ESPWOBV.js → chunk-NC4KGXXE.js} +3 -3
  17. package/dist/{chunk-4ESPWOBV.js.map → chunk-NC4KGXXE.js.map} +1 -1
  18. package/dist/{chunk-QTQH5I2E.js → chunk-OPMDGQFB.js} +38 -36
  19. package/dist/chunk-OPMDGQFB.js.map +1 -0
  20. package/dist/{chunk-P3EQRM7K.js → chunk-S5IPE7TH.js} +5 -4
  21. package/dist/{chunk-P3EQRM7K.js.map → chunk-S5IPE7TH.js.map} +1 -1
  22. package/dist/chunk-T5T6JNB2.js +171 -0
  23. package/dist/chunk-T5T6JNB2.js.map +1 -0
  24. package/dist/{chunk-O642NH7U.js → chunk-TDTORZHC.js} +3 -3
  25. package/dist/{chunk-O642NH7U.js.map → chunk-TDTORZHC.js.map} +1 -1
  26. package/dist/{chunk-6AYHE7ZA.js → chunk-WBJKZOQ7.js} +264 -138
  27. package/dist/chunk-WBJKZOQ7.js.map +1 -0
  28. package/dist/{chunk-Y7YO5TLE.js → chunk-XXML5K3X.js} +5 -2
  29. package/dist/chunk-XXML5K3X.js.map +1 -0
  30. package/dist/{chunk-AY2MZHZN.js → chunk-ZWIRTV7A.js} +5 -6
  31. package/dist/{chunk-AY2MZHZN.js.map → chunk-ZWIRTV7A.js.map} +1 -1
  32. package/dist/{create-config-CgtmCzvb.d.ts → create-config-8sffBvlt.d.ts} +1 -1
  33. package/dist/index.js +4 -4
  34. package/dist/react/_internal/api/index.js +2 -2
  35. package/dist/react/_internal/index.d.ts +1 -1
  36. package/dist/react/_internal/index.js +3 -3
  37. package/dist/react/_internal/wagmi/index.d.ts +1 -1
  38. package/dist/react/_internal/wagmi/index.js +2 -2
  39. package/dist/react/hooks/index.d.ts +664 -77
  40. package/dist/react/hooks/index.js +8 -8
  41. package/dist/react/index.css +17 -0
  42. package/dist/react/index.css.map +1 -1
  43. package/dist/react/index.d.ts +1 -1
  44. package/dist/react/index.js +13 -13
  45. package/dist/react/ssr/index.js +1 -1
  46. package/dist/react/ssr/index.js.map +1 -1
  47. package/dist/react/ui/components/index.css +17 -0
  48. package/dist/react/ui/components/index.css.map +1 -1
  49. package/dist/react/ui/components/index.js +13 -13
  50. package/dist/react/ui/icons/index.js +4 -4
  51. package/dist/react/ui/icons/index.js.map +1 -1
  52. package/dist/react/ui/index.css +17 -0
  53. package/dist/react/ui/index.css.map +1 -1
  54. package/dist/react/ui/index.d.ts +15 -8
  55. package/dist/react/ui/index.js +13 -13
  56. package/dist/react/ui/modals/_internal/components/actionModal/index.css +22 -0
  57. package/dist/react/ui/modals/_internal/components/actionModal/index.css.map +1 -1
  58. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +17 -9
  59. package/dist/react/ui/modals/_internal/components/actionModal/index.js +9 -5
  60. package/dist/react/ui/styles/index.d.ts +1 -1
  61. package/dist/react/ui/styles/index.js +1 -1
  62. package/dist/styles/index.d.ts +1 -1
  63. package/dist/styles/index.js +5 -5
  64. package/dist/types/index.js +3 -3
  65. package/dist/utils/index.js +2 -2
  66. package/package.json +26 -26
  67. package/src/react/_internal/api/marketplace-api.ts +3 -2
  68. package/src/react/_internal/transaction-machine/execute-transaction.ts +95 -122
  69. package/src/react/_internal/transaction-machine/useTransactionMachine.ts +33 -17
  70. package/src/react/_internal/transaction-machine/utils.ts +50 -0
  71. package/src/react/_internal/transaction-machine/wallet.ts +180 -0
  72. package/src/react/hooks/useBuyCollectable.tsx +24 -8
  73. package/src/react/hooks/useCancelOrder.tsx +11 -7
  74. package/src/react/hooks/useCreateListing.tsx +71 -10
  75. package/src/react/hooks/useCurrencies.tsx +1 -1
  76. package/src/react/hooks/useCurrencyBalance.tsx +1 -1
  77. package/src/react/hooks/useCurrencyOptions.tsx +1 -1
  78. package/src/react/hooks/useGenerateListingTransaction.tsx +1 -3
  79. package/src/react/hooks/useGenerateOfferTransaction.tsx +1 -3
  80. package/src/react/hooks/useMakeOffer.tsx +70 -11
  81. package/src/react/hooks/useSell.tsx +69 -11
  82. package/src/react/ui/components/_internals/action-button/ActionButton.tsx +1 -7
  83. package/src/react/ui/components/_internals/action-button/types.ts +7 -0
  84. package/src/react/ui/components/_internals/custom-select/CustomSelect.tsx +18 -15
  85. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +5 -7
  86. package/src/react/ui/components/collectible-card/Footer.tsx +5 -7
  87. package/src/react/ui/components/collectible-card/styles.css.ts +1 -1
  88. package/src/react/ui/icons/ArrowUp.tsx +3 -0
  89. package/src/react/ui/icons/Bell.tsx +3 -0
  90. package/src/react/ui/icons/CalendarIcon.tsx +3 -0
  91. package/src/react/ui/icons/DiamondEye.tsx +3 -0
  92. package/src/react/ui/icons/InfoIcon.tsx +3 -0
  93. package/src/react/ui/icons/InventoryIcon.tsx +3 -0
  94. package/src/react/ui/icons/MinusIcon.tsx +3 -0
  95. package/src/react/ui/icons/PlusIcon.tsx +3 -0
  96. package/src/react/ui/icons/PositiveCircleIcon.tsx +3 -0
  97. package/src/react/ui/modals/BuyModal/index.tsx +43 -10
  98. package/src/react/ui/modals/CreateListingModal/Modal.tsx +252 -0
  99. package/src/react/ui/modals/CreateListingModal/index.tsx +6 -245
  100. package/src/react/ui/modals/CreateListingModal/store.ts +76 -0
  101. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +254 -0
  102. package/src/react/ui/modals/MakeOfferModal/index.tsx +8 -244
  103. package/src/react/ui/modals/MakeOfferModal/{_store.ts → store.ts} +28 -15
  104. package/src/react/ui/modals/SellModal/Modal.tsx +218 -0
  105. package/src/react/ui/modals/SellModal/index.tsx +8 -188
  106. package/src/react/ui/modals/SellModal/{_store.ts → store.ts} +13 -9
  107. package/src/react/ui/modals/TransferModal/_store.ts +1 -1
  108. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/index.tsx +4 -2
  109. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +5 -5
  110. package/src/react/ui/modals/TransferModal/index.tsx +1 -1
  111. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +29 -8
  112. package/src/react/ui/modals/_internal/components/actionModal/ErrorModal.tsx +15 -5
  113. package/src/react/ui/modals/_internal/components/actionModal/LoadingModal.tsx +15 -5
  114. package/src/react/ui/modals/_internal/components/actionModal/store.ts +6 -0
  115. package/src/react/ui/modals/_internal/components/calendar/index.tsx +1 -1
  116. package/src/react/ui/modals/_internal/components/currencyImage/index.tsx +3 -3
  117. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +11 -10
  118. package/src/react/ui/modals/_internal/components/expirationDateSelect/index.tsx +14 -19
  119. package/src/react/ui/modals/_internal/components/priceInput/index.tsx +34 -12
  120. package/src/react/ui/modals/_internal/components/quantityInput/index.tsx +3 -3
  121. package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +7 -4
  122. package/src/react/ui/modals/_internal/components/tokenPreview/index.tsx +1 -0
  123. package/src/react/ui/modals/_internal/components/transaction-footer/index.tsx +6 -5
  124. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +9 -5
  125. package/src/react/ui/modals/_internal/components/transactionPreview/index.tsx +4 -4
  126. package/src/react/ui/modals/_internal/components/transactionPreview/useTransactionPreviewTitle.tsx +1 -1
  127. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +53 -30
  128. package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +2 -2
  129. package/src/react/ui/modals/_internal/components/transactionStatusModal/util/getFormattedType.ts +1 -1
  130. package/src/react/ui/modals/_internal/components/transactionStatusModal/util/getMessage.ts +2 -2
  131. package/src/react/ui/modals/_internal/components/transactionStatusModal/util/getTitle.ts +6 -3
  132. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/index.tsx +146 -0
  133. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/store.ts +12 -0
  134. package/src/react/ui/modals/_internal/components/waasFeeOptionsBox/styles.css.ts +53 -0
  135. package/src/react/ui/modals/_internal/components/waasFeeOptionsSelect/WaasFeeOptionsSelect.tsx +117 -0
  136. package/src/react/ui/modals/modal-provider.tsx +3 -3
  137. package/src/utils/_internal/error/transaction.ts +2 -2
  138. package/src/utils/date.ts +2 -0
  139. package/src/utils/price.ts +3 -4
  140. package/tsconfig.json +1 -21
  141. package/tsconfig.tsbuildinfo +1 -1
  142. package/dist/chunk-6AYHE7ZA.js.map +0 -1
  143. package/dist/chunk-6HEMV2OR.js.map +0 -1
  144. package/dist/chunk-FFCNYF3S.js +0 -153
  145. package/dist/chunk-FFCNYF3S.js.map +0 -1
  146. package/dist/chunk-GVDLVCR5.js.map +0 -1
  147. package/dist/chunk-NMCGA2TB.js +0 -98
  148. package/dist/chunk-NMCGA2TB.js.map +0 -1
  149. package/dist/chunk-QTQH5I2E.js.map +0 -1
  150. package/dist/chunk-Y7YO5TLE.js.map +0 -1
  151. package/src/react/ui/modals/CreateListingModal/_store.ts +0 -52
  152. /package/dist/{chunk-EK5ZSW4M.js.map → chunk-4RKM3VUV.js.map} +0 -0
@@ -1,249 +1,13 @@
1
- import { Show, observer } from '@legendapp/state/react';
2
- import type { QueryKey } from '@tanstack/react-query';
3
- import { useEffect, useState } from 'react';
4
- import { parseUnits, type Hex } from 'viem';
5
- import {
6
- ContractType,
7
- OrderbookKind,
8
- collectableKeys,
9
- } from '../../../_internal';
10
- import { useCollectible, useCollection, useCurrencies } from '../../../hooks';
11
- import { useMakeOffer } from '../../../hooks/useMakeOffer';
12
- import { ActionModal } from '../_internal/components/actionModal/ActionModal';
13
- import { ErrorModal } from '../_internal/components/actionModal/ErrorModal';
14
- import { LoadingModal } from '../_internal/components/actionModal/LoadingModal';
15
- import ExpirationDateSelect from '../_internal/components/expirationDateSelect';
16
- import FloorPriceText from '../_internal/components/floorPriceText';
17
- import PriceInput from '../_internal/components/priceInput';
18
- import QuantityInput from '../_internal/components/quantityInput';
19
- import TokenPreview from '../_internal/components/tokenPreview';
20
- import { useTransactionStatusModal } from '../_internal/components/transactionStatusModal';
21
1
  import type { ModalCallbacks } from '../_internal/types';
22
- import { makeOfferModal$ } from './_store';
23
- import { TransactionType } from '../../../_internal/transaction-machine/execute-transaction';
24
- import { useCurrencyOptions } from '../../../hooks/useCurrencyOptions';
2
+ import { type OpenMakeOfferModalArgs, makeOfferModal$ } from './store';
25
3
 
26
- export type ShowMakeOfferModalArgs = {
27
- collectionAddress: Hex;
28
- chainId: string;
29
- collectibleId: string;
30
- orderbookKind: OrderbookKind;
31
- };
4
+ export type ShowMakeOfferModalArgs = Exclude<
5
+ OpenMakeOfferModalArgs,
6
+ 'callbacks'
7
+ >;
32
8
 
33
- export const useMakeOfferModal = (defaultCallbacks?: ModalCallbacks) => ({
9
+ export const useMakeOfferModal = (callbacks?: ModalCallbacks) => ({
34
10
  show: (args: ShowMakeOfferModalArgs) =>
35
- makeOfferModal$.open({ ...args, callbacks: defaultCallbacks }),
36
- close: makeOfferModal$.close,
11
+ makeOfferModal$.open({ ...args, callbacks }),
12
+ close: () => makeOfferModal$.close(),
37
13
  });
38
-
39
- export const MakeOfferModal = () => {
40
- const { show: showTransactionStatusModal } = useTransactionStatusModal();
41
- return (
42
- <Show if={makeOfferModal$.isOpen}>
43
- <ModalContent showTransactionStatusModal={showTransactionStatusModal} />
44
- </Show>
45
- );
46
- };
47
-
48
- type TransactionStatusModalReturn = ReturnType<
49
- typeof useTransactionStatusModal
50
- >;
51
-
52
- const ModalContent = observer(
53
- ({
54
- showTransactionStatusModal,
55
- }: {
56
- showTransactionStatusModal: TransactionStatusModalReturn['show'];
57
- }) => {
58
- const state = makeOfferModal$.get();
59
- const {
60
- collectionAddress,
61
- chainId,
62
- offerPrice,
63
- collectibleId,
64
- orderbookKind,
65
- } = state;
66
- const [insufficientBalance, setInsufficientBalance] = useState(false);
67
-
68
- const {
69
- data: collectible,
70
- isLoading: collectableIsLoading,
71
- isError: collectableIsError,
72
- } = useCollectible({
73
- chainId,
74
- collectionAddress,
75
- collectibleId,
76
- });
77
-
78
- const {
79
- data: collection,
80
- isLoading: collectionIsLoading,
81
- isError: collectionIsError,
82
- } = useCollection({
83
- chainId,
84
- collectionAddress,
85
- });
86
- const currencyOptions = useCurrencyOptions({ collectionAddress });
87
- const { isLoading: currenciesIsLoading } = useCurrencies({
88
- chainId,
89
- currencyOptions,
90
- });
91
-
92
- const { getMakeOfferSteps } = useMakeOffer({
93
- chainId,
94
- collectionAddress,
95
- orderbookKind,
96
- onTransactionSent: (hash, orderId) => {
97
- if (!hash && !orderId) return;
98
-
99
- showTransactionStatusModal({
100
- hash,
101
- orderId,
102
- price: makeOfferModal$.offerPrice.get(),
103
- collectionAddress,
104
- chainId,
105
- collectibleId,
106
- type: TransactionType.OFFER,
107
- queriesToInvalidate: collectableKeys.all as unknown as QueryKey[],
108
- });
109
- makeOfferModal$.close();
110
- },
111
- onSuccess: (hash) => {
112
- if (typeof makeOfferModal$.callbacks?.onSuccess === 'function') {
113
- makeOfferModal$.callbacks.onSuccess(hash);
114
- } else {
115
- console.debug('onSuccess callback not provided:', hash);
116
- }
117
- },
118
- onError: (error) => {
119
- if (typeof makeOfferModal$.callbacks?.onError === 'function') {
120
- makeOfferModal$.callbacks.onError(error);
121
- } else {
122
- console.debug('onError callback not provided:', error);
123
- }
124
- },
125
- });
126
-
127
- const dateToUnixTime = (date: Date) =>
128
- Math.floor(date.getTime() / 1000).toString();
129
-
130
- const currencyAddress = offerPrice.currency.contractAddress;
131
-
132
- const { isLoading, steps, refreshSteps } = getMakeOfferSteps({
133
- contractType: collection!.type as ContractType,
134
- offer: {
135
- tokenId: collectibleId,
136
- quantity: parseUnits(
137
- makeOfferModal$.quantity.get(),
138
- collectible?.decimals || 0,
139
- ).toString(),
140
- expiry: dateToUnixTime(makeOfferModal$.expiry.get()),
141
- currencyAddress,
142
- pricePerToken: offerPrice.amountRaw,
143
- },
144
- });
145
-
146
- useEffect(() => {
147
- if (!currencyAddress) return;
148
- refreshSteps();
149
- }, [currencyAddress]);
150
-
151
- if (collectableIsLoading || collectionIsLoading || currenciesIsLoading) {
152
- return (
153
- <LoadingModal
154
- store={makeOfferModal$}
155
- onClose={makeOfferModal$.close}
156
- title="Make an offer"
157
- />
158
- );
159
- }
160
-
161
- if (collectableIsError || collectionIsError) {
162
- return (
163
- <ErrorModal
164
- store={makeOfferModal$}
165
- onClose={makeOfferModal$.close}
166
- title="Make an offer"
167
- />
168
- );
169
- }
170
-
171
- const handleStepExecution = async (execute?: any) => {
172
- if (!execute) return;
173
- try {
174
- await refreshSteps();
175
- await execute();
176
- } catch (error) {
177
- makeOfferModal$.callbacks?.onError?.(error as Error);
178
- }
179
- };
180
-
181
- const ctas = [
182
- {
183
- label: 'Approve TOKEN',
184
- onClick: () => handleStepExecution(() => steps?.approval.execute()),
185
- hidden: !steps?.approval.isPending,
186
- pending: steps?.approval.isExecuting,
187
- variant: 'glass' as const,
188
- disabled: makeOfferModal$.invalidQuantity.get(),
189
- },
190
- {
191
- label: 'Make offer',
192
- onClick: () => handleStepExecution(() => steps?.transaction.execute()),
193
- pending: steps?.transaction.isExecuting || isLoading,
194
- disabled:
195
- steps?.approval.isPending ||
196
- offerPrice.amountRaw === '0' ||
197
- insufficientBalance ||
198
- isLoading ||
199
- makeOfferModal$.invalidQuantity.get(),
200
- },
201
- ];
202
-
203
- return (
204
- <ActionModal
205
- store={makeOfferModal$}
206
- onClose={() => makeOfferModal$.close()}
207
- title="Make an offer"
208
- ctas={ctas}
209
- >
210
- <TokenPreview
211
- collectionName={collection?.name}
212
- collectionAddress={collectionAddress}
213
- collectibleId={collectibleId}
214
- chainId={chainId}
215
- />
216
-
217
- <PriceInput
218
- chainId={chainId}
219
- collectionAddress={collectionAddress}
220
- $listingPrice={makeOfferModal$.offerPrice}
221
- checkBalance={{
222
- enabled: true,
223
- callback: (state) => setInsufficientBalance(state),
224
- }}
225
- />
226
-
227
- {collection?.type === ContractType.ERC1155 && (
228
- <QuantityInput
229
- $quantity={makeOfferModal$.quantity}
230
- $invalidQuantity={makeOfferModal$.invalidQuantity}
231
- decimals={collectible?.decimals || 0}
232
- maxQuantity={String(Number.MAX_SAFE_INTEGER)}
233
- />
234
- )}
235
-
236
- {!!offerPrice && (
237
- <FloorPriceText
238
- tokenId={collectibleId}
239
- chainId={chainId}
240
- collectionAddress={collectionAddress}
241
- price={offerPrice}
242
- />
243
- )}
244
-
245
- <ExpirationDateSelect $date={makeOfferModal$.expiry} />
246
- </ActionModal>
247
- );
248
- },
249
- );
@@ -1,42 +1,53 @@
1
1
  import { observable } from '@legendapp/state';
2
2
  import { addDays } from 'date-fns/addDays';
3
3
  import type { Hex } from 'viem';
4
- import { Currency, OrderbookKind, Price } from '../../../../types';
4
+ import { type Currency, OrderbookKind, type Price } from '../../../../types';
5
+ import type { CollectionType } from '../../../_internal';
5
6
  import type { BaseModalState, ModalCallbacks } from '../_internal/types';
6
7
 
7
- type MakeOfferModalState = BaseModalState & {
8
+ type MakeOfferState = BaseModalState & {
8
9
  orderbookKind: OrderbookKind;
9
10
  collectibleId: string;
10
11
  offerPrice: Price;
12
+ offerPriceChanged: boolean;
11
13
  quantity: string;
12
14
  expiry: Date;
13
15
  invalidQuantity: boolean;
16
+ collectionType?: CollectionType;
14
17
  };
15
18
 
16
- const initialState: MakeOfferModalState & {
17
- open: (args: {
18
- collectionAddress: Hex;
19
- chainId: string;
20
- collectibleId: string;
21
- orderbookKind: OrderbookKind;
22
- callbacks?: ModalCallbacks;
23
- }) => void;
19
+ export type OpenMakeOfferModalArgs = {
20
+ collectionAddress: Hex;
21
+ chainId: string;
22
+ collectibleId: string;
23
+ orderbookKind: OrderbookKind;
24
+ callbacks?: ModalCallbacks;
25
+ };
26
+
27
+ type Actions = {
28
+ open: (args: OpenMakeOfferModalArgs) => void;
24
29
  close: () => void;
25
- } = {
30
+ };
31
+
32
+ const initialState: MakeOfferState = {
26
33
  isOpen: false,
27
34
  collectionAddress: '' as Hex,
28
35
  chainId: '',
29
36
  collectibleId: '',
30
- orderbookKind: OrderbookKind.sequence_marketplace_v2,
37
+ orderbookKind: OrderbookKind.reservoir,
31
38
  callbacks: undefined,
32
39
  offerPrice: {
33
40
  amountRaw: '1',
34
41
  currency: {} as Currency,
35
42
  },
43
+ offerPriceChanged: false,
36
44
  quantity: '1',
37
45
  invalidQuantity: false,
38
46
  expiry: new Date(addDays(new Date(), 7).toJSON()),
47
+ collectionType: undefined,
48
+ };
39
49
 
50
+ const actions: Actions = {
40
51
  open: (args) => {
41
52
  makeOfferModal$.collectionAddress.set(args.collectionAddress);
42
53
  makeOfferModal$.chainId.set(args.chainId);
@@ -45,11 +56,13 @@ const initialState: MakeOfferModalState & {
45
56
  makeOfferModal$.callbacks.set(args.callbacks);
46
57
  makeOfferModal$.isOpen.set(true);
47
58
  },
48
-
49
59
  close: () => {
50
60
  makeOfferModal$.isOpen.set(false);
51
- makeOfferModal$.callbacks.set(undefined);
61
+ makeOfferModal$.set({ ...initialState, ...actions });
52
62
  },
53
63
  };
54
64
 
55
- export const makeOfferModal$ = observable(initialState);
65
+ export const makeOfferModal$ = observable<MakeOfferState & Actions>({
66
+ ...initialState,
67
+ ...actions,
68
+ });
@@ -0,0 +1,218 @@
1
+ import { Show, observer } from '@legendapp/state/react';
2
+ import type { QueryKey } from '@tanstack/react-query';
3
+ import { useEffect, useState } from 'react';
4
+ import { parseUnits } from 'viem';
5
+ import { balanceQueries, collectableKeys } from '../../../_internal';
6
+ import type { MarketplaceKind } from '../../../_internal/api/marketplace.gen';
7
+ import { TransactionType } from '../../../_internal/transaction-machine/execute-transaction';
8
+ import { useCollection, useCurrencies } from '../../../hooks';
9
+ import { useCurrencyOptions } from '../../../hooks/useCurrencyOptions';
10
+ import { useSell } from '../../../hooks/useSell';
11
+ import {
12
+ ActionModal,
13
+ type ActionModalProps,
14
+ } from '../_internal/components/actionModal/ActionModal';
15
+ import { ErrorModal } from '../_internal/components/actionModal/ErrorModal';
16
+ import { LoadingModal } from '../_internal/components/actionModal/LoadingModal';
17
+ import TokenPreview from '../_internal/components/tokenPreview';
18
+ import TransactionDetails from '../_internal/components/transactionDetails';
19
+ import TransactionHeader from '../_internal/components/transactionHeader';
20
+ import { useTransactionStatusModal } from '../_internal/components/transactionStatusModal';
21
+ import { sellModal$ } from './store';
22
+
23
+ type TransactionStatusModalReturn = ReturnType<
24
+ typeof useTransactionStatusModal
25
+ >;
26
+
27
+ export const SellModal = () => {
28
+ const { show: showTransactionStatusModal } = useTransactionStatusModal();
29
+ return (
30
+ <Show if={sellModal$.isOpen}>
31
+ {() => <Modal showTransactionStatusModal={showTransactionStatusModal} />}
32
+ </Show>
33
+ );
34
+ };
35
+
36
+ const Modal = observer(
37
+ ({
38
+ showTransactionStatusModal,
39
+ }: {
40
+ showTransactionStatusModal: TransactionStatusModalReturn['show'];
41
+ }) => {
42
+ const { tokenId, collectionAddress, chainId, order, callbacks } =
43
+ sellModal$.get();
44
+ const { data: collectible } = useCollection({
45
+ chainId,
46
+ collectionAddress,
47
+ });
48
+ const [approvalExecutedSuccess, setApprovalExecutedSuccess] =
49
+ useState(false);
50
+ const {
51
+ data: collection,
52
+ isLoading: collectionLoading,
53
+ isError: collectionError,
54
+ } = useCollection({
55
+ chainId,
56
+ collectionAddress,
57
+ });
58
+ const currencyOptions = useCurrencyOptions({ collectionAddress });
59
+ const { data: currencies, isLoading: currenciesLoading } = useCurrencies({
60
+ chainId,
61
+ currencyOptions,
62
+ });
63
+ const { getSellSteps, isLoading: machineLoading } = useSell({
64
+ collectionAddress,
65
+ chainId,
66
+ enabled: sellModal$.isOpen.get(),
67
+ onApprovalSuccess: () => setApprovalExecutedSuccess(true),
68
+ onTransactionSent: (hash) => {
69
+ if (!hash) return;
70
+ showTransactionStatusModal({
71
+ hash: hash,
72
+ price: order
73
+ ? {
74
+ amountRaw: order.priceAmount,
75
+ currency: currencies?.find(
76
+ (currency) =>
77
+ currency.contractAddress === order.priceCurrencyAddress,
78
+ ) ?? {
79
+ chainId: Number(chainId),
80
+ contractAddress: order.priceCurrencyAddress,
81
+ name: 'Unknown',
82
+ symbol: 'UNK',
83
+ decimals: 18,
84
+ imageUrl: '',
85
+ exchangeRate: 0,
86
+ defaultChainCurrency: false,
87
+ nativeCurrency: false,
88
+ createdAt: new Date().toISOString(),
89
+ updatedAt: new Date().toISOString(),
90
+ },
91
+ }
92
+ : undefined,
93
+ collectionAddress,
94
+ chainId,
95
+ collectibleId: tokenId,
96
+ type: TransactionType.SELL,
97
+ queriesToInvalidate: [
98
+ ...collectableKeys.all,
99
+ balanceQueries.all,
100
+ ] as unknown as QueryKey[],
101
+ callbacks,
102
+ });
103
+ sellModal$.close();
104
+ },
105
+ });
106
+
107
+ const { isLoading, steps, refreshSteps } = getSellSteps({
108
+ orderId: order?.orderId ?? '',
109
+ marketplace: order?.marketplace as MarketplaceKind,
110
+ quantity: order?.quantityRemaining
111
+ ? parseUnits(
112
+ order.quantityRemaining,
113
+ collectible?.decimals || 0,
114
+ ).toString()
115
+ : '1',
116
+ });
117
+
118
+ useEffect(() => {
119
+ refreshSteps();
120
+ }, [order, machineLoading]);
121
+
122
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
123
+ const handleStepExecution = async (execute?: any) => {
124
+ if (!execute) return;
125
+ try {
126
+ await refreshSteps();
127
+ await execute();
128
+ } catch (error) {
129
+ if (callbacks?.onError) {
130
+ callbacks.onError(error as Error);
131
+ } else {
132
+ console.debug('onError callback not provided:', error);
133
+ }
134
+ }
135
+ };
136
+
137
+ if (collectionLoading || currenciesLoading || machineLoading) {
138
+ return (
139
+ <LoadingModal
140
+ isOpen={sellModal$.isOpen.get()}
141
+ chainId={Number(chainId)}
142
+ onClose={sellModal$.close}
143
+ title="You have an offer"
144
+ />
145
+ );
146
+ }
147
+
148
+ if (collectionError || order === undefined) {
149
+ return (
150
+ <ErrorModal
151
+ isOpen={sellModal$.isOpen.get()}
152
+ chainId={Number(chainId)}
153
+ onClose={sellModal$.close}
154
+ title="You have an offer"
155
+ />
156
+ );
157
+ }
158
+
159
+ const approvalNeeded = steps?.approval.isPending;
160
+
161
+ const currency = currencies?.find(
162
+ (c) => c.contractAddress === order?.priceCurrencyAddress,
163
+ );
164
+
165
+ const ctas = [
166
+ {
167
+ label: 'Approve TOKEN',
168
+ onClick: () => handleStepExecution(() => steps?.approval.execute()),
169
+ hidden: !approvalNeeded || approvalExecutedSuccess,
170
+ pending: steps?.approval.isExecuting || isLoading,
171
+ variant: 'glass' as const,
172
+ disabled: isLoading || steps?.transaction.isExecuting,
173
+ },
174
+ {
175
+ label: 'Accept',
176
+ onClick: () => handleStepExecution(() => steps?.transaction.execute()),
177
+ pending: steps?.transaction.isExecuting || isLoading,
178
+ disabled: (!approvalExecutedSuccess && approvalNeeded) || isLoading,
179
+ },
180
+ ] satisfies ActionModalProps['ctas'];
181
+
182
+ return (
183
+ <ActionModal
184
+ isOpen={sellModal$.isOpen.get()}
185
+ chainId={Number(chainId)}
186
+ onClose={sellModal$.close}
187
+ title="You have an offer"
188
+ ctas={ctas}
189
+ >
190
+ <TransactionHeader
191
+ title="Offer received"
192
+ currencyImageUrl={currency?.imageUrl}
193
+ date={order && new Date(order.createdAt)}
194
+ />
195
+ <TokenPreview
196
+ collectionName={collection?.name}
197
+ collectionAddress={collectionAddress}
198
+ collectibleId={tokenId}
199
+ chainId={chainId}
200
+ />
201
+ <TransactionDetails
202
+ collectibleId={tokenId}
203
+ collectionAddress={collectionAddress}
204
+ chainId={chainId}
205
+ price={
206
+ currency
207
+ ? {
208
+ amountRaw: order?.priceAmount,
209
+ currency,
210
+ }
211
+ : undefined
212
+ }
213
+ currencyImageUrl={currency?.imageUrl}
214
+ />
215
+ </ActionModal>
216
+ );
217
+ },
218
+ );