@coin-voyage/paykit 2.2.7-beta.2 → 2.2.7-beta.4

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 (90) hide show
  1. package/dist/components/Pages/About/index.js +86 -80
  2. package/dist/components/Pages/Confirmation/index.js +8 -7
  3. package/dist/components/Pages/PayToAddress/copyable-info.d.ts +8 -0
  4. package/dist/components/Pages/PayToAddress/copyable-info.js +11 -0
  5. package/dist/components/Pages/PayToAddress/index.d.ts +1 -0
  6. package/dist/components/Pages/PayToAddress/index.js +77 -0
  7. package/dist/components/Pages/PayToAddress/styles.d.ts +7 -0
  8. package/dist/components/Pages/PayToAddress/styles.js +36 -0
  9. package/dist/components/Pages/PayWithToken/index.js +19 -18
  10. package/dist/components/Pages/SelectChain/index.d.ts +1 -0
  11. package/dist/components/Pages/SelectChain/index.js +30 -0
  12. package/dist/components/Pages/SelectMethod/index.js +4 -9
  13. package/dist/components/Pages/SelectPayToAddressChain/index.d.ts +1 -0
  14. package/dist/components/Pages/SelectPayToAddressChain/index.js +14 -0
  15. package/dist/components/Pages/SelectPayToAddressToken/index.d.ts +1 -0
  16. package/dist/components/Pages/SelectPayToAddressToken/index.js +10 -0
  17. package/dist/components/Pages/SelectToken/index.js +11 -15
  18. package/dist/components/pay-modal/index.js +18 -4
  19. package/dist/components/ui/CircleTimer/index.d.ts +11 -0
  20. package/dist/components/ui/CircleTimer/index.js +40 -0
  21. package/dist/components/ui/CopyableInfo/index.d.ts +9 -0
  22. package/dist/components/ui/CopyableInfo/index.js +25 -0
  23. package/dist/components/ui/CopyableInfo/styles.d.ts +8 -0
  24. package/dist/components/ui/CopyableInfo/styles.js +63 -0
  25. package/dist/components/ui/CountDownTimer/index.d.ts +6 -0
  26. package/dist/components/ui/CountDownTimer/index.js +14 -0
  27. package/dist/components/ui/CountDownTimer/styles.d.ts +2 -0
  28. package/dist/components/ui/CountDownTimer/styles.js +12 -0
  29. package/dist/components/ui/CustomQRCode/styles.js +1 -1
  30. package/dist/components/ui/Modal/index.js +1 -0
  31. package/dist/components/ui/Modal/useModalTransition.d.ts +16 -2
  32. package/dist/components/ui/Modal/useModalTransition.js +72 -4
  33. package/dist/components/ui/SelectAnotherMethod/index.d.ts +6 -0
  34. package/dist/components/ui/SelectAnotherMethod/index.js +6 -0
  35. package/dist/config/route-config.js +40 -4
  36. package/dist/hooks/useChainOptions.d.ts +12 -0
  37. package/dist/hooks/useChainOptions.js +107 -0
  38. package/dist/hooks/useCountdown.d.ts +1 -0
  39. package/dist/hooks/useCountdown.js +23 -0
  40. package/dist/hooks/useDepositAddressQuery.d.ts +6 -0
  41. package/dist/hooks/useDepositAddressQuery.js +35 -0
  42. package/dist/hooks/useLockBodyScroll.js +11 -27
  43. package/dist/hooks/useMethodOptions.d.ts +3 -5
  44. package/dist/hooks/useMethodOptions.js +31 -101
  45. package/dist/hooks/usePayOrderQuotes.d.ts +3 -3
  46. package/dist/hooks/usePayToAddress.d.ts +10 -0
  47. package/dist/hooks/usePayToAddress.js +22 -0
  48. package/dist/hooks/usePayToAddressChainOptions.d.ts +14 -0
  49. package/dist/hooks/usePayToAddressChainOptions.js +31 -0
  50. package/dist/hooks/usePayToAddressTokens.d.ts +9 -0
  51. package/dist/hooks/usePayToAddressTokens.js +36 -0
  52. package/dist/hooks/usePayWithToken.d.ts +5 -4
  53. package/dist/hooks/usePayWithToken.js +29 -34
  54. package/dist/hooks/usePaymentState.d.ts +14 -5
  55. package/dist/hooks/usePaymentState.js +24 -8
  56. package/dist/hooks/useTokenOptions.js +2 -2
  57. package/dist/hooks/useWalletConnectUri.js +1 -1
  58. package/dist/lib/api/payment-details.d.ts +3 -0
  59. package/dist/lib/api/payment-details.js +9 -0
  60. package/dist/lib/localizations/locales/ar-AE.js +14 -0
  61. package/dist/lib/localizations/locales/ca-AD.js +14 -0
  62. package/dist/lib/localizations/locales/de-DE.d.ts +14 -0
  63. package/dist/lib/localizations/locales/de-DE.js +14 -0
  64. package/dist/lib/localizations/locales/ee-EE.js +14 -0
  65. package/dist/lib/localizations/locales/en-US.d.ts +14 -0
  66. package/dist/lib/localizations/locales/en-US.js +14 -0
  67. package/dist/lib/localizations/locales/es-ES.js +14 -0
  68. package/dist/lib/localizations/locales/fa-IR.js +14 -0
  69. package/dist/lib/localizations/locales/fr-FR.js +14 -0
  70. package/dist/lib/localizations/locales/ja-JP.js +14 -0
  71. package/dist/lib/localizations/locales/pt-BR.js +14 -0
  72. package/dist/lib/localizations/locales/ru-RU.js +14 -0
  73. package/dist/lib/localizations/locales/tr-TR.js +14 -0
  74. package/dist/lib/localizations/locales/vi-VN.js +14 -0
  75. package/dist/lib/localizations/locales/zh-CN.js +14 -0
  76. package/dist/providers/paykit-provider.js +25 -4
  77. package/dist/types/enums.d.ts +4 -0
  78. package/dist/types/enums.js +5 -0
  79. package/dist/types/payment-details.d.ts +6 -0
  80. package/dist/types/payment-details.js +1 -0
  81. package/dist/types/route-config.d.ts +10 -4
  82. package/dist/types/routes.d.ts +4 -0
  83. package/dist/types/routes.js +4 -0
  84. package/dist/types/state.d.ts +4 -1
  85. package/dist/types.d.ts +5 -0
  86. package/dist/utils/index.d.ts +1 -0
  87. package/dist/utils/index.js +5 -0
  88. package/package.json +3 -3
  89. package/dist/components/Pages/SelectMethod/styles.d.ts +0 -9
  90. package/dist/components/Pages/SelectMethod/styles.js +0 -237
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Fragment, useEffect, useRef, useState } from "react";
2
+ import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
3
3
  import { Dot, Dots, ImageContainer, ImageContainerInner, MobileImageContainer, Slide, Slider, Slides } from "./styles";
