@lookiero/checkout 10.1.0 → 11.1.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 (80) hide show
  1. package/cypress/integration/checkout.spec.ts +0 -3
  2. package/dist/fake-dependencies/@lookiero/payments-front/index.d.ts +8 -7
  3. package/dist/fake-dependencies/@lookiero/payments-front/index.js +11 -3
  4. package/dist/index.d.ts +3 -3
  5. package/dist/src/Expo.js +8 -2
  6. package/dist/src/ExpoRoot.d.ts +5 -1
  7. package/dist/src/ExpoRoot.js +26 -17
  8. package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.d.ts +1 -1
  9. package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.js +2 -0
  10. package/dist/src/infrastructure/projection/checkout/checkout.mock.d.ts +1 -0
  11. package/dist/src/infrastructure/projection/checkout/checkout.mock.js +3 -3
  12. package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.d.ts +1 -1
  13. package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.js +2 -1
  14. package/dist/src/infrastructure/tracking/tracking.d.ts +2 -2
  15. package/dist/src/infrastructure/tracking/useTrackCheckout.d.ts +10 -17
  16. package/dist/src/infrastructure/tracking/useTrackCheckout.js +27 -12
  17. package/dist/src/infrastructure/ui/Root.d.ts +6 -6
  18. package/dist/src/infrastructure/ui/Root.js +2 -3
  19. package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.d.ts +26 -0
  20. package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.js +127 -0
  21. package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.d.ts +3 -2
  22. package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.js +17 -26
  23. package/dist/src/infrastructure/ui/i18n/i18n.d.ts +1 -0
  24. package/dist/src/infrastructure/ui/i18n/i18n.js +1 -0
  25. package/dist/src/infrastructure/ui/routing/CheckoutMiddleware.js +1 -12
  26. package/dist/src/infrastructure/ui/routing/Routing.d.ts +5 -5
  27. package/dist/src/infrastructure/ui/routing/Routing.js +2 -10
  28. package/dist/src/infrastructure/ui/routing/routes.d.ts +0 -1
  29. package/dist/src/infrastructure/ui/routing/routes.js +0 -1
  30. package/dist/src/infrastructure/ui/views/App.js +5 -6
  31. package/dist/src/infrastructure/ui/views/checkout/Checkout.d.ts +7 -2
  32. package/dist/src/infrastructure/ui/views/checkout/Checkout.js +20 -9
  33. package/dist/src/infrastructure/ui/views/checkout/Checkout.style.d.ts +3 -0
  34. package/dist/src/infrastructure/ui/views/checkout/Checkout.style.js +3 -0
  35. package/dist/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.js +7 -7
  36. package/dist/src/projection/customer/customer.d.ts +2 -0
  37. package/dist/src/projection/order/order.d.ts +1 -1
  38. package/dist/src/projection/subscription/subscription.d.ts +1 -1
  39. package/dist/src/version.d.ts +1 -1
  40. package/dist/src/version.js +1 -1
  41. package/fake-dependencies/@lookiero/payments-front/index.tsx +36 -8
  42. package/index.ts +10 -3
  43. package/package.json +3 -4
  44. package/src/Expo.tsx +10 -2
  45. package/src/ExpoRoot.tsx +58 -43
  46. package/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.ts +4 -1
  47. package/src/infrastructure/projection/checkout/checkout.mock.ts +8 -3
  48. package/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.ts +3 -2
  49. package/src/infrastructure/tracking/tracking.ts +2 -2
  50. package/src/infrastructure/tracking/useTrackCheckout.test.tsx +51 -24
  51. package/src/infrastructure/tracking/useTrackCheckout.ts +66 -56
  52. package/src/infrastructure/ui/Root.tsx +9 -9
  53. package/src/infrastructure/ui/components/templates/header/itemHeader/ItemHeader.tsx +1 -0
  54. package/src/infrastructure/ui/hooks/useCheckoutFlow.test.tsx +302 -0
  55. package/src/infrastructure/ui/hooks/useCheckoutFlow.tsx +203 -0
  56. package/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.ts +18 -60
  57. package/src/infrastructure/ui/i18n/i18n.ts +1 -0
  58. package/src/infrastructure/ui/routing/CheckoutMiddleware.test.tsx +0 -11
  59. package/src/infrastructure/ui/routing/CheckoutMiddleware.tsx +1 -15
  60. package/src/infrastructure/ui/routing/Routing.tsx +14 -25
  61. package/src/infrastructure/ui/routing/routes.ts +0 -1
  62. package/src/infrastructure/ui/views/App.tsx +5 -13
  63. package/src/infrastructure/ui/views/checkout/Checkout.style.ts +3 -0
  64. package/src/infrastructure/ui/views/checkout/Checkout.test.tsx +51 -43
  65. package/src/infrastructure/ui/views/checkout/Checkout.tsx +51 -13
  66. package/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.tsx +8 -8
  67. package/src/infrastructure/ui/views/item/components/itemActions/__snapshots__/ItemActions.test.tsx.snap +8 -0
  68. package/src/infrastructure/ui/views/item/components/selectModal/__snapshots__/SelecModal.test.tsx.snap +8 -0
  69. package/src/infrastructure/ui/views/item/components/sizeWithoutStockModal/__snapshots__/SizeWithoutStockModal.test.tsx.snap +8 -0
  70. package/src/projection/customer/customer.ts +2 -0
  71. package/src/projection/order/order.ts +1 -1
  72. package/src/projection/subscription/subscription.ts +1 -1
  73. package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.d.ts +0 -27
  74. package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.js +0 -97
  75. package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.d.ts +0 -12
  76. package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.js +0 -88
  77. package/src/infrastructure/ui/hooks/useSubmitCheckout.test.ts +0 -297
  78. package/src/infrastructure/ui/hooks/useSubmitCheckout.ts +0 -169
  79. package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.test.tsx +0 -134
  80. package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.tsx +0 -124
