richie-education 2.25.0-b2.dev32 → 2.25.0-b2.dev35

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.
Files changed (27) hide show
  1. package/js/api/joanie.ts +26 -3
  2. package/js/api/lms/dummy.spec.ts +9 -1
  3. package/js/api/lms/dummy.ts +12 -2
  4. package/js/contexts/SessionContext/BaseSessionProvider.tsx +4 -12
  5. package/js/contexts/SessionContext/JoanieSessionProvider.tsx +4 -11
  6. package/js/contexts/SessionContext/index.spec.tsx +2 -4
  7. package/js/hooks/useContractArchive/index.download.spec.tsx +119 -0
  8. package/js/hooks/useContractArchive/index.spec.tsx +91 -0
  9. package/js/hooks/useContractArchive/index.ts +83 -0
  10. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.spec.tsx +136 -0
  11. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.timer.spec.tsx +144 -0
  12. package/js/pages/TeacherDashboardContractsLayout/components/BulkDownloadContractButton/index.tsx +73 -0
  13. package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.spec.tsx +166 -0
  14. package/js/pages/TeacherDashboardContractsLayout/components/ContractActionsBar/index.tsx +23 -8
  15. package/js/pages/TeacherDashboardContractsLayout/components/SignOrganizationContractButton/index.spec.tsx +74 -0
  16. package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.spec.tsx +124 -0
  17. package/js/pages/TeacherDashboardContractsLayout/hooks/useCheckContractArchiveExists/index.tsx +73 -0
  18. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.spec.ts +85 -0
  19. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/contractArchiveLocalStorage.ts +50 -0
  20. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.spec.tsx +266 -0
  21. package/js/pages/TeacherDashboardContractsLayout/hooks/useDownloadContractArchive/index.tsx +153 -0
  22. package/js/pages/TeacherDashboardContractsLayout/hooks/useHasContractToDownload/index.spec.tsx +100 -0
  23. package/js/pages/TeacherDashboardContractsLayout/hooks/useHasContractToDownload/index.tsx +23 -0
  24. package/js/settings.ts +7 -0
  25. package/js/types/Joanie.ts +5 -0
  26. package/js/utils/errors/HttpError.ts +1 -0
  27. package/package.json +1 -1
