herald-exchange-glide-widget 1.0.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.
Files changed (37) hide show
  1. package/.babelrc +3 -0
  2. package/Readme.md +116 -0
  3. package/dist/index.css +1 -0
  4. package/dist/index.d.ts +17 -0
  5. package/dist/index.js +24 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +24 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +58 -0
  10. package/rollup.config.js +90 -0
  11. package/src/assets/css/style.module.css +1352 -0
  12. package/src/assets/icons-one.png +0 -0
  13. package/src/assets/swap.svg +8 -0
  14. package/src/components/ButtonStepper.tsx +143 -0
  15. package/src/components/CommonCenterLoader.tsx +118 -0
  16. package/src/components/CustomeSelect.tsx +179 -0
  17. package/src/components/DotLoader.tsx +8 -0
  18. package/src/components/SellAdminCryptoAccount.tsx +604 -0
  19. package/src/components/SellField.tsx +705 -0
  20. package/src/components/WidgetBankDetails.tsx +592 -0
  21. package/src/components/WidgetComponent.tsx +42 -0
  22. package/src/components/WidgetContent.tsx +36 -0
  23. package/src/components/WidgetSuccesDetails.tsx +122 -0
  24. package/src/components/api.ts +59 -0
  25. package/src/components/api.tsx +61 -0
  26. package/src/components/chains.ts +319 -0
  27. package/src/components/images.d.ts +5 -0
  28. package/src/components/loader.tsx +12 -0
  29. package/src/components/style.module.css.d.ts +4 -0
  30. package/src/components/toast.tsx +43 -0
  31. package/src/components/types.ts +237 -0
  32. package/src/components/utils.ts +17 -0
  33. package/src/components/utils.tsx +10 -0
  34. package/src/hooks/toastProvider.tsx +63 -0
  35. package/src/hooks/useSocketExchange.tsx +48 -0
  36. package/src/index.ts +3 -0
  37. package/tsconfig.json +118 -0
