@lookiero/checkout 14.8.1 → 14.8.2
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 +2 -2
- package/cypress/support/interceptViewPricingByCheckoutId.ts +3 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -2
- package/dist/src/ExpoRoot.js +5 -4
- package/dist/src/infrastructure/delivery/bootstrap.d.ts +3 -0
- package/dist/src/infrastructure/delivery/bootstrap.js +3 -1
- package/dist/src/infrastructure/projection/pricing/httpPricingByCheckoutIdView.d.ts +3 -0
- package/dist/src/infrastructure/projection/pricing/httpPricingByCheckoutIdView.js +4 -3
- package/dist/src/infrastructure/projection/pricing/pricing.d.ts +31 -0
- package/dist/src/infrastructure/projection/pricing/pricing.js +39 -0
- package/dist/src/infrastructure/projection/pricing/pricing.mock.d.ts +3 -2
- package/dist/src/infrastructure/projection/pricing/pricing.mock.js +16 -2
- package/dist/src/infrastructure/ui/Root.d.ts +1 -0
- package/dist/src/infrastructure/ui/Root.js +2 -2
- package/dist/src/infrastructure/ui/hooks/useStaticInfo.d.ts +2 -0
- package/dist/src/infrastructure/ui/hooks/useStaticInfo.js +3 -2
- package/dist/src/infrastructure/ui/routing/Routing.d.ts +1 -0
- package/dist/src/infrastructure/ui/routing/Routing.js +2 -2
- package/dist/src/version.d.ts +2 -2
- package/dist/src/version.js +2 -2
- package/index.ts +4 -2
- package/package.json +1 -1
- package/src/ExpoRoot.tsx +5 -3
- package/src/infrastructure/delivery/bootstrap.ts +6 -1
- package/src/infrastructure/projection/pricing/httpPricingByCheckoutIdView.test.ts +91 -3
- package/src/infrastructure/projection/pricing/httpPricingByCheckoutIdView.ts +12 -4
- package/src/infrastructure/projection/pricing/pricing.mock.ts +17 -2
- package/src/infrastructure/projection/pricing/pricing.ts +83 -0
- package/src/infrastructure/ui/Root.tsx +3 -0
- package/src/infrastructure/ui/hooks/useStaticInfo.test.tsx +9 -1
- package/src/infrastructure/ui/hooks/useStaticInfo.tsx +12 -2
- package/src/infrastructure/ui/routing/Routing.tsx +9 -1
|
@@ -6,7 +6,7 @@ import { checkoutBooking } from "../../src/infrastructure/projection/checkoutBoo
|
|
|
6
6
|
import { checkoutFeedbackDefinition } from "../../src/infrastructure/projection/checkoutFeedback/checkoutFeedbackDefinition.mock";
|
|
7
7
|
import { checkoutItem } from "../../src/infrastructure/projection/checkoutItem/checkoutItem.mock";
|
|
8
8
|
import { paymentFlowPayload } from "../../src/infrastructure/projection/payment/paymentFlowPayload.mock";
|
|
9
|
-
import { pricing } from "../../src/infrastructure/projection/pricing/pricing.mock";
|
|
9
|
+
import { mockPricingDto, pricing } from "../../src/infrastructure/projection/pricing/pricing.mock";
|
|
10
10
|
import { returnQuestions } from "../../src/infrastructure/projection/returnQuestion/returnQuestions.mock";
|
|
11
11
|
import { Routes } from "../../src/infrastructure/ui/routing/routes";
|
|
12
12
|
import { CheckoutFeedbackQuestionType } from "../../src/projection/checkoutFeedback/checkoutFeedback.constants";
|
|
@@ -130,7 +130,7 @@ describe("Checkout", () => {
|
|
|
130
130
|
interceptViewFiveItemsDiscountByCustomerId(0);
|
|
131
131
|
interceptViewBookedProductsVariantsForCheckoutItem(bookedProductsVariants);
|
|
132
132
|
interceptListReturnQuestionsByCheckoutItemId(returnQuestions);
|
|
133
|
-
interceptViewPricingByCheckoutId(
|
|
133
|
+
interceptViewPricingByCheckoutId(mockPricingDto);
|
|
134
134
|
interceptViewPaymentFlowPayloadByCheckoutId(paymentFlowPayload);
|
|
135
135
|
interceptViewCheckoutFeedbackDefinitionByCheckoutId(checkoutFeedbackDefinition);
|
|
136
136
|
interceptViewCheckoutBookingById(checkoutBooking);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { PricingDto } from "../../src/infrastructure/projection/pricing/pricing";
|
|
1
2
|
import { CheckoutPricingProjection } from "../../src/projection/pricing/pricing";
|
|
2
3
|
|
|
3
|
-
const interceptViewPricingByCheckoutId = (response:
|
|
4
|
-
cy.intercept({ method: "POST", url: "/local-to-dev/view-
|
|
4
|
+
const interceptViewPricingByCheckoutId = (response: PricingDto) =>
|
|
5
|
+
cy.intercept({ method: "POST", url: "/local-to-dev/view-pricing-by-checkout-id" }, { body: { result: response } });
|
|
5
6
|
|
|
6
7
|
export { interceptViewPricingByCheckoutId };
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ interface FirstAvailableCheckoutByCustomerIdFunction {
|
|
|
19
19
|
interface BootstrapFunctionArgs {
|
|
20
20
|
readonly getAuthToken: () => Promise<string>;
|
|
21
21
|
readonly apiUrl: () => string;
|
|
22
|
+
readonly tradename: Tradename;
|
|
23
|
+
readonly migrated: boolean;
|
|
22
24
|
readonly sentry: () => SentryEnvironment;
|
|
23
25
|
readonly kameleoon: () => KameleoonEnvironment;
|
|
24
26
|
}
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import { CheckoutStatus } from "./src/domain/checkout/model/checkout";
|
|
|
6
6
|
import { bootstrap as checkoutBootstrap } from "./src/infrastructure/delivery/bootstrap";
|
|
7
7
|
import { root } from "./src/infrastructure/ui/Root";
|
|
8
8
|
import { viewFirstAvailableCheckoutByCustomerId } from "./src/projection/checkout/viewFirstAvailableCheckoutByCustomerId";
|
|
9
|
-
const bootstrap = ({ apiUrl, getAuthToken, sentry, kameleoon }) => {
|
|
10
|
-
const { Component: Messaging, queryBus } = checkoutBootstrap({ apiUrl, getAuthToken });
|
|
9
|
+
const bootstrap = ({ apiUrl, getAuthToken, tradename, migrated, sentry, kameleoon }) => {
|
|
10
|
+
const { Component: Messaging, queryBus } = checkoutBootstrap({ apiUrl, getAuthToken, tradename, migrated });
|
|
11
11
|
const firstAvailableCheckoutByCustomerId = ({ customerId }) => queryBus(viewFirstAvailableCheckoutByCustomerId({ customerId: customerId }));
|
|
12
12
|
return {
|
|
13
13
|
root: root({ Messaging, queryBus, getAuthToken, sentry, kameleoon }),
|
package/dist/src/ExpoRoot.js
CHANGED
|
@@ -17,10 +17,11 @@ import { root } from "./infrastructure/ui/Root";
|
|
|
17
17
|
import { Router } from "./infrastructure/ui/routing/router/Router";
|
|
18
18
|
import { RELEASE } from "./version";
|
|
19
19
|
const tradename = Tradename.LOOKIERO;
|
|
20
|
+
const migrated = false;
|
|
20
21
|
const theme = themeByTradename({ tradename });
|
|
21
22
|
const locale = Locale.es_ES;
|
|
22
23
|
const customer = {
|
|
23
|
-
customerId: "
|
|
24
|
+
customerId: "e4450481-f8d1-47bd-a2f0-a8cb0d292bcd",
|
|
24
25
|
country: Country.ES,
|
|
25
26
|
segment: Segment.WOMEN,
|
|
26
27
|
email: "email@example.com",
|
|
@@ -40,7 +41,7 @@ const apiUrl = Platform.OS !== "web"
|
|
|
40
41
|
? "/local-to-dev"
|
|
41
42
|
: "http://localhost:3004/local-to-dev"
|
|
42
43
|
: "/checkout/api";
|
|
43
|
-
const authToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
|
|
44
|
+
const authToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEzNzI1NDU1LCJleHAiOjE3NzQwMjg4NTUsImRpc3BsYXlOYW1lIjoibWFpbC5kZXYrdGRwLjE4ZjUxODgxLTBkMWMtNDVhYy1iNzhkLWU5ODliYzRkZmFhNkBsb29raWVyby5jb20iLCJjb3VudHJ5X2NvZGUiOiJFUyIsImFjY2Vzc1ZpYSI6ImVtYWlsIiwidHJhZGVuYW1lIjoiTE9PS0lFUk8iLCJ1dWlkIjoiZTQ0NTA0ODEtZjhkMS00N2JkLWEyZjAtYThjYjBkMjkyYmNkIiwiaWF0IjoxNzc0MDAwMDU1fQ.iJflcz8dn3U516LdSht7_P2ixe_-OsEiSfvCvOTGYsw";
|
|
44
45
|
const getAuthToken = () => Promise.resolve(authToken);
|
|
45
46
|
const useRedirect = () => ({
|
|
46
47
|
returnUrl: "https://web2.dev.aws.lookiero.es/user/",
|
|
@@ -73,7 +74,7 @@ const kameleoonConfig = {
|
|
|
73
74
|
};
|
|
74
75
|
const { Component: Messaging, queryBus } = process.env.EXPO_PUBLIC_APP_VARIANT === "test"
|
|
75
76
|
? checkoutMockBootstrap()
|
|
76
|
-
: checkoutBootstrap({ apiUrl: () => apiUrl, getAuthToken });
|
|
77
|
+
: checkoutBootstrap({ apiUrl: () => apiUrl, getAuthToken, tradename, migrated });
|
|
77
78
|
const Root = root({
|
|
78
79
|
Messaging,
|
|
79
80
|
queryBus,
|
|
@@ -100,7 +101,7 @@ const ExpoRoot = () => {
|
|
|
100
101
|
isAccessible === false && React.createElement(Text, { variant: "heading" }, "Checkout is not accessible!"),
|
|
101
102
|
React.createElement(Router, null,
|
|
102
103
|
React.createElement(Routes, null,
|
|
103
|
-
React.createElement(Route, { path: "/checkout/*", element: React.createElement(Root, { basePath: "/checkout", customer: customer, layout: DummyLayout, locale: locale, tradename: tradename, useRedirect: useRedirect, onCheckoutFlowSuccess: () => console.log("Checkout flow success!"), onNotAccessible: onNotAccessible }) }),
|
|
104
|
+
React.createElement(Route, { path: "/checkout/*", element: React.createElement(Root, { basePath: "/checkout", customer: customer, layout: DummyLayout, locale: locale, migrated: migrated, tradename: tradename, useRedirect: useRedirect, onCheckoutFlowSuccess: () => console.log("Checkout flow success!"), onNotAccessible: onNotAccessible }) }),
|
|
104
105
|
React.createElement(Route, { element: React.createElement(Navigate, { to: "/checkout", replace: true }), path: "*" })))))))) : null;
|
|
105
106
|
};
|
|
106
107
|
export { ExpoRoot };
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { BuildBootstrapFunctionReturn } from "@lookiero/messaging-react";
|
|
2
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
2
3
|
interface BootstrapFunctionArgs {
|
|
3
4
|
readonly getAuthToken: () => Promise<string>;
|
|
4
5
|
readonly apiUrl: () => string;
|
|
6
|
+
readonly tradename: Tradename;
|
|
7
|
+
readonly migrated: boolean;
|
|
5
8
|
}
|
|
6
9
|
interface BootstrapFunction {
|
|
7
10
|
(args: BootstrapFunctionArgs): BuildBootstrapFunctionReturn;
|
|
@@ -19,7 +19,7 @@ import { httpPricingByCheckoutIdView } from "../projection/pricing/httpPricingBy
|
|
|
19
19
|
import { httpReturnQuestionsByCheckoutItemIdView } from "../projection/returnQuestion/httpReturnQuestionsByCheckoutItemIdView";
|
|
20
20
|
import { baseBootstrap } from "./baseBootstrap";
|
|
21
21
|
const device = Platform.OS;
|
|
22
|
-
const bootstrap = ({ apiUrl, getAuthToken }) => {
|
|
22
|
+
const bootstrap = ({ apiUrl, getAuthToken, tradename, migrated }) => {
|
|
23
23
|
const httpGet = fetchHttpGet({ apiUrl, getAuthToken, device, version: VERSION });
|
|
24
24
|
const httpPost = fetchHttpPost({ apiUrl, getAuthToken, device, version: VERSION });
|
|
25
25
|
return baseBootstrap({
|
|
@@ -36,6 +36,8 @@ const bootstrap = ({ apiUrl, getAuthToken }) => {
|
|
|
36
36
|
}),
|
|
37
37
|
pricingByCheckoutIdView: httpPricingByCheckoutIdView({
|
|
38
38
|
httpPost,
|
|
39
|
+
tradename,
|
|
40
|
+
migrated,
|
|
39
41
|
}),
|
|
40
42
|
paymentFlowPayloadByCheckoutIdView: httpPaymentFlowPayloadByCheckoutIdView({
|
|
41
43
|
httpPost,
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { HttpPostFunction } from "@lookiero/sty-psp-http";
|
|
2
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
2
3
|
import { PricingByCheckoutIdView } from "../../../projection/pricing/viewPricingByCheckoutId";
|
|
3
4
|
interface HttpPricingByCheckoutIdView extends PricingByCheckoutIdView {
|
|
4
5
|
}
|
|
5
6
|
interface HttpPricingByCheckoutIdViewFunctionArgs {
|
|
6
7
|
readonly httpPost: HttpPostFunction;
|
|
8
|
+
readonly tradename: Tradename;
|
|
9
|
+
readonly migrated: boolean;
|
|
7
10
|
}
|
|
8
11
|
interface HttpPricingByCheckoutIdViewFunction {
|
|
9
12
|
(args: HttpPricingByCheckoutIdViewFunctionArgs): HttpPricingByCheckoutIdView;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { toPricingProjection } from "./pricing";
|
|
2
|
+
const httpPricingByCheckoutIdView = ({ httpPost, tradename, migrated }) => async ({ checkoutId, signal }) => await httpPost({
|
|
3
|
+
endpoint: "/view-pricing-by-checkout-id",
|
|
3
4
|
body: { checkoutId },
|
|
4
5
|
signal,
|
|
5
6
|
result: {
|
|
6
7
|
error: null,
|
|
7
|
-
success: (response) => response,
|
|
8
|
+
success: (response) => toPricingProjection({ pricing: response.result, tradename, migrated }),
|
|
8
9
|
},
|
|
9
10
|
});
|
|
10
11
|
export { httpPricingByCheckoutIdView };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
2
|
+
import { PriceProjection } from "../../../projection/price/price";
|
|
3
|
+
import { CheckoutPricingProjection } from "../../../projection/pricing/pricing";
|
|
4
|
+
interface ServiceDto {
|
|
5
|
+
readonly discount: PriceProjection;
|
|
6
|
+
readonly finalPrice: PriceProjection;
|
|
7
|
+
readonly originalPrice: PriceProjection;
|
|
8
|
+
readonly prepaid: boolean;
|
|
9
|
+
readonly reference: string;
|
|
10
|
+
readonly paidWithPromocode?: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface PricingDto {
|
|
13
|
+
readonly balanceDiscount: PriceProjection;
|
|
14
|
+
readonly discount: PriceProjection;
|
|
15
|
+
readonly discountPercentage: number;
|
|
16
|
+
readonly orderTotal: PriceProjection;
|
|
17
|
+
readonly pendingToPay: PriceProjection;
|
|
18
|
+
readonly service: ServiceDto;
|
|
19
|
+
readonly subtotal: PriceProjection;
|
|
20
|
+
}
|
|
21
|
+
interface ToPricingProjectionFunctionArgs {
|
|
22
|
+
readonly pricing: PricingDto;
|
|
23
|
+
readonly tradename: Tradename;
|
|
24
|
+
readonly migrated: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface ToPricingProjectionFunction {
|
|
27
|
+
(args: ToPricingProjectionFunctionArgs): CheckoutPricingProjection;
|
|
28
|
+
}
|
|
29
|
+
declare const toPricingProjection: ToPricingProjectionFunction;
|
|
30
|
+
export type { PricingDto };
|
|
31
|
+
export { toPricingProjection };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
2
|
+
import { CheckoutPricingContext, CheckoutPricingType, } from "../../../projection/pricing/pricing";
|
|
3
|
+
const toPricingProjection = ({ pricing, tradename, migrated, }) => {
|
|
4
|
+
const shouldDisplayPsFeeModifier = tradename === Tradename.LOOKIERO || (tradename === Tradename.OUTFITTERY && !migrated);
|
|
5
|
+
const modifiers = [
|
|
6
|
+
{
|
|
7
|
+
amount: pricing.discount.amount,
|
|
8
|
+
type: CheckoutPricingType.DISCOUNT,
|
|
9
|
+
context: CheckoutPricingContext.PROMOCODE,
|
|
10
|
+
translationKey: "summary.discount",
|
|
11
|
+
percentage: pricing.discountPercentage,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
amount: pricing.balanceDiscount.amount,
|
|
15
|
+
type: CheckoutPricingType.DISCOUNT,
|
|
16
|
+
context: CheckoutPricingContext.BALANCE,
|
|
17
|
+
translationKey: "summary.credit",
|
|
18
|
+
},
|
|
19
|
+
...(shouldDisplayPsFeeModifier
|
|
20
|
+
? [
|
|
21
|
+
{
|
|
22
|
+
amount: pricing.service.finalPrice.amount,
|
|
23
|
+
type: CheckoutPricingType.DISCOUNT,
|
|
24
|
+
context: CheckoutPricingContext.PS_FEE,
|
|
25
|
+
translationKey: "summary.fee",
|
|
26
|
+
},
|
|
27
|
+
]
|
|
28
|
+
: []),
|
|
29
|
+
]
|
|
30
|
+
.map((modifier) => ({ ...modifier, amount: Math.abs(modifier.amount) }))
|
|
31
|
+
.filter(({ amount }) => amount !== 0);
|
|
32
|
+
return {
|
|
33
|
+
currency: pricing.pendingToPay.currency,
|
|
34
|
+
finalPrice: pricing.pendingToPay.amount,
|
|
35
|
+
originalPrice: pricing.subtotal.amount,
|
|
36
|
+
modifiers,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export { toPricingProjection };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CheckoutPricingProjection } from "../../../projection/pricing/pricing";
|
|
2
|
+
import { PricingDto } from "./pricing";
|
|
2
3
|
declare const mockCheckoutPricingProjection: CheckoutPricingProjection;
|
|
3
|
-
declare const
|
|
4
|
-
export { mockCheckoutPricingProjection,
|
|
4
|
+
declare const mockPricingDto: PricingDto;
|
|
5
|
+
export { mockCheckoutPricingProjection, mockPricingDto };
|
|
@@ -26,5 +26,19 @@ const mockCheckoutPricingProjection = {
|
|
|
26
26
|
},
|
|
27
27
|
],
|
|
28
28
|
};
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const mockPricingDto = {
|
|
30
|
+
pendingToPay: { amount: 12127, currency: Currency.EUR },
|
|
31
|
+
subtotal: { amount: 21195, currency: Currency.EUR },
|
|
32
|
+
discount: { amount: 7068, currency: Currency.EUR },
|
|
33
|
+
discountPercentage: 35,
|
|
34
|
+
balanceDiscount: { amount: 1000, currency: Currency.EUR },
|
|
35
|
+
service: {
|
|
36
|
+
discount: { amount: 0, currency: Currency.EUR },
|
|
37
|
+
finalPrice: { amount: 1000, currency: Currency.EUR },
|
|
38
|
+
originalPrice: { amount: 1000, currency: Currency.EUR },
|
|
39
|
+
prepaid: false,
|
|
40
|
+
reference: "ps-fee",
|
|
41
|
+
},
|
|
42
|
+
orderTotal: { amount: 13127, currency: Currency.EUR },
|
|
43
|
+
};
|
|
44
|
+
export { mockCheckoutPricingProjection, mockPricingDto };
|
|
@@ -26,6 +26,7 @@ interface RootProps {
|
|
|
26
26
|
readonly customer: Customer;
|
|
27
27
|
readonly layout: Layout;
|
|
28
28
|
readonly tradename: Tradename;
|
|
29
|
+
readonly migrated: boolean;
|
|
29
30
|
readonly onNotAccessible: () => void;
|
|
30
31
|
readonly onCheckoutFlowSuccess: OnCheckoutFlowSuccessFunction;
|
|
31
32
|
readonly useRedirect: () => Record<string, string>;
|
|
@@ -9,11 +9,11 @@ const root = ({ Messaging, queryBus, getAuthToken, development, sentry, kameleoo
|
|
|
9
9
|
const logger = sentryLogger(sentry);
|
|
10
10
|
const kameleoon = kameleoonConfig();
|
|
11
11
|
// eslint-disable-next-line react/display-name, react/prop-types
|
|
12
|
-
const Root = ({ basePath, locale, customer, layout, tradename, onNotAccessible, onCheckoutFlowSuccess, useRedirect, useRoutes = reactRouterUseRoutes, }) => {
|
|
12
|
+
const Root = ({ basePath, locale, customer, layout, tradename, migrated, onNotAccessible, onCheckoutFlowSuccess, useRedirect, useRoutes = reactRouterUseRoutes, }) => {
|
|
13
13
|
const handleOnI18nError = useCallback((error) => logger.captureException(error), []);
|
|
14
14
|
return (React.createElement(Messaging, { includeReactQueryDevTools: Platform.OS === "web" },
|
|
15
15
|
React.createElement(QueryBusProvider, { queryBus: queryBus },
|
|
16
|
-
React.createElement(Routing, { I18n: i18n({ tradename }), basePath: basePath, customer: customer, getAuthToken: getAuthToken, kameleoon: kameleoon, layout: layout, locale: locale, tradename: tradename, useRedirect: useRedirect, useRoutes: useRoutes, onCheckoutFlowSuccess: onCheckoutFlowSuccess, onI18nError: development ? undefined : handleOnI18nError, onNotAccessible: onNotAccessible }))));
|
|
16
|
+
React.createElement(Routing, { I18n: i18n({ tradename }), basePath: basePath, customer: customer, getAuthToken: getAuthToken, kameleoon: kameleoon, layout: layout, locale: locale, migrated: migrated, tradename: tradename, useRedirect: useRedirect, useRoutes: useRoutes, onCheckoutFlowSuccess: onCheckoutFlowSuccess, onI18nError: development ? undefined : handleOnI18nError, onNotAccessible: onNotAccessible }))));
|
|
17
17
|
};
|
|
18
18
|
const hoc = sentryLoggerHOC({ logger });
|
|
19
19
|
/**
|
|
@@ -6,6 +6,7 @@ interface StaticInfo {
|
|
|
6
6
|
readonly kameleoon: KameleoonEnvironment;
|
|
7
7
|
readonly customer: Customer;
|
|
8
8
|
readonly tradename: Tradename;
|
|
9
|
+
readonly migrated: boolean;
|
|
9
10
|
readonly basePath: string;
|
|
10
11
|
}
|
|
11
12
|
interface StaticInfoProviderProps {
|
|
@@ -13,6 +14,7 @@ interface StaticInfoProviderProps {
|
|
|
13
14
|
readonly kameleoon: KameleoonEnvironment;
|
|
14
15
|
readonly customer: Customer;
|
|
15
16
|
readonly tradename: Tradename;
|
|
17
|
+
readonly migrated: boolean;
|
|
16
18
|
readonly basePath: string;
|
|
17
19
|
}
|
|
18
20
|
declare const StaticInfoProvider: FC<StaticInfoProviderProps>;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React, { createContext, useContext, useMemo } from "react";
|
|
2
2
|
import invariant from "tiny-invariant";
|
|
3
3
|
const StaticInfoContext = createContext(null);
|
|
4
|
-
const StaticInfoProvider = ({ children, kameleoon, customer, tradename, basePath }) => {
|
|
4
|
+
const StaticInfoProvider = ({ children, kameleoon, customer, tradename, migrated, basePath, }) => {
|
|
5
5
|
const value = useMemo(() => ({
|
|
6
6
|
kameleoon,
|
|
7
7
|
customer,
|
|
8
8
|
tradename,
|
|
9
|
+
migrated,
|
|
9
10
|
basePath,
|
|
10
|
-
}), [basePath, customer, kameleoon, tradename]);
|
|
11
|
+
}), [basePath, customer, kameleoon, migrated, tradename]);
|
|
11
12
|
return React.createElement(StaticInfoContext.Provider, { value: value }, children);
|
|
12
13
|
};
|
|
13
14
|
const useStaticInfo = () => {
|
|
@@ -15,6 +15,7 @@ interface RoutingProps {
|
|
|
15
15
|
readonly kameleoon: KameleoonEnvironment;
|
|
16
16
|
readonly layout: Layout;
|
|
17
17
|
readonly tradename: Tradename;
|
|
18
|
+
readonly migrated: boolean;
|
|
18
19
|
readonly getAuthToken: () => Promise<string>;
|
|
19
20
|
readonly onNotAccessible: () => void;
|
|
20
21
|
readonly onCheckoutFlowSuccess: OnCheckoutFlowSuccessFunction;
|
|
@@ -12,11 +12,11 @@ import { Summary } from "../views/summary/Summary";
|
|
|
12
12
|
import { SummaryTabs } from "../views/summaryTabs/SummaryTabs";
|
|
13
13
|
import { CheckoutMiddleware } from "./CheckoutMiddleware";
|
|
14
14
|
import { Routes } from "./routes";
|
|
15
|
-
const Routing = ({ basePath = "", customer, locale, I18n, kameleoon, layout, tradename, getAuthToken, onI18nError, onNotAccessible, onCheckoutFlowSuccess, useRedirect, useRoutes = reactRouterUseRoutes, }) => {
|
|
15
|
+
const Routing = ({ basePath = "", customer, locale, I18n, kameleoon, layout, tradename, migrated, getAuthToken, onI18nError, onNotAccessible, onCheckoutFlowSuccess, useRedirect, useRoutes = reactRouterUseRoutes, }) => {
|
|
16
16
|
return useRoutes([
|
|
17
17
|
{
|
|
18
18
|
path: "",
|
|
19
|
-
element: (React.createElement(StaticInfoProvider, { basePath: basePath, customer: customer, kameleoon: kameleoon, tradename: tradename },
|
|
19
|
+
element: (React.createElement(StaticInfoProvider, { basePath: basePath, customer: customer, kameleoon: kameleoon, migrated: migrated, tradename: tradename },
|
|
20
20
|
React.createElement(I18n, { loader: React.createElement(Spinner, null), locale: locale, onError: onI18nError },
|
|
21
21
|
React.createElement(Kameleoon, { loader: React.createElement(Spinner, null), siteCode: kameleoon.siteCode },
|
|
22
22
|
React.createElement(CheckoutMiddleware, { customerId: customer?.customerId, onNotAccessible: onNotAccessible },
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "14.8.
|
|
2
|
-
export declare const RELEASE = "checkout@14.8.
|
|
1
|
+
export declare const VERSION = "14.8.2";
|
|
2
|
+
export declare const RELEASE = "checkout@14.8.2";
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "14.8.
|
|
2
|
-
export const RELEASE = "checkout@14.8.
|
|
1
|
+
export const VERSION = "14.8.2";
|
|
2
|
+
export const RELEASE = "checkout@14.8.2";
|
package/index.ts
CHANGED
|
@@ -24,6 +24,8 @@ interface FirstAvailableCheckoutByCustomerIdFunction {
|
|
|
24
24
|
interface BootstrapFunctionArgs {
|
|
25
25
|
readonly getAuthToken: () => Promise<string>;
|
|
26
26
|
readonly apiUrl: () => string;
|
|
27
|
+
readonly tradename: Tradename;
|
|
28
|
+
readonly migrated: boolean;
|
|
27
29
|
readonly sentry: () => SentryEnvironment;
|
|
28
30
|
readonly kameleoon: () => KameleoonEnvironment;
|
|
29
31
|
}
|
|
@@ -37,8 +39,8 @@ interface BootstrapFunction {
|
|
|
37
39
|
(args: BootstrapFunctionArgs): BootstrapFunctionReturn;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
const bootstrap: BootstrapFunction = ({ apiUrl, getAuthToken, sentry, kameleoon }) => {
|
|
41
|
-
const { Component: Messaging, queryBus } = checkoutBootstrap({ apiUrl, getAuthToken });
|
|
42
|
+
const bootstrap: BootstrapFunction = ({ apiUrl, getAuthToken, tradename, migrated, sentry, kameleoon }) => {
|
|
43
|
+
const { Component: Messaging, queryBus } = checkoutBootstrap({ apiUrl, getAuthToken, tradename, migrated });
|
|
42
44
|
|
|
43
45
|
const firstAvailableCheckoutByCustomerId: FirstAvailableCheckoutByCustomerIdFunction = ({ customerId }) =>
|
|
44
46
|
queryBus(viewFirstAvailableCheckoutByCustomerId({ customerId: customerId as string }));
|
package/package.json
CHANGED
package/src/ExpoRoot.tsx
CHANGED
|
@@ -21,11 +21,12 @@ import { Customer } from "./projection/customer/customer";
|
|
|
21
21
|
import { RELEASE } from "./version";
|
|
22
22
|
|
|
23
23
|
const tradename = Tradename.LOOKIERO;
|
|
24
|
+
const migrated = false;
|
|
24
25
|
const theme = themeByTradename({ tradename });
|
|
25
26
|
const locale: Locale = Locale.es_ES;
|
|
26
27
|
|
|
27
28
|
const customer: Customer = {
|
|
28
|
-
customerId: "
|
|
29
|
+
customerId: "e4450481-f8d1-47bd-a2f0-a8cb0d292bcd",
|
|
29
30
|
country: Country.ES,
|
|
30
31
|
segment: Segment.WOMEN,
|
|
31
32
|
email: "email@example.com",
|
|
@@ -49,7 +50,7 @@ const apiUrl =
|
|
|
49
50
|
: "http://localhost:3004/local-to-dev"
|
|
50
51
|
: "/checkout/api";
|
|
51
52
|
const authToken =
|
|
52
|
-
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
|
|
53
|
+
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEzNzI1NDU1LCJleHAiOjE3NzQwMjg4NTUsImRpc3BsYXlOYW1lIjoibWFpbC5kZXYrdGRwLjE4ZjUxODgxLTBkMWMtNDVhYy1iNzhkLWU5ODliYzRkZmFhNkBsb29raWVyby5jb20iLCJjb3VudHJ5X2NvZGUiOiJFUyIsImFjY2Vzc1ZpYSI6ImVtYWlsIiwidHJhZGVuYW1lIjoiTE9PS0lFUk8iLCJ1dWlkIjoiZTQ0NTA0ODEtZjhkMS00N2JkLWEyZjAtYThjYjBkMjkyYmNkIiwiaWF0IjoxNzc0MDAwMDU1fQ.iJflcz8dn3U516LdSht7_P2ixe_-OsEiSfvCvOTGYsw";
|
|
53
54
|
const getAuthToken = () => Promise.resolve(authToken);
|
|
54
55
|
|
|
55
56
|
const useRedirect: () => Record<string, string> = () => ({
|
|
@@ -88,7 +89,7 @@ const kameleoonConfig: KameleoonEnvironment = {
|
|
|
88
89
|
const { Component: Messaging, queryBus } =
|
|
89
90
|
process.env.EXPO_PUBLIC_APP_VARIANT === "test"
|
|
90
91
|
? checkoutMockBootstrap()
|
|
91
|
-
: checkoutBootstrap({ apiUrl: () => apiUrl, getAuthToken });
|
|
92
|
+
: checkoutBootstrap({ apiUrl: () => apiUrl, getAuthToken, tradename, migrated });
|
|
92
93
|
|
|
93
94
|
const Root = root({
|
|
94
95
|
Messaging,
|
|
@@ -129,6 +130,7 @@ const ExpoRoot: FC = () => {
|
|
|
129
130
|
customer={customer}
|
|
130
131
|
layout={DummyLayout}
|
|
131
132
|
locale={locale}
|
|
133
|
+
migrated={migrated}
|
|
132
134
|
tradename={tradename}
|
|
133
135
|
useRedirect={useRedirect}
|
|
134
136
|
onCheckoutFlowSuccess={() => console.log("Checkout flow success!")}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Platform } from "react-native";
|
|
2
2
|
import { BuildBootstrapFunctionReturn } from "@lookiero/messaging-react";
|
|
3
3
|
import { fetchHttpGet, fetchHttpPost } from "@lookiero/sty-psp-http";
|
|
4
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
4
5
|
import { VERSION } from "../../version";
|
|
5
6
|
import { getCheckout, saveCheckout } from "../domain/checkout/model/httpCheckouts";
|
|
6
7
|
import { getCheckoutBooking, saveCheckoutBooking } from "../domain/checkoutBooking/model/httpCheckoutBookings";
|
|
@@ -27,13 +28,15 @@ const device = Platform.OS as Device;
|
|
|
27
28
|
interface BootstrapFunctionArgs {
|
|
28
29
|
readonly getAuthToken: () => Promise<string>;
|
|
29
30
|
readonly apiUrl: () => string;
|
|
31
|
+
readonly tradename: Tradename;
|
|
32
|
+
readonly migrated: boolean;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
interface BootstrapFunction {
|
|
33
36
|
(args: BootstrapFunctionArgs): BuildBootstrapFunctionReturn;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
const bootstrap: BootstrapFunction = ({ apiUrl, getAuthToken }) => {
|
|
39
|
+
const bootstrap: BootstrapFunction = ({ apiUrl, getAuthToken, tradename, migrated }) => {
|
|
37
40
|
const httpGet = fetchHttpGet({ apiUrl, getAuthToken, device, version: VERSION });
|
|
38
41
|
const httpPost = fetchHttpPost({ apiUrl, getAuthToken, device, version: VERSION });
|
|
39
42
|
|
|
@@ -51,6 +54,8 @@ const bootstrap: BootstrapFunction = ({ apiUrl, getAuthToken }) => {
|
|
|
51
54
|
}),
|
|
52
55
|
pricingByCheckoutIdView: httpPricingByCheckoutIdView({
|
|
53
56
|
httpPost,
|
|
57
|
+
tradename,
|
|
58
|
+
migrated,
|
|
54
59
|
}),
|
|
55
60
|
paymentFlowPayloadByCheckoutIdView: httpPaymentFlowPayloadByCheckoutIdView({
|
|
56
61
|
httpPost,
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import { mock } from "jest-mock-extended";
|
|
2
2
|
import { fetchHttpPost } from "@lookiero/sty-psp-http";
|
|
3
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
3
4
|
import { httpPricingByCheckoutIdView as sut } from "./httpPricingByCheckoutIdView";
|
|
4
|
-
import {
|
|
5
|
+
import { PricingDto } from "./pricing";
|
|
6
|
+
import { mockCheckoutPricingProjection, mockPricingDto } from "./pricing.mock";
|
|
5
7
|
|
|
6
8
|
const fetchMock = jest.fn();
|
|
7
9
|
global.fetch = fetchMock;
|
|
8
10
|
const apiUrl = "/api";
|
|
9
11
|
const getAuthToken = () => Promise.resolve("token");
|
|
10
|
-
const view = sut({
|
|
12
|
+
const view = sut({
|
|
13
|
+
httpPost: fetchHttpPost({ apiUrl: () => apiUrl, getAuthToken, device: "web", version: "1.0.0" }),
|
|
14
|
+
tradename: Tradename.LOOKIERO,
|
|
15
|
+
migrated: false,
|
|
16
|
+
});
|
|
11
17
|
const signal = mock<AbortSignal>();
|
|
12
18
|
|
|
13
19
|
const checkoutId = "29790d24-b139-4ab8-b618-d796d101e974";
|
|
14
20
|
const pricingResponseOk: Response = {
|
|
15
21
|
ok: true,
|
|
16
22
|
status: 200,
|
|
17
|
-
text: () => Promise.resolve(JSON.stringify(
|
|
23
|
+
text: () => Promise.resolve(JSON.stringify({ result: mockPricingDto })),
|
|
18
24
|
} as Response;
|
|
19
25
|
const pricingResponseNotFound: Response = {
|
|
20
26
|
ok: false,
|
|
@@ -33,6 +39,88 @@ describe("httpPricingByCheckoutIdView", () => {
|
|
|
33
39
|
expect(returnedPricing).toStrictEqual(mockCheckoutPricingProjection);
|
|
34
40
|
});
|
|
35
41
|
|
|
42
|
+
it("does not include PS_FEE modifier for OUTFITTERY migrated", async () => {
|
|
43
|
+
const outfitteryMigratedView = sut({
|
|
44
|
+
httpPost: fetchHttpPost({ apiUrl: () => apiUrl, getAuthToken, device: "web", version: "1.0.0" }),
|
|
45
|
+
tradename: Tradename.OUTFITTERY,
|
|
46
|
+
migrated: true,
|
|
47
|
+
});
|
|
48
|
+
fetchMock.mockReturnValue(Promise.resolve(pricingResponseOk));
|
|
49
|
+
|
|
50
|
+
const returnedPricing = await outfitteryMigratedView({ checkoutId, signal });
|
|
51
|
+
|
|
52
|
+
expect(returnedPricing).toStrictEqual({
|
|
53
|
+
currency: mockPricingDto.pendingToPay.currency,
|
|
54
|
+
finalPrice: mockPricingDto.pendingToPay.amount,
|
|
55
|
+
originalPrice: mockPricingDto.subtotal.amount,
|
|
56
|
+
modifiers: [
|
|
57
|
+
{
|
|
58
|
+
amount: mockPricingDto.discount.amount,
|
|
59
|
+
type: "DISCOUNT",
|
|
60
|
+
context: "PROMOCODE",
|
|
61
|
+
translationKey: "summary.discount",
|
|
62
|
+
percentage: mockPricingDto.discountPercentage,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
amount: mockPricingDto.balanceDiscount.amount,
|
|
66
|
+
type: "DISCOUNT",
|
|
67
|
+
context: "BALANCE",
|
|
68
|
+
translationKey: "summary.credit",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("filters zero modifiers and maps negative amounts as absolute values", async () => {
|
|
75
|
+
const mockPricingWithZeroAndNegativeAmounts: PricingDto = {
|
|
76
|
+
pendingToPay: { amount: 12127, currency: mockPricingDto.pendingToPay.currency },
|
|
77
|
+
subtotal: { amount: 21195, currency: mockPricingDto.subtotal.currency },
|
|
78
|
+
discount: { amount: -7068, currency: mockPricingDto.discount.currency },
|
|
79
|
+
discountPercentage: 35,
|
|
80
|
+
balanceDiscount: { amount: 0, currency: mockPricingDto.balanceDiscount.currency },
|
|
81
|
+
service: {
|
|
82
|
+
discount: { amount: 0, currency: mockPricingDto.service.discount.currency },
|
|
83
|
+
finalPrice: { amount: -1000, currency: mockPricingDto.service.finalPrice.currency },
|
|
84
|
+
originalPrice: {
|
|
85
|
+
amount: mockPricingDto.service.originalPrice.amount,
|
|
86
|
+
currency: mockPricingDto.service.originalPrice.currency,
|
|
87
|
+
},
|
|
88
|
+
prepaid: false,
|
|
89
|
+
reference: "ps-fee",
|
|
90
|
+
},
|
|
91
|
+
orderTotal: { amount: 13127, currency: mockPricingDto.orderTotal.currency },
|
|
92
|
+
};
|
|
93
|
+
const pricingResponseOkWithNegativeAndZeroModifiers: Response = {
|
|
94
|
+
ok: true,
|
|
95
|
+
status: 200,
|
|
96
|
+
text: () => Promise.resolve(JSON.stringify({ result: mockPricingWithZeroAndNegativeAmounts })),
|
|
97
|
+
} as Response;
|
|
98
|
+
fetchMock.mockReturnValue(Promise.resolve(pricingResponseOkWithNegativeAndZeroModifiers));
|
|
99
|
+
|
|
100
|
+
const returnedPricing = await view({ checkoutId, signal });
|
|
101
|
+
|
|
102
|
+
expect(returnedPricing).toStrictEqual({
|
|
103
|
+
currency: mockPricingDto.pendingToPay.currency,
|
|
104
|
+
finalPrice: 12127,
|
|
105
|
+
originalPrice: 21195,
|
|
106
|
+
modifiers: [
|
|
107
|
+
{
|
|
108
|
+
amount: 7068,
|
|
109
|
+
type: "DISCOUNT",
|
|
110
|
+
context: "PROMOCODE",
|
|
111
|
+
translationKey: "summary.discount",
|
|
112
|
+
percentage: 35,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
amount: 1000,
|
|
116
|
+
type: "DISCOUNT",
|
|
117
|
+
context: "PS_FEE",
|
|
118
|
+
translationKey: "summary.fee",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
36
124
|
it("returns null for a 404 response", async () => {
|
|
37
125
|
fetchMock.mockReturnValue(Promise.resolve(pricingResponseNotFound));
|
|
38
126
|
|
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
import { HttpPostFunction } from "@lookiero/sty-psp-http";
|
|
2
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
2
3
|
import {
|
|
3
4
|
PricingByCheckoutIdView,
|
|
4
5
|
ViewPricingByCheckoutIdResult,
|
|
5
6
|
} from "../../../projection/pricing/viewPricingByCheckoutId";
|
|
7
|
+
import { PricingDto, toPricingProjection } from "./pricing";
|
|
6
8
|
|
|
7
9
|
interface HttpPricingByCheckoutIdView extends PricingByCheckoutIdView {}
|
|
8
10
|
|
|
9
11
|
interface HttpPricingByCheckoutIdViewFunctionArgs {
|
|
10
12
|
readonly httpPost: HttpPostFunction;
|
|
13
|
+
readonly tradename: Tradename;
|
|
14
|
+
readonly migrated: boolean;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
interface HttpPricingByCheckoutIdViewFunction {
|
|
14
18
|
(args: HttpPricingByCheckoutIdViewFunctionArgs): HttpPricingByCheckoutIdView;
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
interface ViewPricingByCheckoutIdResponse {
|
|
22
|
+
readonly result: PricingDto;
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
const httpPricingByCheckoutIdView: HttpPricingByCheckoutIdViewFunction =
|
|
18
|
-
({ httpPost }) =>
|
|
26
|
+
({ httpPost, tradename, migrated }) =>
|
|
19
27
|
async ({ checkoutId, signal }) =>
|
|
20
|
-
await httpPost<ViewPricingByCheckoutIdResult>({
|
|
21
|
-
endpoint: "/view-
|
|
28
|
+
await httpPost<ViewPricingByCheckoutIdResponse, ViewPricingByCheckoutIdResult>({
|
|
29
|
+
endpoint: "/view-pricing-by-checkout-id",
|
|
22
30
|
body: { checkoutId },
|
|
23
31
|
signal,
|
|
24
32
|
result: {
|
|
25
33
|
error: null,
|
|
26
|
-
success: (response) => response,
|
|
34
|
+
success: (response) => toPricingProjection({ pricing: response.result, tradename, migrated }),
|
|
27
35
|
},
|
|
28
36
|
});
|
|
29
37
|
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
CheckoutPricingContext,
|
|
5
5
|
CheckoutPricingType,
|
|
6
6
|
} from "../../../projection/pricing/pricing";
|
|
7
|
+
import { PricingDto } from "./pricing";
|
|
7
8
|
|
|
8
9
|
const mockCheckoutPricingProjection: CheckoutPricingProjection = {
|
|
9
10
|
currency: Currency.EUR,
|
|
@@ -32,6 +33,20 @@ const mockCheckoutPricingProjection: CheckoutPricingProjection = {
|
|
|
32
33
|
],
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
+
const mockPricingDto: PricingDto = {
|
|
37
|
+
pendingToPay: { amount: 12127, currency: Currency.EUR },
|
|
38
|
+
subtotal: { amount: 21195, currency: Currency.EUR },
|
|
39
|
+
discount: { amount: 7068, currency: Currency.EUR },
|
|
40
|
+
discountPercentage: 35,
|
|
41
|
+
balanceDiscount: { amount: 1000, currency: Currency.EUR },
|
|
42
|
+
service: {
|
|
43
|
+
discount: { amount: 0, currency: Currency.EUR },
|
|
44
|
+
finalPrice: { amount: 1000, currency: Currency.EUR },
|
|
45
|
+
originalPrice: { amount: 1000, currency: Currency.EUR },
|
|
46
|
+
prepaid: false,
|
|
47
|
+
reference: "ps-fee",
|
|
48
|
+
},
|
|
49
|
+
orderTotal: { amount: 13127, currency: Currency.EUR },
|
|
50
|
+
};
|
|
36
51
|
|
|
37
|
-
export { mockCheckoutPricingProjection,
|
|
52
|
+
export { mockCheckoutPricingProjection, mockPricingDto };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Tradename } from "@lookiero/sty-sp-tradename";
|
|
2
|
+
import { PriceProjection } from "../../../projection/price/price";
|
|
3
|
+
import {
|
|
4
|
+
CheckoutPricingContext,
|
|
5
|
+
CheckoutPricingProjection,
|
|
6
|
+
CheckoutPricingType,
|
|
7
|
+
} from "../../../projection/pricing/pricing";
|
|
8
|
+
|
|
9
|
+
interface ServiceDto {
|
|
10
|
+
readonly discount: PriceProjection;
|
|
11
|
+
readonly finalPrice: PriceProjection;
|
|
12
|
+
readonly originalPrice: PriceProjection;
|
|
13
|
+
readonly prepaid: boolean;
|
|
14
|
+
readonly reference: string;
|
|
15
|
+
readonly paidWithPromocode?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface PricingDto {
|
|
19
|
+
readonly balanceDiscount: PriceProjection;
|
|
20
|
+
readonly discount: PriceProjection;
|
|
21
|
+
readonly discountPercentage: number;
|
|
22
|
+
readonly orderTotal: PriceProjection;
|
|
23
|
+
readonly pendingToPay: PriceProjection;
|
|
24
|
+
readonly service: ServiceDto;
|
|
25
|
+
readonly subtotal: PriceProjection;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ToPricingProjectionFunctionArgs {
|
|
29
|
+
readonly pricing: PricingDto;
|
|
30
|
+
readonly tradename: Tradename;
|
|
31
|
+
readonly migrated: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface ToPricingProjectionFunction {
|
|
35
|
+
(args: ToPricingProjectionFunctionArgs): CheckoutPricingProjection;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const toPricingProjection: ToPricingProjectionFunction = ({
|
|
39
|
+
pricing,
|
|
40
|
+
tradename,
|
|
41
|
+
migrated,
|
|
42
|
+
}): CheckoutPricingProjection => {
|
|
43
|
+
const shouldDisplayPsFeeModifier =
|
|
44
|
+
tradename === Tradename.LOOKIERO || (tradename === Tradename.OUTFITTERY && !migrated);
|
|
45
|
+
|
|
46
|
+
const modifiers = [
|
|
47
|
+
{
|
|
48
|
+
amount: pricing.discount.amount,
|
|
49
|
+
type: CheckoutPricingType.DISCOUNT,
|
|
50
|
+
context: CheckoutPricingContext.PROMOCODE,
|
|
51
|
+
translationKey: "summary.discount",
|
|
52
|
+
percentage: pricing.discountPercentage,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
amount: pricing.balanceDiscount.amount,
|
|
56
|
+
type: CheckoutPricingType.DISCOUNT,
|
|
57
|
+
context: CheckoutPricingContext.BALANCE,
|
|
58
|
+
translationKey: "summary.credit",
|
|
59
|
+
},
|
|
60
|
+
...(shouldDisplayPsFeeModifier
|
|
61
|
+
? [
|
|
62
|
+
{
|
|
63
|
+
amount: pricing.service.finalPrice.amount,
|
|
64
|
+
type: CheckoutPricingType.DISCOUNT,
|
|
65
|
+
context: CheckoutPricingContext.PS_FEE,
|
|
66
|
+
translationKey: "summary.fee",
|
|
67
|
+
},
|
|
68
|
+
]
|
|
69
|
+
: []),
|
|
70
|
+
]
|
|
71
|
+
.map((modifier) => ({ ...modifier, amount: Math.abs(modifier.amount) }))
|
|
72
|
+
.filter(({ amount }) => amount !== 0);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
currency: pricing.pendingToPay.currency,
|
|
76
|
+
finalPrice: pricing.pendingToPay.amount,
|
|
77
|
+
originalPrice: pricing.subtotal.amount,
|
|
78
|
+
modifiers,
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type { PricingDto };
|
|
83
|
+
export { toPricingProjection };
|
|
@@ -33,6 +33,7 @@ interface RootProps {
|
|
|
33
33
|
readonly customer: Customer;
|
|
34
34
|
readonly layout: Layout;
|
|
35
35
|
readonly tradename: Tradename;
|
|
36
|
+
readonly migrated: boolean;
|
|
36
37
|
readonly onNotAccessible: () => void;
|
|
37
38
|
readonly onCheckoutFlowSuccess: OnCheckoutFlowSuccessFunction;
|
|
38
39
|
readonly useRedirect: () => Record<string, string>;
|
|
@@ -50,6 +51,7 @@ const root: RootFunction = ({ Messaging, queryBus, getAuthToken, development, se
|
|
|
50
51
|
customer,
|
|
51
52
|
layout,
|
|
52
53
|
tradename,
|
|
54
|
+
migrated,
|
|
53
55
|
onNotAccessible,
|
|
54
56
|
onCheckoutFlowSuccess,
|
|
55
57
|
useRedirect,
|
|
@@ -68,6 +70,7 @@ const root: RootFunction = ({ Messaging, queryBus, getAuthToken, development, se
|
|
|
68
70
|
kameleoon={kameleoon}
|
|
69
71
|
layout={layout}
|
|
70
72
|
locale={locale}
|
|
73
|
+
migrated={migrated}
|
|
71
74
|
tradename={tradename}
|
|
72
75
|
useRedirect={useRedirect}
|
|
73
76
|
useRoutes={useRoutes}
|
|
@@ -8,6 +8,7 @@ import { StaticInfoProvider, useStaticInfo as sut } from "./useStaticInfo";
|
|
|
8
8
|
const kameleoon = {} as KameleoonEnvironment;
|
|
9
9
|
const customer = { customerId: "6667283e-5f61-457e-b637-88736265b78f" } as Customer;
|
|
10
10
|
const tradename = Tradename.LOOKIERO;
|
|
11
|
+
const migrated = false;
|
|
11
12
|
const basePath = "";
|
|
12
13
|
|
|
13
14
|
interface WrapperProps {
|
|
@@ -15,7 +16,13 @@ interface WrapperProps {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
const Wrapper: FC<WrapperProps> = ({ children }) => (
|
|
18
|
-
<StaticInfoProvider
|
|
19
|
+
<StaticInfoProvider
|
|
20
|
+
basePath={basePath}
|
|
21
|
+
customer={customer}
|
|
22
|
+
kameleoon={kameleoon}
|
|
23
|
+
migrated={migrated}
|
|
24
|
+
tradename={tradename}
|
|
25
|
+
>
|
|
19
26
|
{children}
|
|
20
27
|
</StaticInfoProvider>
|
|
21
28
|
);
|
|
@@ -28,6 +35,7 @@ describe("useStaticInfo hook", () => {
|
|
|
28
35
|
kameleoon,
|
|
29
36
|
customer,
|
|
30
37
|
tradename,
|
|
38
|
+
migrated,
|
|
31
39
|
basePath,
|
|
32
40
|
};
|
|
33
41
|
|
|
@@ -8,6 +8,7 @@ interface StaticInfo {
|
|
|
8
8
|
readonly kameleoon: KameleoonEnvironment;
|
|
9
9
|
readonly customer: Customer;
|
|
10
10
|
readonly tradename: Tradename;
|
|
11
|
+
readonly migrated: boolean;
|
|
11
12
|
readonly basePath: string;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -18,18 +19,27 @@ interface StaticInfoProviderProps {
|
|
|
18
19
|
readonly kameleoon: KameleoonEnvironment;
|
|
19
20
|
readonly customer: Customer;
|
|
20
21
|
readonly tradename: Tradename;
|
|
22
|
+
readonly migrated: boolean;
|
|
21
23
|
readonly basePath: string;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
const StaticInfoProvider: FC<StaticInfoProviderProps> = ({
|
|
26
|
+
const StaticInfoProvider: FC<StaticInfoProviderProps> = ({
|
|
27
|
+
children,
|
|
28
|
+
kameleoon,
|
|
29
|
+
customer,
|
|
30
|
+
tradename,
|
|
31
|
+
migrated,
|
|
32
|
+
basePath,
|
|
33
|
+
}) => {
|
|
25
34
|
const value = useMemo(
|
|
26
35
|
() => ({
|
|
27
36
|
kameleoon,
|
|
28
37
|
customer,
|
|
29
38
|
tradename,
|
|
39
|
+
migrated,
|
|
30
40
|
basePath,
|
|
31
41
|
}),
|
|
32
|
-
[basePath, customer, kameleoon, tradename],
|
|
42
|
+
[basePath, customer, kameleoon, migrated, tradename],
|
|
33
43
|
);
|
|
34
44
|
|
|
35
45
|
return <StaticInfoContext.Provider value={value}>{children}</StaticInfoContext.Provider>;
|
|
@@ -28,6 +28,7 @@ interface RoutingProps {
|
|
|
28
28
|
readonly kameleoon: KameleoonEnvironment;
|
|
29
29
|
readonly layout: Layout;
|
|
30
30
|
readonly tradename: Tradename;
|
|
31
|
+
readonly migrated: boolean;
|
|
31
32
|
readonly getAuthToken: () => Promise<string>;
|
|
32
33
|
readonly onNotAccessible: () => void;
|
|
33
34
|
readonly onCheckoutFlowSuccess: OnCheckoutFlowSuccessFunction;
|
|
@@ -44,6 +45,7 @@ const Routing: FC<RoutingProps> = ({
|
|
|
44
45
|
kameleoon,
|
|
45
46
|
layout,
|
|
46
47
|
tradename,
|
|
48
|
+
migrated,
|
|
47
49
|
getAuthToken,
|
|
48
50
|
onI18nError,
|
|
49
51
|
onNotAccessible,
|
|
@@ -55,7 +57,13 @@ const Routing: FC<RoutingProps> = ({
|
|
|
55
57
|
{
|
|
56
58
|
path: "",
|
|
57
59
|
element: (
|
|
58
|
-
<StaticInfoProvider
|
|
60
|
+
<StaticInfoProvider
|
|
61
|
+
basePath={basePath}
|
|
62
|
+
customer={customer}
|
|
63
|
+
kameleoon={kameleoon}
|
|
64
|
+
migrated={migrated}
|
|
65
|
+
tradename={tradename}
|
|
66
|
+
>
|
|
59
67
|
<I18n loader={<Spinner />} locale={locale} onError={onI18nError}>
|
|
60
68
|
<Kameleoon loader={<Spinner />} siteCode={kameleoon.siteCode}>
|
|
61
69
|
<CheckoutMiddleware customerId={customer?.customerId as string} onNotAccessible={onNotAccessible}>
|