richie-education 3.1.3-dev23 → 3.1.3-dev24
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/.storybook/__mocks__/utils/context.ts +4 -0
- package/js/components/SaleTunnel/GenericSaleTunnel.tsx +11 -1
- package/js/components/SaleTunnel/SaleTunnelInformation/index.tsx +6 -6
- package/js/components/SaleTunnel/index.spec.tsx +55 -1
- package/js/components/SaleTunnel/index.stories.tsx +17 -2
- package/package.json +1 -1
|
@@ -10,7 +10,15 @@ import {
|
|
|
10
10
|
} from 'react';
|
|
11
11
|
import { SaleTunnelSponsors } from 'components/SaleTunnel/Sponsors/SaleTunnelSponsors';
|
|
12
12
|
import { SaleTunnelProps } from 'components/SaleTunnel/index';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
Address,
|
|
15
|
+
Enrollment,
|
|
16
|
+
Offering,
|
|
17
|
+
CreditCard,
|
|
18
|
+
Order,
|
|
19
|
+
OrderState,
|
|
20
|
+
Product,
|
|
21
|
+
} from 'types/Joanie';
|
|
14
22
|
import useProductOrder from 'hooks/useProductOrder';
|
|
15
23
|
import { SaleTunnelSuccess } from 'components/SaleTunnel/SaleTunnelSuccess';
|
|
16
24
|
import WebAnalyticsAPIHandler from 'api/web-analytics';
|
|
@@ -27,6 +35,7 @@ export interface SaleTunnelContextType {
|
|
|
27
35
|
product: Product;
|
|
28
36
|
webAnalyticsEventKey: string;
|
|
29
37
|
offering?: Offering;
|
|
38
|
+
enrollment?: Enrollment;
|
|
30
39
|
|
|
31
40
|
// internal
|
|
32
41
|
step: SaleTunnelStep;
|
|
@@ -115,6 +124,7 @@ export const GenericSaleTunnel = (props: GenericSaleTunnelProps) => {
|
|
|
115
124
|
order,
|
|
116
125
|
product: props.product,
|
|
117
126
|
offering: props.offering,
|
|
127
|
+
enrollment: props.enrollment,
|
|
118
128
|
props,
|
|
119
129
|
billingAddress,
|
|
120
130
|
setBillingAddress,
|
|
@@ -101,7 +101,11 @@ const Email = () => {
|
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
const Total = () => {
|
|
104
|
-
const { product, offering } = useSaleTunnelContext();
|
|
104
|
+
const { product, offering, enrollment } = useSaleTunnelContext();
|
|
105
|
+
const totalPrice =
|
|
106
|
+
enrollment?.offerings?.[0]?.rules?.discounted_price ??
|
|
107
|
+
offering?.rules.discounted_price ??
|
|
108
|
+
product.price;
|
|
105
109
|
return (
|
|
106
110
|
<div className="sale-tunnel__total">
|
|
107
111
|
<div className="sale-tunnel__total__amount mt-t" data-testid="sale-tunnel__total__amount">
|
|
@@ -109,11 +113,7 @@ const Total = () => {
|
|
|
109
113
|
<FormattedMessage {...messages.totalLabel} />
|
|
110
114
|
</div>
|
|
111
115
|
<div className="block-title">
|
|
112
|
-
<FormattedNumber
|
|
113
|
-
value={offering?.rules.discounted_price || product.price}
|
|
114
|
-
style="currency"
|
|
115
|
-
currency={product.price_currency}
|
|
116
|
-
/>
|
|
116
|
+
<FormattedNumber value={totalPrice} style="currency" currency={product.price_currency} />
|
|
117
117
|
</div>
|
|
118
118
|
</div>
|
|
119
119
|
</div>
|
|
@@ -8,6 +8,7 @@ import { useState } from 'react';
|
|
|
8
8
|
import { OrderState, Product, ProductType, NOT_CANCELED_ORDER_STATES } from 'types/Joanie';
|
|
9
9
|
import {
|
|
10
10
|
RichieContextFactory as mockRichieContextFactory,
|
|
11
|
+
CourseStateFactory,
|
|
11
12
|
UserFactory,
|
|
12
13
|
PacedCourseFactory,
|
|
13
14
|
} from 'utils/test/factories/richie';
|
|
@@ -16,12 +17,14 @@ import {
|
|
|
16
17
|
CertificateOrderFactory,
|
|
17
18
|
CertificateProductFactory,
|
|
18
19
|
OfferingFactory,
|
|
20
|
+
CourseRunFactory,
|
|
19
21
|
CredentialOrderFactory,
|
|
20
22
|
CredentialProductFactory,
|
|
21
23
|
CreditCardFactory,
|
|
22
24
|
EnrollmentFactory,
|
|
23
25
|
PaymentInstallmentFactory,
|
|
24
26
|
} from 'utils/test/factories/joanie';
|
|
27
|
+
import { Priority } from 'types';
|
|
25
28
|
import { render } from 'utils/test/render';
|
|
26
29
|
import { SaleTunnel, SaleTunnelProps } from 'components/SaleTunnel/index';
|
|
27
30
|
import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
|
|
@@ -97,7 +100,7 @@ describe.each([
|
|
|
97
100
|
return (
|
|
98
101
|
<SaleTunnel
|
|
99
102
|
{...props}
|
|
100
|
-
enrollment={enrollment}
|
|
103
|
+
enrollment={props.enrollment ?? enrollment}
|
|
101
104
|
course={productType === ProductType.CREDENTIAL ? course : undefined}
|
|
102
105
|
isOpen={open}
|
|
103
106
|
onClose={() => setOpen(false)}
|
|
@@ -449,6 +452,57 @@ describe.each([
|
|
|
449
452
|
);
|
|
450
453
|
});
|
|
451
454
|
|
|
455
|
+
// Fixes the issue : https://github.com/openfun/richie/issues/2645
|
|
456
|
+
it('should show the certificate product total with discounted price', async () => {
|
|
457
|
+
const product = ProductFactory({
|
|
458
|
+
price: 600,
|
|
459
|
+
target_courses: [course],
|
|
460
|
+
}).one();
|
|
461
|
+
const enrollmentDiscounted = EnrollmentFactory({
|
|
462
|
+
course_run: CourseRunFactory({
|
|
463
|
+
state: CourseStateFactory({ priority: Priority.ONGOING_OPEN }).one(),
|
|
464
|
+
course,
|
|
465
|
+
}).one(),
|
|
466
|
+
offerings: [
|
|
467
|
+
OfferingFactory({
|
|
468
|
+
product,
|
|
469
|
+
rules: {
|
|
470
|
+
discounted_price: 540,
|
|
471
|
+
discount_rate: 0.1,
|
|
472
|
+
},
|
|
473
|
+
}).one(),
|
|
474
|
+
],
|
|
475
|
+
}).one();
|
|
476
|
+
|
|
477
|
+
if (product.type === ProductType.CERTIFICATE) {
|
|
478
|
+
enrollmentDiscounted.offerings[0].product = product;
|
|
479
|
+
|
|
480
|
+
fetchMock.get(
|
|
481
|
+
`https://joanie.endpoint/api/v1.0/orders/?enrollment_id=${enrollmentDiscounted.id}&product_id=${product.id}&state=pending&state=pending_payment&state=no_payment&state=failed_payment&state=completed&state=draft&state=assigned&state=to_sign&state=signing&state=to_save_payment_method`,
|
|
482
|
+
{
|
|
483
|
+
results: [],
|
|
484
|
+
next: null,
|
|
485
|
+
previous: null,
|
|
486
|
+
count: 0,
|
|
487
|
+
},
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
render(
|
|
491
|
+
<Wrapper product={product} enrollment={enrollmentDiscounted} isWithdrawable={true} />,
|
|
492
|
+
{ queryOptions: { client: createTestQueryClient({ user: richieUser }) } },
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
const $totalAmount = screen.getByTestId('sale-tunnel__total__amount');
|
|
496
|
+
expect($totalAmount).toHaveTextContent(
|
|
497
|
+
'Total' +
|
|
498
|
+
formatPrice(
|
|
499
|
+
enrollmentDiscounted.offerings[0].rules.discounted_price!,
|
|
500
|
+
product.price_currency,
|
|
501
|
+
).replace(/(\u202F|\u00a0)/g, ' '),
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
|
|
452
506
|
it('should show the product payment schedule with discounted price', async () => {
|
|
453
507
|
const intl = createIntl({ locale: 'en' });
|
|
454
508
|
const schedule = PaymentInstallmentFactory().many(2);
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { StoryObj, Meta } from '@storybook/react';
|
|
2
2
|
import { BaseJoanieAppWrapper } from 'utils/test/wrappers/BaseJoanieAppWrapper';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CertificateProductFactory,
|
|
5
|
+
EnrollmentFactory,
|
|
6
|
+
OfferingFactory,
|
|
7
|
+
ProductFactory,
|
|
8
|
+
} from 'utils/test/factories/joanie';
|
|
4
9
|
import { PacedCourseFactory } from 'utils/test/factories/richie';
|
|
5
10
|
import { SaleTunnel, SaleTunnelProps } from './index';
|
|
6
11
|
|
|
@@ -28,6 +33,16 @@ export default {
|
|
|
28
33
|
|
|
29
34
|
type Story = StoryObj<typeof SaleTunnel>;
|
|
30
35
|
|
|
31
|
-
export const
|
|
36
|
+
export const Credential: Story = {
|
|
32
37
|
args: {},
|
|
33
38
|
};
|
|
39
|
+
|
|
40
|
+
export const CertificateDiscount: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
product: CertificateProductFactory({ price: 100, price_currency: 'EUR' }).one(),
|
|
43
|
+
course: PacedCourseFactory().one(),
|
|
44
|
+
enrollment: EnrollmentFactory({
|
|
45
|
+
offerings: OfferingFactory({ rules: { discounted_price: 80 } }).many(1),
|
|
46
|
+
}).one(),
|
|
47
|
+
},
|
|
48
|
+
};
|