@@ -0,0 +1,100 @@
1
+ import fetchMock from 'fetch-mock';
2
+ import { faker } from '@faker-js/faker';
3
+ import { renderHook, waitFor } from '@testing-library/react';
4
+ import { IntlProvider } from 'react-intl';
5
+ import { QueryClientProvider } from '@tanstack/react-query';
6
+ import { PropsWithChildren } from 'react';
7
+ import { PER_PAGE } from 'settings';
8
+ import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
9
+ import { ContractState } from 'types/Joanie';
10
+ import { ContractFactory } from 'utils/test/factories/joanie';
11
+ import { createTestQueryClient } from 'utils/test/createTestQueryClient';
12
+ import JoanieSessionProvider from 'contexts/SessionContext/JoanieSessionProvider';
13
+ import useHasContractToDownload from '.';
14
+
15
+ jest.mock('utils/context', () => ({
16
+ __esModule: true,
17
+ default: mockRichieContextFactory({
18
+ authentication: { backend: 'fonzie', endpoint: 'https://auth.test' },
19
+ joanie_backend: { endpoint: 'https://joanie.test' },
20
+ }).one(),
21
+ }));
22
+
23
+ describe('hooks/useHasContractToDownload', () => {
24
+ const Wrapper = ({ children }: PropsWithChildren) => {
25
+ return (
26
+ <IntlProvider locale="en">
27
+ <QueryClientProvider client={createTestQueryClient({ user: true })}>
28
+ <JoanieSessionProvider>{children}</JoanieSessionProvider>
29
+ </QueryClientProvider>
30
+ </IntlProvider>
31
+ );
32
+ };
33
+
34
+ beforeEach(() => {
35
+ // Joanie providers calls
36
+ fetchMock.get('https://joanie.test/api/v1.0/orders/', []);
37
+ fetchMock.get('https://joanie.test/api/v1.0/credit-cards/', []);
38
+ fetchMock.get('https://joanie.test/api/v1.0/addresses/', []);
39
+ });
40
+
41
+ afterEach(() => {
42
+ fetchMock.restore();
43
+ });
44
+
45
+ it('should return null when joanie request is pending', async () => {
46
+ const organizationId = faker.string.uuid();
47
+ const contractListUrl = `https://joanie.test/api/v1.0/organizations/${organizationId}/contracts/?signature_state=${ContractState.SIGNED}&page=1&page_size=${PER_PAGE.teacherContractList}`;
48
+ fetchMock.get(contractListUrl, {
49
+ count: 1,
50
+ next: null,
51
+ previous: null,
52
+ results: [ContractFactory().one()],
53
+ });
54
+
55
+ const { result } = renderHook(() => useHasContractToDownload(organizationId), {
56
+ wrapper: Wrapper,
57
+ });
58
+
59
+ expect(result.current).toBeNull();
60
+ });
61
+
62
+ it('should return true when joanie return some signed contracts', async () => {
63
+ const organizationId = faker.string.uuid();
64
+ const contractListUrl = `https://joanie.test/api/v1.0/organizations/${organizationId}/contracts/?signature_state=${ContractState.SIGNED}&page=1&page_size=${PER_PAGE.teacherContractList}`;
65
+ fetchMock.get(contractListUrl, {
66
+ count: 1,
67
+ next: null,
68
+ previous: null,
69
+ results: [ContractFactory().one()],
70
+ });
71
+
72
+ const { result } = renderHook(() => useHasContractToDownload(organizationId), {
73
+ wrapper: Wrapper,
74
+ });
75
+
76
+ await waitFor(() => {
77
+ expect(fetchMock.calls().map((call) => call[0])).toContain(contractListUrl);
78
+ expect(result.current).toBe(true);
79
+ });
80
+ });
81
+
82
+ it("should return false when joanie doesn't return any signed contracts", async () => {
83
+ const organizationId = faker.string.uuid();
84
+ const contractListUrl = `https://joanie.test/api/v1.0/organizations/${organizationId}/contracts/?signature_state=${ContractState.SIGNED}&page=1&page_size=${PER_PAGE.teacherContractList}`;
85
+ fetchMock.get(contractListUrl, {
86
+ count: 0,
87
+ next: null,
88
+ previous: null,
89
+ results: [],
90
+ });
91
+
92
+ const { result } = renderHook(() => useHasContractToDownload(organizationId), {
93
+ wrapper: Wrapper,
94
+ });
95
+ await waitFor(() => {
96
+ expect(fetchMock.calls().map((call) => call[0])).toContain(contractListUrl);
97
+ expect(result.current).toBe(false);
98
+ });
99
+ });
100
+ });
@@ -0,0 +1,23 @@
1
+ import { useOrganizationContracts } from 'hooks/useContracts';
2
+ import { PER_PAGE } from 'settings';
3
+ import { ContractState, Organization } from 'types/Joanie';
4
+
5
+ const useHasContractToDownload = (organizationId: Organization['id']) => {
6
+ const {
7
+ items: contracts,
8
+ states: { isFetched },
9
+ } = useOrganizationContracts({
10
+ organization_id: organizationId,
11
+ signature_state: ContractState.SIGNED,
12
+ page: 1,
13
+ page_size: PER_PAGE.teacherContractList,
14
+ });
15
+
16
+ if (!isFetched) {
17
+ return null;
18
+ }
19
+
20
+ return contracts.length > 0;
21
+ };
22
+
23
+ export default useHasContractToDownload;
package/js/settings.ts CHANGED
@@ -46,6 +46,13 @@ export const CONTRACT_SETTINGS = {
46
46
  dummySignatureSignTimeout: 2000,
47
47
  };
48
48
 
49
+ export const CONTRACT_DOWNLOAD_SETTINGS = {
50
+ // Interval in ms to poll the related contract's archive.
51
+ pollInterval: 1000,
52
+ contractArchiveLocalStorageKey: 'RICHIE_CONTRACT_ARCHIVE',
53
+ contractArchiveLocalVaklidityDurationMs: 10 * 60 * 60 * 1000, // 10min
54
+ };
55
+
49
56
  const DEFAULT_PER_PAGE = 50;
50
57
  export const PER_PAGE = {
51
58
  teacherContractList: 25,
@@ -520,6 +520,11 @@ interface APIUser {
520
520
  ? Promise<Nullable<Contract>>
521
521
  : Promise<PaginatedResponse<Contract>>;
522
522
  download(id: string): Promise<File>;
523
+ zip_archive: {
524
+ check: (id: string) => Promise<Response>;
525
+ create: ({ organization_id }: { organization_id: string }) => Promise<{ url: string }>;
526
+ get: (id: string) => Promise<File>;
527
+ };
523
528
  };
524
529
  }
525
530
 
@@ -25,6 +25,7 @@ export function isHttpError(error: any): error is HttpError {
25
25
 
26
26
  export enum HttpStatusCode {
27
27
  OK = 200,
28
+ NO_CONTENT = 204,
28
29
  UNAUTHORIZED = 401,
29
30
  BAD_REQUEST = 400,
30
31
  FORBIDDEN = 403,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "richie-education",
3
- "version": "2.25.0-b2.dev32",
3
+ "version": "2.25.0-b2.dev35",
4
4
  "description": "A CMS to build learning portals for Open Education",
5
5
  "main": "sandbox/manage.py",
6
6
  "scripts": {