Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASUB-8301 OrderInformation #2048

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions blocks/subscriptions-block/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -136,24 +136,40 @@
@include scss.block-properties("checkout-payment");
}

&__test {
&-1 {
@include scss.block-components("checkout-payment-test-1");
@include scss.block-properties("checkout-payment-test-1");
&__orderCard {
&--productPrice {
@include scss.block-components("checkout-order-card-productPrice");
@include scss.block-properties("checkout-order-card-productPrice");
}

&-2 {
@include scss.block-components("checkout-payment-test-2");
@include scss.block-properties("checkout-payment-test-2");
&__card--features {
&--feature-item {
@include scss.block-components("checkout-order-card--features--item");
@include scss.block-properties("checkout-order-card--features--item");
}
@include scss.block-components("checkout-order-card--features");
@include scss.block-properties("checkout-order-card--features");
}

&-row {
@include scss.block-components("checkout-payment-test-row");
@include scss.block-properties("checkout-payment-test-row");
&__summary {
&--dueToday{
@include scss.block-components("checkout-order-card--summary--dueToday");
@include scss.block-properties("checkout-order-card--summary--dueToday");
}
&--details{
&--item{
@include scss.block-components("checkout-order-card--summary--details--item");
@include scss.block-properties("checkout-order-card--summary--details--item");
}
@include scss.block-components("checkout-order-card--summary--details");
@include scss.block-properties("checkout-order-card--summary--details");
}
@include scss.block-components("checkout-order-card--summary");
@include scss.block-properties("checkout-order-card--summary");
}

@include scss.block-components("checkout-payment-test");
@include scss.block-properties("checkout-payment-test");
@include scss.block-components("checkout-order-card");
@include scss.block-properties("checkout-order-card");
}

@include scss.block-components("checkout");
Expand Down
39 changes: 22 additions & 17 deletions blocks/subscriptions-block/components/OfferCard/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,25 @@ import React from "react";
import PropTypes from "@arc-fusion/prop-types";
import { Heading, Button, Stack, Paragraph, Icon } from "@wpmedia/arc-themes-components";

// TO-DO: Change the Icon <Icon name="ChevronRight" /> to Check <Icon name="Check"/>
export const FeatureDetails = ({ features, className }) => {
if (features.length) {
return (
<ul className={`${className}__card--features`}>
{features.map((feat) => (
<li
className={`${className}__card--features--feature-item`}
key={`feat-${feat.featureText}`}
>
<Icon name="Check" />
<span dangerouslySetInnerHTML={{ __html: feat.featureText }} />
</li>
))}
</ul>
);
}
return null;
};

const OfferCard = ({
headline,
subHeadline,
Expand All @@ -21,20 +39,7 @@ const OfferCard = ({
<span dangerouslySetInnerHTML={{ __html: actionText }} />
</Button>
) : null}

{features.length ? (
<ul className={`${className}__card--features`}>
{features.map((feat) => (
<li
className={`${className}__card--features--feature-item`}
key={`feat-${feat.featureText}`}
>
<Icon name="Check" />
<span dangerouslySetInnerHTML={{ __html: feat.featureText }} />
</li>
))}
</ul>
) : null}
<FeatureDetails features={features} className={className} />
</Stack>
);

Expand All @@ -46,8 +51,8 @@ OfferCard.propTypes = {
features: PropTypes.arrayOf(
PropTypes.shape({
featureText: PropTypes.string,
})
}),
),
};

export default OfferCard;
export default OfferCard;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { render } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import OfferCard from ".";

const props = {
Expand All @@ -24,51 +24,59 @@ describe("OfferCard", () => {

expect(screen.getByRole("button")).not.toBeNull();

const ul = getByRole("list");
expect(ul).toBeInTheDocument();
const ul = screen.getByRole("list");
expect(ul.childElementCount).toBe(2); // eslint-disable-line

expect(screen.getByText(props.features[0].featureText)).not.toBeNull();
expect(screen.getByText(props.features[1].featureText)).not.toBeNull();
const ulByClass = document.getElementsByClassName("test-block__card--features--feature-item"); // eslint-disable-line
expect(ulByClass.length).toBe(2);

expect(screen.getByText(props.features[0].featureText)).not.toBeNull(); // eslint-disable-line
expect(screen.getByText(props.features[1].featureText)).not.toBeNull(); // eslint-disable-line
});

it("does not render headline if not present", () => {
const { container } = render(
render(
<OfferCard {...props} className={BLOCK_CLASS_NAME} headline={null} />,
);

expect(container.querySelector(".b-offer__card h1")).not.toBeInTheDocument();
const headingElement = document.getElementsByClassName('.b-offer__card h1'); // eslint-disable-line
expect(headingElement.length).toBe(0)
});

it("does not render subHeadline if not present", () => {
const { container } = render(
render(
<OfferCard {...props} className={BLOCK_CLASS_NAME} subHeadline={null} />,
);

expect(container.querySelector(".b-offer__card p")).not.toBeInTheDocument();
const headingElement = document.getElementsByClassName('.b-offer__card p'); // eslint-disable-line
expect(headingElement.length).toBe(0)
});

it("does not render button if no actionText and no ActionEvent", () => {
render(<OfferCard {...props} actionText={null} actionEvent={null} />);

expect(screen.getByRole("button")).not.toBeNull();
const button = screen.queryByRole("button");
expect(button).toBeNull();
});

it("does not render button if no actionText", () => {
render(<OfferCard {...props} actionText={null} />);

expect(screen.getByRole("button")).not.toBeNull();
const button = screen.queryByRole("button");
expect(button).toBeNull();
});

it("does not render button if no actionEvent", () => {
render(<OfferCard {...props} actionEvent={null} />);

expect(screen.getByRole("button")).not.toBeNull();
const button = screen.queryByRole("button");
expect(button).toBeNull();
});

it("does not render features", () => {
const { container } = render(<OfferCard className={BLOCK_CLASS_NAME} headline="Headline" />);
render(<OfferCard className={BLOCK_CLASS_NAME} headline="Headline" />);

const features = expect(container.querySelector(".b-offer__card--features li"));
expect(features.length).toBe(0);
const ulByClass = document.getElementsByClassName("test-block__card--features--feature-item"); // eslint-disable-line
expect(ulByClass.length).toBe(0);
});
});
22 changes: 15 additions & 7 deletions blocks/subscriptions-block/components/OfferToProductList/index.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React from "react";
import PropTypes from "@arc-fusion/prop-types";
import useSales from "../useSales";
import { Grid } from "@wpmedia/arc-themes-components";
import useSales from "../useSales";
import OfferCard from "../OfferCard";

export const ARCXP_CART = 'ArcXP_cart';
export const ARCXP_CAMPAIGN = 'ArcXP_campaignName';

const OfferToProductList = ({ offer, isLoggedIn, checkoutURL, loginURL, className }) => {
const { Sales } = useSales();

Expand All @@ -21,7 +24,7 @@ const OfferToProductList = ({ offer, isLoggedIn, checkoutURL, loginURL, classNam
products[productIdx].attributes.length !== 0
? products[productIdx].attributes.map((feature) => ({
featureText: feature.value,
}))
}))
: [];
const { sku } = products[productIdx];
const { priceCode } = strategies[strategiesIdx];
Expand All @@ -32,21 +35,26 @@ const OfferToProductList = ({ offer, isLoggedIn, checkoutURL, loginURL, classNam
actionText: strategies[strategiesIdx].summary,
actionEvent: () => {
Sales.clearCart()
.then(() =>
.then(() => {
Sales.addItemToCart([
{
sku,
priceCode,
quantity: 1,
},
])
)
]);
const allValidUntil = offer?.campaigns?.map(c => c.validUntil !== undefined && !Number.isNaN(c.validUntil));
const maxEndDate = allValidUntil.length ? Math.max(allValidUntil) : null;
const liveCampaing = offer?.campaigns?.find(c => c.validUntil === null || c.validUntil === maxEndDate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo liveCampaign

localStorage.setItem(ARCXP_CAMPAIGN, liveCampaing?.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ticket says save the offer campaign, in session storage ArcXP_campaignName. Do we want to store in localStorage?

Copy link
Contributor Author

@LauraPinilla LauraPinilla Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@edwardcho1231 yes, by default we are using rememberMe true for login or signUp, for this reason, we need to save this info on localStorage. Thus, if the user opens a new page, the info is available

})
.then(() => {
if (isLoggedIn) {
window.location.href = checkoutURL;
return;
}
window.location.href = `${loginURL}?redirect=${checkoutURL}`;
localStorage.setItem(ARCXP_CART, JSON.stringify({sku, priceCode}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

window.location.href = `${loginURL}&redirect=${checkoutURL}`;
});
},
features,
Expand Down Expand Up @@ -75,7 +83,7 @@ const OfferToProductList = ({ offer, isLoggedIn, checkoutURL, loginURL, classNam
className={className}
/>
))}
</Grid>
</Grid>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { act, render } from "@testing-library/react";
import {render, waitFor } from "@testing-library/react";
import OfferToProductList from "./index";
import useOffer from "../useOffer";
import OfferCard from "../OfferCard";
Expand Down Expand Up @@ -177,31 +177,34 @@ jest.mock("fusion:properties", () =>
script: "https://corecomponents-the-gazette-prod.cdn.arcpublishing.com/arc/subs/p.min.js",
},
},
}))
})),
);