@@ -0,0 +1,705 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import CustomSelect from "./CustomeSelect";
3
+ import WidgetSuccesDetails from "./WidgetSuccesDetails";
4
+ import WidgetBankDetails from "./WidgetBankDetails";
5
+ import SellAdminCryptoAccount from "./SellAdminCryptoAccount";
6
+ import { useToast } from "../hooks/toastProvider";
7
+ import Loader from "./loader";
8
+ import { useExchangeSocket } from "../hooks/useSocketExchange";
9
+ import DotLoader from "./DotLoader";
10
+ import { handleApiCall } from "./api";
11
+ import { getBaseUrl, isValidDecimal } from "./utils";
12
+ import type {
13
+ comissionAPIResponse,
14
+ ConfigurationAPIResponse,
15
+ CurrenciesAPIResponse,
16
+ CustomOption,
17
+ OfframpTransactionAPIResponse,
18
+ rulesType,
19
+ SellParamsType,
20
+ } from "./types";
21
+
22
+ type SellFieldProps = {
23
+ apiKey: string;
24
+ parameters: SellParamsType;
25
+ clientReferenceID: string;
26
+ css: any;
27
+ mode: string;
28
+ };
29
+
30
+ export type tokenSellDataType = {
31
+ from_amount: string;
32
+ selectedCrypto: string;
33
+ selectedFiat: string;
34
+ to_currency_conversion_value: number;
35
+ exchange_rate: number;
36
+ minAmount: string;
37
+ maxAmount: string;
38
+ network_type: string;
39
+ selectedBeneficiary: string;
40
+ transaction_hash?: string;
41
+ response?: OfframpTransactionAPIResponse["data"];
42
+ };
43
+
44
+ // Sell Crypto and receive Fiat
45
+ const SellField = ({ apiKey, parameters, clientReferenceID, css, mode }: SellFieldProps) => {
46
+ const { addToast } = useToast(); // to show toast
47
+ const exchangeSocket: any = useExchangeSocket({}); // socket connevction to fetch exchange rate
48
+
49
+ const [step, setStep] = useState(1); // used to render components
50
+
51
+ const [currenciesLoading, setCurrenciesLoading] = useState(false);
52
+ const [currencies, setCurrencies] = useState<CurrenciesAPIResponse["data"] | null>(null);
53
+ const [tokenSellData, setTokenSellData] = useState<tokenSellDataType>({
54
+ from_amount:
55
+ parameters?.from_amount && parseFloat(parameters?.from_amount) > 0
56
+ ? parameters.from_amount
57
+ : "0",
58
+ selectedCrypto: parameters?.from_currency || "",
59
+ selectedFiat: parameters?.to_currency || "",
60
+ to_currency_conversion_value: 0,
61
+ exchange_rate: 0,
62
+ minAmount: "0.0000001",
63
+ maxAmount: "100000.0000",
64
+ network_type: "",
65
+ selectedBeneficiary: "",
66
+ });
67
+ // From
68
+ const [selectedCrypto, setSelectedCrypto] = useState<CustomOption | null>(null);
69
+ // TO
70
+ const [selectedFiat, setSelectedFiat] = useState<CustomOption | null>(null);
71
+
72
+ // Options
73
+ const [cryptoCurrencyOptions, setCryptoCurrencyOptions] = useState<CustomOption[] | []>([]); // crypto currency options
74
+ const [fiatCurrencyOptions, setFiatCurrencyOptions] = useState<CustomOption[] | []>([]); // fiat currency options
75
+ const [networkOptions, setNetworkOptions] = useState<CustomOption[] | []>([]); // network options
76
+
77
+ // Comissions
78
+ const [commissionApiResponse, setComissionApiResponse] = useState<
79
+ comissionAPIResponse["data"] | null
80
+ >(null);
81
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
82
+ const [commissionForThisUser, setCommissionForThisUser] = useState(0);
83
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
84
+ const [actualCommission, setActualCommission] = useState(0); // original commission
85
+ // Exchange rate
86
+ const [exchangeRate, setExchangeRate] = useState(0); // actual exchange rate
87
+ const [exchangeRateForThisUser, setExchangeRateForThisUser] = useState(0); // exchange rate shown to user
88
+ const [userReceivableFiatValue, setUserReceivableFiatValue] = useState(0); //fiat value shown to user
89
+ const [isRangeComissionEnabled, setIsRangeComissionEnabled] = useState<boolean>(false);
90
+ // Fot loaders and to disable fields
91
+ const [isFetchingExchangeRate, setIsFetchingExchangeRate] = useState(true);
92
+ // Validation
93
+ const [inputRules, setInputRules] = useState<rulesType | null>(null);
94
+ const [invalidAmount, setInvalidAmount] = useState({
95
+ min: false,
96
+ max: false,
97
+ });
98
+
99
+ const [commissionData, setCommissionData] = useState<any>({
100
+ admin_commission: 0,
101
+ merchant_commission: 0,
102
+ });
103
+
104
+ useEffect(() => {
105
+ fetchCurrencies();
106
+ // fetchCommissionRanges();
107
+ fetchCommissions();
108
+ fetchConfiguration();
109
+ }, []);
110
+
111
+ const fetchConfiguration = () => {
112
+ const baseUrl = getBaseUrl(mode);
113
+ handleApiCall({
114
+ url: `${baseUrl}/api/lookup/configurations`,
115
+ headers: {
116
+ "Content-Type": "application/json",
117
+ "X-API-KEY": apiKey,
118
+ "User-Id": clientReferenceID,
119
+ },
120
+ onSuccess: (result: ConfigurationAPIResponse) => {
121
+ if (result?.success) {
122
+ setIsRangeComissionEnabled(result?.data?.merchant_configuration?.range_calculation === 1);
123
+ }
124
+ },
125
+ onError: () => {
126
+ addToast("Error fetching configuration", "error");
127
+ },
128
+ });
129
+ };
130
+
131
+ const fetchCommissions = () => {
132
+ const baseUrl = getBaseUrl(mode);
133
+
134
+ handleApiCall({
135
+ url: `${baseUrl}/api/lookup/commissions`,
136
+ headers: {
137
+ "Content-Type": "application/json",
138
+ "X-API-KEY": apiKey,
139
+ "User-Id": clientReferenceID,
140
+ },
141
+ onSuccess: (result: comissionAPIResponse) => {
142
+ if (result?.success) {
143
+ setComissionApiResponse(result?.data);
144
+ }
145
+ },
146
+ onError: () => {
147
+ addToast("Error fetching comission", "error");
148
+ },
149
+ });
150
+ };
151
+
152
+ const fetchCurrencies = () => {
153
+ const baseUrl = getBaseUrl(mode);
154
+ setCurrenciesLoading(true);
155
+ handleApiCall({
156
+ url: `${baseUrl}/api/lookup/currencies`,
157
+ headers: {
158
+ "Content-Type": "application/json",
159
+ "X-API-KEY": apiKey,
160
+ "User-Id": clientReferenceID,
161
+ },
162
+ onSuccess: (result: CurrenciesAPIResponse) => {
163
+ if (result?.success) {
164
+ setCurrencies(result?.data);
165
+ }
166
+ setCurrenciesLoading(false);
167
+ },
168
+
169
+ onError: () => {
170
+ addToast("Error fetching currency", "error");
171
+ setCurrenciesLoading(false);
172
+ },
173
+ });
174
+ };
175
+
176
+ useEffect(() => {
177
+ if (currencies) {
178
+ const fiatCurrencyOptions =
179
+ currencies?.currencies
180
+ ?.filter(
181
+ (item) => item?.supported_currency?.type === "FIAT" && item?.service === "stream"
182
+ )
183
+ ?.map((item) => ({
184
+ label: item?.supported_currency?.code,
185
+ value: item?.unique_id,
186
+ icon: item?.supported_currency?.icon,
187
+ })) || [];
188
+
189
+ setFiatCurrencyOptions(fiatCurrencyOptions);
190
+
191
+ const selected_forex = tokenSellData?.selectedFiat
192
+ ? currencies?.currencies?.find(
193
+ (currency) => currency?.supported_currency?.code === tokenSellData?.selectedFiat
194
+ ) ||
195
+ currencies?.currencies?.find(
196
+ (currency) => currency?.supported_currency?.code === fiatCurrencyOptions?.[0]?.label
197
+ )
198
+ : currencies?.currencies?.find(
199
+ (currency) => currency?.supported_currency?.code === fiatCurrencyOptions?.[0]?.label
200
+ );
201
+
202
+ const selectedFiat = tokenSellData.selectedFiat
203
+ ? fiatCurrencyOptions.find((fiat) => fiat.label === tokenSellData.selectedFiat) ||
204
+ fiatCurrencyOptions?.[0]
205
+ : fiatCurrencyOptions?.[0];
206
+
207
+ setSelectedFiat(selectedFiat);
208
+
209
+ const cryptoOptions =
210
+ currencies?.currencies
211
+ ?.filter(
212
+ (item) => item?.supported_currency?.type === "CRYPTO" && item?.service === "stream"
213
+ )
214
+ ?.map((item) => ({
215
+ label: item?.supported_currency?.code,
216
+ value: item?.unique_id,
217
+ icon: item?.supported_currency?.icon,
218
+ })) || [];
219
+
220
+ setCryptoCurrencyOptions(cryptoOptions);
221
+
222
+ const networkOptions =
223
+ currencies?.currencies
224
+ ?.filter(
225
+ (item) =>
226
+ item?.supported_currency?.type === "CRYPTO" &&
227
+ item?.service === "stream" &&
228
+ !["USDT", "USDC"].includes(item?.supported_currency?.code)
229
+ )
230
+ ?.map((item) => ({
231
+ label: item?.supported_currency?.code,
232
+ value: item?.supported_currency?.code,
233
+ icon: item?.supported_currency?.icon,
234
+ })) || [];
235
+
236
+ setNetworkOptions(networkOptions);
237
+
238
+ const selected_crypto = parameters?.from_currency
239
+ ? currencies?.currencies?.find(
240
+ (currency) => currency?.supported_currency?.code === parameters?.from_currency
241
+ ) ||
242
+ currencies?.currencies?.find(
243
+ (currency) => currency?.supported_currency?.code === cryptoOptions?.[0]?.label
244
+ )
245
+ : currencies?.currencies?.find(
246
+ (currency) => currency?.supported_currency?.code === cryptoOptions?.[0]?.label
247
+ );
248
+
249
+ setSelectedCrypto(
250
+ parameters?.from_currency
251
+ ? cryptoOptions.find((currency) => currency.label === parameters?.from_currency) ||
252
+ cryptoOptions?.[0]
253
+ : cryptoOptions?.[0] || []
254
+ );
255
+
256
+ setTokenSellData((prev) => ({
257
+ ...prev,
258
+ selectedCrypto: selected_crypto?.supported_currency?.code || "",
259
+ selectedFiat: selected_forex?.supported_currency?.code || "",
260
+ }));
261
+ }
262
+ }, [currencies]);
263
+
264
+ useEffect(() => {
265
+ if (commissionApiResponse && currencies) {
266
+ const rules = commissionApiResponse?.rules?.find((item) => item?.service === "stream");
267
+ if (rules) {
268
+ setInputRules(rules);
269
+ }
270
+ const commission = commissionApiResponse?.commission?.find(
271
+ (item) => item?.service == "stream"
272
+ );
273
+ setActualCommission(commission?.commission ? parseFloat(commission?.commission) : 0);
274
+
275
+ setCommissionData({
276
+ admin_commission: commission?.admin_commission
277
+ ? parseFloat(commission?.admin_commission)
278
+ : 0,
279
+ merchant_commission: commission?.commission ? parseFloat(commission?.commission) : 0,
280
+ });
281
+
282
+ if (rules) {
283
+ setTokenSellData((prev) => ({
284
+ ...prev,
285
+ minAmount:
286
+ parseFloat(rules?.schema?.min) <= 0
287
+ ? "0.0000001"
288
+ : parseFloat(rules?.schema?.min)?.toFixed(8),
289
+ maxAmount:
290
+ parseFloat(rules?.schema?.max) <= 0
291
+ ? "100000"
292
+ : parseFloat(rules?.schema?.max)?.toFixed(8),
293
+ // buy_commission: commission,
294
+ }));
295
+ }
296
+ }
297
+ }, [commissionApiResponse, currencies]);
298
+
299
+ useEffect(() => {
300
+ if (exchangeSocket && selectedFiat && selectedCrypto) {
301
+ setExchangeRateForThisUser(0);
302
+ fetchExchangeRate();
303
+ }
304
+ }, [selectedCrypto, selectedFiat]);
305
+
306
+ useEffect(() => {
307
+ if (exchangeSocket) {
308
+ exchangeSocket.on("getSDKExchangeRate", (data: string) => {
309
+ console.log("ex rate :", data);
310
+ setExchangeRate(parseFloat(data));
311
+ setIsFetchingExchangeRate(false);
312
+ });
313
+ }
314
+ }, [exchangeSocket]);
315
+
316
+ const fetchExchangeRate = () => {
317
+ setExchangeRate(0);
318
+ setIsFetchingExchangeRate(true);
319
+ exchangeSocket.emit("fetchSDKExchangeRate", {
320
+ pair: `${selectedFiat?.label}-${selectedCrypto?.label}`,
321
+ user_id: "",
322
+ type: "sell",
323
+ apiKey: apiKey,
324
+ userId: clientReferenceID,
325
+ });
326
+ };
327
+
328
+ const handleCryptoCurrencyChange = (selectedOption: CustomOption | null) => {
329
+ const fiat = currencies?.currencies?.find((fiat) => fiat.unique_id === selectedOption?.value);
330
+ setTokenSellData({
331
+ ...tokenSellData,
332
+ selectedCrypto: fiat?.supported_currency?.code || "",
333
+ });
334
+ setSelectedCrypto(selectedOption);
335
+ };
336
+
337
+ const handleCryptoCurrencyValueChange = (value: string) => {
338
+ if (value.includes(".")) {
339
+ if (inputRules && !isValidDecimal(value, inputRules?.schema?.decimal)) {
340
+ addToast(`You can input upto ${inputRules?.schema?.decimal} decimal places.`, "error");
341
+ return;
342
+ } else {
343
+ if (value === "") {
344
+ setTokenSellData({
345
+ ...tokenSellData,
346
+ from_amount: "",
347
+ });
348
+ } else {
349
+ if (!isNaN(Number(value))) {
350
+ setTokenSellData({
351
+ ...tokenSellData,
352
+ from_amount: value,
353
+ });
354
+ }
355
+ }
356
+ }
357
+ } else {
358
+ if (value === "") {
359
+ setTokenSellData({
360
+ ...tokenSellData,
361
+ from_amount: "",
362
+ });
363
+ } else {
364
+ if (!isNaN(Number(value))) {
365
+ setTokenSellData({
366
+ ...tokenSellData,
367
+ from_amount: value,
368
+ });
369
+ }
370
+ }
371
+ }
372
+ };
373
+
374
+ const onComplete = () => {
375
+ if (parseFloat(tokenSellData.from_amount) > 0) {
376
+ setTokenSellData({
377
+ ...tokenSellData,
378
+ to_currency_conversion_value: userReceivableFiatValue,
379
+ exchange_rate: exchangeRateForThisUser,
380
+ });
381
+
382
+ setStep(2);
383
+ } else {
384
+ addToast("Please enter valid amount", "error");
385
+ }
386
+ };
387
+
388
+ useEffect(() => {
389
+ setInvalidAmount({
390
+ min:
391
+ parseFloat(tokenSellData.from_amount) < parseFloat(tokenSellData.minAmount) ||
392
+ tokenSellData.from_amount === "" ||
393
+ parseFloat(tokenSellData.from_amount) <= 0,
394
+ max: parseFloat(tokenSellData.from_amount) > parseFloat(tokenSellData.maxAmount),
395
+ });
396
+ }, [exchangeRateForThisUser, tokenSellData]);
397
+
398
+ useEffect(() => {
399
+ if (tokenSellData) {
400
+ const actualExchangeRate = exchangeRate;
401
+
402
+ const range = isRangeComissionEnabled
403
+ ? commissionApiResponse?.commission_ranges?.find(
404
+ (item) =>
405
+ parseFloat(item.from_amount) <=
406
+ parseFloat(tokenSellData.from_amount) * actualExchangeRate &&
407
+ parseFloat(item.to_amount) >=
408
+ parseFloat(tokenSellData.from_amount) * actualExchangeRate &&
409
+ item.currency === selectedFiat?.label &&
410
+ item.type === "c-f"
411
+ )
412
+ : null;
413
+
414
+ const from_commission = range ? parseFloat(range?.from_commission) : 0;
415
+ const to_commission = range ? parseFloat(range?.to_commission) : 0;
416
+ const token_from_amount = tokenSellData.from_amount
417
+ ? parseFloat(tokenSellData.from_amount)
418
+ : 0;
419
+ const range_from_amount = range ? parseFloat(range.from_amount) : 0;
420
+ const range_to_amount = range ? parseFloat(range.to_amount) : 0;
421
+
422
+ const additonalCommissionRate = range
423
+ ? parseFloat(range.from_commission) -
424
+ ((from_commission - to_commission) / (range_to_amount - range_from_amount)) *
425
+ (token_from_amount * actualExchangeRate - range_from_amount)
426
+ : 0;
427
+
428
+ const ceffective: number = totalEffectiveCommission(
429
+ commissionData?.admin_commission + additonalCommissionRate,
430
+ commissionData?.merchant_commission
431
+ );
432
+ // let commissionEffective:any = ((ceffective/100) * actualExchangeRate)
433
+ // console.log("Effective Commission", ceffective, commissionEffective);
434
+ const userCommission = ceffective || 0;
435
+
436
+ const newCommission = (userCommission / 100) * actualExchangeRate;
437
+ setCommissionForThisUser(newCommission || 0);
438
+
439
+ const newExchangeRate = parseFloat((actualExchangeRate - newCommission).toFixed(6));
440
+
441
+ setExchangeRateForThisUser(newExchangeRate || 0);
442
+
443
+ setUserReceivableFiatValue(token_from_amount * newExchangeRate);
444
+ }
445
+ }, [exchangeRate, tokenSellData, commissionApiResponse]);
446
+
447
+ function totalEffectiveCommission(c1: number, c2: number) {
448
+ const factor = (1 - c1 / 100) * (1 - c2 / 100);
449
+ return 100 * (1 - factor);
450
+ }
451
+
452
+ useEffect(() => {
453
+ if (networkOptions?.length > 0) {
454
+ if (["USDT", "USDC"].includes(tokenSellData.selectedCrypto) && !tokenSellData.network_type) {
455
+ setTokenSellData((prev) => ({ ...prev, network_type: networkOptions[0].value }));
456
+ }
457
+ }
458
+ }, [tokenSellData, networkOptions]);
459
+
460
+ const onFiatChange = (selectedOption: CustomOption | null) => {
461
+ const fiat = currencies?.currencies?.find(
462
+ (crypto) => crypto?.unique_id === selectedOption?.value
463
+ );
464
+ setTokenSellData({
465
+ ...tokenSellData,
466
+ selectedFiat: fiat?.supported_currency?.code || "",
467
+ });
468
+ setSelectedFiat(selectedOption);
469
+ };
470
+
471
+ console.log({ cryptoCurrencyOptions });
472
+
473
+ return (
474
+ <>
475
+ {step === 1 ? (
476
+ <>
477
+ {" "}
478
+ <div className={css.gilde_field_card}>
479
+ <div className={css.gilde_field_box}>
480
+ <div className={css.gilde_field_label}>You Pay</div>
481
+ <div className={css.gilde_field_form}>
482
+ <input
483
+ type="text"
484
+ className={css.input_control}
485
+ value={tokenSellData.from_amount}
486
+ onChange={(e) => {
487
+ const newValue = e.target.value;
488
+ handleCryptoCurrencyValueChange(newValue);
489
+ }}
490
+ />
491
+ </div>
492
+ </div>
493
+ <div className={css.gilde_field_select_card}>
494
+ <div className={css.gilde_field_select}>
495
+ {cryptoCurrencyOptions?.length > 0 ? (
496
+ <CustomSelect
497
+ backgroundColor="#DECFFF"
498
+ placeholder="Select"
499
+ image={true}
500
+ singleicons={true}
501
+ value={selectedCrypto}
502
+ isSearchable={false}
503
+ onChange={(selectedOption) => {
504
+ // setExchangeRate(0);
505
+ handleCryptoCurrencyChange(selectedOption);
506
+ }}
507
+ isDisabled={currenciesLoading}
508
+ options={cryptoCurrencyOptions}
509
+ />
510
+ ) : (
511
+ <div style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
512
+ <Loader />
513
+ </div>
514
+ )}
515
+ </div>
516
+ {networkOptions?.length > 0 &&
517
+ ["USDT", "USDC"].includes(tokenSellData.selectedCrypto) && (
518
+ <div className={css.gilde_selected_two}>
519
+ <CustomSelect
520
+ backgroundColor="#fff"
521
+ placeholder="Select"
522
+ options={networkOptions}
523
+ image={true}
524
+ singleicons={true}
525
+ isSearchable={false}
526
+ onChange={(select) => {
527
+ setTokenSellData({
528
+ ...tokenSellData,
529
+ network_type: select?.value || "",
530
+ });
531
+ }}
532
+ value={networkOptions.find(
533
+ (item) => item.value == tokenSellData.network_type
534
+ )}
535
+ isDisabled={currenciesLoading}
536
+ />
537
+ </div>
538
+ )}
539
+ </div>
540
+ </div>
541
+ {invalidAmount?.min && (
542
+ <p>Invalid, Min : {parseFloat(tokenSellData?.minAmount)?.toFixed(8)}</p>
543
+ )}
544
+ {invalidAmount?.max && (
545
+ <p>Invalid, Max : {parseFloat(tokenSellData?.maxAmount)?.toString()}</p>
546
+ )}
547
+ <div className={css.gilde_info_box}>
548
+ <div className={` ${css.gilde_label_card} ${css.gilde_space} `}>
549
+ <div className={css.gilde_label_icons}>
550
+ <svg
551
+ xmlns="http://www.w3.org/2000/svg"
552
+ xmlSpace="preserve"
553
+ width="12"
554
+ height="12"
555
+ viewBox="0 0 300 300"
556
+ >
557
+ <path
558
+ d="M240.3 171.5H59.7c-11.9 0-21.5-9.6-21.5-21.5s9.6-21.5 21.5-21.5h180.6c11.9 0 21.5 9.6 21.5 21.5s-9.6 21.5-21.5 21.5"
559
+ data-original="#000000"
560
+ ></path>
561
+ <circle cx="150" cy="65.5" r="30.5" data-original="#000000"></circle>
562
+ <circle cx="150.5" cy="234.5" r="30.5" data-original="#000000"></circle>
563
+ </svg>
564
+ </div>
565
+ <div className={css.gilde_label_value}>
566
+ <span style={{ marginRight: 10 }}>Rate :</span>
567
+ {isFetchingExchangeRate ? (
568
+ <DotLoader />
569
+ ) : (
570
+ `1 ${tokenSellData.selectedCrypto} = ${
571
+ exchangeRateForThisUser?.toFixed(4) || 0
572
+ } ${tokenSellData.selectedFiat}`
573
+ )}
574
+ </div>
575
+ </div>
576
+
577
+ <div className={` ${css.gilde_label_titles} ${css.gilde_space_top} `}>
578
+ <div className={css.gilde_label_dots}></div>
579
+ <div className={css.gilde_ramp_details}>
580
+ <div className={css.gilde_off_head}>Withdrawal Method</div>
581
+ <div className={css.gilde_payment_box}>
582
+ <div className={` ${css.gilde_payment_check_card} ${css.selected} `}>
583
+ <input type="radio" name="radioDefault" id="radioDefault1" value="0.10234" />
584
+ <div>Bank Transfer</div>
585
+ <svg
586
+ xmlns="http://www.w3.org/2000/svg"
587
+ width="20"
588
+ height="20"
589
+ viewBox="0 0 408.576 408.576"
590
+ >
591
+ <g>
592
+ <path
593
+ d="M204.288 0C91.648 0 0 91.648 0 204.288s91.648 204.288 204.288 204.288 204.288-91.648 204.288-204.288S316.928 0 204.288 0zm114.176 150.528-130.56 129.536c-7.68 7.68-19.968 8.192-28.16.512L90.624 217.6c-8.192-7.68-8.704-20.48-1.536-28.672 7.68-8.192 20.48-8.704 28.672-1.024l54.784 50.176L289.28 121.344c8.192-8.192 20.992-8.192 29.184 0s8.192 20.992 0 29.184z"
594
+ fill="var(--primary-color-des)"
595
+ ></path>
596
+ </g>
597
+ </svg>
598
+ </div>
599
+ </div>
600
+ </div>
601
+ </div>
602
+ </div>
603
+ <div className={css.gilde_field_card}>
604
+ <div className={css.gilde_field_box}>
605
+ <div className={css.gilde_field_label}>You Receive ( estimate )</div>
606
+ <div className={css.gilde_field_form}>
607
+ {isFetchingExchangeRate ? (
608
+ <DotLoader size={20} />
609
+ ) : (
610
+ <input
611
+ type="text"
612
+ className={css.input_control}
613
+ value={
614
+ invalidAmount?.min || invalidAmount?.max
615
+ ? 0
616
+ : Number(userReceivableFiatValue) && Number(userReceivableFiatValue) > 0
617
+ ? userReceivableFiatValue?.toFixed(4)
618
+ : 0
619
+ }
620
+ disabled
621
+ />
622
+ )}
623
+ </div>
624
+ </div>
625
+ <div className={css.gilde_field_select_card}>
626
+ <div className={css.gilde_field_select}>
627
+ {fiatCurrencyOptions?.length > 0 ? (
628
+ <CustomSelect
629
+ backgroundColor="#DECFFF"
630
+ placeholder="Select"
631
+ borderColor="var(--no-color)"
632
+ image={true}
633
+ singleicons={true}
634
+ options={fiatCurrencyOptions}
635
+ value={selectedFiat}
636
+ isSearchable={false}
637
+ onChange={(selectedOption) => {
638
+ // setExchangeRate(0);
639
+ onFiatChange(selectedOption);
640
+ }}
641
+ isDisabled={currenciesLoading || isFetchingExchangeRate}
642
+ />
643
+ ) : (
644
+ <div style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
645
+ <Loader />
646
+ </div>
647
+ )}
648
+ </div>
649
+ </div>
650
+ </div>
651
+ <div style={{ marginTop: 20 }} className={css.gilde_info_card}>
652
+ <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 32 32">
653
+ <g id="Layer_20" data-name="Layer 20">
654
+ <path fill="#fbd63b" d="M28 28H4L16 6z"></path>
655
+ <path fill="#f8be31" d="m16 6 12 22H16z"></path>
656
+ <path fill="#333" d="m16 21-2-7h4z"></path>
657
+ <circle cx="16" cy="25" r="1" fill="#333"></circle>
658
+ <path d="M16 14h2l-2 7zM16 24a1 1 0 0 1 0 2z"></path>
659
+ </g>
660
+ </svg>
661
+ <div className={css.caution_info}>
662
+ Cryptocurrencies are volatile, and prices can change rapidly, make sure to research
663
+ and understand the market risks.
664
+ </div>
665
+ </div>
666
+ <div className={css.gilde_ramp_action}>
667
+ <button
668
+ className={` ${css.action_btn} ${css.primary} `}
669
+ onClick={onComplete}
670
+ disabled={
671
+ currenciesLoading || !(exchangeRate > 0) || invalidAmount.min || invalidAmount.max
672
+ }
673
+ >
674
+ Sell Now
675
+ </button>
676
+ </div>
677
+ </>
678
+ ) : step === 2 ? (
679
+ <WidgetBankDetails
680
+ setStep={setStep}
681
+ data={tokenSellData}
682
+ apiKey={apiKey}
683
+ clientReferenceID={clientReferenceID}
684
+ setTokenSellData={setTokenSellData}
685
+ css={css}
686
+ mode={mode}
687
+ />
688
+ ) : step === 3 ? (
689
+ <SellAdminCryptoAccount
690
+ tokenSellData={tokenSellData}
691
+ setTokenSellData={setTokenSellData}
692
+ apiKey={apiKey}
693
+ clientReferenceID={clientReferenceID}
694
+ setStep={setStep}
695
+ css={css}
696
+ mode={mode}
697
+ />
698
+ ) : step === 4 ? (
699
+ <WidgetSuccesDetails css={css} tokenSellData={tokenSellData} />
700
+ ) : null}
701
+ </>
702
+ );
703
+ };
704
+
705
+ export default SellField;