@lookiero/checkout 10.0.1 → 11.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 (74) 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/ExpoRoot.js +17 -12
  6. package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.d.ts +1 -1
  7. package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.js +2 -0
  8. package/dist/src/infrastructure/projection/checkout/checkout.mock.d.ts +1 -0
  9. package/dist/src/infrastructure/projection/checkout/checkout.mock.js +3 -3
  10. package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.d.ts +1 -1
  11. package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.js +2 -1
  12. package/dist/src/infrastructure/tracking/tracking.d.ts +2 -2
  13. package/dist/src/infrastructure/tracking/useTrackCheckout.d.ts +10 -17
  14. package/dist/src/infrastructure/tracking/useTrackCheckout.js +27 -12
  15. package/dist/src/infrastructure/ui/Root.d.ts +6 -6
  16. package/dist/src/infrastructure/ui/Root.js +2 -3
  17. package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.d.ts +26 -0
  18. package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.js +127 -0
  19. package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.d.ts +3 -2
  20. package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.js +17 -26
  21. package/dist/src/infrastructure/ui/i18n/i18n.d.ts +1 -0
  22. package/dist/src/infrastructure/ui/i18n/i18n.js +1 -0
  23. package/dist/src/infrastructure/ui/routing/CheckoutMiddleware.js +1 -12
  24. package/dist/src/infrastructure/ui/routing/Routing.d.ts +5 -5
  25. package/dist/src/infrastructure/ui/routing/Routing.js +2 -10
  26. package/dist/src/infrastructure/ui/routing/routes.d.ts +0 -1
  27. package/dist/src/infrastructure/ui/routing/routes.js +0 -1
  28. package/dist/src/infrastructure/ui/views/App.js +5 -6
  29. package/dist/src/infrastructure/ui/views/checkout/Checkout.d.ts +7 -2
  30. package/dist/src/infrastructure/ui/views/checkout/Checkout.js +20 -9
  31. package/dist/src/infrastructure/ui/views/checkout/Checkout.style.d.ts +3 -0
  32. package/dist/src/infrastructure/ui/views/checkout/Checkout.style.js +3 -0
  33. package/dist/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.js +7 -7
  34. package/dist/src/projection/customer/customer.d.ts +2 -0
  35. package/dist/src/projection/order/order.d.ts +1 -1
  36. package/dist/src/projection/subscription/subscription.d.ts +1 -1
  37. package/dist/src/version.d.ts +1 -1
  38. package/dist/src/version.js +1 -1
  39. package/fake-dependencies/@lookiero/payments-front/index.tsx +36 -8
  40. package/index.ts +10 -3
  41. package/package.json +4 -4
  42. package/src/ExpoRoot.tsx +43 -36
  43. package/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.ts +4 -1
  44. package/src/infrastructure/projection/checkout/checkout.mock.ts +8 -3
  45. package/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.ts +3 -2
  46. package/src/infrastructure/tracking/tracking.ts +2 -2
  47. package/src/infrastructure/tracking/useTrackCheckout.test.tsx +51 -24
  48. package/src/infrastructure/tracking/useTrackCheckout.ts +66 -56
  49. package/src/infrastructure/ui/Root.tsx +9 -9
  50. package/src/infrastructure/ui/components/templates/header/itemHeader/ItemHeader.tsx +1 -0
  51. package/src/infrastructure/ui/hooks/useCheckoutFlow.test.tsx +302 -0
  52. package/src/infrastructure/ui/hooks/useCheckoutFlow.tsx +203 -0
  53. package/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.ts +18 -60
  54. package/src/infrastructure/ui/i18n/i18n.ts +1 -0
  55. package/src/infrastructure/ui/routing/CheckoutMiddleware.test.tsx +0 -11
  56. package/src/infrastructure/ui/routing/CheckoutMiddleware.tsx +1 -15
  57. package/src/infrastructure/ui/routing/Routing.tsx +14 -25
  58. package/src/infrastructure/ui/routing/routes.ts +0 -1
  59. package/src/infrastructure/ui/views/App.tsx +5 -13
  60. package/src/infrastructure/ui/views/checkout/Checkout.style.ts +3 -0
  61. package/src/infrastructure/ui/views/checkout/Checkout.test.tsx +51 -43
  62. package/src/infrastructure/ui/views/checkout/Checkout.tsx +51 -13
  63. package/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.tsx +8 -8
  64. package/src/projection/customer/customer.ts +2 -0
  65. package/src/projection/order/order.ts +1 -1
  66. package/src/projection/subscription/subscription.ts +1 -1
  67. package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.d.ts +0 -27
  68. package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.js +0 -97
  69. package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.d.ts +0 -12
  70. package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.js +0 -88
  71. package/src/infrastructure/ui/hooks/useSubmitCheckout.test.ts +0 -297
  72. package/src/infrastructure/ui/hooks/useSubmitCheckout.ts +0 -169
  73. package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.test.tsx +0 -134
  74. package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.tsx +0 -124
