richie-education 2.34.0 → 2.34.1-dev2
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/AddressesManagement/index.spec.tsx +1 -1
- package/js/components/AddressesManagement/index.tsx +123 -129
- package/js/components/ContractFrame/AbstractContractFrame.tsx +1 -1
- package/js/components/Icon/index.stories.tsx +1 -1
- package/js/components/PaymentInterfaces/PayplugLightbox.tsx +1 -1
- package/js/components/SaleTunnel/SaleTunnelSavePaymentMethod/index.tsx +2 -2
- package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx +4 -2
- package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.tsx +1 -1
- package/js/pages/TeacherDashboardOrganizationCourseLoader/index.spec.tsx +8 -5
- package/js/utils/test/wrappers/types.ts +2 -2
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentRetryModal/index.tsx +1 -1
- package/js/widgets/Dashboard/components/SearchBar/index.spec.tsx +1 -1
- package/js/widgets/Dashboard/components/SearchResultsCount/index.spec.tsx +1 -1
- package/js/widgets/SyllabusCourseRunsList/components/CourseRunEnrollment/index.tsx +1 -5
- package/package.json +41 -39
- package/scss/vendors/css/cunningham-tokens.css +1 -0
|
@@ -6,7 +6,7 @@ import fetchMock from 'fetch-mock';
|
|
|
6
6
|
import { IntlProvider } from 'react-intl';
|
|
7
7
|
import countries from 'i18n-iso-countries';
|
|
8
8
|
import { QueryClientProvider } from '@tanstack/react-query';
|
|
9
|
-
import { PropsWithChildren } from 'react';
|
|
9
|
+
import React, { PropsWithChildren } from 'react';
|
|
10
10
|
import { CunninghamProvider } from '@openfun/cunningham-react';
|
|
11
11
|
import userEvent, { UserEvent } from '@testing-library/user-event';
|
|
12
12
|
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Children,
|
|
1
|
+
import { Children, useEffect, useState, RefAttributes } from 'react';
|
|
2
2
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|
3
3
|
import { Button } from '@openfun/cunningham-react';
|
|
4
4
|
import AddressForm, { type AddressFormValues } from 'components/AddressesManagement/AddressForm';
|
|
@@ -7,7 +7,6 @@ import { Icon, IconTypeEnum } from 'components/Icon';
|
|
|
7
7
|
import RegisteredAddress from 'components/RegisteredAddress';
|
|
8
8
|
import { useAddressesManagement } from 'hooks/useAddressesManagement';
|
|
9
9
|
import type * as Joanie from 'types/Joanie';
|
|
10
|
-
import { Address } from 'types/Joanie';
|
|
11
10
|
import { Maybe } from 'types/utils';
|
|
12
11
|
|
|
13
12
|
// constant used as `address.id` for local address
|
|
@@ -106,147 +105,142 @@ export const messages = defineMessages({
|
|
|
106
105
|
},
|
|
107
106
|
});
|
|
108
107
|
|
|
109
|
-
interface AddressesManagementProps {
|
|
108
|
+
interface AddressesManagementProps extends RefAttributes<HTMLDivElement> {
|
|
110
109
|
handleClose: () => void;
|
|
111
110
|
selectAddress: (address: Joanie.Address) => void;
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
const AddressesManagement =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
} = useAddressesManagement();
|
|
113
|
+
const AddressesManagement = ({ handleClose, selectAddress, ref }: AddressesManagementProps) => {
|
|
114
|
+
const intl = useIntl();
|
|
115
|
+
const [editedAddress, setEditedAddress] = useState<Maybe<Joanie.Address>>();
|
|
116
|
+
const {
|
|
117
|
+
methods: { setError, create, update, remove, promote },
|
|
118
|
+
states: { error },
|
|
119
|
+
...addresses
|
|
120
|
+
} = useAddressesManagement();
|
|
123
121
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Sort addresses ascending by title according to the locale
|
|
124
|
+
*
|
|
125
|
+
* @param {Joanie.Address} a
|
|
126
|
+
* @param {Joanie.Address} b
|
|
127
|
+
* @returns {Joanie.Address[]} Sorted addresses ascending by title
|
|
128
|
+
*/
|
|
129
|
+
const sortAddressByTitleAsc = (a: Joanie.Address, b: Joanie.Address) => {
|
|
130
|
+
return a.title.localeCompare(b.title, [intl.locale, intl.defaultLocale]);
|
|
131
|
+
};
|
|
134
132
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
133
|
+
/**
|
|
134
|
+
* update `selectedAddress` state with the address provided
|
|
135
|
+
* then close the address management form
|
|
136
|
+
*
|
|
137
|
+
* @param {Joanie.Address} address
|
|
138
|
+
*/
|
|
139
|
+
const handleSelect = (address: Joanie.Address) => {
|
|
140
|
+
setError(undefined);
|
|
141
|
+
selectAddress(address);
|
|
142
|
+
handleClose();
|
|
143
|
+
};
|
|
146
144
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Create a new address according to form values
|
|
147
|
+
* then update `selectedAddress` state with this new one.
|
|
148
|
+
* If `save` checkbox input is checked, the address is persisted
|
|
149
|
+
* otherwise it is only stored through the `selectedAddress` state.
|
|
150
|
+
*
|
|
151
|
+
* @param {AddressFormValues} formValues address fields to update
|
|
152
|
+
*/
|
|
153
|
+
const handleCreate = async ({ save, ...address }: AddressFormValues) => {
|
|
154
|
+
if (save) {
|
|
155
|
+
await create(address, { onSuccess: handleSelect });
|
|
156
|
+
} else {
|
|
157
|
+
handleSelect({
|
|
158
|
+
id: LOCAL_BILLING_ADDRESS_ID,
|
|
159
|
+
is_main: false,
|
|
160
|
+
...address,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
166
164
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Update the `editedAddress` with new values provided as argument
|
|
167
|
+
* then clear `editedAddress` state if request succeeded.
|
|
168
|
+
*
|
|
169
|
+
* @param {AddressFormValues} formValues address fields to update
|
|
170
|
+
*/
|
|
171
|
+
const handleUpdate = async ({ save, ...newAddress }: AddressFormValues) => {
|
|
172
|
+
update(
|
|
173
|
+
{
|
|
174
|
+
...editedAddress!,
|
|
175
|
+
...newAddress,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
onSuccess: () => setEditedAddress(undefined),
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
};
|
|
184
182
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
setError(undefined);
|
|
185
|
+
if (editedAddress) {
|
|
186
|
+
document.querySelector<HTMLElement>('[name="address-form"] input')?.focus();
|
|
187
|
+
}
|
|
188
|
+
}, [editedAddress]);
|
|
191
189
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<header>
|
|
207
|
-
<h2 className="h5">
|
|
208
|
-
<FormattedMessage {...messages.registeredAddresses} />
|
|
209
|
-
</h2>
|
|
210
|
-
</header>
|
|
211
|
-
<ul className="registered-addresses-list">
|
|
212
|
-
{Children.toArray(
|
|
213
|
-
addresses.items
|
|
214
|
-
.sort(sortAddressByTitleAsc)
|
|
215
|
-
.map((address) => (
|
|
216
|
-
<RegisteredAddress
|
|
217
|
-
address={address}
|
|
218
|
-
edit={setEditedAddress}
|
|
219
|
-
promote={promote}
|
|
220
|
-
remove={remove}
|
|
221
|
-
select={handleSelect}
|
|
222
|
-
/>
|
|
223
|
-
)),
|
|
224
|
-
)}
|
|
225
|
-
</ul>
|
|
226
|
-
</section>
|
|
227
|
-
) : null}
|
|
228
|
-
<section className={`address-form ${editedAddress ? 'address-form--highlighted' : ''}`}>
|
|
190
|
+
return (
|
|
191
|
+
<div className="AddressesManagement" ref={ref}>
|
|
192
|
+
<Button
|
|
193
|
+
className="AddressesManagement__closeButton"
|
|
194
|
+
color="tertiary"
|
|
195
|
+
size="small"
|
|
196
|
+
onClick={handleClose}
|
|
197
|
+
>
|
|
198
|
+
<Icon name={IconTypeEnum.CHEVRON_LEFT_OUTLINE} className="button__icon" />
|
|
199
|
+
<FormattedMessage {...messages.closeButton} />
|
|
200
|
+
</Button>
|
|
201
|
+
{error && <Banner message={error} type={BannerType.ERROR} rounded />}
|
|
202
|
+
{addresses.items.length > 0 ? (
|
|
203
|
+
<section className="address-registered">
|
|
229
204
|
<header>
|
|
230
205
|
<h2 className="h5">
|
|
231
|
-
{
|
|
232
|
-
<FormattedMessage
|
|
233
|
-
{...messages.editAddress}
|
|
234
|
-
values={{ title: editedAddress.title }}
|
|
235
|
-
/>
|
|
236
|
-
) : (
|
|
237
|
-
<FormattedMessage {...messages.addAddress} />
|
|
238
|
-
)}
|
|
206
|
+
<FormattedMessage {...messages.registeredAddresses} />
|
|
239
207
|
</h2>
|
|
240
208
|
</header>
|
|
241
|
-
<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
209
|
+
<ul className="registered-addresses-list">
|
|
210
|
+
{Children.toArray(
|
|
211
|
+
addresses.items
|
|
212
|
+
.sort(sortAddressByTitleAsc)
|
|
213
|
+
.map((address) => (
|
|
214
|
+
<RegisteredAddress
|
|
215
|
+
address={address}
|
|
216
|
+
edit={setEditedAddress}
|
|
217
|
+
promote={promote}
|
|
218
|
+
remove={remove}
|
|
219
|
+
select={handleSelect}
|
|
220
|
+
/>
|
|
221
|
+
)),
|
|
222
|
+
)}
|
|
223
|
+
</ul>
|
|
246
224
|
</section>
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
225
|
+
) : null}
|
|
226
|
+
<section className={`address-form ${editedAddress ? 'address-form--highlighted' : ''}`}>
|
|
227
|
+
<header>
|
|
228
|
+
<h2 className="h5">
|
|
229
|
+
{editedAddress ? (
|
|
230
|
+
<FormattedMessage {...messages.editAddress} values={{ title: editedAddress.title }} />
|
|
231
|
+
) : (
|
|
232
|
+
<FormattedMessage {...messages.addAddress} />
|
|
233
|
+
)}
|
|
234
|
+
</h2>
|
|
235
|
+
</header>
|
|
236
|
+
<AddressForm
|
|
237
|
+
address={editedAddress}
|
|
238
|
+
handleReset={() => setEditedAddress(undefined)}
|
|
239
|
+
onSubmit={editedAddress ? handleUpdate : handleCreate}
|
|
240
|
+
/>
|
|
241
|
+
</section>
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
};
|
|
251
245
|
|
|
252
246
|
export default AddressesManagement;
|
|
@@ -134,7 +134,7 @@ const ContractFrameContent = ({
|
|
|
134
134
|
const [signatureType, setSignatureType] = useState<SignatureType>();
|
|
135
135
|
const [invitationLink, setInvitationLink] = useState<Maybe<string>>();
|
|
136
136
|
const [error, setError] = useState<Maybe<string>>();
|
|
137
|
-
const timeoutRef = useRef<NodeJS.Timeout>();
|
|
137
|
+
const timeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
138
138
|
|
|
139
139
|
const setErrored = (e: string) => {
|
|
140
140
|
setStep(ContractSteps.ERROR);
|
|
@@ -29,7 +29,7 @@ type IconContainerProps = {
|
|
|
29
29
|
};
|
|
30
30
|
const IconContainer = ({ name, enumKey }: IconContainerProps) => {
|
|
31
31
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
32
|
-
const timeoutRef = useRef<NodeJS.Timeout>();
|
|
32
|
+
const timeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
33
33
|
const ENUM_NAME = 'IconTypeEnum';
|
|
34
34
|
|
|
35
35
|
const styleContainer: CSSProperties = {
|
|
@@ -17,7 +17,7 @@ const PayplugLightbox = ({
|
|
|
17
17
|
onError,
|
|
18
18
|
...props
|
|
19
19
|
}: PaymentInterfaceProps<PayplugPayment>) => {
|
|
20
|
-
const ref = useRef<ReturnType<typeof setTimeout>>();
|
|
20
|
+
const ref = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
21
21
|
|
|
22
22
|
/** type guard to check if the payment is a payment one click */
|
|
23
23
|
const isPaidPayment = (p: PayplugPayment) => p?.is_paid === true;
|
|
@@ -47,7 +47,7 @@ const messages = defineMessages({
|
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
const SaleTunnelSavePaymentMethod = () => {
|
|
50
|
-
const initialCreditCards = useRef<CreditCard[]>();
|
|
50
|
+
const initialCreditCards = useRef<CreditCard[]>([]);
|
|
51
51
|
const [shouldPoll, setShouldPoll] = useState(false);
|
|
52
52
|
const [payment, setPayment] = useState<Payment>();
|
|
53
53
|
const [error, setError] = useState<string>();
|
|
@@ -71,7 +71,7 @@ const SaleTunnelSavePaymentMethod = () => {
|
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
const waitForNewCreditCard = () => {
|
|
74
|
-
const initialIds = initialCreditCards.current
|
|
74
|
+
const initialIds = initialCreditCards.current.map((cc) => cc.id);
|
|
75
75
|
const newCard = creditCardsQuery.items.find((cc) => !initialIds.includes(cc.id));
|
|
76
76
|
|
|
77
77
|
if (!newCard) return;
|
package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx
CHANGED
|
@@ -98,7 +98,7 @@ describe.each([
|
|
|
98
98
|
expect(mockCheckArchive).not.toHaveBeenCalled();
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
it('should check if archive exist when
|
|
101
|
+
it('should check if archive exist when an id is stored', async () => {
|
|
102
102
|
storeContractArchiveId({
|
|
103
103
|
...localStorageArchiveFilters,
|
|
104
104
|
contractArchiveId: faker.string.uuid(),
|
|
@@ -115,7 +115,9 @@ describe.each([
|
|
|
115
115
|
expect(mockCheckArchive).toHaveBeenCalledTimes(1);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
await waitFor(() => {
|
|
119
|
+
expect(result.current.isPolling).toBe(false);
|
|
120
|
+
});
|
|
119
121
|
expect(result.current.isContractArchiveExists).toBe(true);
|
|
120
122
|
});
|
|
121
123
|
|
package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.tsx
CHANGED
|
@@ -25,7 +25,7 @@ const useCheckContractArchiveExist = (
|
|
|
25
25
|
// stay null until fetched
|
|
26
26
|
const [isContractArchiveExists, setIsContractArchiveExists] = useState<Nullable<boolean>>(null);
|
|
27
27
|
|
|
28
|
-
const timeoutRef = useRef<NodeJS.Timeout>();
|
|
28
|
+
const timeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
29
29
|
|
|
30
30
|
// This method will check if the archive exists on the server
|
|
31
31
|
// option.polling === true will recursivly poll archive existence
|
|
@@ -41,6 +41,9 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
|
|
|
41
41
|
beforeEach(() => {
|
|
42
42
|
nbApiCalls = joanieSessionData.nbSessionApiRequest;
|
|
43
43
|
});
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
fetchMock.restore();
|
|
46
|
+
});
|
|
44
47
|
|
|
45
48
|
it('should render', async () => {
|
|
46
49
|
const organization = OrganizationFactory().one();
|
|
@@ -59,6 +62,10 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
|
|
|
59
62
|
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
|
|
60
63
|
mockPaginatedResponse(CourseProductRelationFactory().many(15), 15, false),
|
|
61
64
|
);
|
|
65
|
+
fetchMock.get(
|
|
66
|
+
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?signature_state=half_signed&page=1`,
|
|
67
|
+
[],
|
|
68
|
+
);
|
|
62
69
|
|
|
63
70
|
render(<TeacherDashboardOrganizationCourseLoader />, {
|
|
64
71
|
routerOptions: {
|
|
@@ -70,6 +77,7 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
|
|
|
70
77
|
|
|
71
78
|
nbApiCalls += 1; // course api call
|
|
72
79
|
nbApiCalls += 1; // course-product-relations api call
|
|
80
|
+
nbApiCalls += 1; // contracts api call
|
|
73
81
|
const calledUrls = fetchMock.calls().map((call) => call[0]);
|
|
74
82
|
expect(calledUrls).toHaveLength(nbApiCalls);
|
|
75
83
|
expect(calledUrls).toContain(
|
|
@@ -78,11 +86,6 @@ describe('components/TeacherDashboardOrganizationCourseLoader', () => {
|
|
|
78
86
|
expect(calledUrls).toContain(
|
|
79
87
|
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/course-product-relations/?product_type=credential&page=1&page_size=${perPage}`,
|
|
80
88
|
);
|
|
81
|
-
|
|
82
|
-
fetchMock.get(
|
|
83
|
-
`https://joanie.endpoint/api/v1.0/organizations/${organization.id}/contracts/?signature_state=half_signed&page=1`,
|
|
84
|
-
[],
|
|
85
|
-
);
|
|
86
89
|
await expectNoSpinner('Loading organization...');
|
|
87
90
|
|
|
88
91
|
expect(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PropsWithChildren } from 'react';
|
|
1
|
+
import { PropsWithChildren, ReactElement } from 'react';
|
|
2
2
|
import { QueryClient } from '@tanstack/query-core';
|
|
3
3
|
import { RenderOptions as TestingLibraryRenderOptions } from '@testing-library/react';
|
|
4
4
|
import { Nullable } from 'types/utils';
|
|
@@ -19,7 +19,7 @@ interface QueryOptions {
|
|
|
19
19
|
* @property queryOptions options to configure a custom client used by react-query for a test
|
|
20
20
|
*/
|
|
21
21
|
export interface AppWrapperProps {
|
|
22
|
-
wrapper?: Nullable<(props: PropsWithChildren<{ options?: AppWrapperProps }>) =>
|
|
22
|
+
wrapper?: Nullable<(props: PropsWithChildren<{ options?: AppWrapperProps }>) => ReactElement>;
|
|
23
23
|
intlOptions?: IntlWrapperProps;
|
|
24
24
|
queryOptions?: QueryOptions;
|
|
25
25
|
historyOptions?: History;
|
package/js/widgets/Dashboard/components/DashboardItem/Order/OrderPaymentRetryModal/index.tsx
CHANGED
|
@@ -83,7 +83,7 @@ enum ComponentStates {
|
|
|
83
83
|
export const OrderPaymentRetryModal = ({ installment, order, ...props }: Props) => {
|
|
84
84
|
const intl = useIntl();
|
|
85
85
|
const API = useJoanieApi();
|
|
86
|
-
const timeoutRef = useRef<NodeJS.Timeout>();
|
|
86
|
+
const timeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
87
87
|
const { methods: orderMethods } = useOrders(undefined, { enabled: false });
|
|
88
88
|
const [payment, setPayment] = useState<Payment>();
|
|
89
89
|
const [state, setState] = useState<ComponentStates>(ComponentStates.IDLE);
|
|
@@ -4,7 +4,7 @@ import { render } from 'utils/test/render';
|
|
|
4
4
|
import { PresentationalAppWrapper } from 'utils/test/wrappers/PresentationalAppWrapper';
|
|
5
5
|
import SearchBar from '.';
|
|
6
6
|
|
|
7
|
-
describe('
|
|
7
|
+
describe('Dashboard/components/SearchBar', () => {
|
|
8
8
|
it('should render', () => {
|
|
9
9
|
render(<SearchBar onSubmit={jest.fn()} />, { wrapper: PresentationalAppWrapper });
|
|
10
10
|
expect(screen.getByRole('textbox', { name: /Search/ })).toBeInTheDocument();
|
|
@@ -3,7 +3,7 @@ import { render } from 'utils/test/render';
|
|
|
3
3
|
import { PresentationalAppWrapper } from 'utils/test/wrappers/PresentationalAppWrapper';
|
|
4
4
|
import SearchResultsCount from '.';
|
|
5
5
|
|
|
6
|
-
describe('
|
|
6
|
+
describe('Dashboard/components/SearchResultsCount', () => {
|
|
7
7
|
it('should render singular message', () => {
|
|
8
8
|
render(<SearchResultsCount nbResults={1} />, {
|
|
9
9
|
wrapper: PresentationalAppWrapper,
|
|
@@ -195,11 +195,7 @@ const CourseRunEnrollment: React.FC<CourseRunEnrollmentProps> = (props) => {
|
|
|
195
195
|
step,
|
|
196
196
|
},
|
|
197
197
|
dispatch,
|
|
198
|
-
] = useReducer
|
|
199
|
-
reducer,
|
|
200
|
-
initialState(user, props.courseRun, enrollmentIsActive),
|
|
201
|
-
(s) => s,
|
|
202
|
-
);
|
|
198
|
+
] = useReducer(reducer, initialState(user, props.courseRun, enrollmentIsActive));
|
|
203
199
|
|
|
204
200
|
const setEnroll = useCallback(
|
|
205
201
|
async (isActive: boolean = true) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "richie-education",
|
|
3
|
-
"version": "2.34.
|
|
3
|
+
"version": "2.34.1-dev2",
|
|
4
4
|
"description": "A CMS to build learning portals for Open Education",
|
|
5
5
|
"main": "sandbox/manage.py",
|
|
6
6
|
"scripts": {
|
|
@@ -40,34 +40,34 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@babel/core": "7.26.0",
|
|
42
42
|
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
|
43
|
-
"@babel/plugin-transform-modules-commonjs": "7.
|
|
43
|
+
"@babel/plugin-transform-modules-commonjs": "7.26.3",
|
|
44
44
|
"@babel/preset-env": "7.26.0",
|
|
45
|
-
"@babel/preset-react": "7.
|
|
45
|
+
"@babel/preset-react": "7.26.3",
|
|
46
46
|
"@babel/preset-typescript": "7.26.0",
|
|
47
|
-
"@faker-js/faker": "9.
|
|
48
|
-
"@formatjs/cli": "6.3.
|
|
49
|
-
"@formatjs/intl-relativetimeformat": "11.4.
|
|
47
|
+
"@faker-js/faker": "9.3.0",
|
|
48
|
+
"@formatjs/cli": "6.3.14",
|
|
49
|
+
"@formatjs/intl-relativetimeformat": "11.4.8",
|
|
50
50
|
"@hookform/resolvers": "3.9.1",
|
|
51
51
|
"@lyracom/embedded-form-glue": "1.4.2",
|
|
52
|
-
"@openfun/cunningham-react": "
|
|
53
|
-
"@openfun/cunningham-tokens": "2.
|
|
52
|
+
"@openfun/cunningham-react": "3.0.0",
|
|
53
|
+
"@openfun/cunningham-tokens": "2.2.0",
|
|
54
54
|
"@sentry/browser": "8.42.0",
|
|
55
55
|
"@sentry/types": "8.42.0",
|
|
56
|
-
"@storybook/addon-actions": "8.4.
|
|
57
|
-
"@storybook/addon-essentials": "8.4.
|
|
58
|
-
"@storybook/addon-interactions": "8.4.
|
|
59
|
-
"@storybook/addon-links": "8.4.
|
|
60
|
-
"@storybook/react": "8.4.
|
|
61
|
-
"@storybook/react-webpack5": "8.4.
|
|
62
|
-
"@storybook/test": "8.4.
|
|
63
|
-
"@tanstack/query-core": "5.62.
|
|
64
|
-
"@tanstack/query-sync-storage-persister": "5.62.
|
|
65
|
-
"@tanstack/react-query": "5.62.
|
|
66
|
-
"@tanstack/react-query-devtools": "5.62.
|
|
67
|
-
"@tanstack/react-query-persist-client": "5.62.
|
|
56
|
+
"@storybook/addon-actions": "8.4.7",
|
|
57
|
+
"@storybook/addon-essentials": "8.4.7",
|
|
58
|
+
"@storybook/addon-interactions": "8.4.7",
|
|
59
|
+
"@storybook/addon-links": "8.4.7",
|
|
60
|
+
"@storybook/react": "8.4.7",
|
|
61
|
+
"@storybook/react-webpack5": "8.4.7",
|
|
62
|
+
"@storybook/test": "8.4.7",
|
|
63
|
+
"@tanstack/query-core": "5.62.3",
|
|
64
|
+
"@tanstack/query-sync-storage-persister": "5.62.3",
|
|
65
|
+
"@tanstack/react-query": "5.62.3",
|
|
66
|
+
"@tanstack/react-query-devtools": "5.62.3",
|
|
67
|
+
"@tanstack/react-query-persist-client": "5.62.3",
|
|
68
68
|
"@testing-library/dom": "10.4.0",
|
|
69
69
|
"@testing-library/jest-dom": "6.6.3",
|
|
70
|
-
"@testing-library/react": "16.0
|
|
70
|
+
"@testing-library/react": "16.1.0",
|
|
71
71
|
"@testing-library/user-event": "14.5.2",
|
|
72
72
|
"@types/fetch-mock": "7.3.8",
|
|
73
73
|
"@types/iframe-resizer": "3.5.13",
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"@types/lodash-es": "4.17.12",
|
|
77
77
|
"@types/node-fetch": "2.6.12",
|
|
78
78
|
"@types/query-string": "6.3.0",
|
|
79
|
-
"@types/react": "
|
|
79
|
+
"@types/react": "19.0.1",
|
|
80
80
|
"@types/react-autosuggest": "10.1.11",
|
|
81
|
-
"@types/react-dom": "
|
|
81
|
+
"@types/react-dom": "19.0.1",
|
|
82
82
|
"@types/react-modal": "3.16.3",
|
|
83
83
|
"@typescript-eslint/eslint-plugin": "8.17.0",
|
|
84
84
|
"@typescript-eslint/parser": "8.17.0",
|
|
@@ -96,12 +96,12 @@
|
|
|
96
96
|
"eslint-config-prettier": "9.1.0",
|
|
97
97
|
"eslint-import-resolver-webpack": "0.13.9",
|
|
98
98
|
"eslint-plugin-compat": "6.0.1",
|
|
99
|
-
"eslint-plugin-formatjs": "5.2.
|
|
99
|
+
"eslint-plugin-formatjs": "5.2.8",
|
|
100
100
|
"eslint-plugin-import": "2.31.0",
|
|
101
101
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
|
102
102
|
"eslint-plugin-prettier": "5.2.1",
|
|
103
103
|
"eslint-plugin-react": "7.37.2",
|
|
104
|
-
"eslint-plugin-react-hooks": "5.
|
|
104
|
+
"eslint-plugin-react-hooks": "5.1.0",
|
|
105
105
|
"eslint-plugin-storybook": "0.11.1",
|
|
106
106
|
"fetch-mock": "<10",
|
|
107
107
|
"file-loader": "6.2.0",
|
|
@@ -114,35 +114,37 @@
|
|
|
114
114
|
"js-cookie": "3.0.5",
|
|
115
115
|
"lodash-es": "4.17.21",
|
|
116
116
|
"mdn-polyfills": "5.20.0",
|
|
117
|
-
"msw": "2.6.
|
|
117
|
+
"msw": "2.6.8",
|
|
118
118
|
"node-fetch": ">2.6.6 <3",
|
|
119
119
|
"nodemon": "3.1.7",
|
|
120
|
-
"prettier": "3.4.
|
|
120
|
+
"prettier": "3.4.2",
|
|
121
121
|
"query-string": "9.1.1",
|
|
122
|
-
"react": "
|
|
122
|
+
"react": "19.0.0",
|
|
123
123
|
"react-autosuggest": "10.1.0",
|
|
124
|
-
"react-dom": "
|
|
125
|
-
"react-hook-form": "7.
|
|
126
|
-
"react-intl": "7.0.
|
|
124
|
+
"react-dom": "19.0.0",
|
|
125
|
+
"react-hook-form": "7.54.0",
|
|
126
|
+
"react-intl": "7.0.4",
|
|
127
127
|
"react-modal": "3.16.1",
|
|
128
|
-
"react-router": "7.0.
|
|
129
|
-
"sass": "1.
|
|
128
|
+
"react-router": "7.0.2",
|
|
129
|
+
"sass": "1.82.0",
|
|
130
130
|
"source-map-loader": "5.0.0",
|
|
131
|
-
"storybook": "8.4.
|
|
131
|
+
"storybook": "8.4.7",
|
|
132
132
|
"tsconfig-paths-webpack-plugin": "4.2.0",
|
|
133
133
|
"typescript": "5.7.2",
|
|
134
134
|
"uuid": "11.0.3",
|
|
135
|
-
"webpack": "5.
|
|
135
|
+
"webpack": "5.97.1",
|
|
136
136
|
"webpack-cli": "5.1.4",
|
|
137
137
|
"whatwg-fetch": "3.6.20",
|
|
138
138
|
"xhr-mock": "2.5.1",
|
|
139
139
|
"yargs": "17.7.2",
|
|
140
|
-
"yup": "1.
|
|
140
|
+
"yup": "1.5.0"
|
|
141
141
|
},
|
|
142
142
|
"resolutions": {
|
|
143
143
|
"@testing-library/dom": "10.4.0",
|
|
144
|
-
"@types/react": "
|
|
145
|
-
"@types/react-dom": "
|
|
144
|
+
"@types/react": "19.0.1",
|
|
145
|
+
"@types/react-dom": "19.0.1",
|
|
146
|
+
"react": "19.0.0",
|
|
147
|
+
"react-dom": "19.0.0"
|
|
146
148
|
},
|
|
147
149
|
"msw": {
|
|
148
150
|
"workerDirectory": "../richie/static/richie/js"
|
|
@@ -152,7 +154,7 @@
|
|
|
152
154
|
"yarn": "1.22.22"
|
|
153
155
|
},
|
|
154
156
|
"devDependencies": {
|
|
155
|
-
"@storybook/addon-mdx-gfm": "8.4.
|
|
157
|
+
"@storybook/addon-mdx-gfm": "8.4.7",
|
|
156
158
|
"@storybook/addon-webpack5-compiler-babel": "3.0.3"
|
|
157
159
|
}
|
|
158
160
|
}
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
--c--theme--breakpoints--lg: 992px;
|
|
133
133
|
--c--theme--breakpoints--xl: 1200px;
|
|
134
134
|
--c--theme--breakpoints--xxl: 1400px;
|
|
135
|
+
--c--components--tabs--border-bottom-color: var(--c--theme--colors--greyscale-300);
|
|
135
136
|
--c--components--button--font-family: Montserrat;
|
|
136
137
|
--c--components--dashboardlistavatar--saturation: 30;
|
|
137
138
|
--c--components--dashboardlistavatar--lightness: 55;
|