jest.mock("../OfferCard", () =>
(jest.fn(() => null))
);

jest.mock("@arc-publishing/sdk-sales");
jest.mock("../../components/useOffer");

useOffer.mockReturnValue({
offer: sampleOffer,
fetchOffer: () => sampleOffer,
});

describe("The OfferToProductList component", () => {
it("renders the correct number of offer cards", () => {
const { container } = render(
it("renders the correct number of offer cards", async () => {
render(
<OfferToProductList
isLoggedIn
loginURL="/login/"
checkoutURL="/checkout/"
offer={sampleOffer}
/>
/>,
);

act(() => {
container.setProps({});
});
const mockedChildComponent = OfferCard;

expect(container.find(OfferCard)).toHaveLength(4);
await waitFor(() => expect(mockedChildComponent).toHaveBeenCalledTimes(4));
});
});
});
87 changes: 87 additions & 0 deletions blocks/subscriptions-block/components/OrderInformation/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from "react";

import { usePhrases, Link, Heading, Paragraph, Stack } from "@wpmedia/arc-themes-components";
import { FeatureDetails } from "../OfferCard";
import currency from "../../utils/currency";

const OrderSummary = ({ orderDetails, className }) => {
const phrases = usePhrases();

return (
<Stack className={`${className}__summary`}>
<Heading>{phrases.t("checkout-block.order-summary")}</Heading>
<Stack className={`${className}__summary--details`}>
<Stack direction="horizontal" justification="space-between" className={`${className}__summary--details--item`}>
<p>{phrases.t("checkout-block.subtotal")}</p>
<p>{`${currency(orderDetails?.currency)}${orderDetails?.subtotal}`}</p>
</Stack>
<Stack direction="horizontal" justification="space-between" className={`${className}__summary--details--item`}>
<p>{phrases.t("checkout-block.salesTax")}</p>
<p>
{orderDetails?.tax > 0
? `${currency(orderDetails?.currency)}${orderDetails?.tax}`
: "--"}
</p>
</Stack>
</Stack>
<div className={`${className}__summary--dueToday`}>
<p>{phrases.t("checkout-block.due-today")}</p>
<p>{`${currency(orderDetails?.currency)}${orderDetails?.total}`}</p>
</div>
</Stack>
);
};

const ProductPriceDetails = ({
details = [],
showPriceDescription,
showProductFeatures,
className,
}) => {
if (details?.items?.length) {
return details?.items?.map((item) =>
<Stack as="div" className={`${className}__orderCard--productPrice`}>
<Heading> {item.priceName}</Heading>
{showPriceDescription && (
<Paragraph dangerouslySetInnerHTML={{ __html: item?.priceDescription }} />
)}
{showProductFeatures && (
<FeatureDetails
features={item?.productAttributes}
className={`${className}__orderCard`}
/>
)}
</Stack>
);
}
return null;
};

const OrderInformation = ({
id,
offerURL,
showOfferURL,
showPriceDescription,
showProductFeatures,
orderDetails,
className,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ticket mentions passing
b. paymentType: ‘stripeIntents’ || ‘paypal’ || undefined
c. campaignName
Do we no longer needs these passed to OrderInformation component?

}) => {
const phrases = usePhrases();

return (
<section key={`orderInfo${id && `-${id}`}`} className={`${className}__orderCard`}>
<ProductPriceDetails
details={orderDetails}
showPriceDescription={showPriceDescription}
showProductFeatures={showProductFeatures}
className={className}
/>
{showOfferURL && (
<Link href={offerURL}>{phrases.t("checkout-block.view-subscription-offers")}</Link>
)}
<OrderSummary orderDetails={orderDetails} className={`${className}__orderCard`} />
</section>
);
};

export default OrderInformation;
Loading
Loading