richie-education 3.3.2-dev6 → 3.4.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/.eslintrc.json +0 -3
- package/.storybook/main.js +11 -12
- package/.storybook/preview.tsx +49 -24
- package/cunningham.cjs +31 -0
- package/i18n/compile-translations.js +12 -10
- package/i18n/locales/ar-SA.json +20 -0
- package/i18n/locales/es-ES.json +20 -0
- package/i18n/locales/fa-IR.json +20 -0
- package/i18n/locales/fr-CA.json +20 -0
- package/i18n/locales/fr-FR.json +21 -1
- package/i18n/locales/ko-KR.json +20 -0
- package/i18n/locales/pt-PT.json +42 -22
- package/i18n/locales/ru-RU.json +20 -0
- package/i18n/locales/vi-VN.json +20 -0
- package/jest.config.js +5 -0
- package/js/components/AddressesManagement/AddressForm/index.stories.tsx +1 -1
- package/js/components/AddressesManagement/AddressForm/index.tsx +4 -3
- package/js/components/AddressesManagement/index.stories.tsx +1 -1
- package/js/components/AddressesManagement/index.tsx +5 -3
- package/js/components/Badge/index.stories.tsx +1 -1
- package/js/components/Badge/index.tsx +1 -1
- package/js/components/Banner/index.stories.tsx +1 -1
- package/js/components/CourseGlimpse/index.stories.tsx +1 -1
- package/js/components/CourseGlimpseList/index.stories.tsx +1 -1
- package/js/components/CreditCardSelector/_styles.scss +2 -2
- package/js/components/CreditCardSelector/index.tsx +11 -3
- package/js/components/DownloadCertificateButton/index.tsx +2 -1
- package/js/components/DownloadContractButton/index.tsx +7 -1
- package/js/components/Form/Form/index.tsx +4 -2
- package/js/components/Icon/index.stories.tsx +2 -1
- package/js/components/Modal/index.stories.tsx +1 -1
- package/js/components/Modal/index.tsx +2 -1
- package/js/components/OpenEdxFullNameForm/index.stories.tsx +1 -1
- package/js/components/OpenEdxFullNameForm/index.tsx +2 -2
- package/js/components/PaymentScheduleGrid/_styles.scss +2 -2
- package/js/components/PurchaseButton/index.stories.tsx +1 -1
- package/js/components/RegisteredAddress/index.stories.tsx +1 -1
- package/js/components/RegisteredAddress/index.tsx +4 -2
- package/js/components/SaleTunnel/AddressSelector/CreateAddressFormModal.tsx +1 -1
- package/js/components/SaleTunnel/AddressSelector/EditAddressFormModal.tsx +1 -1
- package/js/components/SaleTunnel/AddressSelector/index.tsx +4 -2
- package/js/components/SaleTunnel/SaleTunnelInformation/SaleTunnelInformationGroup.tsx +4 -3
- package/js/components/SaleTunnel/SaleTunnelInformation/SaleTunnelInformationSingular.tsx +27 -5
- package/js/components/SaleTunnel/SubscriptionButton/index.tsx +7 -5
- package/js/components/SaleTunnel/_styles.scss +9 -8
- package/js/components/SaleTunnel/index.credential.spec.tsx +50 -1
- package/js/components/SaleTunnel/index.stories.tsx +1 -1
- package/js/components/Spinner/index.stories.tsx +1 -1
- package/js/components/Tabs/index.stories.tsx +1 -1
- package/js/components/Tabs/index.tsx +2 -1
- package/js/components/TeacherDashboardCourseList/index.tsx +2 -1
- package/js/hooks/useAddressesManagement.tsx +4 -2
- package/js/hooks/useCreditCards/index.ts +6 -4
- package/js/hooks/useDashboardAddressForm.tsx +3 -3
- package/js/hooks/useMatchMedia.ts +1 -1
- package/js/hooks/useResources/useResourcesRoot.ts +1 -1
- package/js/hooks/useUnionResource/index.ts +6 -2
- package/js/hooks/useUnionResource/utils/fetchEntity.ts +1 -0
- package/js/pages/DashboardAddressesManagement/DashboardAddressBox.tsx +3 -3
- package/js/pages/DashboardAddressesManagement/DashboardCreateAddress.stories.tsx +1 -1
- package/js/pages/DashboardAddressesManagement/DashboardCreateAddress.tsx +1 -1
- package/js/pages/DashboardAddressesManagement/DashboardEditAddress.stories.tsx +1 -1
- package/js/pages/DashboardAddressesManagement/DashboardEditAddress.tsx +3 -2
- package/js/pages/DashboardAddressesManagement/index.stories.tsx +1 -1
- package/js/pages/DashboardAddressesManagement/index.tsx +1 -1
- package/js/pages/DashboardCourses/index.tsx +2 -1
- package/js/pages/DashboardCreditCardsManagement/CreditCardBrandLogo.stories.tsx +1 -1
- package/js/pages/DashboardCreditCardsManagement/DashboardCreditCardBox.tsx +3 -3
- package/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.stories.tsx +1 -1
- package/js/pages/DashboardCreditCardsManagement/DashboardEditCreditCard.tsx +3 -2
- package/js/pages/DashboardCreditCardsManagement/index.stories.tsx +1 -1
- package/js/pages/DashboardOpenEdxProfile/index.stories.tsx +1 -1
- package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.tsx +4 -2
- package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.tsx +2 -1
- package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx +4 -4
- package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.spec.tsx +8 -9
- package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.tsx +14 -3
- package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.tsx +6 -1
- package/js/pages/TeacherDashboardCourseLoader/CourseRunList/utils.tsx +2 -1
- package/js/pages/TeacherDashboardOrganizationAgreements/BulkAgreementContractButton.tsx +4 -2
- package/js/pages/TeacherDashboardOrganizationAgreements/SignOrganizationAgreementButton.tsx +2 -1
- package/js/pages/TeacherDashboardOrganizationQuotes/index.full-process.spec.tsx +2 -2
- package/js/pages/TeacherDashboardOrganizationQuotes/index.spec.tsx +1 -1
- package/js/pages/TeacherDashboardOrganizationQuotes/index.tsx +3 -2
- package/js/translations/ar-SA.json +1 -1
- package/js/translations/es-ES.json +1 -1
- package/js/translations/fa-IR.json +1 -1
- package/js/translations/fr-CA.json +1 -1
- package/js/translations/fr-FR.json +1 -1
- package/js/translations/ko-KR.json +1 -1
- package/js/translations/pt-PT.json +1 -1
- package/js/translations/ru-RU.json +1 -1
- package/js/translations/vi-VN.json +1 -1
- package/js/types/Joanie.ts +1 -1
- package/js/utils/ProductHelper/index.spec.ts +1 -1
- package/js/utils/StorybookHelper/index.tsx +3 -6
- package/js/utils/cunningham-tokens.ts +1111 -142
- package/js/utils/errors/handle.spec.ts +3 -3
- package/js/utils/react-query/useSessionMutation/index.ts +8 -3
- package/js/utils/test/factories/joanie.ts +1 -1
- package/js/widgets/Dashboard/components/DashboardAvatar/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardBox/index.stories.tsx +13 -5
- package/js/widgets/Dashboard/components/DashboardBreadcrumbs/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardBreadcrumbs/index.tsx +3 -2
- package/js/widgets/Dashboard/components/DashboardCard/index.spec.tsx +13 -2
- package/js/widgets/Dashboard/components/DashboardCard/index.stories.tsx +12 -4
- package/js/widgets/Dashboard/components/DashboardCard/index.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderPaymentModal/BatchOrderPaymentManager.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/BatchOrder/BatchOrderPaymentModal/index.tsx +2 -1
- package/js/widgets/Dashboard/components/DashboardItem/Certificate/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Contract/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/CourseEnrolling/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/CourseEnrolling/index.tsx +8 -4
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderReadonly.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderWritable.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/Installment/index.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentDetailsModal/_styles.scss +2 -2
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentRetryModal/index.tsx +2 -1
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrganizationBlock/index.tsx +6 -3
- package/js/widgets/Dashboard/components/DashboardItem/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardItem/index.tsx +2 -1
- package/js/widgets/Dashboard/components/DashboardListAvatar/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/DashboardSidebar/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/LearnerDashboardSidebar/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/ProtectedOutlet/AuthenticatedOutlet.spec.tsx +1 -1
- package/js/widgets/Dashboard/components/ProtectedOutlet/ProtectedOutlet.spec.tsx +1 -1
- package/js/widgets/Dashboard/components/SearchBar/index.tsx +2 -1
- package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/components/TeacherDashboardProfileSidebar/index.stories.tsx +1 -1
- package/js/widgets/Dashboard/hooks/useRouteInfo/index.spec.tsx +2 -2
- package/js/widgets/Dashboard/index.spec.tsx +1 -1
- package/js/widgets/Search/components/SearchFilterValueParent/index.stories.tsx +1 -1
- package/js/widgets/Search/components/SearchFiltersPane/index.tsx +2 -1
- package/js/widgets/Slider/index.stories.tsx +1 -1
- package/js/widgets/Slider/index.tsx +7 -6
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCertificateItem/index.stories.tsx +1 -1
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseRunItem/index.stories.tsx +1 -1
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.stories.tsx +1 -1
- package/js/widgets/SyllabusCourseRunsList/components/CourseWishButton/index.tsx +4 -2
- package/js/widgets/SyllabusCourseRunsList/components/SyllabusCourseRun/index.stories.tsx +1 -1
- package/js/widgets/SyllabusCourseRunsList/components/SyllabusCourseRunCompacted/index.stories.tsx +41 -0
- package/js/widgets/UserLogin/index.stories.tsx +1 -1
- package/package.json +76 -81
- package/scss/components/_subheader.scss +1 -1
- package/scss/components/templates/richie/slider/_slider.scss +1 -1
- package/scss/objects/_course_glimpses.scss +1 -0
- package/scss/trumps/_bootstrap.scss +1 -0
- package/scss/vendors/css/cunningham-tokens.css +1259 -154
- package/scss/vendors/cunningham-tokens.scss +1479 -150
- package/tsconfig.json +1 -1
- package/webpack.config.js +8 -0
|
@@ -166,7 +166,9 @@ describe('SaleTunnel / Credential', () => {
|
|
|
166
166
|
|
|
167
167
|
// - CPF description and redirect button should be visible.
|
|
168
168
|
expect(
|
|
169
|
-
screen.getByText(
|
|
169
|
+
screen.getByText(
|
|
170
|
+
/purchase your training course by using your Personal Training Account \(CPF\) on Mon Compte Formation/i,
|
|
171
|
+
),
|
|
170
172
|
).toBeInTheDocument();
|
|
171
173
|
const cpfButton = screen.getByRole('link', { name: /go to mon compte formation/i });
|
|
172
174
|
|
|
@@ -222,4 +224,51 @@ describe('SaleTunnel / Credential', () => {
|
|
|
222
224
|
// - Classic billing information section should be displayed.
|
|
223
225
|
expect(screen.getByText(/this information will be used for billing/i)).toBeInTheDocument();
|
|
224
226
|
});
|
|
227
|
+
|
|
228
|
+
it('should display voucher input and subscribe button in CPF mode', async () => {
|
|
229
|
+
const course = PacedCourseFactory().one();
|
|
230
|
+
const product = CredentialProductFactory().one();
|
|
231
|
+
const billingAddress: Joanie.Address = AddressFactory({ is_main: true }).one();
|
|
232
|
+
const deepLink = 'https://placeholder.com/course/1';
|
|
233
|
+
const orderQueryParameters = {
|
|
234
|
+
course_code: course.code,
|
|
235
|
+
product_id: product.id,
|
|
236
|
+
state: NOT_CANCELED_ORDER_STATES,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
fetchMock
|
|
240
|
+
.get(
|
|
241
|
+
`https://joanie.endpoint/api/v1.0/orders/?${queryString.stringify(orderQueryParameters)}`,
|
|
242
|
+
[],
|
|
243
|
+
)
|
|
244
|
+
.get(
|
|
245
|
+
`https://joanie.endpoint/api/v1.0/courses/${course.code}/products/${product.id}/payment-plan/`,
|
|
246
|
+
[],
|
|
247
|
+
)
|
|
248
|
+
.get(
|
|
249
|
+
`https://joanie.endpoint/api/v1.0/courses/${course.code}/products/${product.id}/deep-link/`,
|
|
250
|
+
{ deep_link: deepLink },
|
|
251
|
+
)
|
|
252
|
+
.get('https://joanie.endpoint/api/v1.0/addresses/', [billingAddress], {
|
|
253
|
+
overwriteRoutes: true,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const user = userEvent.setup({ delay: null });
|
|
257
|
+
|
|
258
|
+
render(<Wrapper product={product} course={course} />, {
|
|
259
|
+
queryOptions: { client: createTestQueryClient({ user: richieUser }) },
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
await screen.findByRole('heading', { level: 3, name: /payment method/i });
|
|
263
|
+
|
|
264
|
+
// Switch to CPF mode
|
|
265
|
+
await user.click(screen.getByRole('radio', { name: /my training account \(cpf\)/i }));
|
|
266
|
+
|
|
267
|
+
// - Voucher input should be visible in CPF mode.
|
|
268
|
+
expect(screen.getByLabelText('Voucher code')).toBeInTheDocument();
|
|
269
|
+
expect(screen.getByRole('button', { name: 'Validate' })).toBeInTheDocument();
|
|
270
|
+
|
|
271
|
+
// - Subscribe button should be visible in CPF mode.
|
|
272
|
+
expect(screen.getByRole('button', { name: 'Subscribe' })).toBeInTheDocument();
|
|
273
|
+
});
|
|
225
274
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { defineMessages, useIntl } from 'react-intl';
|
|
2
|
-
import { MutateOptions } from '@tanstack/react-query';
|
|
3
2
|
import { useAddresses } from 'hooks/useAddresses';
|
|
4
3
|
import * as Joanie from 'types/Joanie';
|
|
5
4
|
import { confirm } from 'utils/indirection/window';
|
|
@@ -58,7 +57,10 @@ export function useAddressesManagement() {
|
|
|
58
57
|
* @param {Joanie.Address} address
|
|
59
58
|
* @param {AddressesMutateOptions} options
|
|
60
59
|
*/
|
|
61
|
-
const remove = (
|
|
60
|
+
const remove = (
|
|
61
|
+
address: Joanie.Address,
|
|
62
|
+
options?: Parameters<typeof addresses.methods.delete>[1],
|
|
63
|
+
) => {
|
|
62
64
|
if (address.is_main) {
|
|
63
65
|
addresses.methods.setError(intl.formatMessage(messages.errorCannotRemoveMain));
|
|
64
66
|
return;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { defineMessages, useIntl } from 'react-intl';
|
|
2
2
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
3
|
-
import { MutateOptions } from '@tanstack/query-core';
|
|
4
3
|
import { API, CreditCard } from 'types/Joanie';
|
|
5
4
|
import { useJoanieApi } from 'contexts/JoanieApiContext';
|
|
6
5
|
import { useSessionMutation } from 'utils/react-query/useSessionMutation';
|
|
@@ -84,10 +83,13 @@ const useCreditCardResources =
|
|
|
84
83
|
* If the error is a 409, it means the credit card is used to pay at least one order
|
|
85
84
|
* and the user should be informed about that.
|
|
86
85
|
*/
|
|
87
|
-
const deleteMutateAsync = async (
|
|
86
|
+
const deleteMutateAsync = async (
|
|
87
|
+
creditCard: CreditCard,
|
|
88
|
+
options?: Parameters<typeof custom.methods.delete>[1],
|
|
89
|
+
) => {
|
|
88
90
|
return custom.methods.delete(creditCard.id, {
|
|
89
91
|
...options,
|
|
90
|
-
onError: (error: HttpError, variables, context) => {
|
|
92
|
+
onError: (error: HttpError, variables, context, mutationContext) => {
|
|
91
93
|
if (error.code === HttpStatusCode.CONFLICT) {
|
|
92
94
|
custom.methods.setError(
|
|
93
95
|
intl.formatMessage(messages.errorCannotDelete, {
|
|
@@ -97,7 +99,7 @@ const useCreditCardResources =
|
|
|
97
99
|
} else {
|
|
98
100
|
custom.methods.setError(intl.formatMessage(messages.errorDelete));
|
|
99
101
|
}
|
|
100
|
-
options?.onError?.(error, variables, context);
|
|
102
|
+
options?.onError?.(error, variables, context, mutationContext);
|
|
101
103
|
},
|
|
102
104
|
});
|
|
103
105
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { yupResolver } from '@hookform/resolvers/yup
|
|
2
|
-
import { FormProvider, useForm } from 'react-hook-form';
|
|
1
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
2
|
+
import { FormProvider, Resolver, useForm } from 'react-hook-form';
|
|
3
3
|
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
4
4
|
import * as Yup from 'yup';
|
|
5
5
|
import countries from 'i18n-iso-countries';
|
|
@@ -60,7 +60,7 @@ export const useDashboardAddressForm = (address?: Address) => {
|
|
|
60
60
|
defaultValues: address || defaultValues,
|
|
61
61
|
mode: 'onBlur',
|
|
62
62
|
reValidateMode: 'onChange',
|
|
63
|
-
resolver: yupResolver(validationSchema)
|
|
63
|
+
resolver: yupResolver(validationSchema) as Resolver<AddressFormValues>,
|
|
64
64
|
});
|
|
65
65
|
const { register, handleSubmit, formState } = form;
|
|
66
66
|
|
|
@@ -36,6 +36,6 @@ const useMatchMedia = (query: string): boolean => {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
export const useMatchMediaLg = () =>
|
|
39
|
-
useMatchMedia(`(max-width: ${tokens.themes.default.
|
|
39
|
+
useMatchMedia(`(max-width: ${tokens.themes.default.globals.breakpoints.lg})`);
|
|
40
40
|
|
|
41
41
|
export default useMatchMedia;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useMutation, useQuery, useQueryClient, UseQueryResult } from '@tanstack/react-query';
|
|
2
2
|
import { useCallback, useMemo, useState } from 'react';
|
|
3
3
|
import { defineMessages, useIntl } from 'react-intl';
|
|
4
|
-
import { MutateOptions } from '@tanstack/query-core
|
|
4
|
+
import { MutateOptions } from '@tanstack/query-core';
|
|
5
5
|
import { AddParameters, Maybe } from 'types/utils';
|
|
6
6
|
import { HttpError } from 'utils/errors/HttpError';
|
|
7
7
|
import { useSessionQuery } from 'utils/react-query/useSessionQuery';
|
|
@@ -35,8 +35,12 @@ export interface ResourceUnionPaginationProps {
|
|
|
35
35
|
perPage?: number;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
interface UseUnionResourceProps<
|
|
39
|
-
|
|
38
|
+
interface UseUnionResourceProps<
|
|
39
|
+
DataA,
|
|
40
|
+
DataB,
|
|
41
|
+
FiltersA,
|
|
42
|
+
FiltersB,
|
|
43
|
+
> extends ResourceUnionPaginationProps {
|
|
40
44
|
queryAConfig: QueryConfig<DataA, FiltersA>;
|
|
41
45
|
queryBConfig: QueryConfig<DataB, FiltersB>;
|
|
42
46
|
errorGetMessage?: MessageDescriptor;
|
|
@@ -53,6 +53,7 @@ export const fetchEntity = async <
|
|
|
53
53
|
// Here we need to mimic the behavior of staleTime, which does not seems to be implemented when using `getQueryData`.
|
|
54
54
|
if (
|
|
55
55
|
state &&
|
|
56
|
+
state.status === 'success' &&
|
|
56
57
|
state.dataUpdatedAt >= new Date().getTime() - REACT_QUERY_SETTINGS.staleTimes.sessionItems &&
|
|
57
58
|
!state.isInvalidated
|
|
58
59
|
) {
|
|
@@ -47,16 +47,16 @@ export const DashboardAddressBox = ({
|
|
|
47
47
|
<>
|
|
48
48
|
<div className="dashboard-address-box__buttons">
|
|
49
49
|
{!address.is_main && (
|
|
50
|
-
<Button color="primary" onClick={() => promote(address)}>
|
|
50
|
+
<Button color="brand" variant="primary" onClick={() => promote(address)}>
|
|
51
51
|
<FormattedMessage {...messages.setMain} />
|
|
52
52
|
</Button>
|
|
53
53
|
)}
|
|
54
|
-
<Button color="primary" onClick={() => edit(address)}>
|
|
54
|
+
<Button color="brand" variant="primary" onClick={() => edit(address)}>
|
|
55
55
|
<FormattedMessage {...messages.edit} />
|
|
56
56
|
</Button>
|
|
57
57
|
</div>
|
|
58
58
|
{!address.is_main && (
|
|
59
|
-
<Button color="primary" onClick={() => remove(address)}>
|
|
59
|
+
<Button color="brand" variant="primary" onClick={() => remove(address)}>
|
|
60
60
|
<FormattedMessage {...messages.delete} />
|
|
61
61
|
</Button>
|
|
62
62
|
)}
|
|
@@ -38,7 +38,7 @@ export const DashboardCreateAddress = ({ onSettled }: { onSettled?: Function })
|
|
|
38
38
|
<DashboardCard
|
|
39
39
|
header={<FormattedMessage {...messages.header} />}
|
|
40
40
|
footer={
|
|
41
|
-
<Button color="primary" onClick={handleSubmit(onSubmit)}>
|
|
41
|
+
<Button color="brand" variant="primary" onClick={handleSubmit(onSubmit)}>
|
|
42
42
|
<FormattedMessage {...messages.submit} />
|
|
43
43
|
</Button>
|
|
44
44
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react';
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
2
|
import { StorybookHelper } from 'utils/StorybookHelper';
|
|
3
3
|
import { AddressFactory } from 'utils/test/factories/joanie';
|
|
4
4
|
import { DashboardEditAddress } from './DashboardEditAddress';
|
|
@@ -54,12 +54,13 @@ export const DashboardEditAddress = ({ address, onSettled = noop }: DashboardEdi
|
|
|
54
54
|
header={<FormattedMessage {...messages.header} values={{ title: address.title }} />}
|
|
55
55
|
footer={
|
|
56
56
|
<>
|
|
57
|
-
<Button color="secondary" onClick={handleSubmit(onSubmit)}>
|
|
57
|
+
<Button color="brand" variant="secondary" onClick={handleSubmit(onSubmit)}>
|
|
58
58
|
<FormattedMessage {...messages.submit} />
|
|
59
59
|
</Button>
|
|
60
60
|
{!address.is_main && (
|
|
61
61
|
<Button
|
|
62
|
-
color="
|
|
62
|
+
color="brand"
|
|
63
|
+
variant="secondary"
|
|
63
64
|
onClick={() => {
|
|
64
65
|
remove(address, {
|
|
65
66
|
onSuccess: () => onSettled(),
|
|
@@ -86,7 +86,7 @@ export const DashboardAddressesManagement = ({
|
|
|
86
86
|
))}
|
|
87
87
|
</DashboardBox.List>
|
|
88
88
|
)}
|
|
89
|
-
<Button color="secondary" fullWidth onClick={() => onClickCreate?.()}>
|
|
89
|
+
<Button color="brand" variant="secondary" fullWidth onClick={() => onClickCreate?.()}>
|
|
90
90
|
<Icon name={IconTypeEnum.PLUS} className="button__icon" />
|
|
91
91
|
<FormattedMessage {...messages.add} />
|
|
92
92
|
</Button>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react';
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
2
|
import { CreditCardFactory } from 'utils/test/factories/joanie';
|
|
3
3
|
import { CreditCard, CreditCardBrand } from 'types/Joanie';
|
|
4
4
|
import { CreditCardBrandLogo } from './CreditCardBrandLogo';
|
|
@@ -68,15 +68,15 @@ export const DashboardCreditCardBox = ({ creditCard, promote, edit, remove }: Pr
|
|
|
68
68
|
<>
|
|
69
69
|
<div className="dashboard-credit-card__buttons">
|
|
70
70
|
{!creditCard.is_main && (
|
|
71
|
-
<Button color="primary" onClick={() => promote(creditCard)}>
|
|
71
|
+
<Button color="brand" variant="primary" onClick={() => promote(creditCard)}>
|
|
72
72
|
<FormattedMessage {...messages.setMain} />
|
|
73
73
|
</Button>
|
|
74
74
|
)}
|
|
75
|
-
<Button color="primary" onClick={() => edit(creditCard)}>
|
|
75
|
+
<Button color="brand" variant="primary" onClick={() => edit(creditCard)}>
|
|
76
76
|
<FormattedMessage {...messages.edit} />
|
|
77
77
|
</Button>
|
|
78
78
|
</div>
|
|
79
|
-
<Button color="primary" onClick={() => remove(creditCard)}>
|
|
79
|
+
<Button color="brand" variant="primary" onClick={() => remove(creditCard)}>
|
|
80
80
|
<FormattedMessage {...messages.delete} />
|
|
81
81
|
</Button>
|
|
82
82
|
</>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react';
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
2
|
import { StorybookHelper } from 'utils/StorybookHelper';
|
|
3
3
|
import { CreditCardFactory } from 'utils/test/factories/joanie';
|
|
4
4
|
import { DashboardEditCreditCard } from './DashboardEditCreditCard';
|
|
@@ -159,12 +159,13 @@ export const DashboardEditCreditCard = ({ creditCard, onSettled = noop }: Props)
|
|
|
159
159
|
header={<FormattedMessage {...messages.header} />}
|
|
160
160
|
footer={
|
|
161
161
|
<>
|
|
162
|
-
<Button color="secondary" onClick={handleSubmit(onSubmit)}>
|
|
162
|
+
<Button color="brand" variant="secondary" onClick={handleSubmit(onSubmit)}>
|
|
163
163
|
<FormattedMessage {...messages.submit} />
|
|
164
164
|
</Button>
|
|
165
165
|
{!creditCard.is_main && (
|
|
166
166
|
<Button
|
|
167
|
-
color="
|
|
167
|
+
color="brand"
|
|
168
|
+
variant="secondary"
|
|
168
169
|
onClick={() =>
|
|
169
170
|
safeDelete(creditCard, {
|
|
170
171
|
onSuccess: () => {
|
package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.tsx
CHANGED
|
@@ -49,7 +49,8 @@ const BulkDownloadContractButton = ({
|
|
|
49
49
|
return (
|
|
50
50
|
<Button
|
|
51
51
|
disabled={true}
|
|
52
|
-
color="
|
|
52
|
+
color="brand"
|
|
53
|
+
variant="tertiary"
|
|
53
54
|
size="small"
|
|
54
55
|
icon={<div className="spinner spinner--small" />}
|
|
55
56
|
>
|
|
@@ -62,7 +63,8 @@ const BulkDownloadContractButton = ({
|
|
|
62
63
|
<Button
|
|
63
64
|
onClick={downloadContractArchive}
|
|
64
65
|
disabled={status === ContractDownloadStatus.INITIALIZING}
|
|
65
|
-
color=
|
|
66
|
+
color="brand"
|
|
67
|
+
variant={status === ContractDownloadStatus.READY ? 'primary' : 'tertiary'}
|
|
66
68
|
size="small"
|
|
67
69
|
icon={<span className="material-icons">download</span>}
|
|
68
70
|
>
|
package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx
CHANGED
|
@@ -116,9 +116,9 @@ describe.each([
|
|
|
116
116
|
});
|
|
117
117
|
|
|
118
118
|
await waitFor(() => {
|
|
119
|
-
expect(result.current.
|
|
119
|
+
expect(result.current.isContractArchiveExists).toBe(true);
|
|
120
120
|
});
|
|
121
|
-
expect(result.current.
|
|
121
|
+
expect(result.current.isPolling).toBe(false);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
124
|
it('should do nothing when enable is false', () => {
|
|
@@ -160,8 +160,8 @@ describe.each([
|
|
|
160
160
|
mockCheckArchive.mockResolvedValue(true);
|
|
161
161
|
await waitFor(() => {
|
|
162
162
|
expect(mockCheckArchive).toHaveBeenCalledTimes(2);
|
|
163
|
+
expect(result.current.isContractArchiveExists).toBe(true);
|
|
164
|
+
expect(result.current.isPolling).toBe(false);
|
|
163
165
|
});
|
|
164
|
-
expect(result.current.isPolling).toBe(false);
|
|
165
|
-
expect(result.current.isContractArchiveExists).toBe(true);
|
|
166
166
|
});
|
|
167
167
|
});
|
package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.spec.tsx
CHANGED
|
@@ -232,6 +232,7 @@ describe.each([
|
|
|
232
232
|
const contractArchiveId = faker.string.uuid();
|
|
233
233
|
storeContractArchiveId({ ...localStorageArchiveFilters, contractArchiveId });
|
|
234
234
|
mockCheckArchive.mockResolvedValue(true);
|
|
235
|
+
mockGetArchive.mockResolvedValue('fake-content');
|
|
235
236
|
|
|
236
237
|
const { result } = renderHook(
|
|
237
238
|
() => useDownloadContractArchive(localStorageArchiveFilters),
|
|
@@ -246,8 +247,8 @@ describe.each([
|
|
|
246
247
|
});
|
|
247
248
|
expect(mockCheckArchive).toHaveBeenCalledTimes(1);
|
|
248
249
|
|
|
249
|
-
act(() => {
|
|
250
|
-
result.current.downloadContractArchive();
|
|
250
|
+
await act(async () => {
|
|
251
|
+
await result.current.downloadContractArchive();
|
|
251
252
|
});
|
|
252
253
|
|
|
253
254
|
await waitFor(() => {
|
|
@@ -255,11 +256,8 @@ describe.each([
|
|
|
255
256
|
});
|
|
256
257
|
|
|
257
258
|
expect(mockCheckArchive).toHaveBeenCalledTimes(1);
|
|
258
|
-
// backend is called to download the archive
|
|
259
|
-
expect(mockGetArchive).toHaveBeenCalledTimes(1);
|
|
260
|
-
|
|
261
|
-
// but not to generate the archive
|
|
262
259
|
expect(mockCreateArchive).not.toHaveBeenCalled();
|
|
260
|
+
expect(mockGetArchive).toHaveBeenCalledTimes(1);
|
|
263
261
|
});
|
|
264
262
|
|
|
265
263
|
it("doDownloadArchive should call 'createArchive' if no contractArchiveId is stored", async () => {
|
|
@@ -271,9 +269,11 @@ describe.each([
|
|
|
271
269
|
);
|
|
272
270
|
|
|
273
271
|
mockCheckArchive.mockResolvedValue(true);
|
|
272
|
+
|
|
274
273
|
mockCreateArchive.mockResolvedValue(faker.string.uuid());
|
|
275
|
-
|
|
276
|
-
|
|
274
|
+
|
|
275
|
+
await act(async () => {
|
|
276
|
+
await result.current.downloadContractArchive();
|
|
277
277
|
});
|
|
278
278
|
|
|
279
279
|
await waitFor(() => {
|
|
@@ -282,7 +282,6 @@ describe.each([
|
|
|
282
282
|
|
|
283
283
|
expect(mockCreateArchive).toHaveBeenCalledTimes(1);
|
|
284
284
|
expect(mockCheckArchive).toHaveBeenCalledTimes(1);
|
|
285
|
-
expect(mockGetArchive).toHaveBeenCalledTimes(1);
|
|
286
285
|
});
|
|
287
286
|
});
|
|
288
287
|
|
|
@@ -157,10 +157,21 @@ const useDownloadContractArchive = ({
|
|
|
157
157
|
// this effect will trigger the download
|
|
158
158
|
// if it have been previously requested by the user
|
|
159
159
|
useEffect(() => {
|
|
160
|
-
if (isDownloadRequest && isContractArchiveExists) {
|
|
161
|
-
|
|
160
|
+
if (isDownloadRequest && isContractArchiveExists && contractArchiveId !== null) {
|
|
161
|
+
(async () => {
|
|
162
|
+
await getArchive(contractArchiveId);
|
|
163
|
+
setIsDownloadRequest(false);
|
|
164
|
+
setContractArchiveId(null);
|
|
165
|
+
unstoreContractArchiveId(localstorageArchiveFilters);
|
|
166
|
+
})();
|
|
162
167
|
}
|
|
163
|
-
}, [
|
|
168
|
+
}, [
|
|
169
|
+
isDownloadRequest,
|
|
170
|
+
isContractArchiveExists,
|
|
171
|
+
contractArchiveId,
|
|
172
|
+
localstorageArchiveFilters,
|
|
173
|
+
getArchive,
|
|
174
|
+
]);
|
|
164
175
|
|
|
165
176
|
return {
|
|
166
177
|
status: contractDownloadStatus,
|
package/js/pages/TeacherDashboardCourseLearnersLayout/components/CourseLearnerDataGrid/index.tsx
CHANGED
|
@@ -82,7 +82,12 @@ const CourseLearnerDataGrid = ({
|
|
|
82
82
|
headerName: intl.formatMessage(messages.columnActions),
|
|
83
83
|
renderCell: (params: { row: Row }) => {
|
|
84
84
|
return (
|
|
85
|
-
<Button
|
|
85
|
+
<Button
|
|
86
|
+
href={`mailto:${params.row.owner__email}`}
|
|
87
|
+
size="small"
|
|
88
|
+
color="brand"
|
|
89
|
+
variant="secondary"
|
|
90
|
+
>
|
|
86
91
|
<FormattedMessage {...messages.contactButton} />
|
|
87
92
|
</Button>
|
|
88
93
|
);
|
|
@@ -69,7 +69,8 @@ export const buildCourseRunData = (intl: IntlShape, courseRuns: CourseRun[]) =>
|
|
|
69
69
|
<CourseRunListCell variant={CourseRunListCell.ALIGN_RIGHT}>
|
|
70
70
|
<Button
|
|
71
71
|
href={courseRun.resource_link}
|
|
72
|
-
color="
|
|
72
|
+
color="brand"
|
|
73
|
+
variant="secondary"
|
|
73
74
|
size="small"
|
|
74
75
|
icon={<Icon name={IconTypeEnum.LOGOUT_SQUARE} size="small" />}
|
|
75
76
|
>
|
|
@@ -50,7 +50,8 @@ const BulkDownloadAgreementButton = ({
|
|
|
50
50
|
return (
|
|
51
51
|
<Button
|
|
52
52
|
disabled={true}
|
|
53
|
-
color="
|
|
53
|
+
color="brand"
|
|
54
|
+
variant="tertiary"
|
|
54
55
|
size="small"
|
|
55
56
|
icon={<div className="spinner spinner--small" />}
|
|
56
57
|
>
|
|
@@ -63,7 +64,8 @@ const BulkDownloadAgreementButton = ({
|
|
|
63
64
|
<Button
|
|
64
65
|
onClick={downloadContractArchive}
|
|
65
66
|
disabled={status === ContractDownloadStatus.INITIALIZING}
|
|
66
|
-
color=
|
|
67
|
+
color="brand"
|
|
68
|
+
variant={status === ContractDownloadStatus.READY ? 'primary' : 'tertiary'}
|
|
67
69
|
size="small"
|
|
68
70
|
icon={<span className="material-icons">download</span>}
|
|
69
71
|
>
|
|
@@ -37,7 +37,7 @@ describe('full process for the organization quotes dashboard', () => {
|
|
|
37
37
|
|
|
38
38
|
const organization = OrganizationFactory({
|
|
39
39
|
abilities: {
|
|
40
|
-
|
|
40
|
+
can_manage_batch_order_agreement: true,
|
|
41
41
|
confirm_bank_transfer: true,
|
|
42
42
|
confirm_quote: true,
|
|
43
43
|
download_quote: true,
|
|
@@ -206,7 +206,7 @@ describe('full process for the organization quotes dashboard', () => {
|
|
|
206
206
|
fetchMock.get(`https://joanie.endpoint/api/v1.0/organizations/`, []);
|
|
207
207
|
const organization = OrganizationFactory({
|
|
208
208
|
abilities: {
|
|
209
|
-
|
|
209
|
+
can_manage_batch_order_agreement: true,
|
|
210
210
|
confirm_bank_transfer: true,
|
|
211
211
|
confirm_quote: true,
|
|
212
212
|
download_quote: true,
|
|
@@ -165,7 +165,7 @@ describe('pages/TeacherDashboardOrganizationQuotes', () => {
|
|
|
165
165
|
|
|
166
166
|
const organization = OrganizationFactory({
|
|
167
167
|
abilities: {
|
|
168
|
-
|
|
168
|
+
can_manage_batch_order_agreement: false,
|
|
169
169
|
confirm_bank_transfer: false,
|
|
170
170
|
confirm_quote: false,
|
|
171
171
|
download_quote: true,
|
|
@@ -371,7 +371,8 @@ const TeacherDashboardOrganizationQuotes = () => {
|
|
|
371
371
|
<div>
|
|
372
372
|
<Button
|
|
373
373
|
size="small"
|
|
374
|
-
color="
|
|
374
|
+
color="brand"
|
|
375
|
+
variant="secondary"
|
|
375
376
|
className="mr-2"
|
|
376
377
|
onClick={() => handleDownloadQuote(quote.id)}
|
|
377
378
|
icon={<span className="material-icons">download</span>}
|
|
@@ -415,7 +416,7 @@ const TeacherDashboardOrganizationQuotes = () => {
|
|
|
415
416
|
const submitForSignatureButton = (
|
|
416
417
|
<Button
|
|
417
418
|
size="small"
|
|
418
|
-
disabled={batchOrder.contract_submitted || !abilities?.
|
|
419
|
+
disabled={batchOrder.contract_submitted || !abilities?.can_manage_batch_order_agreement}
|
|
419
420
|
onClick={() =>
|
|
420
421
|
!batchOrder.contract_submitted && handleSubmitForSignature(quote.batch_order.id)
|
|
421
422
|
}
|