@@ -7,13 +7,12 @@ import { Locale } from "@lookiero/sty-psp-locale";
7
7
  import { Layout } from "@lookiero/sty-psp-ui";
8
8
  import { Tradename } from "@lookiero/sty-sp-tradename";
9
9
  import { Customer } from "../../../projection/customer/customer";
10
- import { Order } from "../../../projection/order/order";
11
- import { Subscription } from "../../../projection/subscription/subscription";
10
+ import { OrderProjection } from "../../../projection/order/order";
11
+ import { SubscriptionProjection } from "../../../projection/subscription/subscription";
12
12
  import { KameleoonEnvironment } from "../../ab-testing/kameleoonEnvironment";
13
13
  import { StaticInfoProvider } from "../hooks/useStaticInfo";
14
14
  import { App } from "../views/App";
15
15
  import { Checkout } from "../views/checkout/Checkout";
16
- import { CheckoutPaymentModal } from "../views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal";
17
16
  import { Feedback } from "../views/feedback/Feedback";
18
17
  import { Item } from "../views/item/Item";
19
18
  import { Return } from "../views/return/Return";
@@ -25,8 +24,8 @@ import { Routes } from "./routes";
25
24
  interface RoutingProps {
26
25
  readonly basePath?: string;
27
26
  readonly customer: Customer;
28
- readonly order: Order | undefined;
29
- readonly subscription: Subscription | undefined;
27
+ readonly order: OrderProjection;
28
+ readonly subscription: SubscriptionProjection;
30
29
  readonly locale: Locale;
31
30
  readonly I18n: I18n;
32
31
  readonly kameleoon: KameleoonEnvironment;
@@ -34,7 +33,7 @@ interface RoutingProps {
34
33
  readonly tradename: Tradename;
35
34
  readonly getAuthToken: () => Promise<string>;
36
35
  readonly onNotAccessible: () => void;
37
- readonly onCheckoutSubmitted?: () => void;
36
+ readonly onCheckoutFlowSuccess: () => void;
38
37
  readonly onI18nError?: (err: Error) => void;
39
38
  readonly useRedirect: () => Record<string, string>;
40
39
  readonly useRoutes: typeof reactRouterUseRoutes;
@@ -53,7 +52,7 @@ const Routing: FC<RoutingProps> = ({
53
52
  getAuthToken,
54
53
  onI18nError,
55
54
  onNotAccessible,
56
- onCheckoutSubmitted,
55
+ onCheckoutFlowSuccess,
57
56
  useRedirect,
58
57
  useRoutes = reactRouterUseRoutes,
59
58
  }) => {
@@ -114,26 +113,16 @@ const Routing: FC<RoutingProps> = ({
114
113
  path: Routes.CHECKOUT,
115
114
  element: (
116
115
  <Suspense fallback={<Spinner />}>
117
- <Checkout layout={layout} useRedirect={useRedirect}>
118
- <Outlet />
119
- </Checkout>
116
+ <Checkout
117
+ getAuthToken={getAuthToken}
118
+ layout={layout}
119
+ order={order}
120
+ subscription={subscription}
121
+ useRedirect={useRedirect}
122
+ onCheckoutFlowSuccess={onCheckoutFlowSuccess}
123
+ />
120
124
  </Suspense>
121
125
  ),
122
- children: [
123
- {
124
- path: Routes.CHECKOUT_PAYMENT,
125
- element: (
126
- <CheckoutPaymentModal
127
- coupon={order?.coupon || null}
128
- getAuthToken={getAuthToken}
129
- isFirstOrder={order?.isFirstOrder as boolean}
130
- orderNumber={order?.orderNumber as number}
131
- subscription={subscription as Subscription}
132
- onCheckoutSubmitted={onCheckoutSubmitted}
133
- />
134
- ),
135
- },
136
- ],
137
126
  },
138
127
  {
139
128
  path: Routes.FEEDBACK,
@@ -5,7 +5,6 @@ export enum Routes {
5
5
  SUMMARY = "summary",
6
6
  SUMMARY_TABS = "tabs/:tab",
7
7
  CHECKOUT = "checkout",
8
- CHECKOUT_PAYMENT = "payment",
9
8
  FEEDBACK = "feedback",
10
9
  RETURN = "return/:id",
11
10
  }
@@ -1,8 +1,7 @@
1
- import { PortalProvider } from "@gorhom/portal";
1
+ import { PortalHost } from "@gorhom/portal";
2
2
  import React, { FC } from "react";
3
3
  import { StatusBar } from "react-native";
4
4
  import { SafeAreaProvider } from "react-native-safe-area-context";
5
- import { PortalProvider as AuroraPortalProvider } from "@lookiero/aurora";
6
5
  import { Notifications } from "@lookiero/sty-psp-notifications";
7
6
  import { theme } from "@lookiero/sty-psp-ui";
8
7
  import { MESSAGING_CONTEXT_ID } from "../../delivery/baseBootstrap";
@@ -16,17 +15,10 @@ interface AppProps {
16
15
 
17
16
  const App: FC<AppProps> = ({ children }) => (
18
17
  <SafeAreaProvider>
19
- <PortalProvider rootHostName="Checkout">
20
- <StatusBar backgroundColor={colorBgBase} barStyle="dark-content" translucent />
21
- <Notifications contextId={MESSAGING_CONTEXT_ID} domain={DOMAIN} portalHostName="Checkout" />
22
- {/*
23
- We are using the Aurora's PortalProvider at this level for notifications to work properly.
24
-
25
- PaymentInstrumentSelect uses Aurora's Portal, and if we rely on UAF's Portal (injected by <Aurora>)
26
- notifications would be displayed in a layer below Portal's one (not visible).
27
- */}
28
- <AuroraPortalProvider>{children}</AuroraPortalProvider>
29
- </PortalProvider>
18
+ <StatusBar backgroundColor={colorBgBase} barStyle="dark-content" translucent />
19
+ <Notifications contextId={MESSAGING_CONTEXT_ID} domain={DOMAIN} portalHostName="Checkout" />
20
+ <PortalHost name="Checkout" />
21
+ {children}
30
22
  </SafeAreaProvider>
31
23
  );
32
24
 
@@ -30,6 +30,9 @@ const style = StyleSheet.create({
30
30
  paymentSelector: {
31
31
  marginTop: space6,
32
32
  },
33
+ paymentSelectorNL: {
34
+ marginBottom: space6,
35
+ },
33
36
  princingWrapper: {
34
37
  padding: space6,
35
38
  },
@@ -1,10 +1,13 @@
1
1
  import { fireEvent } from "@testing-library/react-native";
2
- import React from "react";
2
+ import React, { ReactNode } from "react";
3
+ import { View } from "react-native";
3
4
  import { QueryStatus } from "@lookiero/messaging-react";
4
5
  import { Country } from "@lookiero/sty-psp-locale";
5
6
  import { Segment } from "@lookiero/sty-psp-segment";
6
7
  import { DummyLayout } from "@lookiero/sty-psp-ui";
7
8
  import { CheckoutItemStatus } from "../../../../domain/checkoutItem/model/checkoutItem";
9
+ import { OrderProjection } from "../../../../projection/order/order";
10
+ import { SubscriptionProjection } from "../../../../projection/subscription/subscription";
8
11
  import { checkout } from "../../../projection/checkout/checkout.mock";
9
12
  import { useViewFirstAvailableCheckoutByCustomerId } from "../../../projection/checkout/react/useViewFirstAvailableCheckoutByCustomerId";
10
13
  import { pricing } from "../../../projection/pricing/pricing.mock";
@@ -14,7 +17,9 @@ import { Routes } from "../../routing/routes";
14
17
  import { render } from "../../test/render";
15
18
  import { Checkout } from "./Checkout";
16
19
 
20
+ const getAuthToken = () => Promise.resolve("token");
17
21
  const customerId = "a8fff6d7-708c-41a7-b42a-58c5706d33df";
22
+ const basePath = "/checkout";
18
23
  const country = Country.ES;
19
24
  const segment = Segment.WOMEN;
20
25
  const mockCheckout = checkout({
@@ -26,49 +31,29 @@ const mockCheckout = checkout({
26
31
  { status: CheckoutItemStatus.REPLACED },
27
32
  ],
28
33
  });
34
+ const order: OrderProjection = {
35
+ orderNumber: 12345,
36
+ isFirstOrder: false,
37
+ coupon: null,
38
+ };
39
+ const subscription: SubscriptionProjection = "o";
29
40
  const mockUseRedirect = jest.fn(() => ({ returnUrl: "https://web2.dev.aws.lookiero.es/user/" }));
30
41
 
31
- jest.mock("../../hooks/useStaticInfo", () => ({
32
- useStaticInfo: () => ({
33
- customer: { customerId, country, segment },
34
- basePath: "",
35
- }),
42
+ const mockOnSuccess = jest.fn();
43
+ const mockCheckoutFlow = jest.fn();
44
+ const paymentFlowTestId = "payment-flow";
45
+ const mockPaymentFlowComponent: ReactNode = <View testID={paymentFlowTestId}>PaymentFlow</View>;
46
+ jest.mock("../../hooks/useCheckoutFlow", () => ({
47
+ useCheckoutFlow: () => [mockCheckoutFlow, QueryStatus.SUCCESS, mockPaymentFlowComponent],
36
48
  }));
37
49
 
50
+ jest.mock("../../hooks/useStaticInfo", () => ({
51
+ useStaticInfo: () => ({ customer: { customerId, country, segment }, basePath }),
52
+ }));
53
+ // eslint-disable-next-line @typescript-eslint/naming-convention
54
+ jest.mock("./components/paymentInstrument/PaymentInstrument", () => ({ PaymentInstrument: () => null }));
38
55
  jest.mock("../../../projection/checkout/react/useViewFirstAvailableCheckoutByCustomerId");
39
56
  jest.mock("../../../projection/pricing/react/useViewPricingByCheckoutId");
40
- jest.mock("../../hooks/usePaymentInstrumentEvents");
41
-
42
- const mockStartLegacyBoxCheckout = jest.fn();
43
- jest.mock("@lookiero/payments-front", () => {
44
- // eslint-disable-next-line @typescript-eslint/no-var-requires
45
- const { useImperativeHandle, forwardRef } = require("react");
46
-
47
- return {
48
- CheckoutStatus: {
49
- REJECTED: "REJECTED",
50
- ERROR: "ERROR",
51
- FULFILLED: "FULFILLED",
52
- },
53
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
54
- // @ts-ignore
55
- // eslint-disable-next-line @typescript-eslint/naming-convention, react/display-name
56
- PaymentFlow: forwardRef((params, ref) => {
57
- useImperativeHandle(ref, () => ({
58
- startLegacyBoxCheckout: mockStartLegacyBoxCheckout,
59
- }));
60
-
61
- return null;
62
- }),
63
- PaymentMethod: {
64
- ["GOOGLE_PAY"]: "google_pay",
65
- },
66
- Section: {
67
- ["BOX_CHECKOUT"]: "box-checkout",
68
- },
69
- PaymentInstrumentSelect: jest.fn(() => <></>),
70
- };
71
- });
72
57
 
73
58
  const mockTrackPressContinue = jest.fn();
74
59
  jest.mock("../../../tracking/useTrackPressContinue", () => ({
@@ -87,13 +72,25 @@ jest.mock("react-router-native", () => ({
87
72
  useNavigate: () => mockUseNavigate,
88
73
  }));
89
74
 
75
+ beforeEach(() => {
76
+ mockCheckoutFlow.mockClear();
77
+ mockTrackPressContinue.mockClear();
78
+ mockTrackPressBack.mockClear();
79
+ });
80
+
90
81
  describe("Checkout view", () => {
91
82
  it("renders correctly", async () => {
92
83
  (useViewFirstAvailableCheckoutByCustomerId as jest.Mock).mockReturnValue([mockCheckout, QueryStatus.SUCCESS]);
93
84
  (useViewPricingByCheckoutId as jest.Mock).mockReturnValue([pricing(), QueryStatus.SUCCESS]);
94
-
95
85
  const { findByText, getAllByTestId, getByText, getByTestId } = render(
96
- <Checkout layout={DummyLayout} useRedirect={mockUseRedirect} />,
86
+ <Checkout
87
+ getAuthToken={getAuthToken}
88
+ layout={DummyLayout}
89
+ order={order}
90
+ subscription={subscription}
91
+ useRedirect={mockUseRedirect}
92
+ onCheckoutFlowSuccess={mockOnSuccess}
93
+ />,
97
94
  );
98
95
 
99
96
  expect(await findByText(I18nMessages.CHECKOUT_TITLE)).toBeTruthy();
@@ -114,15 +111,17 @@ describe("Checkout view", () => {
114
111
  expect(getByText(I18nMessages.SUMMARY_FEE)).toBeTruthy();
115
112
  expect(getByText("-€10.00")).toBeTruthy();
116
113
 
114
+ expect(getByTestId(paymentFlowTestId)).toBeTruthy();
115
+
117
116
  expect(getByText(I18nMessages.CHECKOUT_PAY_BUTTON)).toBeTruthy();
118
117
  fireEvent.press(getByText(I18nMessages.CHECKOUT_PAY_BUTTON));
119
118
  expect(mockTrackPressContinue).toHaveBeenCalled();
120
- expect(mockUseNavigate).toHaveBeenCalledWith(`/${Routes.CHECKOUT}/${Routes.CHECKOUT_PAYMENT}`, { replace: true });
119
+ expect(mockCheckoutFlow).toHaveBeenCalled();
121
120
 
122
121
  expect(getByTestId("checkout-header")).toBeTruthy();
123
122
  fireEvent.press(getByTestId("arrow-left-button-icon"));
124
123
  expect(mockTrackPressBack).toHaveBeenCalled();
125
- expect(mockUseNavigate).toHaveBeenCalledWith(`/${Routes.SUMMARY}`);
124
+ expect(mockUseNavigate).toHaveBeenCalledWith(`${basePath}/${Routes.SUMMARY}`);
126
125
  });
127
126
 
128
127
  it("does not render a delivery banner", async () => {
@@ -138,7 +137,16 @@ describe("Checkout view", () => {
138
137
  (useViewFirstAvailableCheckoutByCustomerId as jest.Mock).mockReturnValue([mockCheckout, QueryStatus.SUCCESS]);
139
138
  (useViewPricingByCheckoutId as jest.Mock).mockReturnValue([pricing(), QueryStatus.SUCCESS]);
140
139
 
141
- const { findByText, queryByText } = render(<Checkout layout={DummyLayout} useRedirect={mockUseRedirect} />);
140
+ const { findByText, queryByText } = render(
141
+ <Checkout
142
+ getAuthToken={getAuthToken}
143
+ layout={DummyLayout}
144
+ order={order}
145
+ subscription={subscription}
146
+ useRedirect={mockUseRedirect}
147
+ onCheckoutFlowSuccess={mockOnSuccess}
148
+ />,
149
+ );
142
150
 
143
151
  expect(await findByText(I18nMessages.CHECKOUT_TITLE)).toBeTruthy();
144
152
 
@@ -1,11 +1,14 @@
1
- import React, { FC, ReactNode, useCallback, useMemo, useState } from "react";
1
+ import React, { FC, useCallback, useMemo, useState } from "react";
2
2
  import { LayoutRectangle, Platform, ScrollView, View } from "react-native";
3
3
  import { useNavigate } from "react-router-native";
4
4
  import { Box, Button, Layout as AuroraLayout, Spinner, Text, useDevice } from "@lookiero/aurora";
5
5
  import { useI18nMessage } from "@lookiero/i18n-react";
6
6
  import { QueryStatus } from "@lookiero/messaging-react";
7
+ import { Country } from "@lookiero/sty-psp-locale";
7
8
  import { Layout as UiLayout, Sticky } from "@lookiero/sty-psp-ui";
8
9
  import { CheckoutItemStatus } from "../../../../domain/checkoutItem/model/checkoutItem";
10
+ import { OrderProjection } from "../../../../projection/order/order";
11
+ import { SubscriptionProjection } from "../../../../projection/subscription/subscription";
9
12
  import { useViewFirstAvailableCheckoutByCustomerId } from "../../../projection/checkout/react/useViewFirstAvailableCheckoutByCustomerId";
10
13
  import { useViewPricingByCheckoutId } from "../../../projection/pricing/react/useViewPricingByCheckoutId";
11
14
  import { TrackingPage } from "../../../tracking/tracking";
@@ -14,6 +17,7 @@ import { useTrackPressBack } from "../../../tracking/useTrackPressBack";
14
17
  import { useTrackPressContinue } from "../../../tracking/useTrackPressContinue";
15
18
  import { Body } from "../../components/layouts/body/Body";
16
19
  import { CheckoutHeader } from "../../components/templates/header/checkoutHeader/CheckoutHeader";
20
+ import { useCheckoutFlow } from "../../hooks/useCheckoutFlow";
17
21
  import { useStaticInfo } from "../../hooks/useStaticInfo";
18
22
  import { DOMAIN, I18nMessages } from "../../i18n/i18n";
19
23
  import { Routes } from "../../routing/routes";
@@ -24,12 +28,22 @@ import { DeliveryBanner } from "./components/deliveryBanner/DeliveryBanner";
24
28
  import { PaymentInstrument } from "./components/paymentInstrument/PaymentInstrument";
25
29
 
26
30
  interface CheckoutProps {
27
- readonly children?: ReactNode;
28
31
  readonly layout: UiLayout;
32
+ readonly order: OrderProjection;
33
+ readonly subscription: SubscriptionProjection;
34
+ readonly getAuthToken: () => Promise<string>;
35
+ readonly onCheckoutFlowSuccess: () => void;
29
36
  readonly useRedirect: () => Record<string, string>;
30
37
  }
31
38
 
32
- const Checkout: FC<CheckoutProps> = ({ children, layout: Layout, useRedirect }) => {
39
+ const Checkout: FC<CheckoutProps> = ({
40
+ layout: Layout,
41
+ order,
42
+ subscription,
43
+ getAuthToken,
44
+ useRedirect,
45
+ onCheckoutFlowSuccess,
46
+ }) => {
33
47
  const {
34
48
  customer: { customerId, country, segment },
35
49
  basePath,
@@ -43,6 +57,14 @@ const Checkout: FC<CheckoutProps> = ({ children, layout: Layout, useRedirect })
43
57
  const [checkout, checkoutStatus] = useViewFirstAvailableCheckoutByCustomerId({ customerId });
44
58
  const [pricing, pricingStatus] = useViewPricingByCheckoutId({ checkoutId: checkout?.id as string });
45
59
 
60
+ const [checkoutFlow, checkoutFlowStatus, paymentFlowComponent] = useCheckoutFlow({
61
+ checkout,
62
+ order,
63
+ subscription,
64
+ getAuthToken,
65
+ onSuccess: onCheckoutFlowSuccess,
66
+ });
67
+
46
68
  useTrackPageView({
47
69
  page: TrackingPage.CHECKOUT,
48
70
  country,
@@ -51,17 +73,16 @@ const Checkout: FC<CheckoutProps> = ({ children, layout: Layout, useRedirect })
51
73
  });
52
74
 
53
75
  const navigate = useNavigate();
54
-
55
76
  const trackPressContinue = useTrackPressContinue({
56
77
  page: TrackingPage.CHECKOUT,
57
78
  country,
58
79
  segment,
59
80
  checkoutId: checkout?.id,
60
81
  });
61
- const handleOnSubmit = useCallback(() => {
82
+ const handleOnSubmit = useCallback(async () => {
62
83
  trackPressContinue();
63
- navigate(`${basePath}/${Routes.CHECKOUT}/${Routes.CHECKOUT_PAYMENT}`, { replace: true });
64
- }, [basePath, navigate, trackPressContinue]);
84
+ await checkoutFlow();
85
+ }, [checkoutFlow, trackPressContinue]);
65
86
 
66
87
  const checkoutItemsKept = useMemo(
67
88
  () =>
@@ -115,6 +136,12 @@ const Checkout: FC<CheckoutProps> = ({ children, layout: Layout, useRedirect })
115
136
  >
116
137
  <Box size={{ L: "2/3" }} style={screen.L && style.desktopListSpacing}>
117
138
  <View style={[style.contentWrapper, screen.L && style.desktopContentWrapper]}>
139
+ {country === Country.NL && (
140
+ <View style={style.paymentSelectorNL}>
141
+ <PaymentInstrument useRedirect={useRedirect} />
142
+ </View>
143
+ )}
144
+
118
145
  <Text level={3} style={style.title} heading>
119
146
  {titleText}
120
147
  </Text>
@@ -138,9 +165,11 @@ const Checkout: FC<CheckoutProps> = ({ children, layout: Layout, useRedirect })
138
165
  </View>
139
166
  ))}
140
167
 
141
- <View style={style.paymentSelector}>
142
- <PaymentInstrument useRedirect={useRedirect} />
143
- </View>
168
+ {country !== Country.NL && (
169
+ <View style={style.paymentSelector}>
170
+ <PaymentInstrument useRedirect={useRedirect} />
171
+ </View>
172
+ )}
144
173
  </View>
145
174
  </Box>
146
175
 
@@ -150,7 +179,11 @@ const Checkout: FC<CheckoutProps> = ({ children, layout: Layout, useRedirect })
150
179
  <Pricing pricing={pricing} totalCheckoutItemsKept={checkoutItemsKept?.length || 0} />
151
180
 
152
181
  {screen.L ? (
153
- <Button testID="confirm-checkout-button" onPress={handleOnSubmit}>
182
+ <Button
183
+ busy={checkoutFlowStatus === "loading"}
184
+ testID="confirm-checkout-button"
185
+ onPress={handleOnSubmit}
186
+ >
154
187
  {submitButtonText}
155
188
  </Button>
156
189
  ) : null}
@@ -163,14 +196,19 @@ const Checkout: FC<CheckoutProps> = ({ children, layout: Layout, useRedirect })
163
196
  {pricing && !screen.L ? (
164
197
  <Sticky style={style.sticky} onLayout={Platform.OS !== "web" ? handleOnPricingLayout : undefined}>
165
198
  <Body>
166
- <Button testID="confirm-checkout-button" small onPress={handleOnSubmit}>
199
+ <Button
200
+ busy={checkoutFlowStatus === "loading"}
201
+ testID="confirm-checkout-button"
202
+ small
203
+ onPress={handleOnSubmit}
204
+ >
167
205
  {submitButtonText}
168
206
  </Button>
169
207
  </Body>
170
208
  </Sticky>
171
209
  ) : null}
172
210
 
173
- {children}
211
+ {paymentFlowComponent}
174
212
  </Layout>
175
213
  );
176
214
  };
@@ -1,24 +1,24 @@
1
- import React, { FC, useRef } from "react";
1
+ import React, { FC } from "react";
2
2
  import { PaymentInstrumentSelect, Section } from "@lookiero/payments-front";
3
- import { useLogger } from "@lookiero/sty-psp-logging";
4
- import { usePaymentInstrumentEvents } from "../../../../hooks/usePaymentInstrumentEvents";
3
+ import { useStaticInfo } from "../../../../hooks/useStaticInfo";
5
4
 
6
5
  interface PaymentInstrumentProps {
7
6
  readonly useRedirect: () => Record<string, string>;
8
7
  }
9
8
  const PaymentInstrument: FC<PaymentInstrumentProps> = ({ useRedirect }) => {
10
- const paymentInstrumentSelectRef = useRef(null);
11
9
  const { returnUrl } = useRedirect();
12
- const logger = useLogger();
13
-
14
- usePaymentInstrumentEvents({ logger });
10
+ const { customer } = useStaticInfo();
15
11
 
16
12
  return (
17
13
  <PaymentInstrumentSelect
18
- ref={paymentInstrumentSelectRef}
19
14
  beforeRedirect={returnUrl ? () => Promise.resolve(returnUrl) : undefined}
20
15
  hasError={false}
21
16
  section={Section.BOX_CHECKOUT}
17
+ userInformation={{
18
+ email: customer.email,
19
+ name: customer.name,
20
+ }}
21
+ showSingleUsePaymentMethods
22
22
  />
23
23
  );
24
24
  };
@@ -793,6 +793,14 @@ exports[`ItemActions component matches the snapshot 1`] = `
793
793
  "fontStyle": "normal",
794
794
  "fontWeight": "normal",
795
795
  "height": 24,
796
+ "letterSpacing": -0.2,
797
+ "lineHeight": 24,
798
+ "minHeight": 24,
799
+ "minWidth": 24,
800
+ "paddingBottom": 0,
801
+ "paddingLeft": 0,
802
+ "paddingRight": 0,
803
+ "paddingTop": 0,
796
804
  "width": 24,
797
805
  },
798
806
  ]
@@ -219,6 +219,14 @@ exports[`SelectField component matches the snapshot 1`] = `
219
219
  "fontStyle": "normal",
220
220
  "fontWeight": "normal",
221
221
  "height": 24,
222
+ "letterSpacing": -0.2,
223
+ "lineHeight": 24,
224
+ "minHeight": 24,
225
+ "minWidth": 24,
226
+ "paddingBottom": 0,
227
+ "paddingLeft": 0,
228
+ "paddingRight": 0,
229
+ "paddingTop": 0,
222
230
  "width": 24,
223
231
  },
224
232
  ]
@@ -219,6 +219,14 @@ exports[`SizeWithoutStockModal component matches the snapshot 1`] = `
219
219
  "fontStyle": "normal",
220
220
  "fontWeight": "normal",
221
221
  "height": 24,
222
+ "letterSpacing": -0.2,
223
+ "lineHeight": 24,
224
+ "minHeight": 24,
225
+ "minWidth": 24,
226
+ "paddingBottom": 0,
227
+ "paddingLeft": 0,
228
+ "paddingRight": 0,
229
+ "paddingTop": 0,
222
230
  "width": 24,
223
231
  },
224
232
  ]
@@ -5,6 +5,8 @@ interface Customer {
5
5
  readonly customerId: string;
6
6
  readonly country: Country;
7
7
  readonly segment: Segment;
8
+ readonly name: string;
9
+ readonly email: string;
8
10
  }
9
11
 
10
12
  export type { Customer };
@@ -4,4 +4,4 @@ interface Order {
4
4
  readonly coupon: string | null;
5
5
  }
6
6
 
7
- export type { Order };
7
+ export type { Order as OrderProjection };
@@ -1,3 +1,3 @@
1
1
  type Subscription = "o" | "m" | "b" | "q";
2
2
 
3
- export type { Subscription };
3
+ export type { Subscription as SubscriptionProjection };
@@ -1,27 +0,0 @@
1
- import { RefObject } from "react";
2
- import { PaymentFlowRef } from "@lookiero/payments-front";
3
- import { Logger } from "@lookiero/sty-psp-logging";
4
- import { PaymentFlowPayloadProjection } from "../../../projection/payment/paymentFlowPayload";
5
- type Status = "idle" | "loading" | "success" | "error";
6
- interface SubmitCheckoutFunctionArgs {
7
- readonly paymentFlowPayload: PaymentFlowPayloadProjection;
8
- readonly sizeChangeEnabled: boolean;
9
- }
10
- interface SubmitCheckoutFunction {
11
- (args: SubmitCheckoutFunctionArgs): Promise<void>;
12
- }
13
- type UseSubmitCheckoutResult = [submitCheckout: SubmitCheckoutFunction, status: Status];
14
- interface UseSubmitCheckoutFunctionArgs {
15
- readonly checkoutId: string;
16
- readonly checkoutBookingId: string;
17
- readonly paymentFlowRef: RefObject<PaymentFlowRef>;
18
- readonly onError: () => void;
19
- readonly onSuccess?: () => void;
20
- readonly logger: Logger;
21
- }
22
- interface UseSubmitCheckoutFunction {
23
- (args: UseSubmitCheckoutFunctionArgs): UseSubmitCheckoutResult;
24
- }
25
- declare const useSubmitCheckout: UseSubmitCheckoutFunction;
26
- export type { Status, SubmitCheckoutFunction };
27
- export { useSubmitCheckout };
@@ -1,97 +0,0 @@
1
- import { useCallback, useMemo, useState } from "react";
2
- import { CommandStatus } from "@lookiero/messaging-react";
3
- import { NotificationLevel, useCreateToastNotification } from "@lookiero/sty-psp-notifications";
4
- import { viewCheckoutBookingById, } from "../../../projection/checkoutBooking/viewCheckoutBookingById";
5
- import { MESSAGING_CONTEXT_ID } from "../../delivery/baseBootstrap";
6
- import { useSubmitCheckout as useSubmitCheckoutCommand } from "../../domain/checkout/react/useSubmitCheckout";
7
- import { useBlockCheckoutBooking } from "../../domain/checkoutBooking/react/useBlockCheckoutBooking";
8
- import { I18nMessages } from "../i18n/i18n";
9
- import { useQueryBus } from "./useQueryBus";
10
- var ChargeStatus;
11
- (function (ChargeStatus) {
12
- ChargeStatus["EXECUTED"] = "EXECUTED";
13
- ChargeStatus["REQUIRES_ACTION"] = "REQUIRES_ACTION";
14
- ChargeStatus["REQUIRED_ACTION_CANCELLED"] = "REQUIRED_ACTION_CANCELLED";
15
- ChargeStatus["REJECTED"] = "REJECTED";
16
- ChargeStatus["CANCELLED"] = "CANCELLED";
17
- ChargeStatus["TO_CONFIRM"] = "TO_CONFIRM";
18
- ChargeStatus["ERROR"] = "ERROR";
19
- ChargeStatus["UNKNOWN"] = "UNKNOWN";
20
- })(ChargeStatus || (ChargeStatus = {}));
21
- const useSubmitCheckout = ({ checkoutId, checkoutBookingId, paymentFlowRef, onError, onSuccess, logger, }) => {
22
- const queryBus = useQueryBus();
23
- const [submitCheckoutCommand, submitCheckoutCommandStatus] = useSubmitCheckoutCommand({ checkoutId, logger });
24
- const [blockCheckoutBooking, blockCheckoutBookingStatus] = useBlockCheckoutBooking({ checkoutBookingId, logger });
25
- const [createNotification] = useCreateToastNotification({ contextId: MESSAGING_CONTEXT_ID, logger });
26
- const [checkoutBookingExpired, setCheckoutBookingExpired] = useState(false);
27
- const [startLegacyBoxCheckoutStatus, setStartLegacyBoxCheckoutStatus] = useState("idle");
28
- const submitCheckout = useCallback(async ({ paymentFlowPayload, sizeChangeEnabled }) => {
29
- try {
30
- sizeChangeEnabled && (await blockCheckoutBooking());
31
- }
32
- catch (error) {
33
- return;
34
- }
35
- const checkoutBooking = await queryBus(viewCheckoutBookingById({ checkoutBookingId }));
36
- if (checkoutBooking?.isExpired) {
37
- setCheckoutBookingExpired(true);
38
- return;
39
- }
40
- paymentFlowRef.current?.startLegacyBoxCheckout(
41
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
42
- // @ts-ignore
43
- paymentFlowPayload, async ({ status, toaster, final }) => {
44
- setStartLegacyBoxCheckoutStatus("loading");
45
- if (final) {
46
- if (status === ChargeStatus.EXECUTED) {
47
- setStartLegacyBoxCheckoutStatus("success");
48
- await submitCheckoutCommand();
49
- onSuccess?.();
50
- }
51
- else {
52
- createNotification({
53
- level: NotificationLevel.ERROR,
54
- bodyI18nKey: toaster?.id || I18nMessages.CHECKOUT_TOAST_PAYMENT_ERROR,
55
- });
56
- setStartLegacyBoxCheckoutStatus("error");
57
- }
58
- }
59
- });
60
- }, [
61
- queryBus,
62
- checkoutBookingId,
63
- paymentFlowRef,
64
- blockCheckoutBooking,
65
- submitCheckoutCommand,
66
- onSuccess,
67
- createNotification,
68
- ]);
69
- const status = useMemo(() => {
70
- if (blockCheckoutBookingStatus === CommandStatus.LOADING ||
71
- startLegacyBoxCheckoutStatus === "loading" ||
72
- submitCheckoutCommandStatus === CommandStatus.LOADING) {
73
- return "loading";
74
- }
75
- if (blockCheckoutBookingStatus === CommandStatus.SUCCESS &&
76
- startLegacyBoxCheckoutStatus === "success" &&
77
- submitCheckoutCommandStatus === CommandStatus.SUCCESS) {
78
- return "success";
79
- }
80
- if (blockCheckoutBookingStatus === CommandStatus.ERROR ||
81
- startLegacyBoxCheckoutStatus === "error" ||
82
- submitCheckoutCommandStatus === CommandStatus.ERROR ||
83
- checkoutBookingExpired) {
84
- onError();
85
- return "error";
86
- }
87
- return "idle";
88
- }, [
89
- blockCheckoutBookingStatus,
90
- startLegacyBoxCheckoutStatus,
91
- submitCheckoutCommandStatus,
92
- checkoutBookingExpired,
93
- onError,
94
- ]);
95
- return [submitCheckout, status];
96
- };
97
- export { useSubmitCheckout };