@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.
- package/cypress/integration/checkout.spec.ts +0 -3
- package/dist/fake-dependencies/@lookiero/payments-front/index.d.ts +8 -7
- package/dist/fake-dependencies/@lookiero/payments-front/index.js +11 -3
- package/dist/index.d.ts +3 -3
- package/dist/src/Expo.js +8 -2
- package/dist/src/ExpoRoot.d.ts +5 -1
- package/dist/src/ExpoRoot.js +26 -17
- package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.d.ts +1 -1
- package/dist/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.js +2 -0
- package/dist/src/infrastructure/projection/checkout/checkout.mock.d.ts +1 -0
- package/dist/src/infrastructure/projection/checkout/checkout.mock.js +3 -3
- package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.d.ts +1 -1
- package/dist/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.js +2 -1
- package/dist/src/infrastructure/tracking/tracking.d.ts +2 -2
- package/dist/src/infrastructure/tracking/useTrackCheckout.d.ts +10 -17
- package/dist/src/infrastructure/tracking/useTrackCheckout.js +27 -12
- package/dist/src/infrastructure/ui/Root.d.ts +6 -6
- package/dist/src/infrastructure/ui/Root.js +2 -3
- package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.d.ts +26 -0
- package/dist/src/infrastructure/ui/hooks/useCheckoutFlow.js +127 -0
- package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.d.ts +3 -2
- package/dist/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.js +17 -26
- package/dist/src/infrastructure/ui/i18n/i18n.d.ts +1 -0
- package/dist/src/infrastructure/ui/i18n/i18n.js +1 -0
- package/dist/src/infrastructure/ui/routing/CheckoutMiddleware.js +1 -12
- package/dist/src/infrastructure/ui/routing/Routing.d.ts +5 -5
- package/dist/src/infrastructure/ui/routing/Routing.js +2 -10
- package/dist/src/infrastructure/ui/routing/routes.d.ts +0 -1
- package/dist/src/infrastructure/ui/routing/routes.js +0 -1
- package/dist/src/infrastructure/ui/views/App.js +5 -6
- package/dist/src/infrastructure/ui/views/checkout/Checkout.d.ts +7 -2
- package/dist/src/infrastructure/ui/views/checkout/Checkout.js +20 -9
- package/dist/src/infrastructure/ui/views/checkout/Checkout.style.d.ts +3 -0
- package/dist/src/infrastructure/ui/views/checkout/Checkout.style.js +3 -0
- package/dist/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.js +7 -7
- package/dist/src/projection/customer/customer.d.ts +2 -0
- package/dist/src/projection/order/order.d.ts +1 -1
- package/dist/src/projection/subscription/subscription.d.ts +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/fake-dependencies/@lookiero/payments-front/index.tsx +36 -8
- package/index.ts +10 -3
- package/package.json +3 -4
- package/src/Expo.tsx +10 -2
- package/src/ExpoRoot.tsx +58 -43
- package/src/infrastructure/domain/checkoutBooking/react/useBlockCheckoutBooking.ts +4 -1
- package/src/infrastructure/projection/checkout/checkout.mock.ts +8 -3
- package/src/infrastructure/projection/pricing/react/useViewPricingByCheckoutId.ts +3 -2
- package/src/infrastructure/tracking/tracking.ts +2 -2
- package/src/infrastructure/tracking/useTrackCheckout.test.tsx +51 -24
- package/src/infrastructure/tracking/useTrackCheckout.ts +66 -56
- package/src/infrastructure/ui/Root.tsx +9 -9
- package/src/infrastructure/ui/components/templates/header/itemHeader/ItemHeader.tsx +1 -0
- package/src/infrastructure/ui/hooks/useCheckoutFlow.test.tsx +302 -0
- package/src/infrastructure/ui/hooks/useCheckoutFlow.tsx +203 -0
- package/src/infrastructure/ui/hooks/usePaymentInstrumentEvents.ts +18 -60
- package/src/infrastructure/ui/i18n/i18n.ts +1 -0
- package/src/infrastructure/ui/routing/CheckoutMiddleware.test.tsx +0 -11
- package/src/infrastructure/ui/routing/CheckoutMiddleware.tsx +1 -15
- package/src/infrastructure/ui/routing/Routing.tsx +14 -25
- package/src/infrastructure/ui/routing/routes.ts +0 -1
- package/src/infrastructure/ui/views/App.tsx +5 -13
- package/src/infrastructure/ui/views/checkout/Checkout.style.ts +3 -0
- package/src/infrastructure/ui/views/checkout/Checkout.test.tsx +51 -43
- package/src/infrastructure/ui/views/checkout/Checkout.tsx +51 -13
- package/src/infrastructure/ui/views/checkout/components/paymentInstrument/PaymentInstrument.tsx +8 -8
- package/src/infrastructure/ui/views/item/components/itemActions/__snapshots__/ItemActions.test.tsx.snap +8 -0
- package/src/infrastructure/ui/views/item/components/selectModal/__snapshots__/SelecModal.test.tsx.snap +8 -0
- package/src/infrastructure/ui/views/item/components/sizeWithoutStockModal/__snapshots__/SizeWithoutStockModal.test.tsx.snap +8 -0
- package/src/projection/customer/customer.ts +2 -0
- package/src/projection/order/order.ts +1 -1
- package/src/projection/subscription/subscription.ts +1 -1
- package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.d.ts +0 -27
- package/dist/src/infrastructure/ui/hooks/useSubmitCheckout.js +0 -97
- package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.d.ts +0 -12
- package/dist/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.js +0 -88
- package/src/infrastructure/ui/hooks/useSubmitCheckout.test.ts +0 -297
- package/src/infrastructure/ui/hooks/useSubmitCheckout.ts +0 -169
- package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.test.tsx +0 -134
- package/src/infrastructure/ui/views/checkout/components/checkoutPaymentModal/CheckoutPaymentModal.tsx +0 -124
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { act, render, renderHook, waitFor } from "@testing-library/react-native";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { CommandStatus, QueryStatus } from "@lookiero/messaging-react";
|
|
4
|
+
import { Country } from "@lookiero/sty-psp-locale";
|
|
5
|
+
import { NotificationLevel, useCreateToastNotification } from "@lookiero/sty-psp-notifications";
|
|
6
|
+
import { Segment } from "@lookiero/sty-psp-segment";
|
|
7
|
+
import { CheckoutItemStatus } from "../../../domain/checkoutItem/model/checkoutItem";
|
|
8
|
+
import { CheckoutBookingProjection } from "../../../projection/checkoutBooking/checkoutBooking";
|
|
9
|
+
import { OrderProjection } from "../../../projection/order/order";
|
|
10
|
+
import { SubscriptionProjection } from "../../../projection/subscription/subscription";
|
|
11
|
+
import { useSubmitCheckout } from "../../domain/checkout/react/useSubmitCheckout";
|
|
12
|
+
import { useBlockCheckoutBooking } from "../../domain/checkoutBooking/react/useBlockCheckoutBooking";
|
|
13
|
+
import { checkout } from "../../projection/checkout/checkout.mock";
|
|
14
|
+
import { useViewIsSizeChangeEnabledByCheckoutId } from "../../projection/checkout/react/useViewIsSizeChangeEnabledByCheckoutId";
|
|
15
|
+
import { paymentFlowPayload as mockPaymentFlowPayload } from "../../projection/payment/paymentFlowPayload.mock";
|
|
16
|
+
import { useViewPaymentFlowPayloadByCheckoutId } from "../../projection/payment/react/useViewPaymentFlowPayloadByCheckoutId";
|
|
17
|
+
import { pricing } from "../../projection/pricing/pricing.mock";
|
|
18
|
+
import { useViewPricingByCheckoutId } from "../../projection/pricing/react/useViewPricingByCheckoutId";
|
|
19
|
+
import { I18nMessages } from "../i18n/i18n";
|
|
20
|
+
import { Routes } from "../routing/routes";
|
|
21
|
+
import { useCheckoutFlow as sut } from "./useCheckoutFlow";
|
|
22
|
+
import { usePaymentInstrumentEvents } from "./usePaymentInstrumentEvents";
|
|
23
|
+
import { useQueryBus } from "./useQueryBus";
|
|
24
|
+
|
|
25
|
+
const getAuthToken = () => Promise.resolve("token");
|
|
26
|
+
const mockCheckout = checkout({
|
|
27
|
+
items: [
|
|
28
|
+
{ status: CheckoutItemStatus.KEPT },
|
|
29
|
+
{ status: CheckoutItemStatus.KEPT },
|
|
30
|
+
{ status: CheckoutItemStatus.KEPT },
|
|
31
|
+
{ status: CheckoutItemStatus.KEPT },
|
|
32
|
+
{ status: CheckoutItemStatus.RETURNED },
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
const order: OrderProjection = {
|
|
36
|
+
orderNumber: 12345,
|
|
37
|
+
isFirstOrder: false,
|
|
38
|
+
coupon: null,
|
|
39
|
+
};
|
|
40
|
+
const mockPricing = pricing();
|
|
41
|
+
const subscription: SubscriptionProjection = "o";
|
|
42
|
+
const customerId = "a8fff6d7-708c-41a7-b42a-58c5706d33df";
|
|
43
|
+
const basePath = "/checkout";
|
|
44
|
+
const country = Country.ES;
|
|
45
|
+
const email = "email@example.com";
|
|
46
|
+
const name = "Adèle Léonce Émilie";
|
|
47
|
+
const segment = Segment.WOMEN;
|
|
48
|
+
jest.mock("./useStaticInfo", () => ({
|
|
49
|
+
useStaticInfo: () => ({ customer: { customerId, country, segment, name, email }, basePath }),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
// const errorChargeStatuses = Object.values(ChargeStatus).filter((status) => status !== ChargeStatus.EXECUTED);
|
|
53
|
+
const mockStartLegacyBoxCheckout = jest.fn();
|
|
54
|
+
jest.mock("@lookiero/payments-front", () => {
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
56
|
+
const { useImperativeHandle, forwardRef } = require("react");
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention, react/display-name
|
|
62
|
+
PaymentFlow: forwardRef((params, ref) => {
|
|
63
|
+
useImperativeHandle(ref, () => ({
|
|
64
|
+
startLegacyBoxCheckout: mockStartLegacyBoxCheckout,
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
return null;
|
|
68
|
+
}),
|
|
69
|
+
Section: {
|
|
70
|
+
["BOX_CHECKOUT"]: "box-checkout",
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
jest.mock("@lookiero/sty-psp-logging", () => ({
|
|
76
|
+
useLogger: () => jest.fn(),
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
jest.mock("@lookiero/sty-psp-notifications");
|
|
80
|
+
jest.mock("./useQueryBus");
|
|
81
|
+
jest.mock("../../domain/checkout/react/useSubmitCheckout");
|
|
82
|
+
jest.mock("../../domain/checkoutBooking/react/useBlockCheckoutBooking");
|
|
83
|
+
jest.mock("../../domain/checkout/react/useSubmitCheckout");
|
|
84
|
+
jest.mock("../../projection/payment/react/useViewPaymentFlowPayloadByCheckoutId");
|
|
85
|
+
jest.mock("../../projection/checkout/react/useViewIsSizeChangeEnabledByCheckoutId");
|
|
86
|
+
jest.mock("../../projection/pricing/react/useViewPricingByCheckoutId");
|
|
87
|
+
jest.mock("./usePaymentInstrumentEvents");
|
|
88
|
+
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
mockStartLegacyBoxCheckout.mockClear();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("useCheckoutFlow custom hook", () => {
|
|
94
|
+
test("successfully executes 'checkoutFlow'", async () => {
|
|
95
|
+
const mockBlockCheckoutBooking = jest.fn();
|
|
96
|
+
const mockSubmitCheckout = jest.fn();
|
|
97
|
+
const mockCreateToastNotification = jest.fn();
|
|
98
|
+
const mockOnSuccess = jest.fn();
|
|
99
|
+
|
|
100
|
+
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
101
|
+
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
102
|
+
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
103
|
+
(useViewPaymentFlowPayloadByCheckoutId as jest.Mock).mockReturnValue([mockPaymentFlowPayload, QueryStatus.SUCCESS]);
|
|
104
|
+
(useViewIsSizeChangeEnabledByCheckoutId as jest.Mock).mockReturnValue([true, QueryStatus.SUCCESS]);
|
|
105
|
+
(useViewPricingByCheckoutId as jest.Mock).mockReturnValue([mockPricing, QueryStatus.SUCCESS]);
|
|
106
|
+
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, "success"]);
|
|
107
|
+
(usePaymentInstrumentEvents as jest.Mock).mockImplementation(({ onSuccess }) => {
|
|
108
|
+
setTimeout(() => onSuccess(), 1000);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const { result } = renderHook(() =>
|
|
112
|
+
sut({ checkout: mockCheckout, order, subscription, getAuthToken, onSuccess: mockOnSuccess }),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
let checkoutFlow: () => void, status, paymentFlowComponent;
|
|
116
|
+
|
|
117
|
+
await waitFor(() => {
|
|
118
|
+
[checkoutFlow, , paymentFlowComponent] = result.current;
|
|
119
|
+
|
|
120
|
+
expect(paymentFlowComponent).not.toBeNull();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
render(<>{paymentFlowComponent}</>);
|
|
124
|
+
|
|
125
|
+
await act(async () => {
|
|
126
|
+
await checkoutFlow();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await waitFor(() => {
|
|
130
|
+
[, status] = result.current;
|
|
131
|
+
|
|
132
|
+
expect(status).toBe("success");
|
|
133
|
+
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
134
|
+
expect(mockStartLegacyBoxCheckout).toHaveBeenCalledWith(
|
|
135
|
+
expect.objectContaining({
|
|
136
|
+
...mockPaymentFlowPayload,
|
|
137
|
+
userInformation: { email, name },
|
|
138
|
+
returnUrl: `${basePath}/${Routes.CHECKOUT}`,
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
expect(mockSubmitCheckout).toHaveBeenCalled();
|
|
142
|
+
expect(mockCreateToastNotification).toHaveBeenCalledWith({
|
|
143
|
+
bodyI18nKey: I18nMessages.CHECKOUT_TOAST_PAYMENT_SUCCESS,
|
|
144
|
+
level: NotificationLevel.SUCCESS,
|
|
145
|
+
});
|
|
146
|
+
expect(mockOnSuccess).toHaveBeenCalled();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("does not call blockCheckoutBooking if sizeChange is not enabled", async () => {
|
|
151
|
+
const mockBlockCheckoutBooking = jest.fn();
|
|
152
|
+
const mockSubmitCheckout = jest.fn();
|
|
153
|
+
const mockCreateToastNotification = jest.fn();
|
|
154
|
+
const mockOnSuccess = jest.fn();
|
|
155
|
+
|
|
156
|
+
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
157
|
+
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
158
|
+
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
159
|
+
(useViewPaymentFlowPayloadByCheckoutId as jest.Mock).mockReturnValue([mockPaymentFlowPayload, QueryStatus.SUCCESS]);
|
|
160
|
+
(useViewIsSizeChangeEnabledByCheckoutId as jest.Mock).mockReturnValue([false, QueryStatus.SUCCESS]);
|
|
161
|
+
(useViewPricingByCheckoutId as jest.Mock).mockReturnValue([mockPricing, QueryStatus.SUCCESS]);
|
|
162
|
+
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, "success"]);
|
|
163
|
+
(usePaymentInstrumentEvents as jest.Mock).mockImplementation(({ onSuccess }) => {
|
|
164
|
+
setTimeout(() => onSuccess(), 1000);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const { result } = renderHook(() =>
|
|
168
|
+
sut({ checkout: mockCheckout, order, subscription, getAuthToken, onSuccess: mockOnSuccess }),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
let checkoutFlow: () => void, status, paymentFlowComponent;
|
|
172
|
+
|
|
173
|
+
await waitFor(() => {
|
|
174
|
+
[checkoutFlow, , paymentFlowComponent] = result.current;
|
|
175
|
+
|
|
176
|
+
expect(paymentFlowComponent).not.toBeNull();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
render(<>{paymentFlowComponent}</>);
|
|
180
|
+
|
|
181
|
+
await act(async () => {
|
|
182
|
+
await checkoutFlow();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await waitFor(() => {
|
|
186
|
+
[, status] = result.current;
|
|
187
|
+
|
|
188
|
+
expect(status).toBe("success");
|
|
189
|
+
expect(mockBlockCheckoutBooking).not.toHaveBeenCalled();
|
|
190
|
+
expect(mockStartLegacyBoxCheckout).toHaveBeenCalledWith(
|
|
191
|
+
expect.objectContaining({
|
|
192
|
+
...mockPaymentFlowPayload,
|
|
193
|
+
userInformation: { email, name },
|
|
194
|
+
returnUrl: `${basePath}/${Routes.CHECKOUT}`,
|
|
195
|
+
}),
|
|
196
|
+
);
|
|
197
|
+
expect(mockSubmitCheckout).toHaveBeenCalled();
|
|
198
|
+
expect(mockCreateToastNotification).toHaveBeenCalledWith({
|
|
199
|
+
bodyI18nKey: I18nMessages.CHECKOUT_TOAST_PAYMENT_SUCCESS,
|
|
200
|
+
level: NotificationLevel.SUCCESS,
|
|
201
|
+
});
|
|
202
|
+
expect(mockOnSuccess).toHaveBeenCalled();
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("breaks execution and returns error as the status when blockCheckoutBooking fails", async () => {
|
|
207
|
+
const mockBlockCheckoutBooking = jest.fn().mockRejectedValue("error");
|
|
208
|
+
const mockSubmitCheckout = jest.fn();
|
|
209
|
+
const mockCreateToastNotification = jest.fn();
|
|
210
|
+
const mockOnSuccess = jest.fn();
|
|
211
|
+
|
|
212
|
+
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
213
|
+
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.ERROR]);
|
|
214
|
+
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
215
|
+
(useViewPaymentFlowPayloadByCheckoutId as jest.Mock).mockReturnValue([mockPaymentFlowPayload, QueryStatus.SUCCESS]);
|
|
216
|
+
(useViewIsSizeChangeEnabledByCheckoutId as jest.Mock).mockReturnValue([true, QueryStatus.SUCCESS]);
|
|
217
|
+
(useViewPricingByCheckoutId as jest.Mock).mockReturnValue([mockPricing, QueryStatus.SUCCESS]);
|
|
218
|
+
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, "success"]);
|
|
219
|
+
(usePaymentInstrumentEvents as jest.Mock).mockImplementation(({ onSuccess }) => {
|
|
220
|
+
setTimeout(() => onSuccess(), 1000);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const { result } = renderHook(() =>
|
|
224
|
+
sut({ checkout: mockCheckout, order, subscription, getAuthToken, onSuccess: mockOnSuccess }),
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
let checkoutFlow: () => void, status, paymentFlowComponent;
|
|
228
|
+
|
|
229
|
+
await waitFor(() => {
|
|
230
|
+
[checkoutFlow, , paymentFlowComponent] = result.current;
|
|
231
|
+
|
|
232
|
+
expect(paymentFlowComponent).not.toBeNull();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
render(<>{paymentFlowComponent}</>);
|
|
236
|
+
|
|
237
|
+
await act(async () => {
|
|
238
|
+
await checkoutFlow();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
await waitFor(() => {
|
|
242
|
+
[, status] = result.current;
|
|
243
|
+
|
|
244
|
+
expect(status).toBe("error");
|
|
245
|
+
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
246
|
+
expect(mockStartLegacyBoxCheckout).not.toHaveBeenCalled();
|
|
247
|
+
expect(mockSubmitCheckout).not.toHaveBeenCalled();
|
|
248
|
+
expect(mockCreateToastNotification).not.toHaveBeenCalled();
|
|
249
|
+
expect(mockOnSuccess).not.toHaveBeenCalled();
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test("shows a notification and returns error as the status when payment fails", async () => {
|
|
254
|
+
const mockBlockCheckoutBooking = jest.fn();
|
|
255
|
+
const mockSubmitCheckout = jest.fn();
|
|
256
|
+
const mockCreateToastNotification = jest.fn();
|
|
257
|
+
const mockOnSuccess = jest.fn();
|
|
258
|
+
|
|
259
|
+
(useQueryBus as jest.Mock).mockReturnValue(() => ({ isExpired: false }) as CheckoutBookingProjection);
|
|
260
|
+
(useBlockCheckoutBooking as jest.Mock).mockReturnValue([mockBlockCheckoutBooking, CommandStatus.SUCCESS]);
|
|
261
|
+
(useCreateToastNotification as jest.Mock).mockReturnValue([mockCreateToastNotification, CommandStatus.SUCCESS]);
|
|
262
|
+
(useViewPaymentFlowPayloadByCheckoutId as jest.Mock).mockReturnValue([mockPaymentFlowPayload, QueryStatus.SUCCESS]);
|
|
263
|
+
(useViewIsSizeChangeEnabledByCheckoutId as jest.Mock).mockReturnValue([true, QueryStatus.SUCCESS]);
|
|
264
|
+
(useViewPricingByCheckoutId as jest.Mock).mockReturnValue([mockPricing, QueryStatus.SUCCESS]);
|
|
265
|
+
(useSubmitCheckout as jest.Mock).mockReturnValue([mockSubmitCheckout, "success"]);
|
|
266
|
+
(usePaymentInstrumentEvents as jest.Mock).mockImplementation(({ onError }) => {
|
|
267
|
+
setTimeout(() => onError({ metadata: null }), 1000);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const { result } = renderHook(() =>
|
|
271
|
+
sut({ checkout: mockCheckout, order, subscription, getAuthToken, onSuccess: mockOnSuccess }),
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
let checkoutFlow: () => void, status, paymentFlowComponent;
|
|
275
|
+
|
|
276
|
+
await waitFor(() => {
|
|
277
|
+
[checkoutFlow, , paymentFlowComponent] = result.current;
|
|
278
|
+
|
|
279
|
+
expect(paymentFlowComponent).not.toBeNull();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
render(<>{paymentFlowComponent}</>);
|
|
283
|
+
|
|
284
|
+
await act(async () => {
|
|
285
|
+
await checkoutFlow();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
await waitFor(() => {
|
|
289
|
+
[, status] = result.current;
|
|
290
|
+
|
|
291
|
+
expect(status).toBe("error");
|
|
292
|
+
expect(mockBlockCheckoutBooking).toHaveBeenCalled();
|
|
293
|
+
expect(mockStartLegacyBoxCheckout).toHaveBeenCalled();
|
|
294
|
+
expect(mockSubmitCheckout).not.toHaveBeenCalled();
|
|
295
|
+
expect(mockCreateToastNotification).toHaveBeenCalledWith({
|
|
296
|
+
bodyI18nKey: I18nMessages.CHECKOUT_TOAST_PAYMENT_ERROR,
|
|
297
|
+
level: NotificationLevel.ERROR,
|
|
298
|
+
});
|
|
299
|
+
expect(mockOnSuccess).not.toHaveBeenCalled();
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
});
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import React, { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { CommandStatus } from "@lookiero/messaging-react";
|
|
3
|
+
import { PaymentFlow, PaymentFlowRef, PaymentPayload, Section } from "@lookiero/payments-front";
|
|
4
|
+
import { LegacyBoxCheckoutStrategyPayload } from "@lookiero/payments-front/build/components/PaymentFlow/internals/strategies/LegacyBoxCheckoutStrategy";
|
|
5
|
+
import { useLogger } from "@lookiero/sty-psp-logging";
|
|
6
|
+
import { NotificationLevel, useCreateToastNotification } from "@lookiero/sty-psp-notifications";
|
|
7
|
+
import { CheckoutProjection } from "../../../projection/checkout/checkout";
|
|
8
|
+
import {
|
|
9
|
+
ViewCheckoutBookingById,
|
|
10
|
+
viewCheckoutBookingById,
|
|
11
|
+
ViewCheckoutBookingByIdResult,
|
|
12
|
+
} from "../../../projection/checkoutBooking/viewCheckoutBookingById";
|
|
13
|
+
import { OrderProjection } from "../../../projection/order/order";
|
|
14
|
+
import { SubscriptionProjection } from "../../../projection/subscription/subscription";
|
|
15
|
+
import { MESSAGING_CONTEXT_ID } from "../../delivery/baseBootstrap";
|
|
16
|
+
import { useSubmitCheckout } from "../../domain/checkout/react/useSubmitCheckout";
|
|
17
|
+
import { useBlockCheckoutBooking } from "../../domain/checkoutBooking/react/useBlockCheckoutBooking";
|
|
18
|
+
import { useViewIsSizeChangeEnabledByCheckoutId } from "../../projection/checkout/react/useViewIsSizeChangeEnabledByCheckoutId";
|
|
19
|
+
import { useViewPaymentFlowPayloadByCheckoutId } from "../../projection/payment/react/useViewPaymentFlowPayloadByCheckoutId";
|
|
20
|
+
import { useViewPricingByCheckoutId } from "../../projection/pricing/react/useViewPricingByCheckoutId";
|
|
21
|
+
import { useTrackCheckout } from "../../tracking/useTrackCheckout";
|
|
22
|
+
import { I18nMessages } from "../i18n/i18n";
|
|
23
|
+
import { Routes } from "../routing/routes";
|
|
24
|
+
import { usePaymentInstrumentEvents } from "./usePaymentInstrumentEvents";
|
|
25
|
+
import { useQueryBus } from "./useQueryBus";
|
|
26
|
+
import { useStaticInfo } from "./useStaticInfo";
|
|
27
|
+
|
|
28
|
+
type CheckoutFlowStatus = "idle" | "loading" | "success" | "error";
|
|
29
|
+
|
|
30
|
+
interface CheckoutFlowFunction {
|
|
31
|
+
(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type CheckoutFlowReturn = [
|
|
35
|
+
checkoutFlow: CheckoutFlowFunction,
|
|
36
|
+
checkoutFlowStatus: CheckoutFlowStatus,
|
|
37
|
+
paymentFlow: ReactNode,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
interface UseCheckoutFlowArgs {
|
|
41
|
+
readonly checkout: CheckoutProjection | undefined;
|
|
42
|
+
readonly order: OrderProjection;
|
|
43
|
+
readonly subscription: SubscriptionProjection;
|
|
44
|
+
readonly getAuthToken: () => Promise<string>;
|
|
45
|
+
readonly onSuccess: () => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface UseCheckoutFlowFunction {
|
|
49
|
+
(args: UseCheckoutFlowArgs): CheckoutFlowReturn;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const useCheckoutFlow: UseCheckoutFlowFunction = ({
|
|
53
|
+
checkout: checkoutProjection,
|
|
54
|
+
order: orderProjection,
|
|
55
|
+
subscription: subscriptionProjection,
|
|
56
|
+
getAuthToken,
|
|
57
|
+
onSuccess,
|
|
58
|
+
}) => {
|
|
59
|
+
const logger = useLogger();
|
|
60
|
+
const queryBus = useQueryBus();
|
|
61
|
+
const {
|
|
62
|
+
customer: { customerId, country, segment, name, email },
|
|
63
|
+
basePath,
|
|
64
|
+
} = useStaticInfo();
|
|
65
|
+
const paymentFlowRef = useRef<PaymentFlowRef>(null);
|
|
66
|
+
const [paymentFlowPayload] = useViewPaymentFlowPayloadByCheckoutId({
|
|
67
|
+
checkoutId: checkoutProjection?.id as string,
|
|
68
|
+
});
|
|
69
|
+
const [sizeChangeEnabled] = useViewIsSizeChangeEnabledByCheckoutId({ checkoutId: checkoutProjection?.id as string });
|
|
70
|
+
const [pricing] = useViewPricingByCheckoutId({
|
|
71
|
+
checkoutId: checkoutProjection?.id,
|
|
72
|
+
queryOptions: { refetchOnMount: true },
|
|
73
|
+
});
|
|
74
|
+
const [submitCheckout, submitCheckoutStatus] = useSubmitCheckout({
|
|
75
|
+
checkoutId: checkoutProjection?.id,
|
|
76
|
+
logger,
|
|
77
|
+
});
|
|
78
|
+
const [blockCheckoutBooking, blockCheckoutBookingStatus] = useBlockCheckoutBooking({
|
|
79
|
+
checkoutBookingId: checkoutProjection?.checkoutBookingId,
|
|
80
|
+
logger,
|
|
81
|
+
});
|
|
82
|
+
const [createNotification] = useCreateToastNotification({ contextId: MESSAGING_CONTEXT_ID, logger });
|
|
83
|
+
const [checkoutBookingExpired, setCheckoutBookingExpired] = useState(false);
|
|
84
|
+
const [startLegacyBoxCheckoutStatus, setStartLegacyBoxCheckoutStatus] = useState<CheckoutFlowStatus>("idle");
|
|
85
|
+
const [authToken, setAuthToken] = useState<string>();
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const loadAuthToken = async () => setAuthToken(await getAuthToken());
|
|
88
|
+
loadAuthToken();
|
|
89
|
+
}, [getAuthToken]);
|
|
90
|
+
const trackCheckout = useTrackCheckout({
|
|
91
|
+
checkout: checkoutProjection,
|
|
92
|
+
order: orderProjection,
|
|
93
|
+
pricing,
|
|
94
|
+
subscription: subscriptionProjection,
|
|
95
|
+
userId: customerId,
|
|
96
|
+
country,
|
|
97
|
+
segment,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const checkoutFlow: CheckoutFlowFunction = useCallback(async () => {
|
|
101
|
+
try {
|
|
102
|
+
sizeChangeEnabled && (await blockCheckoutBooking());
|
|
103
|
+
} catch (error) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (checkoutProjection?.checkoutBookingId) {
|
|
108
|
+
const checkoutBooking = await queryBus<ViewCheckoutBookingById, ViewCheckoutBookingByIdResult>(
|
|
109
|
+
viewCheckoutBookingById({ checkoutBookingId: checkoutProjection?.checkoutBookingId }),
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (checkoutBooking?.isExpired) {
|
|
113
|
+
setCheckoutBookingExpired(true);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
setStartLegacyBoxCheckoutStatus("loading");
|
|
119
|
+
|
|
120
|
+
paymentFlowRef.current?.startLegacyBoxCheckout({
|
|
121
|
+
...paymentFlowPayload,
|
|
122
|
+
userInformation: { email, name },
|
|
123
|
+
returnUrl: `${basePath}/${Routes.CHECKOUT}`,
|
|
124
|
+
} as unknown as LegacyBoxCheckoutStrategyPayload);
|
|
125
|
+
}, [
|
|
126
|
+
checkoutProjection?.checkoutBookingId,
|
|
127
|
+
paymentFlowPayload,
|
|
128
|
+
email,
|
|
129
|
+
name,
|
|
130
|
+
basePath,
|
|
131
|
+
sizeChangeEnabled,
|
|
132
|
+
blockCheckoutBooking,
|
|
133
|
+
queryBus,
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
const onPaymentSuccess = useCallback(async () => {
|
|
137
|
+
setStartLegacyBoxCheckoutStatus("success");
|
|
138
|
+
|
|
139
|
+
await submitCheckout();
|
|
140
|
+
|
|
141
|
+
createNotification({
|
|
142
|
+
bodyI18nKey: I18nMessages.CHECKOUT_TOAST_PAYMENT_SUCCESS,
|
|
143
|
+
level: NotificationLevel.SUCCESS,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
trackCheckout();
|
|
147
|
+
onSuccess();
|
|
148
|
+
}, [createNotification, onSuccess, submitCheckout, trackCheckout]);
|
|
149
|
+
const onPaymentError = useCallback(
|
|
150
|
+
(payload: PaymentPayload) => {
|
|
151
|
+
setStartLegacyBoxCheckoutStatus("error");
|
|
152
|
+
|
|
153
|
+
createNotification({
|
|
154
|
+
bodyI18nKey: payload.metadata?.toaster?.id || I18nMessages.CHECKOUT_TOAST_PAYMENT_ERROR,
|
|
155
|
+
level: NotificationLevel.ERROR,
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
[createNotification],
|
|
159
|
+
);
|
|
160
|
+
usePaymentInstrumentEvents({ onSuccess: onPaymentSuccess, onError: onPaymentError });
|
|
161
|
+
|
|
162
|
+
const checkoutFlowStatus: CheckoutFlowStatus = useMemo(() => {
|
|
163
|
+
if (
|
|
164
|
+
blockCheckoutBookingStatus === CommandStatus.LOADING ||
|
|
165
|
+
startLegacyBoxCheckoutStatus === "loading" ||
|
|
166
|
+
submitCheckoutStatus === CommandStatus.LOADING
|
|
167
|
+
) {
|
|
168
|
+
return "loading";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
blockCheckoutBookingStatus === CommandStatus.SUCCESS &&
|
|
173
|
+
startLegacyBoxCheckoutStatus === "success" &&
|
|
174
|
+
submitCheckoutStatus === CommandStatus.SUCCESS
|
|
175
|
+
) {
|
|
176
|
+
return "success";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (
|
|
180
|
+
blockCheckoutBookingStatus === CommandStatus.ERROR ||
|
|
181
|
+
startLegacyBoxCheckoutStatus === "error" ||
|
|
182
|
+
submitCheckoutStatus === CommandStatus.ERROR ||
|
|
183
|
+
checkoutBookingExpired
|
|
184
|
+
) {
|
|
185
|
+
return "error";
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return "idle";
|
|
189
|
+
}, [blockCheckoutBookingStatus, startLegacyBoxCheckoutStatus, submitCheckoutStatus, checkoutBookingExpired]);
|
|
190
|
+
|
|
191
|
+
const paymentFlow = useMemo(
|
|
192
|
+
() => (authToken ? <PaymentFlow ref={paymentFlowRef} section={Section.BOX_CHECKOUT} token={authToken} /> : null),
|
|
193
|
+
[authToken],
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
return useMemo(
|
|
197
|
+
() => [checkoutFlow, checkoutFlowStatus, paymentFlow],
|
|
198
|
+
[checkoutFlow, paymentFlow, checkoutFlowStatus],
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export type { CheckoutFlowStatus };
|
|
203
|
+
export { useCheckoutFlow };
|
|
@@ -1,75 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Logger } from "@lookiero/sty-psp-logging";
|
|
4
|
-
import { NotificationLevel, useCreateToastNotification } from "@lookiero/sty-psp-notifications";
|
|
5
|
-
import { MESSAGING_CONTEXT_ID } from "../../delivery/baseBootstrap";
|
|
6
|
-
import { I18nMessages } from "../i18n/i18n";
|
|
7
|
-
|
|
8
|
-
const PAYMENT_ERROR = "ERROR";
|
|
9
|
-
const PAYMENT_SUCCESS = "PAYMENT_INSTRUMENT_UPDATED";
|
|
10
|
-
|
|
11
|
-
interface Message {
|
|
12
|
-
readonly id: string;
|
|
13
|
-
}
|
|
14
|
-
interface OnSuccessFunctionArgs {
|
|
15
|
-
readonly message: Message;
|
|
16
|
-
}
|
|
17
|
-
interface OnSuccessFunction {
|
|
18
|
-
(args: OnSuccessFunctionArgs): void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface Toaster {
|
|
22
|
-
readonly id: string;
|
|
23
|
-
}
|
|
24
|
-
interface Error {
|
|
25
|
-
readonly toaster?: Toaster;
|
|
26
|
-
}
|
|
27
|
-
interface OnErrorFunctionArgs {
|
|
28
|
-
readonly error: Error;
|
|
29
|
-
}
|
|
30
|
-
interface OnErrorFunction {
|
|
31
|
-
(args: OnErrorFunctionArgs): void;
|
|
32
|
-
}
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { PaymentPayload, Section, usePaymentStatusManager } from "@lookiero/payments-front";
|
|
33
3
|
|
|
34
4
|
interface UsePaymentInstrumentEventsFunctionArgs {
|
|
35
|
-
readonly
|
|
5
|
+
readonly onSuccess: (payload: PaymentPayload) => void;
|
|
6
|
+
readonly onError: (payload: PaymentPayload) => void;
|
|
36
7
|
}
|
|
37
8
|
|
|
38
9
|
interface UsePaymentInstrumentEventsFunction {
|
|
39
10
|
(args: UsePaymentInstrumentEventsFunctionArgs): void;
|
|
40
11
|
}
|
|
41
12
|
|
|
42
|
-
const usePaymentInstrumentEvents: UsePaymentInstrumentEventsFunction = ({
|
|
43
|
-
const
|
|
13
|
+
const usePaymentInstrumentEvents: UsePaymentInstrumentEventsFunction = ({ onSuccess, onError }) => {
|
|
14
|
+
const refreshStatus = usePaymentStatusManager(Section.BOX_CHECKOUT);
|
|
44
15
|
|
|
45
|
-
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const { isLoading, consumePayload } = refreshStatus;
|
|
46
18
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
);
|
|
19
|
+
if (isLoading) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
51
22
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
level: NotificationLevel.ERROR,
|
|
58
|
-
});
|
|
23
|
+
consumePayload((payload) => {
|
|
24
|
+
if (payload.success) {
|
|
25
|
+
onSuccess(payload);
|
|
26
|
+
} else {
|
|
27
|
+
onError(payload);
|
|
59
28
|
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
subscribe({ event: PAYMENT_ERROR }, onError);
|
|
66
|
-
subscribe({ event: PAYMENT_SUCCESS }, onSuccess);
|
|
67
|
-
|
|
68
|
-
return () => {
|
|
69
|
-
unsubscribe({ event: PAYMENT_ERROR }, onError);
|
|
70
|
-
unsubscribe({ event: PAYMENT_SUCCESS }, onSuccess);
|
|
71
|
-
};
|
|
72
|
-
}, [subscribe, unsubscribe, createNotification, onError, onSuccess]);
|
|
29
|
+
});
|
|
30
|
+
}, [onError, onSuccess, refreshStatus]);
|
|
73
31
|
};
|
|
74
32
|
|
|
75
33
|
export { usePaymentInstrumentEvents };
|
|
@@ -50,6 +50,7 @@ enum I18nMessages {
|
|
|
50
50
|
CHECKOUT_TITLE = "checkout.title",
|
|
51
51
|
CHECKOUT_PAY_BUTTON = "checkout.pay_button",
|
|
52
52
|
CHECKOUT_TOAST_PAYMENT_ERROR = "checkout.toast_payment_error",
|
|
53
|
+
CHECKOUT_TOAST_PAYMENT_SUCCESS = "checkout.toast_payment_success",
|
|
53
54
|
CHECKOUT_SUCCESS_MODAL_TITLE = "checkout.success_modal_title",
|
|
54
55
|
CHECKOUT_SUCCESS_MODAL_DESCRIPTION = "checkout.success_modal_description",
|
|
55
56
|
CHECKOUT_SUCCESS_MODAL_BUTTON = "checkout.success_modal_button",
|
|
@@ -158,17 +158,6 @@ describe("CheckoutMiddleware component", () => {
|
|
|
158
158
|
expect(onNotAccessible).toHaveBeenCalled();
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
it("payment route should not be directly accessible", async () => {
|
|
162
|
-
const checkoutMock = checkout({ items: [{ status: CheckoutItemStatus.INITIAL }] });
|
|
163
|
-
(useViewFirstAvailableCheckoutByCustomerId as jest.Mock).mockReturnValue([checkoutMock, QueryStatus.SUCCESS]);
|
|
164
|
-
(useStartCheckout as jest.Mock).mockReturnValue([mockStartCheckout, CommandStatus.SUCCESS]);
|
|
165
|
-
|
|
166
|
-
const onNotAccessible = jest.fn();
|
|
167
|
-
renderCheckoutMiddleware({ path: `${Routes.CHECKOUT}/${Routes.CHECKOUT_PAYMENT}`, onNotAccessible });
|
|
168
|
-
|
|
169
|
-
expect(onNotAccessible).toHaveBeenCalled();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
161
|
it("should redirect to 'feedback' if checkout's status is SUBMITTED", async () => {
|
|
173
162
|
const checkoutMock = checkout({
|
|
174
163
|
status: CheckoutStatus.SUBMITTED,
|
|
@@ -48,12 +48,6 @@ const CheckoutMiddleware: FC<CheckoutMiddlewareProps> = ({
|
|
|
48
48
|
const feedbackRouteMatch = useMatch(`${basePath}/${Routes.FEEDBACK}`);
|
|
49
49
|
const feedbackRouteMatchRef = useRef(feedbackRouteMatch);
|
|
50
50
|
feedbackRouteMatchRef.current = feedbackRouteMatch;
|
|
51
|
-
const checkoutPaymentRouteMatch = useMatch(`${basePath}/${Routes.CHECKOUT}/${Routes.CHECKOUT_PAYMENT}`);
|
|
52
|
-
const checkoutPaymentRouteMatchRef = useRef(checkoutPaymentRouteMatch);
|
|
53
|
-
checkoutPaymentRouteMatchRef.current = checkoutPaymentRouteMatch;
|
|
54
|
-
|
|
55
|
-
const checkoutShown = useRef(false);
|
|
56
|
-
checkoutShown.current = checkoutShown.current || (Boolean(checkoutRouteMatch) && !Boolean(checkoutPaymentRouteMatch));
|
|
57
51
|
|
|
58
52
|
const [checkout] = useViewFirstAvailableCheckoutByCustomerId({ customerId });
|
|
59
53
|
const checkoutItemsRef = useRef<CheckoutItemProjection[]>();
|
|
@@ -99,8 +93,7 @@ const CheckoutMiddleware: FC<CheckoutMiddlewareProps> = ({
|
|
|
99
93
|
summaryRouteMatchRef.current ||
|
|
100
94
|
summaryTabsRouteMatchRef.current ||
|
|
101
95
|
itemDetailRouteMatchRef.current ||
|
|
102
|
-
checkoutRouteMatchRef.current
|
|
103
|
-
checkoutPaymentRouteMatchRef.current
|
|
96
|
+
checkoutRouteMatchRef.current
|
|
104
97
|
)
|
|
105
98
|
) {
|
|
106
99
|
navigateRef.current(`${basePath}/${Routes.SUMMARY}`, { replace: true });
|
|
@@ -127,13 +120,6 @@ const CheckoutMiddleware: FC<CheckoutMiddlewareProps> = ({
|
|
|
127
120
|
return null;
|
|
128
121
|
}
|
|
129
122
|
|
|
130
|
-
/* Prevent direct payment access */
|
|
131
|
-
if (checkoutPaymentRouteMatch && !checkoutShown.current) {
|
|
132
|
-
onNotAccessible();
|
|
133
|
-
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
123
|
return children;
|
|
138
124
|
};
|
|
139
125
|
|