4
4
  import { ModalBody, ModalContent, ModalH1, PageContent } from "../../ui/Modal/styles";
5
5
  import { AnimatePresence, MotionConfig } from "framer-motion";
@@ -9,6 +9,10 @@ import Button from "../../ui/Button/index";
9
9
  import { OrDivider } from "../../ui/Divider/OrDivider";
10
10
  import FitText from "../../ui/FitText/index";
11
11
  import { SlideOne, SlideThree, SlideTwo } from "./graphics";
12
+ const ANIMATION_EASE = [0.16, 1, 0.3, 1];
13
+ const ANIMATION_DURATION = 600;
14
+ const AUTOPLAY_DELAY = 5100;
15
+ const SLIDE_COUNT = 3;
12
16
  export default function About() {
13
17
  const locales = useLocales({
14
18
  //CONNECTORNAME: connector.name,
@@ -18,85 +22,88 @@ export default function About() {
18
22
  const [slider, setSlider] = useState(0);
19
23
  const interacted = useRef(false);
20
24
  const scrollPos = useRef(0);
21
- const animationEase = [0.16, 1, 0.3, 1];
22
- const animationDuration = 600;
23
- const autoplayDelay = 5100;
24
- const intervalRef = useRef(null);
25
- useEffect(() => {
26
- return () => {
27
- if (intervalRef.current) {
28
- clearInterval(intervalRef.current);
29
- }
30
- };
31
- }, []);
32
- const isSwipe = () => {
25
+ const sliderRef = useRef(null);
26
+ const timeoutRef = useRef(null);
27
+ const isSwipe = useCallback(() => {
33
28
  if (sliderRef.current) {
34
29
  const { overflow } = getComputedStyle(sliderRef.current);
35
30
  return overflow !== "visible";
36
31
  }
37
32
  return false;
38
- };
39
- const gotoSlide = (index) => {
40
- if (isSwipe()) {
41
- scrollToSlide(index);
42
- }
43
- else {
44
- setSlider(index);
45
- }
46
- };
47
- const _nextSlide = () => {
48
- if (interacted.current) {
49
- return;
50
- }
51
- setSlider((prevSlider) => {
52
- const index = (prevSlider + 1) % slides.length;
53
- scrollToSlide(index);
54
- return index;
55
- });
56
- intervalRef.current = setTimeout(_nextSlide, autoplayDelay);
57
- };
58
- const scrollToSlide = (index) => {
33
+ }, []);
34
+ const scrollToSlide = useCallback((index) => {
59
35
  if (sliderRef.current) {
60
36
  const { offsetWidth: width } = sliderRef.current;
61
37
  sliderRef.current.scrollLeft = width * index;
62
38
  setTimeout(() => setSlider(index), 100);
63
39
  }
64
- };
65
- // This event should not fire on mobile
66
- const onScroll = () => {
67
- if (!sliderRef.current) {
68
- return;
40
+ }, []);
41
+ const gotoSlide = useCallback((index) => {
42
+ if (isSwipe()) {
43
+ scrollToSlide(index);
69
44
  }
70
- const { offsetWidth: width, scrollLeft: x } = sliderRef.current;
71
- const prevScroll = scrollPos.current;
72
- scrollPos.current = x;
73
- // Limit when the slider should be set after swipe
74
- const threshold = 4;
75
- if (prevScroll - x > -threshold && prevScroll - x < threshold) {
76
- const currentSlide = Math.round(x / width);
77
- setSlider(currentSlide);
45
+ else {
46
+ setSlider(index);
78
47
  }
79
- };
80
- const onTouchMove = () => {
81
- didInteract();
82
- };
83
- const onTouchEnd = () => {
84
- const { offsetWidth: width, scrollLeft: x } = sliderRef.current;
85
- const currentSlide = Math.round(x / width);
86
- setSlider(currentSlide);
87
- };
88
- const didInteract = () => {
48
+ }, [isSwipe, scrollToSlide]);
49
+ const didInteract = useCallback(() => {
89
50
  interacted.current = true;
90
- if (intervalRef.current) {
91
- clearTimeout(intervalRef.current);
92
- intervalRef.current = null;
51
+ if (timeoutRef.current) {
52
+ clearTimeout(timeoutRef.current);
53
+ timeoutRef.current = null;
93
54
  }
94
- };
95
- const sliderRef = useRef(null);
55
+ }, []);
56
+ const scheduleNextRef = useRef(() => { });
57
+ const scheduleNext = useCallback(() => {
58
+ if (interacted.current)
59
+ return;
60
+ setSlider((prev) => {
61
+ const next = (prev + 1) % SLIDE_COUNT;
62
+ if (isSwipe()) {
63
+ scrollToSlide(next);
64
+ }
65
+ return next;
66
+ });
67
+ timeoutRef.current = setTimeout(() => scheduleNextRef.current(), AUTOPLAY_DELAY);
68
+ }, [isSwipe, scrollToSlide]);
69
+ useEffect(() => {
70
+ scheduleNextRef.current = scheduleNext;
71
+ }, [scheduleNext]);
72
+ useEffect(() => {
73
+ timeoutRef.current = setTimeout(() => scheduleNextRef.current(), AUTOPLAY_DELAY);
74
+ return () => {
75
+ if (timeoutRef.current) {
76
+ clearTimeout(timeoutRef.current);
77
+ timeoutRef.current = null;
78
+ }
79
+ };
80
+ }, []);
96
81
  useEffect(() => {
97
82
  const sr = sliderRef.current;
98
83
  if (!sr)
99
84
  return;
85
+ const onScroll = () => {
86
+ if (!sliderRef.current)
87
+ return;
88
+ const { offsetWidth: width, scrollLeft: x } = sliderRef.current;
89
+ const prevScroll = scrollPos.current;
90
+ scrollPos.current = x;
91
+ const threshold = 4;
92
+ if (prevScroll - x > -threshold && prevScroll - x < threshold) {
93
+ const currentSlide = Math.round(x / width);
94
+ setSlider(currentSlide);
95
+ }
96
+ };
97
+ const onTouchMove = () => {
98
+ didInteract();
99
+ };
100
+ const onTouchEnd = () => {
101
+ if (!sliderRef.current)
102
+ return;
103
+ const { offsetWidth: width, scrollLeft: x } = sliderRef.current;
104
+ const currentSlide = Math.round(x / width);
105
+ setSlider(currentSlide);
106
+ };
100
107
  sr.addEventListener("scroll", onScroll);
101
108
  sr.addEventListener("touchmove", onTouchMove);
102
109
  sr.addEventListener("touchend", onTouchEnd);
@@ -105,19 +112,18 @@ export default function About() {
105
112
  sr.removeEventListener("touchmove", onTouchMove);
106
113
  sr.removeEventListener("touchend", onTouchEnd);
107
114
  };
108
- }, [sliderRef]);
109
- const graphics = [
110
- _jsx(SlideOne, { layoutId: "graphicCircle", duration: animationDuration, ease: animationEase }, "slide-1"),
111
- _jsx(SlideTwo, { layoutId: "graphicCircle", duration: animationDuration, ease: animationEase }, "slide-2"),
112
- _jsx(SlideThree, { layoutId: "graphicCircle", duration: animationDuration, ease: animationEase }, "slide-3"),
113
- ];
114
- const mobileGraphics = [
115
- _jsx(SlideOne, { duration: animationDuration, ease: animationEase }, "slige-1"),
116
- _jsx(SlideTwo, { duration: animationDuration, ease: animationEase }, "slige-2"),
117
- _jsx(SlideThree, { duration: animationDuration, ease: animationEase }, "slige-3"),
118
- ];
119
- // Adjust height of ModalBody to fit content based on language
120
- const slideHeight = (() => {
115
+ }, [didInteract]);
116
+ const graphics = useMemo(() => [
117
+ _jsx(SlideOne, { layoutId: "graphicCircle", duration: ANIMATION_DURATION, ease: ANIMATION_EASE }, "slide-1"),
118
+ _jsx(SlideTwo, { layoutId: "graphicCircle", duration: ANIMATION_DURATION, ease: ANIMATION_EASE }, "slide-2"),
119
+ _jsx(SlideThree, { layoutId: "graphicCircle", duration: ANIMATION_DURATION, ease: ANIMATION_EASE }, "slide-3"),
120
+ ], []);
121
+ const mobileGraphics = useMemo(() => [
122
+ _jsx(SlideOne, { duration: ANIMATION_DURATION, ease: ANIMATION_EASE }, "slide-1"),
123
+ _jsx(SlideTwo, { duration: ANIMATION_DURATION, ease: ANIMATION_EASE }, "slide-2"),
124
+ _jsx(SlideThree, { duration: ANIMATION_DURATION, ease: ANIMATION_EASE }, "slide-3"),
125
+ ], []);
126
+ const slideHeight = useMemo(() => {
121
127
  switch (context.options?.language) {
122
128
  case "en-US":
123
129
  case "zh-CN":
@@ -125,15 +131,15 @@ export default function About() {
125
131
  default:
126
132
  return 84;
127
133
  }
128
- })();
129
- const slides = [
134
+ }, [context.options?.language]);
135
+ const slides = useMemo(() => [
130
136
  _jsxs(Fragment, { children: [_jsx(ModalH1, { style: { height: 24 }, "$small": true, children: _jsx(FitText, { children: locales.aboutScreen_a_h1 }) }), _jsx(ModalBody, { style: { height: slideHeight }, children: _jsx(FitText, { children: locales.aboutScreen_a_p }) })] }, "aboutScreen_a"),
131
137
  _jsxs(Fragment, { children: [_jsx(ModalH1, { style: { height: 24 }, "$small": true, children: _jsx(FitText, { children: locales.aboutScreen_b_h1 }) }), _jsx(ModalBody, { style: { height: slideHeight }, children: _jsx(FitText, { children: locales.aboutScreen_b_p }) })] }, "aboutScreen_b"),
132
138
  _jsxs(Fragment, { children: [_jsx(ModalH1, { style: { height: 24 }, "$small": true, children: _jsx(FitText, { children: locales.aboutScreen_c_h1 }) }), _jsx(ModalBody, { style: { height: slideHeight }, children: _jsx(FitText, { children: locales.aboutScreen_c_p }) })] }, "aboutScreen_c"),
133
- ];
139
+ ], [locales, slideHeight]);
134
140
  return (_jsxs(PageContent, { children: [_jsxs(Slider, { children: [_jsx(ImageContainer, { children: _jsx(MotionConfig, { transition: {
135
- duration: animationDuration / 1000,
136
- ease: animationEase,
141
+ duration: ANIMATION_DURATION / 1000,
142
+ ease: ANIMATION_EASE,
137
143
  }, children: _jsx(AnimatePresence, { initial: false, children: graphics.map((g, i) => slider === i && (_jsx(ImageContainerInner, { style: { position: "absolute" }, children: g }, i))) }) }) }), _jsx(Slides, { ref: sliderRef, children: _jsx(AnimatePresence, { children: slides.map((s, i) => (_jsxs(Slide, { "$active": slider === i, children: [_jsx(MobileImageContainer, { children: _jsx(MotionConfig, { transition: {
138
144
  duration: 0,
139
145
  }, children: _jsx(ImageContainerInner, { children: mobileGraphics[i] }) }) }), _jsx(ModalContent, { style: { gap: 8, paddingBottom: 0 }, children: s })] }, i))) }) })] }), _jsx(OrDivider, { children: _jsx(Dots, { children: slides.map((_s, i) => (_jsx(Dot, { "$active": slider === i, onClick: () => {
@@ -10,10 +10,10 @@ import PoweredByFooter from "../../ui/PoweredByFooter/index";
10
10
  import { AnimationContainer, ErrorIcon, InsetContainer, Link, Spinner, SuccessIcon } from "./styles";
11
11
  export default function Confirmation() {
12
12
  const locales = useLocales();
13
- const { paymentState, onSuccess } = usePayContext();
13
+ const { paymentState, onSuccess, options } = usePayContext();
14
14
  const { payOrder } = paymentState;
15
15
  const isDeposit = payOrder?.mode === PayOrderMode.DEPOSIT;
16
- const { title, uiState, txURL } = useMemo(() => getConfirmationState(payOrder, isDeposit, locales), [payOrder, isDeposit, locales]);
16
+ const { title, uiState, txURL } = useMemo(() => getConfirmationState(payOrder, isDeposit, locales, options?.optimisticConfirmation), [payOrder, isDeposit, locales, options?.optimisticConfirmation]);
17
17
  useEffect(() => {
18
18
  if (uiState === "success") {
19
19
  onSuccess();
@@ -21,7 +21,7 @@ export default function Confirmation() {
21
21
  }, [uiState, onSuccess]);
22
22
  return (_jsx(PageContent, { "$center": true, children: _jsxs(ModalContent, { "$center": true, style: { paddingBottom: 0 }, children: [_jsx(AnimationContainer, { children: _jsxs(InsetContainer, { children: [_jsx(Spinner, { "$status": uiState === "loading" }), _jsx(SuccessIcon, { "$status": uiState === "success" }), _jsx(ErrorIcon, { "$status": uiState === "error" })] }) }), _jsx(ModalH1, { children: title }), txURL && (_jsxs(Link, { href: txURL, target: "_blank", rel: "noopener noreferrer", children: [_jsx(ExternalLinkIcon, { width: 14, height: 14, fillOpacity: 0.9 }), "view transaction"] })), _jsx(PoweredByFooter, {})] }) }));
23
23
  }
24
- function getConfirmationState(payOrder, isDeposit, locales) {
24
+ function getConfirmationState(payOrder, isDeposit, locales, optimisticConfirmation) {
25
25
  if (!payOrder) {
26
26
  return {
27
27
  title: _jsxs(_Fragment, { children: [locales.confirmationScreen_awaiting, "..."] }),
@@ -29,6 +29,7 @@ function getConfirmationState(payOrder, isDeposit, locales) {
29
29
  };
30
30
  }
31
31
  const payment = payOrder.payment;
32
+ const confirmOptimistically = optimisticConfirmation && !isDeposit;
32
33
  const sourceTxURL = payment?.src.chain_id && payOrder.deposit_tx_hash
33
34
  ? getChainExplorerTxUrl(payment.src.chain_id, payOrder.deposit_tx_hash)
34
35
  : undefined;
@@ -41,15 +42,15 @@ function getConfirmationState(payOrder, isDeposit, locales) {
41
42
  if (payOrder.status === PayOrderStatus.AWAITING_CONFIRMATION ||
42
43
  payOrder.status === PayOrderStatus.OPTIMISTIC_CONFIRMED) {
43
44
  return {
44
- title: isDeposit ? _jsxs(_Fragment, { children: [locales.awaitingConfirmation, "..."] }) : locales.confirmationScreen_completed,
45
- uiState: isDeposit ? "loading" : "success",
45
+ title: confirmOptimistically ? locales.confirmationScreen_completed : _jsxs(_Fragment, { children: [locales.awaitingConfirmation, "..."] }),
46
+ uiState: confirmOptimistically ? "success" : "loading",
46
47
  txURL: sourceTxURL,
47
48
  };
48
49
  }
49
50
  if (payOrder.status === PayOrderStatus.EXECUTING_ORDER) {
50
51
  return {
51
- title: isDeposit ? _jsxs(_Fragment, { children: [locales.confirmationScreen_executing, "..."] }) : locales.confirmationScreen_completed,
52
- uiState: isDeposit ? "loading" : "success",
52
+ title: confirmOptimistically ? (locales.confirmationScreen_completed) : (_jsxs(_Fragment, { children: [locales.confirmationScreen_executing, "..."] })),
53
+ uiState: confirmOptimistically ? "success" : "loading",
53
54
  txURL: sourceTxURL,
54
55
  };
55
56
  }
@@ -0,0 +1,8 @@
1
+ import type { PaymentDetails } from "../../../types/payment-details";
2
+ interface CopyableInfoProps {
3
+ details?: PaymentDetails;
4
+ remainingS: number;
5
+ totalS: number;
6
+ }
7
+ export declare function CopyableInfo({ details, remainingS, totalS }: CopyableInfoProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { truncateAddress } from "@coin-voyage/shared/common";
3
+ import useLocales from "../../../hooks/useLocales";
4
+ import { CopyRowOrThrobber } from "../../ui/CopyableInfo";
5
+ import { CountdownTimer } from "../../ui/CountDownTimer";
6
+ import { CopyableInfoWrapper, CountdownWrap } from "./styles";
7
+ export function CopyableInfo({ details, remainingS, totalS }) {
8
+ const isExpired = details?.expirationS != null && remainingS === 0;
9
+ const locales = useLocales();
10
+ return (_jsxs(CopyableInfoWrapper, { children: [_jsx(CopyRowOrThrobber, { title: locales.sendExactly, value: details?.amount?.toString(), smallText: details?.ticker, disabled: isExpired }), _jsx(CopyRowOrThrobber, { title: locales.depositAddress, value: details?.depositAddress, valueText: details?.depositAddress && truncateAddress(details.depositAddress), disabled: isExpired }), _jsx(CountdownWrap, { children: _jsx(CountdownTimer, { remainingS: remainingS, totalS: totalS }) })] }));
11
+ }
@@ -0,0 +1 @@
1
+ export default function PayToAddress(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,77 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PayOrderMode } from "@coin-voyage/shared/types";
3
+ import { useCallback, useEffect, useMemo } from "react";
4
+ import { AlertIcon } from "../../../assets/icons";
5
+ import { useCountdown } from "../../../hooks/useCountdown";
6
+ import { useDepositAddressQuery } from "../../../hooks/useDepositAddressQuery";
7
+ import useLocales from "../../../hooks/useLocales";
8
+ import { ROUTES } from "../../../types/routes";
9
+ import usePayContext from "../../contexts/pay";
10
+ import Button from "../../ui/Button";
11
+ import CustomQRCode from "../../ui/CustomQRCode";
12
+ import { ModalBody, ModalContent, ModalH1, PageContent } from "../../ui/Modal/styles";
13
+ import PoweredByFooter from "../../ui/PoweredByFooter";
14
+ import SelectAnotherMethod from "../../ui/SelectAnotherMethod";
15
+ import { Spinner } from "../../ui/Spinner";
16
+ import TokenChainLogo from "../../ui/TokenChainLogo";
17
+ import { CopyableInfo } from "./copyable-info";
18
+ import { LogoRow, QRWrap } from "./styles";
19
+ export default function PayToAddress() {
20
+ return (_jsxs(PageContent, { children: [_jsx(PayToAddressView, {}), _jsx(PoweredByFooter, {})] }));
21
+ }
22
+ function PayToAddressView() {
23
+ const { paymentState, triggerResize } = usePayContext();
24
+ const { payToAddressChainId: payToAddressChain, payToAddressCurrency } = paymentState;
25
+ const { data: paymentDetails, isLoading, isError, } = useDepositAddressQuery({
26
+ enabled: payToAddressCurrency != undefined,
27
+ });
28
+ if (isError) {
29
+ return payToAddressChain ? _jsx(DepositFailed, {}) : null;
30
+ }
31
+ if (isLoading || !paymentDetails) {
32
+ return _jsx(DepositAddressLoading, {});
33
+ }
34
+ return (_jsx(DepositAddressInfo, { details: paymentDetails, triggerResize: triggerResize, isDeposit: paymentState.payOrder?.mode === PayOrderMode.DEPOSIT }));
35
+ }
36
+ function DepositAddressLoading() {
37
+ const locales = useLocales();
38
+ return (_jsxs(ModalContent, { "$center": true, style: { paddingTop: 32, paddingBottom: 32 }, children: [_jsx(Spinner, {}), _jsx(ModalBody, { style: { marginTop: 12 }, children: locales.payToAddressScreen_generatingDepositAddress })] }));
39
+ }
40
+ function DepositAddressInfo({ details, triggerResize, isDeposit, }) {
41
+ const locales = useLocales();
42
+ const [remainingS, totalS] = useCountdown(details.expirationS);
43
+ const isExpired = details.expirationS != null && remainingS === 0;
44
+ useEffect(triggerResize, [details, isExpired, triggerResize]);
45
+ const logoElement = useMemo(() => (_jsx(TokenChainLogo, { chainId: details.chainId, src: details.logoURI, alt: details.ticker }, `${details.ticker}-${details.chainId}`)), [details.chainId, details.ticker, details.logoURI]);
46
+ return (_jsxs(ModalContent, { children: [_jsx(DepositAddressView, { isExpired: isExpired, isDeposit: isDeposit, depositAddress: details.depositAddress, logoElement: logoElement, localesRefreshLabel: locales.refresh }), _jsx("div", { style: { height: 8 } }), _jsx(CopyableInfo, { details: details, remainingS: remainingS, totalS: totalS })] }));
47
+ }
48
+ function DepositAddressView({ isExpired, isDeposit, depositAddress, logoElement, localesRefreshLabel, }) {
49
+ const locales = useLocales();
50
+ const { paymentState } = usePayContext();
51
+ if (isExpired) {
52
+ if (!isDeposit) {
53
+ return (_jsxs(ModalContent, { "$center": true, style: { paddingTop: 32, paddingBottom: 32 }, children: [_jsxs(ModalH1, { "$warning": true, children: [_jsx(AlertIcon, {}), locales.payWithTokenScreen_expired_h1] }), _jsx(ModalBody, { children: locales.payWithTokenScreen_expired_p })] }));
54
+ }
55
+ return (_jsx(LogoRow, { children: _jsx(Button, { onClick: () => {
56
+ // Create a new deposit pay order and trigger a refetch of the payment details query
57
+ paymentState.copyDepositPayOrder();
58
+ }, style: { width: 128 }, children: localesRefreshLabel }) }));
59
+ }
60
+ return (_jsx(QRWrap, { children: _jsx(CustomQRCode, { value: depositAddress, image: logoElement }) }));
61
+ }
62
+ function DepositFailed() {
63
+ const locales = useLocales();
64
+ const { setRoute, paymentState } = usePayContext();
65
+ const { setPayToAddressChainId: setPayToAddressChain, setPayToAddressCurrency } = paymentState;
66
+ const onSelectAnotherMethod = useCallback(() => {
67
+ setPayToAddressChain(undefined);
68
+ setPayToAddressCurrency(undefined);
69
+ setRoute(ROUTES.SELECT_PAY_TO_ADDRESS_CHAIN);
70
+ }, [setRoute, setPayToAddressChain, setPayToAddressCurrency]);
71
+ return (_jsxs(ModalContent, { "$center": true, style: {
72
+ marginLeft: 24,
73
+ marginRight: 24,
74
+ paddingTop: 16,
75
+ paddingBottom: 16,
76
+ }, children: [_jsx(ModalH1, { children: locales.selectPayToAddressWaitingScreen_unavailable_h1 }), _jsx(ModalBody, { children: locales.selectPayToAddressWaitingScreen_unavailable_p }), _jsx(SelectAnotherMethod, { buttonText: locales.selectTokenScreen_selectAnotherMethod, onSelectAnotherMethod: onSelectAnotherMethod })] }));
77
+ }
@@ -0,0 +1,7 @@
1
+ export declare const ShowQRWrap: import("styled-components").StyledComponent<"div", any, {}, never>;
2
+ export declare const ShowQRIcon: import("styled-components").StyledComponent<"div", any, {}, never>;
3
+ export declare const LogoWrap: import("styled-components").StyledComponent<"div", any, {}, never>;
4
+ export declare const LogoRow: import("styled-components").StyledComponent<"div", any, {}, never>;
5
+ export declare const QRWrap: import("styled-components").StyledComponent<"div", any, {}, never>;
6
+ export declare const CopyableInfoWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
7
+ export declare const CountdownWrap: import("styled-components").StyledComponent<"div", any, {}, never>;
@@ -0,0 +1,36 @@
1
+ import styled from "styled-components";
2
+ export const ShowQRWrap = styled.div `
3
+ display: flex;
4
+ justify-content: center;
5
+ color: var(--ck-primary-button-color);
6
+ `;
7
+ export const ShowQRIcon = styled.div `
8
+ width: 20px;
9
+ `;
10
+ export const LogoWrap = styled.div `
11
+ position: relative;
12
+ width: 64px;
13
+ height: 64px;
14
+ `;
15
+ export const LogoRow = styled.div `
16
+ padding: 32px 0;
17
+ height: 128px;
18
+ display: flex;
19
+ align-items: center;
20
+ gap: 8px;
21
+ justify-content: center;
22
+ `;
23
+ export const QRWrap = styled.div `
24
+ margin: 0 auto;
25
+ width: 280px;
26
+ `;
27
+ export const CopyableInfoWrapper = styled.div `
28
+ display: flex;
29
+ flex-direction: column;
30
+ justify-content: stretch;
31
+ gap: 0;
32
+ `;
33
+ export const CountdownWrap = styled.div `
34
+ margin-top: 24px;
35
+ height: 16px;
36
+ `;
@@ -3,7 +3,7 @@ import { useAccount } from "@coin-voyage/crypto/hooks";
3
3
  import { assert, getChainTypeByChainId } from "@coin-voyage/shared/common";
4
4
  import { ChainType, PayOrderMode, PayOrderStatus } from "@coin-voyage/shared/types";
5
5
  import { AnimatePresence, motion } from "framer-motion";
6
- import { useEffect, useMemo, useState } from "react";
6
+ import { useCallback, useEffect, useMemo, useState } from "react";
7
7
  import { useChainId, useSwitchChain } from "wagmi";
8
8
  import { chainToLogo } from "../../../assets/chains";
9
9
  import { AlertIcon, RetryIconCircle } from "../../../assets/icons";
@@ -25,7 +25,7 @@ var PayState;
25
25
  })(PayState || (PayState = {}));
26
26
  export default function PayWithToken() {
27
27
  const { triggerResize, paymentState, setRoute, log, allowedWallets } = usePayContext();
28
- const { selectedTokenOption, payWithToken, payOrder } = paymentState;
28
+ const { selectedCurrencyOption, payFromWallet, payOrder } = paymentState;
29
29
  const { account } = useAccount();
30
30
  const [payState, setPayState] = useState(PayState.RequestingPayment);
31
31
  const locales = useLocales();
@@ -34,8 +34,8 @@ export default function PayWithToken() {
34
34
  assert(payOrder !== undefined, "Pay order must be defined");
35
35
  const isExpired = payOrder.status === PayOrderStatus.EXPIRED;
36
36
  const isDeposit = payOrder.mode === PayOrderMode.DEPOSIT;
37
- const chainType = getChainTypeByChainId(paymentState.selectedTokenOption?.chain_id);
38
- const trySwitchingChain = async (option, forceSwitch = false) => {
37
+ const chainType = getChainTypeByChainId(paymentState.selectedCurrencyOption?.chain_id);
38
+ const trySwitchingChain = useCallback(async (option, forceSwitch = false) => {
39
39
  if (walletChainId === option.chain_id && !forceSwitch)
40
40
  return true;
41
41
  try {
@@ -46,24 +46,24 @@ export default function PayWithToken() {
46
46
  console.error("Failed to switch chain", e);
47
47
  return false;
48
48
  }
49
- };
50
- const ensureCorrectChain = async (token) => {
49
+ }, [walletChainId, switchChainAsync]);
50
+ const ensureCorrectChain = useCallback(async (token) => {
51
51
  if (chainType !== ChainType.EVM)
52
52
  return true;
53
53
  setPayState(PayState.SwitchingChain);
54
54
  return trySwitchingChain(token);
55
- };
56
- const executePayment = async (token) => {
57
- const txHash = await payWithToken(token);
55
+ }, [chainType, trySwitchingChain]);
56
+ const executePayment = useCallback(async (token) => {
57
+ const txHash = await payFromWallet(token);
58
58
  if (!txHash)
59
59
  throw new Error("Payment rejected");
60
- };
60
+ }, [payFromWallet]);
61
61
  const isRestricted = useMemo(() => {
62
62
  if (allowedWallets === null)
63
63
  return false;
64
64
  return !allowedWallets.some((w) => w.address === account.address && w.chainType === account.chainType && w.allowed);
65
65
  }, [allowedWallets, account]);
66
- const handleTransfer = async (token) => {
66
+ const handleTransfer = useCallback(async (token) => {
67
67
  if (isRestricted)
68
68
  return;
69
69
  if (!(await ensureCorrectChain(token))) {
@@ -87,15 +87,16 @@ export default function PayWithToken() {
87
87
  setPayState(PayState.RequestCancelled);
88
88
  log("Failed to pay with token", e);
89
89
  }
90
- };
90
+ }, [isRestricted, ensureCorrectChain, executePayment, trySwitchingChain, setPayState, setRoute, log]);
91
91
  useEffect(() => {
92
- if (!selectedTokenOption)
92
+ if (!selectedCurrencyOption)
93
93
  return;
94
94
  const timeoutId = setTimeout(() => {
95
- handleTransfer(selectedTokenOption);
95
+ handleTransfer(selectedCurrencyOption);
96
96
  }, 100);
97
97
  return () => clearTimeout(timeoutId);
98
- }, [selectedTokenOption]);
98
+ // eslint-disable-next-line react-hooks/exhaustive-deps
99
+ }, [selectedCurrencyOption]);
99
100
  useEffect(() => {
100
101
  triggerResize();
101
102
  }, [payState, triggerResize]);
@@ -104,11 +105,11 @@ export default function PayWithToken() {
104
105
  paymentState.copyDepositPayOrder();
105
106
  setRoute(ROUTES.SELECT_TOKEN);
106
107
  }
107
- else if (selectedTokenOption) {
108
- handleTransfer(selectedTokenOption);
108
+ else if (selectedCurrencyOption) {
109
+ handleTransfer(selectedCurrencyOption);
109
110
  }
110
111
  };
111
- return (_jsxs(PageContent, { children: [_jsx(LoadingContainer, { children: _jsxs(AnimationContainer, { "$shake": payState === PayState.RequestCancelled, "$circle": true, children: [_jsx(AnimatePresence, { children: payState === PayState.RequestCancelled || (isExpired && isDeposit) ? (_jsx(RetryButton, { "aria-label": "Retry", initial: { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.8 }, whileTap: { scale: 0.9 }, transition: { duration: 0.1 }, onClick: onRetry, children: _jsx(RetryIconContainer, { children: _jsx(Tooltip, { open: payState === PayState.RequestCancelled, message: locales.tryAgainQuestion, xOffset: -6, children: _jsx(RetryIconCircle, {}) }) }) })) : (_jsx(ChainLogoContainer, { children: selectedTokenOption && chainToLogo[selectedTokenOption.chain_id] }, "ChainLogoContainer")) }), _jsx(AnimatePresence, { children: _jsx(CircleSpinner, { logo: _jsx("img", { src: selectedTokenOption?.image_uri, alt: selectedTokenOption?.ticker }, selectedTokenOption?.image_uri), loading: payState === PayState.RequestingPayment && !isExpired, unavailable: false }, "CircleSpinner") })] }) }), !isExpired ? (_jsxs(ModalContent, { children: [payState === PayState.RequestCancelled && (_jsxs(_Fragment, { children: [_jsxs(ModalH1, { "$warning": true, children: [_jsx(AlertIcon, {}), locales.injectionScreen_rejected_h1] }), _jsx(ModalBody, { children: locales.injectionScreen_rejected_p })] })), payState === PayState.SwitchingChain && _jsx(ModalH1, { children: locales.switchNetworkScreen_heading }), payState === PayState.RequestingPayment && (_jsxs(_Fragment, { children: [_jsx(ModalH1, { children: locales.requesting_payment_h1 }), _jsx(ModalBody, { children: locales.requesting_payment_p })] })), payState === PayState.RequestSuccessful && _jsx(ModalH1, { children: locales.injectionScreen_connected_h1 })] })) : (_jsxs(ModalContent, { children: [_jsxs(ModalH1, { "$warning": true, children: [_jsx(AlertIcon, {}), locales.payWithTokenScreen_expired_h1] }), _jsx(ModalBody, { children: locales.payWithTokenScreen_expired_p })] }))] }));
112
+ return (_jsxs(PageContent, { children: [_jsx(LoadingContainer, { children: _jsxs(AnimationContainer, { "$shake": payState === PayState.RequestCancelled, "$circle": true, children: [_jsx(AnimatePresence, { children: payState === PayState.RequestCancelled || (isExpired && isDeposit) ? (_jsx(RetryButton, { "aria-label": "Retry", initial: { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.8 }, whileTap: { scale: 0.9 }, transition: { duration: 0.1 }, onClick: onRetry, children: _jsx(RetryIconContainer, { children: _jsx(Tooltip, { open: payState === PayState.RequestCancelled, message: locales.tryAgainQuestion, xOffset: -6, children: _jsx(RetryIconCircle, {}) }) }) })) : (_jsx(ChainLogoContainer, { children: selectedCurrencyOption && chainToLogo[selectedCurrencyOption.chain_id] }, "ChainLogoContainer")) }), _jsx(AnimatePresence, { children: _jsx(CircleSpinner, { logo: _jsx("img", { src: selectedCurrencyOption?.image_uri, alt: selectedCurrencyOption?.ticker }, selectedCurrencyOption?.image_uri), loading: payState === PayState.RequestingPayment && !isExpired, unavailable: false }, "CircleSpinner") })] }) }), !isExpired ? (_jsxs(ModalContent, { children: [payState === PayState.RequestCancelled && (_jsxs(_Fragment, { children: [_jsxs(ModalH1, { "$warning": true, children: [_jsx(AlertIcon, {}), locales.injectionScreen_rejected_h1] }), _jsx(ModalBody, { children: locales.injectionScreen_rejected_p })] })), payState === PayState.SwitchingChain && _jsx(ModalH1, { children: locales.switchNetworkScreen_heading }), payState === PayState.RequestingPayment && (_jsxs(_Fragment, { children: [_jsx(ModalH1, { children: locales.requesting_payment_h1 }), _jsx(ModalBody, { children: locales.requesting_payment_p })] })), payState === PayState.RequestSuccessful && _jsx(ModalH1, { children: locales.injectionScreen_connected_h1 })] })) : (_jsxs(ModalContent, { children: [_jsxs(ModalH1, { "$warning": true, children: [_jsx(AlertIcon, {}), locales.payWithTokenScreen_expired_h1] }), _jsx(ModalBody, { children: locales.payWithTokenScreen_expired_p })] }))] }));
112
113
  }
113
114
  const LoadingContainer = styled(motion.div) `
114
115
  display: flex;
@@ -0,0 +1 @@
1
+ export default function SelectChain(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAccount, useAccountDisconnect } from "@coin-voyage/crypto/hooks";
3
+ import { useIsMobile } from "@coin-voyage/shared/hooks";
4
+ import { useChainOptions } from "../../../hooks/useChainOptions";
5
+ import { ROUTES } from "../../../types/routes";
6
+ import usePayContext from "../../contexts/pay";
7
+ import { PageContent } from "../../ui/Modal/styles";
8
+ import OptionsList from "../../ui/OptionsList";
9
+ import { OrderHeader } from "../../ui/OrderHeader";
10
+ import PoweredByFooter from "../../ui/PoweredByFooter";
11
+ export default function SelectChain() {
12
+ const isMobile = useIsMobile();
13
+ const { setRoute, paymentState } = usePayContext();
14
+ const disconnect = useAccountDisconnect();
15
+ const { account } = useAccount({
16
+ selectedWallet: paymentState.selectedWallet,
17
+ chainType: paymentState.connectorChainType,
18
+ });
19
+ const handleClick = (chainType) => {
20
+ disconnect(account);
21
+ paymentState.setConnectorChainType(chainType);
22
+ setRoute(ROUTES.CONNECTORS);
23
+ };
24
+ const { options } = useChainOptions({
25
+ account,
26
+ mode: paymentState.payOrder?.mode,
27
+ onClick: handleClick,
28
+ });
29
+ return (_jsxs(PageContent, { children: [_jsx(OrderHeader, {}), _jsx(OptionsList, { requiredSkeletons: isMobile ? 3 : 4, options: options }), _jsx(PoweredByFooter, {})] }));
30
+ }
@@ -1,29 +1,24 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useAccount, useAccountDisconnect } from "@coin-voyage/crypto/hooks";
3
3
  import { useIsMobile } from "@coin-voyage/shared/hooks";
4
- import { useMethodOptions } from "../../../hooks/useMethodOptions";
5
- import { ROUTES } from "../../../types/routes";
6
4
  import usePayContext from "../../contexts/pay";
7
5
  import { PageContent } from "../../ui/Modal/styles";
8
6
  import OptionsList from "../../ui/OptionsList";
9
7
  import { OrderHeader } from "../../ui/OrderHeader";
10
8
  import PoweredByFooter from "../../ui/PoweredByFooter";
9
+ import { useMethodOptions } from "../../../hooks/useMethodOptions";
11
10
  export default function SelectMethod() {
12
11
  const isMobile = useIsMobile();
13
- const { setRoute, paymentState } = usePayContext();
12
+ const { paymentState } = usePayContext();
14
13
  const disconnect = useAccountDisconnect();
15
14
  const { account } = useAccount({
16
15
  selectedWallet: paymentState.selectedWallet,
17
16
  chainType: paymentState.connectorChainType,
18
17
  });
19
- const handleClick = (chainType) => {
20
- if (account)
21
- disconnect(account);
22
- paymentState.setConnectorChainType(chainType);
23
- setRoute(ROUTES.CONNECTORS);
18
+ const handleClick = () => {
19
+ disconnect(account);
24
20
  };
25
21
  const { options } = useMethodOptions({
26
- account,
27
22
  mode: paymentState.payOrder?.mode,
28
23
  onClick: handleClick,
29
24
  });
@@ -0,0 +1 @@
1
+ export default function SelectPayToAddressChain(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import usePayContext from "../../contexts/pay";
3
+ import { PageContent } from "../../ui/Modal/styles";
4
+ import { OrderHeader } from "../../ui/OrderHeader";
5
+ import OptionsList from "../../ui/OptionsList";
6
+ import PoweredByFooter from "../../ui/PoweredByFooter";
7
+ import { usePayToAddressChainOptions } from "../../../hooks/usePayToAddressChainOptions";
8
+ export default function SelectPayToAddressChain() {
9
+ const { paymentState } = usePayContext();
10
+ const { payOrder } = paymentState;
11
+ const fiatAmount = payOrder?.fulfillment.amount.value_usd;
12
+ const { options, isLoading } = usePayToAddressChainOptions({ fiatAmount });
13
+ return (_jsxs(PageContent, { children: [_jsx(OrderHeader, { minified: true }), _jsx(OptionsList, { isLoading: isLoading, requiredSkeletons: 4, options: options }), _jsx(PoweredByFooter, {})] }));
14
+ }
@@ -0,0 +1 @@
1
+ export default function SelectPayToAddressToken(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PageContent } from "../../ui/Modal/styles";
3
+ import { OrderHeader } from "../../ui/OrderHeader";
4
+ import OptionsList from "../../ui/OptionsList";
5
+ import PoweredByFooter from "../../ui/PoweredByFooter";
6
+ import { usePayToAddressTokens } from "../../../hooks/usePayToAddressTokens";
7
+ export default function SelectPayToAddressToken() {
8
+ const { options, isLoading } = usePayToAddressTokens();
9
+ return (_jsxs(PageContent, { children: [_jsx(OrderHeader, { minified: true }), _jsx(OptionsList, { isLoading: isLoading, requiredSkeletons: 4, options: options }), _jsx(PoweredByFooter, {})] }));
10
+ }