richie-education 2.25.0-b2.dev111 → 2.25.0-b2.dev115
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/Address/index.tsx +13 -0
- package/js/components/SaleTunnel/components/SaleTunnelStepPayment/index.tsx +4 -7
- package/js/settings.dev.ts +12 -0
- package/js/types/Joanie.ts +5 -0
- package/js/utils/test/expectBanner.ts +2 -2
- package/js/utils/test/factories/joanie.ts +5 -0
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.spec.tsx +24 -0
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.tsx +167 -24
- package/js/widgets/Dashboard/components/DashboardItem/Order/_styles.scss +129 -0
- package/js/widgets/Dashboard/components/DashboardOrderLoader/_styles.scss +9 -0
- package/js/widgets/Dashboard/components/DashboardOrderLoader/index.tsx +19 -4
- package/package.json +1 -1
- package/scss/colors/_theme.scss +7 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Address } from 'types/Joanie';
|
|
2
|
+
|
|
3
|
+
export const AddressView = ({ address }: { address: Address }) => {
|
|
4
|
+
return (
|
|
5
|
+
<address>
|
|
6
|
+
{address.first_name} {address.last_name}
|
|
7
|
+
<br />
|
|
8
|
+
{address.address}
|
|
9
|
+
<br />
|
|
10
|
+
{address.postcode} {address.city}, {address.country}
|
|
11
|
+
</address>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -11,6 +11,7 @@ import type { Maybe, Nullable } from 'types/utils';
|
|
|
11
11
|
import { Icon, IconTypeEnum } from 'components/Icon';
|
|
12
12
|
import { useSaleTunnelContext } from 'components/SaleTunnel/context';
|
|
13
13
|
import { UserHelper } from 'utils/UserHelper';
|
|
14
|
+
import { AddressView } from 'components/Address';
|
|
14
15
|
import { RegisteredCreditCard } from '../RegisteredCreditCard';
|
|
15
16
|
|
|
16
17
|
const messages = defineMessages({
|
|
@@ -229,13 +230,9 @@ export const SaleTunnelStepPayment = ({ next }: SaleTunnelStepPaymentProps) => {
|
|
|
229
230
|
value: id,
|
|
230
231
|
}))}
|
|
231
232
|
/>
|
|
232
|
-
<
|
|
233
|
-
{selectedAddress
|
|
234
|
-
|
|
235
|
-
{selectedAddress!.address}
|
|
236
|
-
<br />
|
|
237
|
-
{selectedAddress!.postcode} {selectedAddress!.city}, {selectedAddress!.country}
|
|
238
|
-
</address>
|
|
233
|
+
<div className="SaleTunnelStepPayment__block--buyer__address-selection__address">
|
|
234
|
+
<AddressView address={selectedAddress!} />
|
|
235
|
+
</div>
|
|
239
236
|
</Fragment>
|
|
240
237
|
) : (
|
|
241
238
|
<Fragment>
|
package/js/types/Joanie.ts
CHANGED
|
@@ -30,6 +30,10 @@ export interface Organization {
|
|
|
30
30
|
code: string;
|
|
31
31
|
title: string;
|
|
32
32
|
logo: Nullable<JoanieFile>;
|
|
33
|
+
contact_email: Nullable<string>;
|
|
34
|
+
contact_phone: Nullable<string>;
|
|
35
|
+
dpo_email: Nullable<string>;
|
|
36
|
+
address?: Address;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
export interface OrganizationResourceQuery extends ResourcesQuery {
|
|
@@ -263,6 +267,7 @@ export interface Order {
|
|
|
263
267
|
course: Maybe<CourseLight>;
|
|
264
268
|
enrollment: Maybe<EnrollmentLight>;
|
|
265
269
|
organization_id: Organization['id'];
|
|
270
|
+
organization: Organization;
|
|
266
271
|
order_group_id?: OrderGroup['id'];
|
|
267
272
|
}
|
|
268
273
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { screen, waitFor } from '@testing-library/react';
|
|
2
2
|
import { BannerType, getBannerTestId } from 'components/Banner';
|
|
3
3
|
|
|
4
4
|
export const expectBannerError = async (message: string, rootElement: ParentNode = document) => {
|
|
@@ -16,7 +16,7 @@ export const expectBanner = async (
|
|
|
16
16
|
await waitFor(async () => {
|
|
17
17
|
const banner = rootElement.querySelector('.banner--' + type) as HTMLElement;
|
|
18
18
|
expect(banner).not.toBeNull();
|
|
19
|
-
|
|
19
|
+
expect(banner).toHaveTextContent(message);
|
|
20
20
|
});
|
|
21
21
|
};
|
|
22
22
|
|
|
@@ -157,6 +157,10 @@ export const OrganizationFactory = factory((): Organization => {
|
|
|
157
157
|
code: faker.string.alphanumeric(5),
|
|
158
158
|
title: FactoryHelper.unique(faker.lorem.words, { args: [1] }),
|
|
159
159
|
logo: JoanieFileFactory().one(),
|
|
160
|
+
contact_email: faker.internet.email(),
|
|
161
|
+
dpo_email: faker.internet.email(),
|
|
162
|
+
contact_phone: faker.phone.number(),
|
|
163
|
+
address: AddressFactory().one(),
|
|
160
164
|
};
|
|
161
165
|
});
|
|
162
166
|
|
|
@@ -400,6 +404,7 @@ const AbstractOrderFactory = factory((): Order => {
|
|
|
400
404
|
enrollment: undefined,
|
|
401
405
|
course: undefined,
|
|
402
406
|
organization_id: faker.string.uuid(),
|
|
407
|
+
organization: OrganizationFactory().one(),
|
|
403
408
|
};
|
|
404
409
|
});
|
|
405
410
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
render,
|
|
9
9
|
screen,
|
|
10
10
|
waitFor,
|
|
11
|
+
within,
|
|
11
12
|
} from '@testing-library/react';
|
|
12
13
|
import { IntlProvider } from 'react-intl';
|
|
13
14
|
import { faker } from '@faker-js/faker';
|
|
@@ -858,4 +859,27 @@ describe('<DashboardItemOrder/>', () => {
|
|
|
858
859
|
screen.queryByTestId('dashboard-item__course-enrolling__run__' + courseRun.id),
|
|
859
860
|
).toBeNull();
|
|
860
861
|
});
|
|
862
|
+
|
|
863
|
+
it('renders a writable order with organization details', async () => {
|
|
864
|
+
const order: CredentialOrder = CredentialOrderFactory().one();
|
|
865
|
+
const { product } = mockCourseProductWithOrder(order);
|
|
866
|
+
|
|
867
|
+
render(<DashboardItemOrder order={order} writable={true} showDetailsButton={false} />, {
|
|
868
|
+
wrapper,
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
await screen.findByRole('heading', { level: 5, name: product.title });
|
|
872
|
+
|
|
873
|
+
const block = screen.getByTestId('organization-block');
|
|
874
|
+
within(block).getByText(order.organization!.title);
|
|
875
|
+
within(block).getByRole('link', { name: order.organization!.contact_email! });
|
|
876
|
+
within(block).getByRole('link', { name: order.organization!.dpo_email! });
|
|
877
|
+
within(block).getByRole('link', { name: order.organization!.contact_phone! });
|
|
878
|
+
within(block).getByText(new RegExp(order.organization?.address?.first_name!));
|
|
879
|
+
within(block).getByText(new RegExp(order.organization?.address?.last_name!));
|
|
880
|
+
within(block).getByText(new RegExp(order.organization?.address?.address!));
|
|
881
|
+
within(block).getByText(new RegExp(order.organization?.address?.city!));
|
|
882
|
+
within(block).getByText(new RegExp(order.organization?.address?.postcode!));
|
|
883
|
+
within(block).getByText(new RegExp(order.organization?.address?.country!));
|
|
884
|
+
});
|
|
861
885
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { FormattedMessage, useIntl, defineMessages } from 'react-intl';
|
|
2
|
+
import { Button } from '@openfun/cunningham-react';
|
|
3
|
+
import classNames from 'classnames';
|
|
2
4
|
import { CourseLight, CredentialOrder, Product } from 'types/Joanie';
|
|
3
5
|
import { Icon, IconTypeEnum } from 'components/Icon';
|
|
4
6
|
import { CoursesHelper } from 'utils/CoursesHelper';
|
|
@@ -11,7 +13,9 @@ import { LearnerDashboardPaths } from 'widgets/Dashboard/utils/learnerRouteMessa
|
|
|
11
13
|
import { getDashboardRoutePath } from 'widgets/Dashboard/utils/dashboardRoutes';
|
|
12
14
|
import { useCourseProduct } from 'hooks/useCourseProducts';
|
|
13
15
|
import { OrderHelper } from 'utils/OrderHelper';
|
|
14
|
-
|
|
16
|
+
import ContractStatus from 'components/ContractStatus';
|
|
17
|
+
import SignContractButton from 'components/SignContractButton';
|
|
18
|
+
import { AddressView } from 'components/Address';
|
|
15
19
|
import { DashboardSubItemsList } from '../DashboardSubItemsList';
|
|
16
20
|
import { DashboardItemCourseEnrolling } from '../CourseEnrolling';
|
|
17
21
|
import { DashboardItem } from '../index';
|
|
@@ -34,6 +38,46 @@ const messages = defineMessages({
|
|
|
34
38
|
description: 'Syllabus link label on order details',
|
|
35
39
|
defaultMessage: 'Go to syllabus',
|
|
36
40
|
},
|
|
41
|
+
contactDescription: {
|
|
42
|
+
id: 'components.DashboardItemOrder.contactDescription',
|
|
43
|
+
description: 'Description of the contact information for the organization',
|
|
44
|
+
defaultMessage: 'Your training reference is {name} - {email}.',
|
|
45
|
+
},
|
|
46
|
+
contactButton: {
|
|
47
|
+
id: 'components.DashboardItemOrder.contactButton',
|
|
48
|
+
description: 'Button to contact the organization',
|
|
49
|
+
defaultMessage: 'Contact',
|
|
50
|
+
},
|
|
51
|
+
organizationHeader: {
|
|
52
|
+
id: 'components.DashboardItemOrder.organizationHeader',
|
|
53
|
+
description: 'Header of the organization section',
|
|
54
|
+
defaultMessage: 'This training is provided by',
|
|
55
|
+
},
|
|
56
|
+
organizationLogoAlt: {
|
|
57
|
+
id: 'components.DashboardItemOrder.organizationLogoAlt',
|
|
58
|
+
description: 'Alt text for the organization logo',
|
|
59
|
+
defaultMessage: 'Logo of the organization',
|
|
60
|
+
},
|
|
61
|
+
trainingContractTitle: {
|
|
62
|
+
id: 'components.DashboardItemOrder.trainingContractTitle',
|
|
63
|
+
description: 'Title of the training contract section',
|
|
64
|
+
defaultMessage: 'Training contract',
|
|
65
|
+
},
|
|
66
|
+
organizationMailContactLabel: {
|
|
67
|
+
id: 'components.DashboardItemOrder.organizationMailContactLabel',
|
|
68
|
+
description: 'Label for the organization mail contact',
|
|
69
|
+
defaultMessage: 'Email',
|
|
70
|
+
},
|
|
71
|
+
organizationPhoneContactLabel: {
|
|
72
|
+
id: 'components.DashboardItemOrder.organizationPhoneContactLabel',
|
|
73
|
+
description: 'Label for the organization phone contact',
|
|
74
|
+
defaultMessage: 'Phone',
|
|
75
|
+
},
|
|
76
|
+
organizationDpoContactLabel: {
|
|
77
|
+
id: 'components.DashboardItemOrder.organizationDpoContactLabel',
|
|
78
|
+
description: 'Label for the organization DPO contact',
|
|
79
|
+
defaultMessage: 'Data protection email',
|
|
80
|
+
},
|
|
37
81
|
});
|
|
38
82
|
|
|
39
83
|
interface DashboardItemOrderProps {
|
|
@@ -88,27 +132,16 @@ export const DashboardItemOrder = ({
|
|
|
88
132
|
const course = order.course as CourseLight;
|
|
89
133
|
|
|
90
134
|
const intl = useIntl();
|
|
91
|
-
const {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
135
|
+
const { item: courseProductRelation } = useCourseProduct({
|
|
136
|
+
product_id: order.product_id,
|
|
137
|
+
course_id: course.code,
|
|
138
|
+
});
|
|
95
139
|
const { product } = courseProductRelation || {};
|
|
96
140
|
const needsSignature = OrderHelper.orderNeedsSignature(order, product?.contract_definition);
|
|
97
141
|
const getRoutePath = getDashboardRoutePath(useIntl());
|
|
98
142
|
|
|
99
143
|
return (
|
|
100
144
|
<div className="dashboard-item-order">
|
|
101
|
-
{writable && needsSignature && (
|
|
102
|
-
<DashboardItemContract
|
|
103
|
-
key={`DashboardItemOrderContract_${order.id}`}
|
|
104
|
-
title={product.title}
|
|
105
|
-
order={order}
|
|
106
|
-
contract_definition={product?.contract_definition!}
|
|
107
|
-
contract={order.contract}
|
|
108
|
-
writable={writable}
|
|
109
|
-
mode="compact"
|
|
110
|
-
/>
|
|
111
|
-
)}
|
|
112
145
|
<DashboardItem
|
|
113
146
|
data-testid={`dashboard-item-order-${order.id}`}
|
|
114
147
|
title={product?.title ?? ''}
|
|
@@ -183,17 +216,127 @@ export const DashboardItemOrder = ({
|
|
|
183
216
|
{showCertificate && !!product?.certificate_definition && (
|
|
184
217
|
<DashboardItemOrderCertificate order={order} product={product} />
|
|
185
218
|
)}
|
|
186
|
-
{writable &&
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
219
|
+
{writable && <OrganizationBlock order={order} product={product} />}
|
|
220
|
+
</div>
|
|
221
|
+
);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const OrganizationBlock = ({ order, product }: { order: CredentialOrder; product: Product }) => {
|
|
225
|
+
const { organization } = order;
|
|
226
|
+
if (!organization) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const showContactsBlock =
|
|
231
|
+
organization.contact_email || organization.contact_phone || organization.dpo_email;
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<div className="dashboard-splitted-card mt-s" data-testid="organization-block">
|
|
235
|
+
<div className="dashboard-splitted-card__column order-organization__caption">
|
|
236
|
+
<div className="dashboard-item-order__organization">
|
|
237
|
+
<div className="dashboard-item-order__organization__header">
|
|
238
|
+
<FormattedMessage {...messages.organizationHeader} />
|
|
239
|
+
</div>
|
|
240
|
+
<div
|
|
241
|
+
className="dashboard-item-order__organization__logo"
|
|
242
|
+
style={{
|
|
243
|
+
backgroundImage: `url(${organization.logo?.src})`,
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
246
|
+
<div className="dashboard-item-order__organization__name">{organization.title}</div>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
<div className="dashboard-splitted-card__separator order-organization__separator" />
|
|
250
|
+
<div className="dashboard-splitted-card__column order-organization__items">
|
|
251
|
+
<ContractItem order={order} product={product} />
|
|
252
|
+
{showContactsBlock && (
|
|
253
|
+
<div className="dashboard-splitted-card__item">
|
|
254
|
+
<div className="dashboard-splitted-card__item__title">Contacts</div>
|
|
255
|
+
<div className="dashboard-splitted-card__item__description">
|
|
256
|
+
{organization.contact_email && (
|
|
257
|
+
<div className="organization-block__contact__item">
|
|
258
|
+
<FormattedMessage {...messages.organizationMailContactLabel} />
|
|
259
|
+
<Button
|
|
260
|
+
size="small"
|
|
261
|
+
color="tertiary"
|
|
262
|
+
href={'mailto:' + (organization.contact_email ?? '')}
|
|
263
|
+
>
|
|
264
|
+
{organization.contact_email}
|
|
265
|
+
</Button>
|
|
266
|
+
</div>
|
|
267
|
+
)}
|
|
268
|
+
{organization.contact_phone && (
|
|
269
|
+
<div className="organization-block__contact__item">
|
|
270
|
+
<FormattedMessage {...messages.organizationPhoneContactLabel} />
|
|
271
|
+
<Button
|
|
272
|
+
size="small"
|
|
273
|
+
color="tertiary"
|
|
274
|
+
href={'tel:' + (organization.contact_phone ?? '')}
|
|
275
|
+
>
|
|
276
|
+
{organization.contact_phone}
|
|
277
|
+
</Button>
|
|
278
|
+
</div>
|
|
279
|
+
)}
|
|
280
|
+
{organization.dpo_email && (
|
|
281
|
+
<div className="organization-block__contact__item">
|
|
282
|
+
<FormattedMessage {...messages.organizationDpoContactLabel} />
|
|
283
|
+
<Button
|
|
284
|
+
size="small"
|
|
285
|
+
color="tertiary"
|
|
286
|
+
href={'mailto:' + (organization.dpo_email ?? '')}
|
|
287
|
+
>
|
|
288
|
+
{organization.dpo_email}
|
|
289
|
+
</Button>
|
|
290
|
+
</div>
|
|
291
|
+
)}
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
)}
|
|
295
|
+
{organization.address && (
|
|
296
|
+
<div className="dashboard-splitted-card__item dashboard-splitted-card__item__address">
|
|
297
|
+
<div className="dashboard-splitted-card__item__title">Address</div>
|
|
298
|
+
<div className="dashboard-splitted-card__item__description">
|
|
299
|
+
<AddressView address={organization.address} />
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
)}
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const ContractItem = ({ product, order }: { order: CredentialOrder; product: Product }) => {
|
|
309
|
+
if (!product?.contract_definition) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const needsSignature = OrderHelper.orderNeedsSignature(order, product.contract_definition);
|
|
314
|
+
return (
|
|
315
|
+
<div
|
|
316
|
+
id={`dashboard-item-contract-${order.id}`}
|
|
317
|
+
className="dashboard-splitted-card__item"
|
|
318
|
+
data-testid={`dashboard-item-contract-${order.id}`}
|
|
319
|
+
>
|
|
320
|
+
<div
|
|
321
|
+
className={classNames('dashboard-splitted-card__item__title', {
|
|
322
|
+
'dashboard-splitted-card__item__title--dot': needsSignature,
|
|
323
|
+
})}
|
|
324
|
+
>
|
|
325
|
+
<span>
|
|
326
|
+
<FormattedMessage {...messages.trainingContractTitle} />
|
|
327
|
+
</span>
|
|
328
|
+
</div>
|
|
329
|
+
<div className="dashboard-splitted-card__item__description">
|
|
330
|
+
<ContractStatus contract={order.contract} />
|
|
331
|
+
</div>
|
|
332
|
+
<div className="dashboard-splitted-card__item__actions">
|
|
333
|
+
<SignContractButton
|
|
190
334
|
order={order}
|
|
191
|
-
contract_definition={product?.contract_definition!}
|
|
192
335
|
contract={order.contract}
|
|
193
|
-
writable={
|
|
194
|
-
|
|
336
|
+
writable={true}
|
|
337
|
+
className="dashboard-item__button"
|
|
195
338
|
/>
|
|
196
|
-
|
|
339
|
+
</div>
|
|
197
340
|
</div>
|
|
198
341
|
);
|
|
199
342
|
};
|
|
@@ -41,3 +41,132 @@
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
.dashboard-splitted-card {
|
|
46
|
+
background-color: r-theme-val(dashboard-splitted-card, background-color);
|
|
47
|
+
border-radius: 0.25rem;
|
|
48
|
+
box-shadow: r-theme-val(dashboard-splitted-card, base-shadow);
|
|
49
|
+
padding: 2rem;
|
|
50
|
+
display: flex;
|
|
51
|
+
color: r-theme-val(dashboard-splitted-card, color);
|
|
52
|
+
|
|
53
|
+
@include media-breakpoint-down(sm) {
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&__separator {
|
|
58
|
+
margin: 0 2rem;
|
|
59
|
+
border-right: 1px r-theme-val(dashboard-splitted-card, separator-color) solid;
|
|
60
|
+
|
|
61
|
+
@include media-breakpoint-down(sm) {
|
|
62
|
+
margin: 2rem 0;
|
|
63
|
+
border-right: none;
|
|
64
|
+
border-bottom: 1px r-theme-val(dashboard-splitted-card, separator-color) solid;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&__column {
|
|
69
|
+
width: 50%;
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
gap: 2rem;
|
|
73
|
+
|
|
74
|
+
@include media-breakpoint-down(sm) {
|
|
75
|
+
width: auto;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&:last-child {
|
|
79
|
+
justify-content: center;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&__item {
|
|
84
|
+
&__title {
|
|
85
|
+
font-weight: 800;
|
|
86
|
+
font-size: 1rem;
|
|
87
|
+
font-family: $r-font-family-montserrat;
|
|
88
|
+
margin-bottom: 0.5rem;
|
|
89
|
+
|
|
90
|
+
span {
|
|
91
|
+
position: relative;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&--dot {
|
|
95
|
+
span::after {
|
|
96
|
+
content: '';
|
|
97
|
+
margin-left: 0.25rem;
|
|
98
|
+
background-color: r-theme-val(dashboard-splitted-card, dot-color);
|
|
99
|
+
width: 8px;
|
|
100
|
+
height: 8px;
|
|
101
|
+
display: block;
|
|
102
|
+
border-radius: 100%;
|
|
103
|
+
position: absolute;
|
|
104
|
+
right: -12px;
|
|
105
|
+
top: -4px;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
&__description {
|
|
111
|
+
font-size: 0.875rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&__actions {
|
|
115
|
+
margin-top: 0.25rem;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.dashboard-item-order__organization {
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
gap: 2rem;
|
|
126
|
+
margin-bottom: 0.5rem;
|
|
127
|
+
font-size: 0.875rem;
|
|
128
|
+
flex-grow: 1;
|
|
129
|
+
|
|
130
|
+
&__name {
|
|
131
|
+
font-size: 24px;
|
|
132
|
+
font-weight: 800;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&__logo {
|
|
136
|
+
min-height: 64px;
|
|
137
|
+
max-height: 128px;
|
|
138
|
+
width: 100%;
|
|
139
|
+
flex-grow: 1;
|
|
140
|
+
background-size: contain;
|
|
141
|
+
background-repeat: no-repeat;
|
|
142
|
+
background-position: center;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.dashboard-splitted-card__item__address {
|
|
147
|
+
address {
|
|
148
|
+
margin: 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.organization-block__contact__item {
|
|
153
|
+
font-weight: bold;
|
|
154
|
+
|
|
155
|
+
a {
|
|
156
|
+
margin-left: 0.25rem;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.order-organization {
|
|
161
|
+
&__caption {
|
|
162
|
+
order: 3;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
&__separator {
|
|
166
|
+
order: 2;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
&__misc {
|
|
170
|
+
order: 1;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -17,10 +17,15 @@ const messages = defineMessages({
|
|
|
17
17
|
id: 'components.DashboardOrderLoader.loading',
|
|
18
18
|
},
|
|
19
19
|
signatureNeeded: {
|
|
20
|
-
defaultMessage: 'You need to
|
|
20
|
+
defaultMessage: 'You need to {signLink} before enrolling in a course run',
|
|
21
21
|
description: 'Banner displayed when the contract is not signed',
|
|
22
22
|
id: 'components.DashboardOrderLoader.signatureNeeded',
|
|
23
23
|
},
|
|
24
|
+
signLink: {
|
|
25
|
+
defaultMessage: 'sign your contract',
|
|
26
|
+
description: 'Link to sign the contract',
|
|
27
|
+
id: 'components.DashboardOrderLoader.signLink',
|
|
28
|
+
},
|
|
24
29
|
wrongLinkedProductError: {
|
|
25
30
|
defaultMessage: 'This page is not available for this order.',
|
|
26
31
|
description: "Error message displayed when order's linked product type is not handle.",
|
|
@@ -48,7 +53,6 @@ export const DashboardOrderLoader = () => {
|
|
|
48
53
|
}
|
|
49
54
|
}, [credentialOrder]);
|
|
50
55
|
const error = errorOrder || errorCourseProduct || wrongLinkedProductError;
|
|
51
|
-
|
|
52
56
|
const fetching = fetchingOrder || fetchingCourseProduct;
|
|
53
57
|
const needsSignature = OrderHelper.orderNeedsSignature(
|
|
54
58
|
order,
|
|
@@ -66,8 +70,19 @@ export const DashboardOrderLoader = () => {
|
|
|
66
70
|
)}
|
|
67
71
|
<div className="dashboard-order-loader__banners">
|
|
68
72
|
{error && <Banner message={error} type={BannerType.ERROR} />}
|
|
69
|
-
{needsSignature && (
|
|
70
|
-
<Banner
|
|
73
|
+
{order && needsSignature && (
|
|
74
|
+
<Banner
|
|
75
|
+
message={
|
|
76
|
+
intl.formatMessage(messages.signatureNeeded, {
|
|
77
|
+
signLink: (
|
|
78
|
+
<a href={'#dashboard-item-contract-' + order.id}>
|
|
79
|
+
<FormattedMessage {...messages.signLink} />
|
|
80
|
+
</a>
|
|
81
|
+
),
|
|
82
|
+
}) as any
|
|
83
|
+
}
|
|
84
|
+
type={BannerType.ERROR}
|
|
85
|
+
/>
|
|
71
86
|
)}
|
|
72
87
|
</div>
|
|
73
88
|
{credentialOrder && (
|
package/package.json
CHANGED
package/scss/colors/_theme.scss
CHANGED
|
@@ -276,6 +276,13 @@ $r-theme: (
|
|
|
276
276
|
base-border: r-color('light-grey'),
|
|
277
277
|
menu-link-inline-padding: 16px,
|
|
278
278
|
),
|
|
279
|
+
dashboard-splitted-card: (
|
|
280
|
+
color: r-color('charcoal'),
|
|
281
|
+
base-shadow: 0 0 6px r-color('light-grey'),
|
|
282
|
+
background-color: r-color('white'),
|
|
283
|
+
dot-color: r-color('firebrick6'),
|
|
284
|
+
separator-color: r-color('grey87'),
|
|
285
|
+
),
|
|
279
286
|
dashboard-list: (
|
|
280
287
|
background-color-loading: r-color('smoke'),
|
|
281
288
|
),
|