@@ -47,6 +47,7 @@ declare enum I18nMessages {
47
47
  CHECKOUT_TITLE = "checkout.title",
48
48
  CHECKOUT_PAY_BUTTON = "checkout.pay_button",
49
49
  CHECKOUT_TOAST_PAYMENT_ERROR = "checkout.toast_payment_error",
50
+ CHECKOUT_TOAST_PAYMENT_SUCCESS = "checkout.toast_payment_success",
50
51
  CHECKOUT_SUCCESS_MODAL_TITLE = "checkout.success_modal_title",
51
52
  CHECKOUT_SUCCESS_MODAL_DESCRIPTION = "checkout.success_modal_description",
52
53
  CHECKOUT_SUCCESS_MODAL_BUTTON = "checkout.success_modal_button",
@@ -49,6 +49,7 @@ var I18nMessages;
49
49
  I18nMessages["CHECKOUT_TITLE"] = "checkout.title";
50
50
  I18nMessages["CHECKOUT_PAY_BUTTON"] = "checkout.pay_button";
51
51
  I18nMessages["CHECKOUT_TOAST_PAYMENT_ERROR"] = "checkout.toast_payment_error";
52
+ I18nMessages["CHECKOUT_TOAST_PAYMENT_SUCCESS"] = "checkout.toast_payment_success";
52
53
  I18nMessages["CHECKOUT_SUCCESS_MODAL_TITLE"] = "checkout.success_modal_title";
53
54
  I18nMessages["CHECKOUT_SUCCESS_MODAL_DESCRIPTION"] = "checkout.success_modal_description";
54
55
  I18nMessages["CHECKOUT_SUCCESS_MODAL_BUTTON"] = "checkout.success_modal_button";
@@ -33,11 +33,6 @@ const CheckoutMiddleware = ({ customerId, onNotAccessible, loader = React.create
33
33
  const feedbackRouteMatch = useMatch(`${basePath}/${Routes.FEEDBACK}`);
34
34
  const feedbackRouteMatchRef = useRef(feedbackRouteMatch);
35
35
  feedbackRouteMatchRef.current = feedbackRouteMatch;
36
- const checkoutPaymentRouteMatch = useMatch(`${basePath}/${Routes.CHECKOUT}/${Routes.CHECKOUT_PAYMENT}`);
37
- const checkoutPaymentRouteMatchRef = useRef(checkoutPaymentRouteMatch);
38
- checkoutPaymentRouteMatchRef.current = checkoutPaymentRouteMatch;
39
- const checkoutShown = useRef(false);
40
- checkoutShown.current = checkoutShown.current || (Boolean(checkoutRouteMatch) && !Boolean(checkoutPaymentRouteMatch));
41
36
  const [checkout] = useViewFirstAvailableCheckoutByCustomerId({ customerId });
42
37
  const checkoutItemsRef = useRef();
43
38
  /* This hook is mounted at this level, although not being used directly, for optimization (regarding cache) */
@@ -66,8 +61,7 @@ const CheckoutMiddleware = ({ customerId, onNotAccessible, loader = React.create
66
61
  !(summaryRouteMatchRef.current ||
67
62
  summaryTabsRouteMatchRef.current ||
68
63
  itemDetailRouteMatchRef.current ||
69
- checkoutRouteMatchRef.current ||
70
- checkoutPaymentRouteMatchRef.current)) {
64
+ checkoutRouteMatchRef.current)) {
71
65
  navigateRef.current(`${basePath}/${Routes.SUMMARY}`, { replace: true });
72
66
  }
73
67
  if (itemWithoutCustomerDecision &&
@@ -85,11 +79,6 @@ const CheckoutMiddleware = ({ customerId, onNotAccessible, loader = React.create
85
79
  onNotAccessible();
86
80
  return null;
87
81
  }
88
- /* Prevent direct payment access */
89
- if (checkoutPaymentRouteMatch && !checkoutShown.current) {
90
- onNotAccessible();
91
- return null;
92
- }
93
82
  return children;
94
83
  };
95
84
  export { CheckoutMiddleware };
@@ -5,14 +5,14 @@ import { Locale } from "@lookiero/sty-psp-locale";
5
5
  import { Layout } from "@lookiero/sty-psp-ui";
6
6
  import { Tradename } from "@lookiero/sty-sp-tradename";
7
7
  import { Customer } from "../../../projection/customer/customer";
8
- import { Order } from "../../../projection/order/order";
9
- import { Subscription } from "../../../projection/subscription/subscription";
8
+ import { OrderProjection } from "../../../projection/order/order";
9
+ import { SubscriptionProjection } from "../../../projection/subscription/subscription";
10
10
  import { KameleoonEnvironment } from "../../ab-testing/kameleoonEnvironment";
11
11
  interface RoutingProps {
12
12
  readonly basePath?: string;
13
13
  readonly customer: Customer;
14
- readonly order: Order | undefined;
15
- readonly subscription: Subscription | undefined;
14
+ readonly order: OrderProjection;
15
+ readonly subscription: SubscriptionProjection;
16
16
  readonly locale: Locale;
17
17
  readonly I18n: I18n;
18
18
  readonly kameleoon: KameleoonEnvironment;
@@ -20,7 +20,7 @@ interface RoutingProps {
20
20
  readonly tradename: Tradename;
21
21
  readonly getAuthToken: () => Promise<string>;
22
22
  readonly onNotAccessible: () => void;
23
- readonly onCheckoutSubmitted?: () => void;
23
+ readonly onCheckoutFlowSuccess: () => void;
24
24
  readonly onI18nError?: (err: Error) => void;
25
25
  readonly useRedirect: () => Record<string, string>;
26
26
  readonly useRoutes: typeof reactRouterUseRoutes;
@@ -5,7 +5,6 @@ import { Kameleoon } from "@lookiero/sty-psp-ab-testing";
5
5
  import { StaticInfoProvider } from "../hooks/useStaticInfo";
6
6
  import { App } from "../views/App";
7
7
  import { Checkout } from "../views/checkout/Checkout";
8
- import { CheckoutPaymentModal } from "../views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal";
9
8
  import { Feedback } from "../views/feedback/Feedback";
10
9
  import { Item } from "../views/item/Item";
11
10
  import { Return } from "../views/return/Return";
@@ -13,7 +12,7 @@ import { Summary } from "../views/summary/Summary";
13
12
  import { SummaryTabs } from "../views/summaryTabs/SummaryTabs";
14
13
  import { CheckoutMiddleware } from "./CheckoutMiddleware";
15
14
  import { Routes } from "./routes";
16
- const Routing = ({ basePath = "", customer, order, subscription, locale, I18n, kameleoon, layout, tradename, getAuthToken, onI18nError, onNotAccessible, onCheckoutSubmitted, useRedirect, useRoutes = reactRouterUseRoutes, }) => {
15
+ const Routing = ({ basePath = "", customer, order, subscription, locale, I18n, kameleoon, layout, tradename, getAuthToken, onI18nError, onNotAccessible, onCheckoutFlowSuccess, useRedirect, useRoutes = reactRouterUseRoutes, }) => {
17
16
  return useRoutes([
18
17
  {
19
18
  path: "",
@@ -50,14 +49,7 @@ const Routing = ({ basePath = "", customer, order, subscription, locale, I18n, k
50
49
  {
51
50
  path: Routes.CHECKOUT,
52
51
  element: (React.createElement(Suspense, { fallback: React.createElement(Spinner, null) },
53
- React.createElement(Checkout, { layout: layout, useRedirect: useRedirect },
54
- React.createElement(Outlet, null)))),
55
- children: [
56
- {
57
- path: Routes.CHECKOUT_PAYMENT,
58
- element: (React.createElement(CheckoutPaymentModal, { coupon: order?.coupon || null, getAuthToken: getAuthToken, isFirstOrder: order?.isFirstOrder, orderNumber: order?.orderNumber, subscription: subscription, onCheckoutSubmitted: onCheckoutSubmitted })),
59
- },
60
- ],
52
+ React.createElement(Checkout, { getAuthToken: getAuthToken, layout: layout, order: order, subscription: subscription, useRedirect: useRedirect, onCheckoutFlowSuccess: onCheckoutFlowSuccess }))),
61
53
  },
62
54
  {
63
55
  path: Routes.FEEDBACK,
@@ -5,7 +5,6 @@ export declare 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
  }
@@ -6,7 +6,6 @@ export var Routes;
6
6
  Routes["SUMMARY"] = "summary";
7
7
  Routes["SUMMARY_TABS"] = "tabs/:tab";
8
8
  Routes["CHECKOUT"] = "checkout";
9
- Routes["CHECKOUT_PAYMENT"] = "payment";
10
9
  Routes["FEEDBACK"] = "feedback";
11
10
  Routes["RETURN"] = "return/:id";
12
11
  })(Routes || (Routes = {}));
@@ -1,16 +1,15 @@
1
- import { PortalProvider } from "@gorhom/portal";
1
+ import { PortalHost } from "@gorhom/portal";
2
2
  import React 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";
9
8
  import { DOMAIN } from "../i18n/i18n";
10
9
  const { colorBgBase } = theme();
11
10
  const App = ({ children }) => (React.createElement(SafeAreaProvider, null,
12
- React.createElement(PortalProvider, { rootHostName: "Checkout" },
13
- React.createElement(StatusBar, { backgroundColor: colorBgBase, barStyle: "dark-content", translucent: true }),
14
- React.createElement(Notifications, { contextId: MESSAGING_CONTEXT_ID, domain: DOMAIN, portalHostName: "Checkout" }),
15
- React.createElement(AuroraPortalProvider, null, children))));
11
+ React.createElement(StatusBar, { backgroundColor: colorBgBase, barStyle: "dark-content", translucent: true }),
12
+ React.createElement(Notifications, { contextId: MESSAGING_CONTEXT_ID, domain: DOMAIN, portalHostName: "Checkout" }),
13
+ React.createElement(PortalHost, { name: "Checkout" }),
14
+ children));
16
15
  export { App };
@@ -1,8 +1,13 @@
1
- import { FC, ReactNode } from "react";
1
+ import { FC } from "react";
2
2
  import { Layout as UiLayout } from "@lookiero/sty-psp-ui";
3
+ import { OrderProjection } from "../../../../projection/order/order";
4
+ import { SubscriptionProjection } from "../../../../projection/subscription/subscription";
3
5
  interface CheckoutProps {
4
- readonly children?: ReactNode;
5
6
  readonly layout: UiLayout;
7
+ readonly order: OrderProjection;
8
+ readonly subscription: SubscriptionProjection;
9
+ readonly getAuthToken: () => Promise<string>;
10
+ readonly onCheckoutFlowSuccess: () => void;
6
11
  readonly useRedirect: () => Record<string, string>;
7
12
  }
8
13
  declare const Checkout: FC<CheckoutProps>;
@@ -4,6 +4,7 @@ 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 { Sticky } from "@lookiero/sty-psp-ui";
8
9
  import { CheckoutItemStatus } from "../../../../domain/checkoutItem/model/checkoutItem";
9
10
  import { useViewFirstAvailableCheckoutByCustomerId } from "../../../projection/checkout/react/useViewFirstAvailableCheckoutByCustomerId";
@@ -14,6 +15,7 @@ import { useTrackPressBack } from "../../../tracking/useTrackPressBack";
14
15
  import { useTrackPressContinue } from "../../../tracking/useTrackPressContinue";
15
16
  import { Body } from "../../components/layouts/body/Body";
16
17
  import { CheckoutHeader } from "../../components/templates/header/checkoutHeader/CheckoutHeader";
18
+ import { useCheckoutFlow } from "../../hooks/useCheckoutFlow";
17
19
  import { useStaticInfo } from "../../hooks/useStaticInfo";
18
20
  import { DOMAIN, I18nMessages } from "../../i18n/i18n";
19
21
  import { Routes } from "../../routing/routes";
@@ -22,7 +24,7 @@ import { Pricing } from "../summary/components/pricing/Pricing";
22
24
  import { style } from "./Checkout.style";
23
25
  import { DeliveryBanner } from "./components/deliveryBanner/DeliveryBanner";
24
26
  import { PaymentInstrument } from "./components/paymentInstrument/PaymentInstrument";
25
- const Checkout = ({ children, layout: Layout, useRedirect }) => {
27
+ const Checkout = ({ layout: Layout, order, subscription, getAuthToken, useRedirect, onCheckoutFlowSuccess, }) => {
26
28
  const { customer: { customerId, country, segment }, basePath, } = useStaticInfo();
27
29
  const titleText = useI18nMessage({ domain: DOMAIN, id: I18nMessages.CHECKOUT_TITLE });
28
30
  const submitButtonText = useI18nMessage({ domain: DOMAIN, id: I18nMessages.CHECKOUT_PAY_BUTTON });
@@ -31,6 +33,13 @@ const Checkout = ({ children, layout: Layout, useRedirect }) => {
31
33
  const handleOnPricingLayout = useCallback(({ height }) => setPricingHeight(height), []);
32
34
  const [checkout, checkoutStatus] = useViewFirstAvailableCheckoutByCustomerId({ customerId });
33
35
  const [pricing, pricingStatus] = useViewPricingByCheckoutId({ checkoutId: checkout?.id });
36
+ const [checkoutFlow, checkoutFlowStatus, paymentFlowComponent] = useCheckoutFlow({
37
+ checkout,
38
+ order,
39
+ subscription,
40
+ getAuthToken,
41
+ onSuccess: onCheckoutFlowSuccess,
42
+ });
34
43
  useTrackPageView({
35
44
  page: TrackingPage.CHECKOUT,
36
45
  country,
@@ -44,10 +53,10 @@ const Checkout = ({ children, layout: Layout, useRedirect }) => {
44
53
  segment,
45
54
  checkoutId: checkout?.id,
46
55
  });
47
- const handleOnSubmit = useCallback(() => {
56
+ const handleOnSubmit = useCallback(async () => {
48
57
  trackPressContinue();
49
- navigate(`${basePath}/${Routes.CHECKOUT}/${Routes.CHECKOUT_PAYMENT}`, { replace: true });
50
- }, [basePath, navigate, trackPressContinue]);
58
+ await checkoutFlow();
59
+ }, [checkoutFlow, trackPressContinue]);
51
60
  const checkoutItemsKept = useMemo(() => checkout?.items.filter((checkoutItem) => checkoutItem.status === CheckoutItemStatus.KEPT || checkoutItem.status === CheckoutItemStatus.REPLACED), [checkout?.items]);
52
61
  const hasReplacedCheckoutItem = useMemo(() => checkout?.items.some((checkoutItem) => checkoutItem.status === CheckoutItemStatus.REPLACED), [checkout?.items]);
53
62
  const trackPressBack = useTrackPressBack({
@@ -75,19 +84,21 @@ const Checkout = ({ children, layout: Layout, useRedirect }) => {
75
84
  React.createElement(AuroraLayout, { fullWidth: !screen.L, style: [screen.L && style.desktopLayoutSpacing, !screen.L && { paddingBottom: pricingHeight }] },
76
85
  React.createElement(Box, { size: { L: "2/3" }, style: screen.L && style.desktopListSpacing },
77
86
  React.createElement(View, { style: [style.contentWrapper, screen.L && style.desktopContentWrapper] },
87
+ country === Country.NL && (React.createElement(View, { style: style.paymentSelectorNL },
88
+ React.createElement(PaymentInstrument, { useRedirect: useRedirect }))),
78
89
  React.createElement(Text, { level: 3, style: style.title, heading: true }, titleText),
79
90
  checkoutItemsKept?.map((checkoutItem) => (React.createElement(View, { key: checkoutItem.id, testID: "checkout-items-kept" },
80
91
  React.createElement(ProductVariant, { brand: checkoutItem.productVariant.brand, color: checkoutItem.productVariant.color, country: country, media: checkoutItem.productVariant.media, name: checkoutItem.productVariant.name, price: checkoutItem.price, status: checkoutItem.status, size: checkoutItem.status === CheckoutItemStatus.REPLACED && checkoutItem.replacedFor
81
92
  ? checkoutItem.replacedFor.size
82
93
  : checkoutItem.productVariant.size })))),
83
- React.createElement(View, { style: style.paymentSelector },
84
- React.createElement(PaymentInstrument, { useRedirect: useRedirect })))),
94
+ country !== Country.NL && (React.createElement(View, { style: style.paymentSelector },
95
+ React.createElement(PaymentInstrument, { useRedirect: useRedirect }))))),
85
96
  React.createElement(Box, { size: { L: "1/3" }, style: [style.resume, screen.L && style.desktopResume] }, pricing ? (React.createElement(View, { style: [style.princingWrapper, !screen.L && style.princingWrapperSmall] },
86
97
  React.createElement(Pricing, { pricing: pricing, totalCheckoutItemsKept: checkoutItemsKept?.length || 0 }),
87
- screen.L ? (React.createElement(Button, { testID: "confirm-checkout-button", onPress: handleOnSubmit }, submitButtonText)) : null)) : null))),
98
+ screen.L ? (React.createElement(Button, { busy: checkoutFlowStatus === "loading", testID: "confirm-checkout-button", onPress: handleOnSubmit }, submitButtonText)) : null)) : null))),
88
99
  pricing && !screen.L ? (React.createElement(Sticky, { style: style.sticky, onLayout: Platform.OS !== "web" ? handleOnPricingLayout : undefined },
89
100
  React.createElement(Body, null,
90
- React.createElement(Button, { testID: "confirm-checkout-button", small: true, onPress: handleOnSubmit }, submitButtonText)))) : null,
91
- children));
101
+ React.createElement(Button, { busy: checkoutFlowStatus === "loading", testID: "confirm-checkout-button", small: true, onPress: handleOnSubmit }, submitButtonText)))) : null,
102
+ paymentFlowComponent));
92
103
  };
