richie-education 3.1.3-dev24 → 3.1.3-dev28
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/CourseGlimpse/CourseGlimpseFooter.tsx +30 -5
- package/js/components/CourseGlimpse/index.spec.tsx +16 -0
- package/js/components/CourseGlimpse/index.stories.tsx +75 -4
- package/js/components/CourseGlimpse/index.tsx +2 -0
- package/js/components/CourseGlimpse/utils.ts +6 -0
- package/js/types/Course.ts +2 -0
- package/js/types/Joanie.ts +2 -0
- package/js/types/index.ts +2 -0
- package/js/utils/test/factories/joanie.ts +2 -0
- package/js/utils/test/factories/richie.ts +4 -0
- package/js/widgets/SyllabusCourseRunsList/components/SyllabusCourseRun/index.stories.tsx +81 -0
- package/js/widgets/SyllabusCourseRunsList/components/SyllabusCourseRun/index.tsx +14 -0
- package/js/widgets/SyllabusCourseRunsList/components/SyllabusCourseRunCompacted/index.tsx +14 -0
- package/js/widgets/SyllabusCourseRunsList/index.spec.tsx +46 -0
- package/package.json +1 -1
- package/scss/objects/_course_glimpses.scss +15 -0
|
@@ -65,6 +65,35 @@ export const CourseGlimpseFooter: React.FC<{ course: CourseGlimpseCourse } & Com
|
|
|
65
65
|
const offerIcon = `icon-offer-${offer}` as OfferIconType;
|
|
66
66
|
const offerCertificateIcon = hasCertificateOffer && IconTypeEnum.SCHOOL;
|
|
67
67
|
const offerPrice = hasEnrollmentOffer && course.price;
|
|
68
|
+
const discountedPrice = course.discounted_price ?? null;
|
|
69
|
+
const hasDiscount = discountedPrice !== null;
|
|
70
|
+
|
|
71
|
+
let $price = null;
|
|
72
|
+
|
|
73
|
+
if (offerPrice) {
|
|
74
|
+
if (hasDiscount) {
|
|
75
|
+
$price = (
|
|
76
|
+
<div className="offer_prices">
|
|
77
|
+
<span className="offer__price offer__price--striked">
|
|
78
|
+
<FormattedNumber value={offerPrice} currency={course.price_currency} style="currency" />
|
|
79
|
+
</span>
|
|
80
|
+
<span className="offer__price offer__price--discounted">
|
|
81
|
+
<FormattedNumber
|
|
82
|
+
value={discountedPrice}
|
|
83
|
+
currency={course.price_currency}
|
|
84
|
+
style="currency"
|
|
85
|
+
/>
|
|
86
|
+
</span>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
} else {
|
|
90
|
+
$price = (
|
|
91
|
+
<span className="offer__price">
|
|
92
|
+
<FormattedNumber value={offerPrice} currency={course.price_currency} style="currency" />
|
|
93
|
+
</span>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
68
97
|
|
|
69
98
|
return (
|
|
70
99
|
<div className="course-glimpse-footer">
|
|
@@ -99,11 +128,7 @@ export const CourseGlimpseFooter: React.FC<{ course: CourseGlimpseCourse } & Com
|
|
|
99
128
|
name={offerIcon}
|
|
100
129
|
title={intl.formatMessage(courseOfferMessages[offer])}
|
|
101
130
|
/>
|
|
102
|
-
{
|
|
103
|
-
<span className="offer__price">
|
|
104
|
-
<FormattedNumber value={offerPrice} currency={course.price_currency} style="currency" />
|
|
105
|
-
</span>
|
|
106
|
-
)}
|
|
131
|
+
{$price}
|
|
107
132
|
</div>
|
|
108
133
|
</div>
|
|
109
134
|
);
|
|
@@ -61,6 +61,8 @@ describe('widgets/Search/components/CourseGlimpse', () => {
|
|
|
61
61
|
price_currency: 'EUR',
|
|
62
62
|
discounted_price: null,
|
|
63
63
|
discount: null,
|
|
64
|
+
certificate_discounted_price: null,
|
|
65
|
+
certificate_discount: null,
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
const contextProps: CommonDataProps['context'] = RichieContextFactory().one();
|
|
@@ -170,6 +172,20 @@ describe('widgets/Search/components/CourseGlimpse', () => {
|
|
|
170
172
|
);
|
|
171
173
|
});
|
|
172
174
|
|
|
175
|
+
it('renders a course glimpse with a discount', () => {
|
|
176
|
+
const { container } = renderCourseGlimpse({
|
|
177
|
+
contextProps,
|
|
178
|
+
course: { ...course, price: 100.0, discount: '30%', discounted_price: 70.0 },
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const prices = container.getElementsByClassName('offer_prices');
|
|
182
|
+
expect(prices.length).toBe(1);
|
|
183
|
+
expect(prices[0].children.length).toBe(2);
|
|
184
|
+
const discountedPrice = container.getElementsByClassName('offer__price--discounted');
|
|
185
|
+
expect(discountedPrice.length).toBe(1);
|
|
186
|
+
expect(discountedPrice[0]).toHaveTextContent('€70.00');
|
|
187
|
+
});
|
|
188
|
+
|
|
173
189
|
it('does not show certificate offer if the course does not offer a certificate', () => {
|
|
174
190
|
const { container } = renderCourseGlimpse({
|
|
175
191
|
contextProps,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { CourseLightFactory, RichieContextFactory } from 'utils/test/factories/richie';
|
|
3
|
+
import { CourseGlimpse, getCourseGlimpseProps } from 'components/CourseGlimpse';
|
|
4
|
+
import { CourseCertificateOffer, CourseOffer } from 'types/Course';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
component: CourseGlimpse,
|
|
@@ -8,9 +9,79 @@ export default {
|
|
|
8
9
|
|
|
9
10
|
type Story = StoryObj<typeof CourseGlimpse>;
|
|
10
11
|
|
|
12
|
+
const richieContext = RichieContextFactory().one();
|
|
13
|
+
const courseLight = CourseLightFactory().one();
|
|
14
|
+
const courseGlimpseCourse = getCourseGlimpseProps(courseLight);
|
|
15
|
+
|
|
11
16
|
export const RichieCourse: Story = {
|
|
12
17
|
args: {
|
|
13
|
-
context:
|
|
14
|
-
course:
|
|
18
|
+
context: richieContext,
|
|
19
|
+
course: { ...courseGlimpseCourse },
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const certificateProduct: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
context: richieContext,
|
|
26
|
+
course: {
|
|
27
|
+
...courseGlimpseCourse,
|
|
28
|
+
title: 'Certificate Product',
|
|
29
|
+
offer: CourseOffer.FREE,
|
|
30
|
+
price: null,
|
|
31
|
+
certificate_offer: CourseCertificateOffer.PAID,
|
|
32
|
+
certificate_price: 100,
|
|
33
|
+
discounted_price: null,
|
|
34
|
+
discount: null,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const certificateProductDiscount: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
context: richieContext,
|
|
42
|
+
course: {
|
|
43
|
+
...courseGlimpseCourse,
|
|
44
|
+
title: 'Certificate Product with Discount',
|
|
45
|
+
offer: CourseOffer.FREE,
|
|
46
|
+
price: null,
|
|
47
|
+
certificate_offer: CourseCertificateOffer.PAID,
|
|
48
|
+
certificate_price: 100,
|
|
49
|
+
discounted_price: 80,
|
|
50
|
+
discount: '-20 €',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const credentialProduct: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
context: richieContext,
|
|
58
|
+
course: {
|
|
59
|
+
...courseGlimpseCourse,
|
|
60
|
+
title: 'Credential Product',
|
|
61
|
+
icon: null,
|
|
62
|
+
offer: CourseOffer.PAID,
|
|
63
|
+
price: 100,
|
|
64
|
+
certificate_offer: null,
|
|
65
|
+
certificate_price: null,
|
|
66
|
+
discounted_price: null,
|
|
67
|
+
discount: null,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const credentialProductDiscount: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
context: richieContext,
|
|
75
|
+
course: {
|
|
76
|
+
...courseGlimpseCourse,
|
|
77
|
+
title: 'Credential Product with Discount',
|
|
78
|
+
icon: null,
|
|
79
|
+
offer: CourseOffer.PAID,
|
|
80
|
+
price: 100,
|
|
81
|
+
certificate_offer: null,
|
|
82
|
+
certificate_price: null,
|
|
83
|
+
discounted_price: 80,
|
|
84
|
+
discount: '-20 €',
|
|
85
|
+
},
|
|
15
86
|
},
|
|
16
87
|
};
|
|
@@ -49,6 +49,8 @@ export interface CourseGlimpseCourse {
|
|
|
49
49
|
price_currency: string;
|
|
50
50
|
discounted_price: Nullable<number>;
|
|
51
51
|
discount: Nullable<string>;
|
|
52
|
+
certificate_discounted_price: Nullable<number>;
|
|
53
|
+
certificate_discount: Nullable<string>;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
export interface CourseGlimpseProps {
|
|
@@ -55,6 +55,8 @@ const getCourseGlimpsePropsFromOffering = (
|
|
|
55
55
|
price_currency: offering.product.price_currency,
|
|
56
56
|
discounted_price: offering.product.discounted_price || null,
|
|
57
57
|
discount: offering.product.discount || null,
|
|
58
|
+
certificate_discounted_price: offering.product.certificate_discounted_price || null,
|
|
59
|
+
certificate_discount: offering.product.certificate_discount || null,
|
|
58
60
|
};
|
|
59
61
|
};
|
|
60
62
|
|
|
@@ -79,6 +81,8 @@ const getCourseGlimpsePropsFromRichieCourse = (course: RichieCourse): CourseGlim
|
|
|
79
81
|
certificate_offer: course.certificate_offer,
|
|
80
82
|
offer: course.offer,
|
|
81
83
|
certificate_price: course.certificate_price,
|
|
84
|
+
certificate_discounted_price: course.certificate_discounted_price,
|
|
85
|
+
certificate_discount: course.certificate_discount,
|
|
82
86
|
discounted_price: course.discounted_price,
|
|
83
87
|
discount: course.discount,
|
|
84
88
|
});
|
|
@@ -120,6 +124,8 @@ const getCourseGlimpsePropsFromJoanieCourse = (
|
|
|
120
124
|
certificate_price: null,
|
|
121
125
|
discounted_price: null,
|
|
122
126
|
discount: null,
|
|
127
|
+
certificate_discounted_price: null,
|
|
128
|
+
certificate_discount: null,
|
|
123
129
|
};
|
|
124
130
|
};
|
|
125
131
|
|
package/js/types/Course.ts
CHANGED
|
@@ -49,6 +49,8 @@ export interface Course extends Resource {
|
|
|
49
49
|
price_currency: string;
|
|
50
50
|
discounted_price: Nullable<number>;
|
|
51
51
|
discount: Nullable<string>;
|
|
52
|
+
certificate_discounted_price: Nullable<number>;
|
|
53
|
+
certificate_discount: Nullable<string>;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
export function isRichieCourse(course: Course | JoanieCourse): course is Course {
|
package/js/types/Joanie.ts
CHANGED
|
@@ -151,6 +151,8 @@ export interface Product {
|
|
|
151
151
|
contract_definition?: ContractDefinition;
|
|
152
152
|
discounted_price: Nullable<number>;
|
|
153
153
|
discount: Nullable<string>;
|
|
154
|
+
certificate_discounted_price: Nullable<number>;
|
|
155
|
+
certificate_discount: Nullable<string>;
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
export interface CredentialProduct extends Product {
|
package/js/types/index.ts
CHANGED
|
@@ -85,6 +85,8 @@ export const CourseRunFactory = factory<CourseRun>(() => {
|
|
|
85
85
|
certificate_offer: certificateOffer,
|
|
86
86
|
discounted_price: null,
|
|
87
87
|
discount: null,
|
|
88
|
+
certificate_discounted_price: null,
|
|
89
|
+
certificate_discount: null,
|
|
88
90
|
};
|
|
89
91
|
});
|
|
90
92
|
|
|
@@ -248,5 +250,7 @@ export const CourseLightFactory = factory<Course>(() => {
|
|
|
248
250
|
price_currency: 'EUR',
|
|
249
251
|
discounted_price: null,
|
|
250
252
|
discount: null,
|
|
253
|
+
certificate_discounted_price: null,
|
|
254
|
+
certificate_discount: null,
|
|
251
255
|
};
|
|
252
256
|
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { CourseRunFactory, PacedCourseFactory } from 'utils/test/factories/richie';
|
|
3
|
+
import { StorybookHelper } from 'utils/StorybookHelper';
|
|
4
|
+
import { CourseCertificateOffer, CourseOffer } from '../../../../types/Course';
|
|
5
|
+
import { SyllabusCourseRun } from '.';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
component: SyllabusCourseRun,
|
|
9
|
+
render: (args) => {
|
|
10
|
+
return StorybookHelper.wrapInApp(<SyllabusCourseRun {...args} />);
|
|
11
|
+
},
|
|
12
|
+
} as Meta<typeof SyllabusCourseRun>;
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof SyllabusCourseRun>;
|
|
15
|
+
|
|
16
|
+
const courseRun = CourseRunFactory().one();
|
|
17
|
+
|
|
18
|
+
export const certificateSyllabusCourseRun: Story = {
|
|
19
|
+
args: {
|
|
20
|
+
courseRun: {
|
|
21
|
+
...courseRun,
|
|
22
|
+
title: 'Certificate Product',
|
|
23
|
+
price_currency: 'EUR',
|
|
24
|
+
offer: CourseOffer.FREE,
|
|
25
|
+
certificate_offer: CourseCertificateOffer.PAID,
|
|
26
|
+
certificate_price: 100,
|
|
27
|
+
discounted_price: null,
|
|
28
|
+
discount: null,
|
|
29
|
+
},
|
|
30
|
+
course: PacedCourseFactory().one(),
|
|
31
|
+
showLanguages: true,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export const certificateDiscountSyllabusCourseRun: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
courseRun: {
|
|
37
|
+
...courseRun,
|
|
38
|
+
title: 'Certificate Product',
|
|
39
|
+
price_currency: 'EUR',
|
|
40
|
+
offer: CourseOffer.FREE,
|
|
41
|
+
certificate_offer: CourseCertificateOffer.PAID,
|
|
42
|
+
certificate_price: 100,
|
|
43
|
+
certificate_discounted_price: 80,
|
|
44
|
+
certificate_discount: '-20 €',
|
|
45
|
+
},
|
|
46
|
+
course: PacedCourseFactory().one(),
|
|
47
|
+
showLanguages: true,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
export const credentialSyllabusCourseRun: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
courseRun: {
|
|
53
|
+
...courseRun,
|
|
54
|
+
title: 'Certificate Product',
|
|
55
|
+
price_currency: 'EUR',
|
|
56
|
+
offer: CourseOffer.PAID,
|
|
57
|
+
price: 100,
|
|
58
|
+
certificate_offer: CourseCertificateOffer.FREE,
|
|
59
|
+
discounted_price: null,
|
|
60
|
+
discount: null,
|
|
61
|
+
},
|
|
62
|
+
course: PacedCourseFactory().one(),
|
|
63
|
+
showLanguages: true,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
export const credentialDiscountSyllabusCourseRun: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
courseRun: {
|
|
69
|
+
...courseRun,
|
|
70
|
+
title: 'Certificate Product',
|
|
71
|
+
price_currency: 'EUR',
|
|
72
|
+
offer: CourseOffer.PAID,
|
|
73
|
+
price: 100,
|
|
74
|
+
certificate_offer: CourseCertificateOffer.FREE,
|
|
75
|
+
discounted_price: 80,
|
|
76
|
+
discount: '-20 €',
|
|
77
|
+
},
|
|
78
|
+
course: PacedCourseFactory().one(),
|
|
79
|
+
showLanguages: true,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
@@ -128,6 +128,13 @@ const OpenedCourseRun = ({
|
|
|
128
128
|
currency: courseRun.price_currency,
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
if ((courseRun.discounted_price ?? -1) >= 0) {
|
|
133
|
+
enrollmentPrice = intl.formatNumber(courseRun.discounted_price!, {
|
|
134
|
+
style: 'currency',
|
|
135
|
+
currency: courseRun.price_currency,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
if (courseRun.certificate_offer) {
|
|
@@ -144,6 +151,13 @@ const OpenedCourseRun = ({
|
|
|
144
151
|
currency: courseRun.price_currency,
|
|
145
152
|
});
|
|
146
153
|
}
|
|
154
|
+
|
|
155
|
+
if ((courseRun.certificate_discounted_price ?? -1) >= 0) {
|
|
156
|
+
certificatePrice = intl.formatNumber(courseRun.certificate_discounted_price!, {
|
|
157
|
+
style: 'currency',
|
|
158
|
+
currency: courseRun.price_currency,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
147
161
|
}
|
|
148
162
|
|
|
149
163
|
return (
|
|
@@ -119,6 +119,13 @@ const OpenedSelfPacedCourseRun = ({
|
|
|
119
119
|
currency: courseRun.price_currency,
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
|
+
|
|
123
|
+
if ((courseRun.discounted_price ?? -1) >= 0) {
|
|
124
|
+
enrollmentPrice = intl.formatNumber(courseRun.discounted_price!, {
|
|
125
|
+
style: 'currency',
|
|
126
|
+
currency: courseRun.price_currency,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
if (courseRun.certificate_offer) {
|
|
@@ -135,6 +142,13 @@ const OpenedSelfPacedCourseRun = ({
|
|
|
135
142
|
currency: courseRun.price_currency,
|
|
136
143
|
});
|
|
137
144
|
}
|
|
145
|
+
|
|
146
|
+
if ((courseRun.certificate_discounted_price ?? -1) >= 0) {
|
|
147
|
+
certificatePrice = intl.formatNumber(courseRun.certificate_discounted_price!, {
|
|
148
|
+
style: 'currency',
|
|
149
|
+
currency: courseRun.price_currency,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
138
152
|
}
|
|
139
153
|
|
|
140
154
|
return (
|
|
@@ -1465,4 +1465,50 @@ describe('<SyllabusCourseRunsList/>', () => {
|
|
|
1465
1465
|
expect(content).not.toContain('The certification process is');
|
|
1466
1466
|
expect(content).not.toContain('<br>€59.99');
|
|
1467
1467
|
});
|
|
1468
|
+
|
|
1469
|
+
it('renders price discount on SyllabusCourseRun', async () => {
|
|
1470
|
+
const course = PacedCourseFactory().one();
|
|
1471
|
+
const courseRun: CourseRun = CourseRunFactoryFromPriority(Priority.ONGOING_OPEN)({
|
|
1472
|
+
languages: ['en'],
|
|
1473
|
+
price_currency: 'EUR',
|
|
1474
|
+
offer: 'paid',
|
|
1475
|
+
price: 49.99,
|
|
1476
|
+
certificate_offer: undefined,
|
|
1477
|
+
certificate_price: undefined,
|
|
1478
|
+
discounted_price: 30.0,
|
|
1479
|
+
discount: '-20%',
|
|
1480
|
+
}).one();
|
|
1481
|
+
|
|
1482
|
+
render(
|
|
1483
|
+
<div className="course-detail__row course-detail__runs course-detail__runs--open">
|
|
1484
|
+
<SyllabusCourseRunCompacted courseRun={courseRun} course={course} showLanguages={false} />
|
|
1485
|
+
</div>,
|
|
1486
|
+
);
|
|
1487
|
+
|
|
1488
|
+
const content = getHeaderContainer().innerHTML;
|
|
1489
|
+
expect(content).toContain('<dd>Paid access<br>€30.00</dd>');
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1492
|
+
it('renders certificate discount on SyllabusCourseRun', async () => {
|
|
1493
|
+
const course = PacedCourseFactory().one();
|
|
1494
|
+
const courseRun: CourseRun = CourseRunFactoryFromPriority(Priority.ONGOING_OPEN)({
|
|
1495
|
+
languages: ['en'],
|
|
1496
|
+
price_currency: 'EUR',
|
|
1497
|
+
offer: 'free',
|
|
1498
|
+
price: undefined,
|
|
1499
|
+
certificate_offer: 'paid',
|
|
1500
|
+
certificate_price: 100.0,
|
|
1501
|
+
certificate_discounted_price: 70.0,
|
|
1502
|
+
certificate_discount: '-30%',
|
|
1503
|
+
}).one();
|
|
1504
|
+
|
|
1505
|
+
render(
|
|
1506
|
+
<div className="course-detail__row course-detail__runs course-detail__runs--open">
|
|
1507
|
+
<SyllabusCourseRunCompacted courseRun={courseRun} course={course} showLanguages={false} />
|
|
1508
|
+
</div>,
|
|
1509
|
+
);
|
|
1510
|
+
|
|
1511
|
+
const content = getHeaderContainer().innerHTML;
|
|
1512
|
+
expect(content).toContain('<dd>Paid certificate<br>€70.00</dd>');
|
|
1513
|
+
});
|
|
1468
1514
|
});
|
package/package.json
CHANGED
|
@@ -396,6 +396,11 @@ $course-glimpse-content-padding-sides: 0.7rem !default;
|
|
|
396
396
|
}
|
|
397
397
|
}
|
|
398
398
|
|
|
399
|
+
.offer_prices {
|
|
400
|
+
display: flex;
|
|
401
|
+
flex-direction: column;
|
|
402
|
+
}
|
|
403
|
+
|
|
399
404
|
.offer__price {
|
|
400
405
|
$visibility: r-theme-val(course-glimpse, offer-price-visibility);
|
|
401
406
|
@if $visibility == hidden {
|
|
@@ -404,6 +409,16 @@ $course-glimpse-content-padding-sides: 0.7rem !default;
|
|
|
404
409
|
visibility: $visibility;
|
|
405
410
|
// Align vertically the price with the icon
|
|
406
411
|
margin-top: calc(1ex - 1cap);
|
|
412
|
+
|
|
413
|
+
&--striked,
|
|
414
|
+
&--discounted {
|
|
415
|
+
display: inline-block;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
&--striked {
|
|
419
|
+
text-decoration: line-through;
|
|
420
|
+
opacity: 0.5;
|
|
421
|
+
}
|
|
407
422
|
}
|
|
408
423
|
}
|
|
409
424
|
}
|