richie-education 2.25.0-b2.dev27 → 2.25.0-b2.dev31
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/hooks/useContracts/index.tsx +5 -5
- package/js/hooks/useTeacherPendingContractsCount/index.ts +6 -23
- package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.spec.tsx +6 -3
- package/js/pages/TeacherDashboardContractsLayout/TeacherDashboardContracts/index.tsx +4 -5
- package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.tsx +4 -6
- package/js/pages/TeacherDashboardContractsLayout/components/{ContractFilters → ContractFiltersBar}/index.spec.tsx +6 -6
- package/js/pages/TeacherDashboardContractsLayout/components/{ContractFilters → ContractFiltersBar}/index.tsx +4 -4
- package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractFilters.tsx +5 -7
- package/js/pages/TeacherDashboardContractsLayout/hooks/useTeacherContractsToSign.tsx +11 -11
- package/js/types/Joanie.ts +6 -7
- package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.tsx +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineMessages } from 'react-intl';
|
|
2
2
|
import { useJoanieApi } from 'contexts/JoanieApiContext';
|
|
3
3
|
import { QueryOptions, useResource, useResources, UseResourcesProps } from 'hooks/useResources';
|
|
4
|
-
import { API, Contract,
|
|
4
|
+
import { API, Contract, ContractResourceQuery } from 'types/Joanie';
|
|
5
5
|
|
|
6
6
|
const messages = defineMessages({
|
|
7
7
|
errorGet: {
|
|
@@ -16,7 +16,7 @@ const messages = defineMessages({
|
|
|
16
16
|
},
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
const props: UseResourcesProps<Contract,
|
|
19
|
+
const props: UseResourcesProps<Contract, ContractResourceQuery, API['user']['contracts']> = {
|
|
20
20
|
queryKey: ['contracts'],
|
|
21
21
|
apiInterface: () => useJoanieApi().user.contracts,
|
|
22
22
|
session: true,
|
|
@@ -34,7 +34,7 @@ export const useUserContracts = useResources(props);
|
|
|
34
34
|
*/
|
|
35
35
|
const organizationProps: UseResourcesProps<
|
|
36
36
|
Contract,
|
|
37
|
-
|
|
37
|
+
ContractResourceQuery,
|
|
38
38
|
API['organizations']['contracts']
|
|
39
39
|
> = {
|
|
40
40
|
...props,
|
|
@@ -44,7 +44,7 @@ const organizationProps: UseResourcesProps<
|
|
|
44
44
|
|
|
45
45
|
export const useOrganizationContract = (
|
|
46
46
|
id: string,
|
|
47
|
-
filters:
|
|
47
|
+
filters: ContractResourceQuery,
|
|
48
48
|
queryOptions?: QueryOptions<Contract>,
|
|
49
49
|
) => {
|
|
50
50
|
return useResource(organizationProps)(id, filters, {
|
|
@@ -57,7 +57,7 @@ export const useOrganizationContract = (
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
export const useOrganizationContracts = (
|
|
60
|
-
filters:
|
|
60
|
+
filters: ContractResourceQuery,
|
|
61
61
|
queryOptions?: QueryOptions<Contract>,
|
|
62
62
|
) => {
|
|
63
63
|
return useResources(organizationProps)(filters, {
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
1
|
import { useOrganizationContracts } from 'hooks/useContracts';
|
|
3
|
-
import { useCourseProductRelation } from 'hooks/useCourseProductRelation';
|
|
4
2
|
import { PER_PAGE } from 'settings';
|
|
5
3
|
import { ContractState, CourseProductRelation, Organization } from 'types/Joanie';
|
|
6
4
|
|
|
@@ -13,30 +11,15 @@ const useTeacherPendingContractsCount = ({
|
|
|
13
11
|
organizationId,
|
|
14
12
|
courseProductRelationId,
|
|
15
13
|
}: UseTeacherPendingContractsCountProps) => {
|
|
16
|
-
const {
|
|
17
|
-
item: training,
|
|
18
|
-
states: { isFetched: isTrainingFetched },
|
|
19
|
-
} = useCourseProductRelation(courseProductRelationId, {
|
|
14
|
+
const { items: contracts, meta } = useOrganizationContracts({
|
|
20
15
|
organization_id: organizationId,
|
|
16
|
+
course_product_relation_id: courseProductRelationId,
|
|
17
|
+
signature_state: ContractState.LEARNER_SIGNED,
|
|
18
|
+
page: 1,
|
|
19
|
+
page_size: PER_PAGE.teacherContractList,
|
|
21
20
|
});
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
return !!(organizationId && (!courseProductRelationId || isTrainingFetched));
|
|
25
|
-
}, [organizationId, courseProductRelationId, isTrainingFetched]);
|
|
26
|
-
|
|
27
|
-
const { items: contracts, meta } = useOrganizationContracts(
|
|
28
|
-
{
|
|
29
|
-
organization_id: organizationId,
|
|
30
|
-
course_id: training?.course.id,
|
|
31
|
-
product_id: training?.product.id,
|
|
32
|
-
signature_state: ContractState.LEARNER_SIGNED,
|
|
33
|
-
page: 1,
|
|
34
|
-
page_size: PER_PAGE.teacherContractList,
|
|
35
|
-
},
|
|
36
|
-
{ enabled: isActive },
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
if (isActive) {
|
|
22
|
+
if (organizationId) {
|
|
40
23
|
return {
|
|
41
24
|
contracts,
|
|
42
25
|
pendingContractCount: meta?.pagination?.count ?? 0,
|
|
@@ -78,19 +78,22 @@ describe('pages/TeacherDashboardContracts', () => {
|
|
|
78
78
|
}).many(3);
|
|
79
79
|
const organization = OrganizationFactory().one();
|
|
80
80
|
|
|
81
|
+
// OrganizationContractFilter request all organizations forwho the user have access
|
|
81
82
|
fetchMock.get(`https://joanie.test/api/v1.0/organizations/`, [organization]);
|
|
83
|
+
// TeacherDashboardContracts request a paginated list of contracts to display
|
|
82
84
|
fetchMock.get(
|
|
83
|
-
`https://joanie.test/api/v1.0/organizations/${organization.id}/contracts/?signature_state=signed&
|
|
85
|
+
`https://joanie.test/api/v1.0/organizations/${organization.id}/contracts/?signature_state=signed&course_product_relation_id=2&page=1&page_size=25`,
|
|
84
86
|
{ results: contracts, count: 0, previous: null, next: null },
|
|
85
87
|
);
|
|
88
|
+
// useTeacherContractsToSign request all contract to sign, without pagination
|
|
86
89
|
fetchMock.get(
|
|
87
|
-
`https://joanie.test/api/v1.0/organizations/${organization.id}/contracts/?signature_state=half_signed&
|
|
90
|
+
`https://joanie.test/api/v1.0/organizations/${organization.id}/contracts/?signature_state=half_signed&course_product_relation_id=2`,
|
|
88
91
|
{ results: [], count: 0, previous: null, next: null },
|
|
89
92
|
);
|
|
90
93
|
|
|
91
94
|
render(
|
|
92
95
|
<Wrapper
|
|
93
|
-
path="/courses/:courseId/products/:
|
|
96
|
+
path="/courses/:courseId/products/:courseProductRelationId/contracts"
|
|
94
97
|
initialEntry="/courses/1/products/2/contracts"
|
|
95
98
|
/>,
|
|
96
99
|
);
|
|
@@ -7,9 +7,9 @@ import { ContractHelper, ContractStatePoV } from 'utils/ContractHelper';
|
|
|
7
7
|
import { useOrganizationContracts } from 'hooks/useContracts';
|
|
8
8
|
import Banner, { BannerType } from 'components/Banner';
|
|
9
9
|
import { PER_PAGE } from 'settings';
|
|
10
|
-
import {
|
|
10
|
+
import { ContractResourceQuery } from 'types/Joanie';
|
|
11
11
|
|
|
12
|
-
import ContractFiltersBar from '../components/
|
|
12
|
+
import ContractFiltersBar from '../components/ContractFiltersBar';
|
|
13
13
|
import useTeacherContractFilters, {
|
|
14
14
|
TeacherDashboardContractsParams,
|
|
15
15
|
} from '../hooks/useTeacherContractFilters';
|
|
@@ -62,7 +62,7 @@ const TeacherDashboardContracts = () => {
|
|
|
62
62
|
}));
|
|
63
63
|
}, [contracts]);
|
|
64
64
|
|
|
65
|
-
const handleFiltersChange = (newFilters: Partial<
|
|
65
|
+
const handleFiltersChange = (newFilters: Partial<ContractResourceQuery>) => {
|
|
66
66
|
// Reset pagination
|
|
67
67
|
pagination.setPage(1);
|
|
68
68
|
setFilters((prevFilters) => ({ ...prevFilters, ...newFilters }));
|
|
@@ -83,8 +83,7 @@ const TeacherDashboardContracts = () => {
|
|
|
83
83
|
<div className="dashboard__page__actions">
|
|
84
84
|
<ContractActionsBar
|
|
85
85
|
organizationId={filters.organization_id!}
|
|
86
|
-
|
|
87
|
-
productId={filters.product_id}
|
|
86
|
+
courseProductRelationId={filters.course_product_relation_id}
|
|
88
87
|
/>
|
|
89
88
|
<ContractFiltersBar
|
|
90
89
|
defaultValues={initialFilters}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Organization, CourseProductRelation } from 'types/Joanie';
|
|
2
2
|
import useTeacherContractsToSign from 'pages/TeacherDashboardContractsLayout/hooks/useTeacherContractsToSign';
|
|
3
3
|
import SignOrganizationContractButton from '../SignOrganizationContractButton';
|
|
4
4
|
|
|
5
5
|
interface ContractActionsProps {
|
|
6
|
-
courseId?: CourseListItem['id'];
|
|
7
|
-
productId?: Product['id'];
|
|
8
6
|
organizationId: Organization['id'];
|
|
7
|
+
courseProductRelationId?: CourseProductRelation['id'];
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
const ContractActionsBar = ({
|
|
10
|
+
const ContractActionsBar = ({ organizationId, courseProductRelationId }: ContractActionsProps) => {
|
|
12
11
|
const { canSignContracts, contractsToSignCount } = useTeacherContractsToSign({
|
|
13
12
|
organizationId,
|
|
14
|
-
|
|
15
|
-
productId,
|
|
13
|
+
courseProductRelationId,
|
|
16
14
|
});
|
|
17
15
|
return (
|
|
18
16
|
canSignContracts && (
|
|
@@ -12,7 +12,7 @@ import { ContractState } from 'types/Joanie';
|
|
|
12
12
|
import { OrganizationFactory } from 'utils/test/factories/joanie';
|
|
13
13
|
import { expectNoSpinner } from 'utils/test/expectSpinner';
|
|
14
14
|
import { noop } from 'utils';
|
|
15
|
-
import
|
|
15
|
+
import ContractFiltersBar from '.';
|
|
16
16
|
|
|
17
17
|
jest.mock('utils/context', () => ({
|
|
18
18
|
__esModule: true,
|
|
@@ -22,7 +22,7 @@ jest.mock('utils/context', () => ({
|
|
|
22
22
|
}).one(),
|
|
23
23
|
}));
|
|
24
24
|
|
|
25
|
-
describe('
|
|
25
|
+
describe('<ContractFiltersBar/>', () => {
|
|
26
26
|
const Wrapper = ({ children }: PropsWithChildren) => {
|
|
27
27
|
return (
|
|
28
28
|
<IntlProvider locale="en">
|
|
@@ -58,7 +58,7 @@ describe('ContractFilters', () => {
|
|
|
58
58
|
|
|
59
59
|
render(
|
|
60
60
|
<Wrapper>
|
|
61
|
-
<
|
|
61
|
+
<ContractFiltersBar onFiltersChange={filterChange} defaultValues={defaultValues} />
|
|
62
62
|
</Wrapper>,
|
|
63
63
|
);
|
|
64
64
|
|
|
@@ -105,7 +105,7 @@ describe('ContractFilters', () => {
|
|
|
105
105
|
|
|
106
106
|
render(
|
|
107
107
|
<Wrapper>
|
|
108
|
-
<
|
|
108
|
+
<ContractFiltersBar
|
|
109
109
|
onFiltersChange={noop}
|
|
110
110
|
defaultValues={defaultValues}
|
|
111
111
|
hideFilterSignatureState={true}
|
|
@@ -136,7 +136,7 @@ describe('ContractFilters', () => {
|
|
|
136
136
|
|
|
137
137
|
render(
|
|
138
138
|
<Wrapper>
|
|
139
|
-
<
|
|
139
|
+
<ContractFiltersBar
|
|
140
140
|
onFiltersChange={noop}
|
|
141
141
|
defaultValues={defaultValues}
|
|
142
142
|
hideFilterOrganization={true}
|
|
@@ -165,7 +165,7 @@ describe('ContractFilters', () => {
|
|
|
165
165
|
|
|
166
166
|
render(
|
|
167
167
|
<Wrapper>
|
|
168
|
-
<
|
|
168
|
+
<ContractFiltersBar onFiltersChange={handleChange} />
|
|
169
169
|
</Wrapper>,
|
|
170
170
|
);
|
|
171
171
|
|
|
@@ -24,7 +24,7 @@ export interface ContractListFilters {
|
|
|
24
24
|
signature_state?: ContractState;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
interface
|
|
27
|
+
interface ContractFiltersBarProps {
|
|
28
28
|
onFiltersChange: (filters: Partial<ContractListFilters>) => void;
|
|
29
29
|
defaultValues?: ContractListFilters;
|
|
30
30
|
hideFilterOrganization?: boolean;
|
|
@@ -36,12 +36,12 @@ interface FilterProps {
|
|
|
36
36
|
onChange: (value: Partial<ContractListFilters>) => void;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const
|
|
39
|
+
const ContractFiltersBar = ({
|
|
40
40
|
defaultValues,
|
|
41
41
|
onFiltersChange,
|
|
42
42
|
hideFilterOrganization = false,
|
|
43
43
|
hideFilterSignatureState = false,
|
|
44
|
-
}:
|
|
44
|
+
}: ContractFiltersBarProps) => {
|
|
45
45
|
return (
|
|
46
46
|
<div className="dashboard__page__actions-row dashboard__page__actions-row--end">
|
|
47
47
|
{!hideFilterOrganization && (
|
|
@@ -122,4 +122,4 @@ const SignatureStateFilter = ({ defaultValue, onChange }: FilterProps) => {
|
|
|
122
122
|
);
|
|
123
123
|
};
|
|
124
124
|
|
|
125
|
-
export default
|
|
125
|
+
export default ContractFiltersBar;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { useMemo, useState } from 'react';
|
|
2
2
|
import { useParams, useSearchParams } from 'react-router-dom';
|
|
3
|
-
import {
|
|
3
|
+
import { ContractResourceQuery, ContractState } from 'types/Joanie';
|
|
4
4
|
|
|
5
5
|
export type TeacherDashboardContractsParams = {
|
|
6
6
|
organizationId?: string;
|
|
7
|
-
|
|
8
|
-
productId?: string;
|
|
7
|
+
courseProductRelationId?: string;
|
|
9
8
|
};
|
|
10
9
|
|
|
11
10
|
const useTeacherContractFilters = () => {
|
|
12
|
-
const {
|
|
11
|
+
const { organizationId, courseProductRelationId } = useParams<TeacherDashboardContractsParams>();
|
|
13
12
|
const [searchParams] = useSearchParams();
|
|
14
13
|
|
|
15
14
|
const initialFilters = useMemo(
|
|
@@ -17,12 +16,11 @@ const useTeacherContractFilters = () => {
|
|
|
17
16
|
signature_state:
|
|
18
17
|
(searchParams.get('signature_state') as ContractState) || ContractState.SIGNED,
|
|
19
18
|
organization_id: organizationId,
|
|
20
|
-
|
|
21
|
-
product_id: productId,
|
|
19
|
+
course_product_relation_id: courseProductRelationId,
|
|
22
20
|
}),
|
|
23
21
|
[],
|
|
24
22
|
);
|
|
25
|
-
const [filters, setFilters] = useState<
|
|
23
|
+
const [filters, setFilters] = useState<ContractResourceQuery>(initialFilters);
|
|
26
24
|
|
|
27
25
|
return { initialFilters, filters, setFilters };
|
|
28
26
|
};
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import useContractAbilities from 'hooks/useContractAbilities';
|
|
2
2
|
import { useOrganizationContracts } from 'hooks/useContracts';
|
|
3
|
-
import { ContractState,
|
|
3
|
+
import { ContractState, Organization, CourseProductRelation } from 'types/Joanie';
|
|
4
4
|
import { ContractActions } from 'utils/AbilitiesHelper/types';
|
|
5
5
|
|
|
6
6
|
interface UseTeacherContractsToSignProps {
|
|
7
|
-
courseId?: CourseListItem['id'];
|
|
8
|
-
productId?: Product['id'];
|
|
9
7
|
organizationId?: Organization['id'];
|
|
8
|
+
courseProductRelationId?: CourseProductRelation['id'];
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
const useTeacherContractsToSign = ({
|
|
13
|
-
courseId,
|
|
14
|
-
productId,
|
|
15
12
|
organizationId,
|
|
13
|
+
courseProductRelationId,
|
|
16
14
|
}: UseTeacherContractsToSignProps) => {
|
|
17
|
-
const { items: contractsToSign, meta: contractsToSignMeta } = useOrganizationContracts(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
const { items: contractsToSign, meta: contractsToSignMeta } = useOrganizationContracts(
|
|
16
|
+
{
|
|
17
|
+
signature_state: ContractState.LEARNER_SIGNED,
|
|
18
|
+
organization_id: organizationId,
|
|
19
|
+
course_product_relation_id: courseProductRelationId,
|
|
20
|
+
},
|
|
21
|
+
{ enabled: !!organizationId },
|
|
22
|
+
);
|
|
23
23
|
const contractAbilities = useContractAbilities(contractsToSign);
|
|
24
24
|
const contractsToSignCount = contractsToSignMeta?.pagination?.count ?? 0;
|
|
25
25
|
|
package/js/types/Joanie.ts
CHANGED
|
@@ -427,10 +427,9 @@ export enum ContractState {
|
|
|
427
427
|
LEARNER_SIGNED = 'half_signed',
|
|
428
428
|
SIGNED = 'signed',
|
|
429
429
|
}
|
|
430
|
-
export interface
|
|
430
|
+
export interface ContractResourceQuery extends PaginatedResourceQuery {
|
|
431
431
|
organization_id?: Organization['id'];
|
|
432
|
-
|
|
433
|
-
product_id?: Product['id'];
|
|
432
|
+
course_product_relation_id?: CourseProductRelation['id'];
|
|
434
433
|
contract_ids?: Contract['id'][];
|
|
435
434
|
signature_state?: ContractState;
|
|
436
435
|
}
|
|
@@ -516,8 +515,8 @@ interface APIUser {
|
|
|
516
515
|
};
|
|
517
516
|
contracts: {
|
|
518
517
|
get(
|
|
519
|
-
filters?:
|
|
520
|
-
):
|
|
518
|
+
filters?: ContractResourceQuery,
|
|
519
|
+
): ContractResourceQuery extends { id: string }
|
|
521
520
|
? Promise<Nullable<Contract>>
|
|
522
521
|
: Promise<PaginatedResponse<Contract>>;
|
|
523
522
|
download(id: string): Promise<File>;
|
|
@@ -542,8 +541,8 @@ export interface API {
|
|
|
542
541
|
): Filters extends { id: string } ? Promise<Nullable<Organization>> : Promise<Organization[]>;
|
|
543
542
|
contracts: {
|
|
544
543
|
get(
|
|
545
|
-
filters?:
|
|
546
|
-
):
|
|
544
|
+
filters?: ContractResourceQuery,
|
|
545
|
+
): ContractResourceQuery extends { id: string }
|
|
547
546
|
? Promise<Nullable<Contract>>
|
|
548
547
|
: Promise<PaginatedResponse<Contract>>;
|
|
549
548
|
getSignatureLinks(
|
|
@@ -33,9 +33,9 @@ export const TeacherDashboardOrganizationSidebar = () => {
|
|
|
33
33
|
const intl = useIntl();
|
|
34
34
|
const getRoutePath = getDashboardRoutePath(intl);
|
|
35
35
|
const getRouteLabel = getDashboardRouteLabel(intl);
|
|
36
|
-
const { organizationId,
|
|
36
|
+
const { organizationId, courseProductRelationId } = useParams<{
|
|
37
37
|
organizationId: string;
|
|
38
|
-
|
|
38
|
+
courseProductRelationId?: string;
|
|
39
39
|
}>();
|
|
40
40
|
const {
|
|
41
41
|
item: organization,
|