93
104
  export { Checkout };
@@ -24,6 +24,9 @@ declare const style: {
24
24
  paymentSelector: {
25
25
  marginTop: number;
26
26
  };
27
+ paymentSelectorNL: {
28
+ marginBottom: number;
29
+ };
27
30
  princingWrapper: {
28
31
  padding: number;
29
32
  };
@@ -28,6 +28,9 @@ const style = StyleSheet.create({
28
28
  paymentSelector: {
29
29
  marginTop: space6,
30
30
  },
31
+ paymentSelectorNL: {
32
+ marginBottom: space6,
33
+ },
31
34
  princingWrapper: {
32
35
  padding: space6,
33
36
  },
@@ -1,12 +1,12 @@
1
- import React, { useRef } from "react";
1
+ import React 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
  const PaymentInstrument = ({ useRedirect }) => {
6
- const paymentInstrumentSelectRef = useRef(null);
7
5
  const { returnUrl } = useRedirect();
8
- const logger = useLogger();
9
- usePaymentInstrumentEvents({ logger });
10
- return (React.createElement(PaymentInstrumentSelect, { ref: paymentInstrumentSelectRef, beforeRedirect: returnUrl ? () => Promise.resolve(returnUrl) : undefined, hasError: false, section: Section.BOX_CHECKOUT }));
6
+ const { customer } = useStaticInfo();
7
+ return (React.createElement(PaymentInstrumentSelect, { beforeRedirect: returnUrl ? () => Promise.resolve(returnUrl) : undefined, hasError: false, section: Section.BOX_CHECKOUT, userInformation: {
8
+ email: customer.email,
9
+ name: customer.name,
10
+ }, showSingleUsePaymentMethods: true }));
11
11
  };
12
12
  export { PaymentInstrument };
@@ -4,5 +4,7 @@ interface Customer {
4
4
  readonly customerId: string;
5
5
  readonly country: Country;
6
6
  readonly segment: Segment;
7
+ readonly name: string;
8
+ readonly email: string;
7
9
  }
8
10
  export type { Customer };
@@ -3,4 +3,4 @@ interface Order {
3
3
  readonly isFirstOrder: boolean;
4
4
  readonly coupon: string | null;
5
5
  }
6
- export type { Order };
6
+ export type { Order as OrderProjection };
@@ -1,2 +1,2 @@
1
1
  type Subscription = "o" | "m" | "b" | "q";
2
- export type { Subscription };
2
+ export type { Subscription as SubscriptionProjection };
@@ -1 +1 @@
1
- export declare const VERSION = "10.0.1";
1
+ export declare const VERSION = "11.0.0";
@@ -1 +1 @@
1
- export const VERSION = "10.0.1";
1
+ export const VERSION = "11.0.0";
@@ -7,34 +7,62 @@ import {
7
7
  RefAttributes,
8
8
  useImperativeHandle,
9
9
  } from "react";
10
+ import { PaymentPayload } from "@lookiero/payments-front";
11
+
12
+ let startLegacyBoxCheckoutListener: ({ success }: { success: boolean }) => void;
10
13
 
11
14
  const setPaymentsBridge = () => void 0;
12
15
  const PaymentsQueryProvider: FC<PropsWithChildren> = ({ children }) => children;
13
16
  const PaymentInstrumentSelect: FC = () => null;
14
- interface StartLegacyBoxCheckoutCallbackArgs {
15
- readonly status: string;
16
- readonly final: boolean;
17
- }
17
+
18
18
  interface StartLegacyBoxCheckoutFunction {
19
- (paymentFlowPayload: unknown, callback: (params: StartLegacyBoxCheckoutCallbackArgs) => Promise<void>): void;
19
+ (paymentFlowPayload: unknown): void;
20
20
  }
21
+
21
22
  interface PaymentFlowRef {
22
23
  readonly startLegacyBoxCheckout: StartLegacyBoxCheckoutFunction;
23
24
  }
25
+
24
26
  const paymentFlowRef: PaymentFlowRef = {
25
- startLegacyBoxCheckout: async (_paymentFlowPayload, callback) => {
26
- await callback({ status: "EXECUTED", final: true });
27
+ startLegacyBoxCheckout: async () => {
28
+ startLegacyBoxCheckoutListener?.({ success: true });
27
29
  },
28
30
  };
31
+
29
32
  const PaymentFlow: ForwardRefExoticComponent<RefAttributes<PaymentFlowRef>> = forwardRef<PaymentFlowRef, unknown>(
30
33
  (_props, ref) => {
31
34
  useImperativeHandle(ref, () => paymentFlowRef, []);
32
35
  return null;
33
36
  },
34
37
  );
38
+
35
39
  PaymentFlow.displayName = "PaymentFlow";
40
+
41
+ interface UsePaymentStatusManagerResult {
42
+ isLoading: boolean;
43
+ consumePayload: (callback: (payload: PaymentPayload) => void) => void;
44
+ }
45
+
46
+ const paymentStatusManagerResult: UsePaymentStatusManagerResult = {
47
+ isLoading: false,
48
+ consumePayload: (callback) => {
49
+ startLegacyBoxCheckoutListener = () => callback({ success: true } as PaymentPayload);
50
+ },
51
+ };
52
+
53
+ const usePaymentStatusManager: (section: Section) => UsePaymentStatusManagerResult = () => paymentStatusManagerResult;
54
+
36
55
  enum Section {
37
56
  BOX_CHECKOUT = "box-checkout",
38
57
  }
58
+
39
59
  export type { PaymentFlowRef };
40
- export { PaymentsQueryProvider, PaymentInstrumentSelect, PaymentFlow, Section, setPaymentsBridge, paymentFlowRef };
60
+
61
+ export {
62
+ PaymentsQueryProvider,
63
+ PaymentInstrumentSelect,
64
+ PaymentFlow,
65
+ Section,
66
+ setPaymentsBridge,
67
+ usePaymentStatusManager,
68
+ };
package/index.ts CHANGED
@@ -14,8 +14,8 @@ import { DOMAIN } from "./src/infrastructure/ui/i18n/i18n";
14
14
  import { CheckoutProjection } from "./src/projection/checkout/checkout";
15
15
  import { viewFirstAvailableCheckoutByCustomerId } from "./src/projection/checkout/viewFirstAvailableCheckoutByCustomerId";
16
16
  import { Customer } from "./src/projection/customer/customer";
17
- import { Order } from "./src/projection/order/order";
18
- import { Subscription } from "./src/projection/subscription/subscription";
17
+ import { OrderProjection } from "./src/projection/order/order";
18
+ import { SubscriptionProjection } from "./src/projection/subscription/subscription";
19
19
 
20
20
  interface FirstAvailableCheckoutByCustomerIdFunctionArgs {
21
21
  readonly customerId: string | undefined;
@@ -59,4 +59,11 @@ const bootstrap: BootstrapFunction = ({ apiUrl, getAuthToken, translations, sent
59
59
  };
60
60
 
61
61
  export { bootstrap, translationEndpoint, translationExternalEndpoint, Country, Segment, CheckoutStatus, Tradename };
62
- export type { SentryEnvironment, KameleoonEnvironment, Customer, Subscription, Order, Locale };
62
+ export type {
63
+ SentryEnvironment,
64
+ KameleoonEnvironment,
65
+ Customer,
66
+ SubscriptionProjection as Subscription,
67
+ OrderProjection as Order,
68
+ Locale,
69
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lookiero/checkout",
3
- "version": "10.0.1",
3
+ "version": "11.0.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": "false",
@@ -32,7 +32,7 @@
32
32
  "@lookiero/sty-psp-segment": "^0.1",
33
33
  "@lookiero/sty-psp-storage": "^0.2",
34
34
  "@lookiero/sty-psp-tracking": "^0.2",
35
- "@lookiero/sty-sp-tradename": "^0.1",
35
+ "@lookiero/sty-sp-tradename": "^1.0",
36
36
  "@lookiero/sty-psp-ui": "^0.7",
37
37
  "@lookiero/sty-psp-ui-settings": "^0.2",
38
38
  "@lookiero/sty-psp-units": "^0.1",
@@ -46,7 +46,7 @@
46
46
  "@cypress/webpack-preprocessor": "^6.0.2",
47
47
  "@lookiero/eslint-config-sty-psp": "*",
48
48
  "@lookiero/event": "^0.3",
49
- "@lookiero/payments-front": "6.0.3",
49
+ "@lookiero/payments-front": "^7.0.0",
50
50
  "@lookiero/sty-psp-jest-config": "*",
51
51
  "@lookiero/sty-psp-prettier-config": "*",
52
52
  "@lookiero/sty-psp-scripts": "*",
@@ -76,7 +76,7 @@
76
76
  "@lookiero/event": "^0.3",
77
77
  "@lookiero/i18n": ">=2",
78
78
  "@lookiero/i18n-react": ">=2",
79
- "@lookiero/payments-front": "6.0.3",
79
+ "@lookiero/payments-front": ">=7",
80
80
  "apollo-boost": "0.4.4",
81
81
  "expo": ">=51",
82
82
  "expo-font": ">=12",
package/src/ExpoRoot.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ import { PortalProvider } from "@gorhom/portal";
1
2
  import { useFonts } from "expo-font";
2
3
  import "expo/build/Expo.fx";
3
4
  import React, { FC, useCallback, useState } from "react";
@@ -21,22 +22,24 @@ import { root } from "./infrastructure/ui/Root";
21
22
  import { DOMAIN } from "./infrastructure/ui/i18n/i18n";
22
23
  import { Router } from "./infrastructure/ui/routing/router/Router";
23
24
  import { Customer } from "./projection/customer/customer";
24
- import { Order } from "./projection/order/order";
25
- import { Subscription } from "./projection/subscription/subscription";
25
+ import { OrderProjection } from "./projection/order/order";
26
+ import { SubscriptionProjection } from "./projection/subscription/subscription";
26
27
  import { VERSION } from "./version";
27
28
 
28
- const locale: Locale = Locale.en_GB;
29
- const subscription: Subscription = "b";
30
- const order: Order = {
29
+ const locale: Locale = Locale.es_ES;
30
+ const subscription: SubscriptionProjection = "b";
31
+ const order: OrderProjection = {
31
32
  isFirstOrder: false,
32
33
  orderNumber: 3687582,
33
34
  coupon: "MYLOOKIERO",
34
35
  };
35
36
 
36
37
  const customer: Customer = {
37
- customerId: "a4355713-469b-4684-bf90-3215702dfb1c",
38
- country: Country.ES,
38
+ customerId: "9cfb056e-6008-44b1-9075-320479bf92ac",
39
+ country: Country.NL,
39
40
  segment: Segment.WOMEN,
41
+ email: "email@example.com",
42
+ name: "Adèle Léonce Émilie",
40
43
  };
41
44
 
42
45
  const sentryConfig: SentryEnvironment = {
@@ -53,7 +56,7 @@ const apiUrl =
53
56
  ? "/local-to-dev"
54
57
  : "/checkout/api";
55
58
  const authToken =
56
- "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjU2ODkxMDAsImV4cCI6MTc0NjI3ODQwMiwiZGlzcGxheU5hbWUiOiJUZXN0aW5nIiwiY291bnRyeV9jb2RlIjoiRVMiLCJhY2Nlc3NWaWEiOiJlbWFpbCIsInN1YnNjcmlwdGlvblN0YXJ0aW5nRGF0ZSI6IjIwMjUtMDQtMDMiLCJpbXBlcnNvbmF0ZWQiOmZhbHNlLCJ1dWlkIjoiYTQzNTU3MTMtNDY5Yi00Njg0LWJmOTAtMzIxNTcwMmRmYjFjIiwiaWF0IjoxNzQzNjg2NDAyfQ.pmqFo-4s0USFpzCnijRt78bWuBdu2Q7f4L9UtOkfAwo";
59
+ "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjU2NDk0NjYsImV4cCI6MTc0MjQ3MDI5OSwiZGlzcGxheU5hbWUiOiJNaWtlbCIsImNvdW50cnlfY29kZSI6IkVTIiwiYWNjZXNzVmlhIjoiZW1haWwiLCJzdWJzY3JpcHRpb25TdGFydGluZ0RhdGUiOiIyMDI0LTExLTExIiwiaW1wZXJzb25hdGVkIjpmYWxzZSwidXVpZCI6ImQzYzIzNTRiLTk4MTEtNDZkNC1iMmJhLTVmYmEwMTJlZDk0ZCIsImlhdCI6MTc0MDA1MTA5OX0.AkuUZTsn9mgplQwatg0dPKyv1Hsc6r267UMahxMH19g";
57
60
  const getAuthToken = () => Promise.resolve(authToken);
58
61
 
59
62
  const externalTranslationsUrl =
@@ -94,6 +97,7 @@ setPaymentsBridge({
94
97
  useFeatureFlags: () => ({}),
95
98
  locale: () => Promise.resolve("es-ES"),
96
99
  scrollView: ScrollView,
100
+ hostUrl: "",
97
101
  });
98
102
 
99
103
  const kameleoonConfig: KameleoonEnvironment = {
@@ -131,36 +135,39 @@ const ExpoRoot: FC = () => {
131
135
  const onNotAccessible = useCallback(() => setIsAccessible(false), []);
132
136
 
133
137
  return fontsLoaded ? (
134
- <PaymentsQueryProvider>
135
- <EventProvider>
136
- <Aurora>
137
- {isAccessible === false && <Text heading={true}>Checkout is not accessible!</Text>}
138
+ <PortalProvider>
139
+ <PaymentsQueryProvider>
140
+ <EventProvider>
141
+ <Aurora>
142
+ {isAccessible === false && <Text heading={true}>Checkout is not accessible!</Text>}
138
143
 
139
- <Router>
140
- <Routes>
141
- <Route
142
- path="/checkout/*"
143
- element={
144
- <Root
145
- basePath="/checkout"
146
- customer={customer}
147
- layout={DummyLayout}
148
- locale={locale}
149
- order={order}
150
- subscription={subscription}
151
- tradename={Tradename.LOOKIERO}
152
- useRedirect={useRedirect}
153
- onNotAccessible={onNotAccessible}
154
- />
155
- }
156
- />
144
+ <Router>
145
+ <Routes>
146
+ <Route
147
+ path="/checkout/*"
148
+ element={
149
+ <Root
150
+ basePath="/checkout"
151
+ customer={customer}
152
+ layout={DummyLayout}
153
+ locale={locale}
154
+ order={order}
155
+ subscription={subscription}
156
+ tradename={Tradename.LOOKIERO}
157
+ useRedirect={useRedirect}
158
+ onCheckoutFlowSuccess={() => console.log("Checkout flow success!")}
159
+ onNotAccessible={onNotAccessible}
160
+ />
161
+ }
162
+ />
157
163
 
158
- <Route element={<Navigate to="/checkout" replace />} path="*" />
159
- </Routes>
160
- </Router>
161
- </Aurora>
162
- </EventProvider>
163
- </PaymentsQueryProvider>
164
+ <Route element={<Navigate to="/checkout" replace />} path="*" />
165
+ </Routes>
166
+ </Router>
167
+ </Aurora>
168
+ </EventProvider>
169
+ </PaymentsQueryProvider>
170
+ </PortalProvider>
164
171
  ) : null;
165
172
  };
166
173
 
@@ -1,4 +1,5 @@
1
1
  import { useCallback } from "react";
2
+ import invariant from "tiny-invariant";
2
3
  import { CommandStatus, useCommand } from "@lookiero/messaging-react";
3
4
  import { Logger } from "@lookiero/sty-psp-logging";
4
5
  import { NotificationLevel, useCreateToastNotification } from "@lookiero/sty-psp-notifications";
@@ -13,7 +14,7 @@ interface BlockCheckoutBookingFunction {
13
14
  type UseBlockCheckoutBooking = [blockCheckoutBooking: BlockCheckoutBookingFunction, status: CommandStatus];
14
15
 
15
16
  interface UseBlockCheckoutBookingFunctionArgs {
16
- readonly checkoutBookingId: string;
17
+ readonly checkoutBookingId: string | undefined;
17
18
  readonly logger: Logger;
18
19
  }
19
20
 
@@ -26,6 +27,8 @@ const useBlockCheckoutBooking: UseBlockCheckoutBookingFunction = ({ checkoutBook
26
27
  const [createNotification] = useCreateToastNotification({ contextId: MESSAGING_CONTEXT_ID, logger });
27
28
 
28
29
  const blockCheckoutBooking = useCallback(async () => {
30
+ invariant(checkoutBookingId, "checkoutBookingId is required");
31
+
29
32
  try {
30
33
  await commandBus(
31
34
  blockCheckoutBookingCommand({
@@ -11,6 +11,7 @@ const itemIds = [
11
11
  "8890e00b-d4ed-4220-ae13-52cd88ae8ed5",
12
12
  ];
13
13
  interface CheckoutDtoFunctionArgs {
14
+ readonly id?: string;
14
15
  readonly status?: CheckoutStatus;
15
16
  readonly items: CheckoutItemFunctionArgs[];
16
17
  }
@@ -19,8 +20,12 @@ interface CheckoutDtoFunction {
19
20
  (args: CheckoutDtoFunctionArgs): CheckoutDto;
20
21
  }
21
22
 
22
- const checkoutDto: CheckoutDtoFunction = ({ status = CheckoutStatus.STARTED, items }) => ({
23
- id: "9c450400-0cd7-44a4-b0e3-e0002a9bf8df",
23
+ const checkoutDto: CheckoutDtoFunction = ({
24
+ id = "9c450400-0cd7-44a4-b0e3-e0002a9bf8df",
25
+ status = CheckoutStatus.STARTED,
26
+ items,
27
+ }) => ({
28
+ id,
24
29
  status,
25
30
  customerId: "0df61ca7-7e4d-462b-a422-a57de0d116b4",
26
31
  boxId: "9c406e57-100a-4aa6-83c5-016e7c2970e7",
@@ -37,6 +42,6 @@ interface CheckoutFunction {
37
42
  (args: CheckoutFunctionArgs): CheckoutProjection;
38
43
  }
39
44
 
40
- const checkout: CheckoutFunction = ({ status, items }) => toCheckoutProjection(checkoutDto({ status, items }));
45
+ const checkout: CheckoutFunction = ({ id, status, items }) => toCheckoutProjection(checkoutDto({ id, status, items }));
41
46
 
42
47
  export { checkout, checkoutDto };