richie-education 3.2.0 → 3.2.1-dev3
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/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +1 -1
- package/js/components/SaleTunnel/index.spec.tsx +2 -2
- package/js/types/Joanie.ts +1 -1
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/CourseProductItemFooter/index.tsx +2 -2
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +37 -2
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.tsx +4 -4
- package/package.json +1 -1
|
@@ -104,7 +104,7 @@ const Total = () => {
|
|
|
104
104
|
const { product, offering, enrollment } = useSaleTunnelContext();
|
|
105
105
|
const totalPrice =
|
|
106
106
|
enrollment?.offerings?.[0]?.rules?.discounted_price ??
|
|
107
|
-
offering?.rules
|
|
107
|
+
offering?.rules?.discounted_price ??
|
|
108
108
|
product.price;
|
|
109
109
|
return (
|
|
110
110
|
<div className="sale-tunnel__total">
|
|
@@ -496,7 +496,7 @@ describe.each([
|
|
|
496
496
|
expect($totalAmount).toHaveTextContent(
|
|
497
497
|
'Total' +
|
|
498
498
|
formatPrice(
|
|
499
|
-
enrollmentDiscounted.offerings[0].rules
|
|
499
|
+
enrollmentDiscounted.offerings[0].rules?.discounted_price!,
|
|
500
500
|
product.price_currency,
|
|
501
501
|
).replace(/(\u202F|\u00a0)/g, ' '),
|
|
502
502
|
);
|
|
@@ -569,7 +569,7 @@ describe.each([
|
|
|
569
569
|
const $totalAmount = screen.getByTestId('sale-tunnel__total__amount');
|
|
570
570
|
expect($totalAmount).toHaveTextContent(
|
|
571
571
|
'Total' +
|
|
572
|
-
formatPrice(offering!.rules
|
|
572
|
+
formatPrice(offering!.rules!.discounted_price!, product.price_currency).replace(
|
|
573
573
|
/(\u202F|\u00a0)/g,
|
|
574
574
|
' ',
|
|
575
575
|
),
|
package/js/types/Joanie.ts
CHANGED
|
@@ -200,7 +200,7 @@ export interface OfferingRule {
|
|
|
200
200
|
|
|
201
201
|
export interface Offering extends OfferingLight {
|
|
202
202
|
is_withdrawable: boolean;
|
|
203
|
-
rules
|
|
203
|
+
rules?: OfferingRule;
|
|
204
204
|
}
|
|
205
205
|
export function isOffering(
|
|
206
206
|
entity: CourseListItem | OfferingLight | RichieCourse,
|
|
@@ -33,7 +33,7 @@ const CourseProductItemFooter = ({
|
|
|
33
33
|
offering,
|
|
34
34
|
canPurchase,
|
|
35
35
|
}: CourseProductItemFooterProps) => {
|
|
36
|
-
if (!offering
|
|
36
|
+
if (!offering?.rules?.has_seats_left)
|
|
37
37
|
return (
|
|
38
38
|
<p className="product-widget__footer__message">
|
|
39
39
|
<FormattedMessage {...messages.noSeatsAvailable} />
|
|
@@ -50,7 +50,7 @@ const CourseProductItemFooter = ({
|
|
|
50
50
|
disabled={!canPurchase}
|
|
51
51
|
buttonProps={{ fullWidth: true }}
|
|
52
52
|
/>
|
|
53
|
-
{offering
|
|
53
|
+
{offering?.rules?.has_seat_limit && (
|
|
54
54
|
<p className="product-widget__footer__message">
|
|
55
55
|
<FormattedMessage
|
|
56
56
|
{...messages.nbSeatsAvailable}
|
|
@@ -194,7 +194,7 @@ describe('CourseProductItem', () => {
|
|
|
194
194
|
const discountedPriceLabel = screen.getByText('Discounted price:');
|
|
195
195
|
expect(discountedPriceLabel.classList.contains('offscreen')).toBe(true);
|
|
196
196
|
const discountedPrice = screen.getByText(
|
|
197
|
-
priceFormatter(product.price_currency, offering.rules
|
|
197
|
+
priceFormatter(product.price_currency, offering.rules!.discounted_price!).replace(
|
|
198
198
|
/(\u202F|\u00a0)/g,
|
|
199
199
|
' ',
|
|
200
200
|
),
|
|
@@ -257,7 +257,7 @@ describe('CourseProductItem', () => {
|
|
|
257
257
|
const discountedPriceLabel = screen.getByText('Discounted price:');
|
|
258
258
|
expect(discountedPriceLabel.classList.contains('offscreen')).toBe(true);
|
|
259
259
|
const discountedPrice = screen.getByText(
|
|
260
|
-
priceFormatter(product.price_currency, offering.rules
|
|
260
|
+
priceFormatter(product.price_currency, offering.rules!.discounted_price!).replace(
|
|
261
261
|
/(\u202F|\u00a0)/g,
|
|
262
262
|
' ',
|
|
263
263
|
),
|
|
@@ -838,4 +838,39 @@ describe('CourseProductItem', () => {
|
|
|
838
838
|
expect(screen.queryByRole('button', { name: product.call_to_action })).not.toBeInTheDocument();
|
|
839
839
|
screen.getByText('Sorry, no seats available for now');
|
|
840
840
|
});
|
|
841
|
+
|
|
842
|
+
it('renders product information without rules in offering', async () => {
|
|
843
|
+
const offering = OfferingFactory({
|
|
844
|
+
product: CredentialProductFactory({
|
|
845
|
+
price: 840,
|
|
846
|
+
price_currency: 'EUR',
|
|
847
|
+
}).one(),
|
|
848
|
+
rules: undefined,
|
|
849
|
+
}).one();
|
|
850
|
+
const { product } = offering;
|
|
851
|
+
fetchMock.get(
|
|
852
|
+
`https://joanie.endpoint/api/v1.0/courses/00000/products/${product.id}/`,
|
|
853
|
+
offering,
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
render(
|
|
857
|
+
<CourseProductItem
|
|
858
|
+
course={PacedCourseFactory({ code: '00000' }).one()}
|
|
859
|
+
productId={product.id}
|
|
860
|
+
/>,
|
|
861
|
+
{ queryOptions: { client: createTestQueryClient({ user: null }) } },
|
|
862
|
+
);
|
|
863
|
+
|
|
864
|
+
// Wait for product information to be fetched
|
|
865
|
+
await screen.findByRole('heading', { level: 3, name: product.title });
|
|
866
|
+
|
|
867
|
+
// Expect to render the component without rules information
|
|
868
|
+
expect(
|
|
869
|
+
screen.getByText(
|
|
870
|
+
priceFormatter(product.price_currency, product.price).replace(/(\u202F|\u00a0)/g, ' '),
|
|
871
|
+
),
|
|
872
|
+
).toBeInTheDocument();
|
|
873
|
+
expect(document.querySelector('.product-widget__price-discounted')).not.toBeInTheDocument();
|
|
874
|
+
expect(screen.getByText('Sorry, no seats available for now')).toBeInTheDocument();
|
|
875
|
+
});
|
|
841
876
|
});
|
|
@@ -103,7 +103,7 @@ const Header = ({ product, order, offering, hasPurchased, canPurchase, compact }
|
|
|
103
103
|
return null;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (offering
|
|
106
|
+
if (offering?.rules?.discounted_price != null) {
|
|
107
107
|
return (
|
|
108
108
|
<>
|
|
109
109
|
<span id="original-price" className="offscreen">
|
|
@@ -133,7 +133,7 @@ const Header = ({ product, order, offering, hasPurchased, canPurchase, compact }
|
|
|
133
133
|
return (
|
|
134
134
|
<FormattedNumber currency={product.price_currency} value={product.price} style="currency" />
|
|
135
135
|
);
|
|
136
|
-
}, [canPurchase, offering
|
|
136
|
+
}, [canPurchase, offering?.rules?.discounted_price, product.price]);
|
|
137
137
|
|
|
138
138
|
return (
|
|
139
139
|
<header className="product-widget__header">
|
|
@@ -144,10 +144,10 @@ const Header = ({ product, order, offering, hasPurchased, canPurchase, compact }
|
|
|
144
144
|
{hasPurchased && <FormattedMessage {...messages.purchased} />}
|
|
145
145
|
{displayPrice}
|
|
146
146
|
</strong>
|
|
147
|
-
{offering?.rules
|
|
147
|
+
{offering?.rules?.description && (
|
|
148
148
|
<p className="product-widget__header-description">{offering.rules.description}</p>
|
|
149
149
|
)}
|
|
150
|
-
{offering?.rules
|
|
150
|
+
{offering?.rules?.discounted_price && (
|
|
151
151
|
<p className="product-widget__header-discount">
|
|
152
152
|
{offering.rules.discount_rate ? (
|
|
153
153
|
<span className="product-widget__header-discount-rate">
|