From 7f3a02a48ca0ad915fda72f043e1d93d0960c945 Mon Sep 17 00:00:00 2001 From: Pierre-Eric Garcia Date: Wed, 2 Aug 2023 12:51:07 +0200 Subject: [PATCH] Finish migration templates to typescript --- .../components/atoms/icons/fr-fi-icons.tsx | 272 +++++++++++++++--- .../{Accessibilite.js => Accessibilite.tsx} | 1 - .../{CopyEnrollment.js => CopyEnrollment.tsx} | 32 ++- ...llmentList.js => PublicEnrollmentList.tsx} | 32 +-- ...=> RedirectToTheRightDataProviderForm.tsx} | 16 +- .../templates/{Stats.js => Stats.tsx} | 63 ++-- ...entListStyle.js => enrollmentListStyle.ts} | 0 .../hooks/use-data-provider-configurations.ts | 7 +- 8 files changed, 322 insertions(+), 101 deletions(-) rename frontend/src/components/templates/{Accessibilite.js => Accessibilite.tsx} (99%) rename frontend/src/components/templates/{CopyEnrollment.js => CopyEnrollment.tsx} (70%) rename frontend/src/components/templates/{PublicEnrollmentList.js => PublicEnrollmentList.tsx} (83%) rename frontend/src/components/templates/{RedirectToTheRightDataProviderForm.js => RedirectToTheRightDataProviderForm.tsx} (81%) rename frontend/src/components/templates/{Stats.js => Stats.tsx} (85%) rename frontend/src/components/templates/{enrollmentListStyle.js => enrollmentListStyle.ts} (100%) diff --git a/frontend/src/components/atoms/icons/fr-fi-icons.tsx b/frontend/src/components/atoms/icons/fr-fi-icons.tsx index b1ed7e967..00ff13445 100644 --- a/frontend/src/components/atoms/icons/fr-fi-icons.tsx +++ b/frontend/src/components/atoms/icons/fr-fi-icons.tsx @@ -15,6 +15,7 @@ export type IconProps = { small?: boolean; type?: string; size?: number; + title?: string; }; const FrFiIcon: React.FC = ({ @@ -37,24 +38,64 @@ const FrFiIcon: React.FC = ({ }; // Icons - Business -export const MailIcon: React.FC = ({ color, large, small }) => ( - +export const MailIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const MailIconFill: React.FC = ({ color, large, small }) => ( - +export const MailIconFill: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const MailOpenIcon: React.FC = ({ color, large, small }) => ( - +export const MailOpenIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); export const MailOpenIconFill: React.FC = ({ color, large, small, + title, }) => ( - + ); // Icons - Media @@ -62,43 +103,106 @@ export const NotificationIcon: React.FC = ({ color, large, small, + title, }) => ( ); // Icons - System DSFR -export const InfoFillIcon: React.FC = ({ color, large, small }) => ( - +export const InfoFillIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const InfoIcon: React.FC = ({ color, large, small }) => ( - +export const InfoIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const WarningIcon: React.FC = ({ color, large, small }) => ( - +export const WarningIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); // RemixIcon -export const AddCircleIcon: React.FC = ({ color, large, small }) => ( - +export const AddCircleIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const ArrowUpIcon: React.FC = ({ color, large, small }) => ( - +export const ArrowUpIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const ArrowDownIcon: React.FC = ({ color, large, small }) => ( +export const ArrowDownIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( ); @@ -106,12 +210,14 @@ export const ArrowRightIcon: React.FC = ({ color, large, small, + title, }) => ( ); @@ -119,52 +225,148 @@ export const CheckCircleIcon: React.FC = ({ color, large, small, + title, }) => ( ); -export const ErrorIcon: React.FC = ({ color, large, small }) => ( +export const ErrorIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( ); -export const HelpIcon: React.FC = ({ color, large, small }) => ( - +export const HelpIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const RefreshIcon: React.FC = ({ color, large, small }) => ( - +export const RefreshIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const ScheduleIcon: React.FC = ({ color, large, small }) => ( - +export const ScheduleIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const EyeIcon: React.FC = ({ color, large, small }) => ( - +export const EyeIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const EditIcon: React.FC = ({ color, large, small }) => ( - +export const EditIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const FilterIcon: React.FC = ({ color, large, small }) => ( - +export const FilterIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const ArchiveIcon: React.FC = ({ color, large, small }) => ( - +export const ArchiveIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); -export const RecycleIcon: React.FC = ({ color, large, small }) => ( - +export const RecycleIcon: React.FC = ({ + color, + large, + small, + title, +}) => ( + ); diff --git a/frontend/src/components/templates/Accessibilite.js b/frontend/src/components/templates/Accessibilite.tsx similarity index 99% rename from frontend/src/components/templates/Accessibilite.js rename to frontend/src/components/templates/Accessibilite.tsx index be9d6feeb..697f6e07b 100644 --- a/frontend/src/components/templates/Accessibilite.js +++ b/frontend/src/components/templates/Accessibilite.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import Button from '../atoms/hyperTexts/Button'; const Accessibilite = () => ( diff --git a/frontend/src/components/templates/CopyEnrollment.js b/frontend/src/components/templates/CopyEnrollment.tsx similarity index 70% rename from frontend/src/components/templates/CopyEnrollment.js rename to frontend/src/components/templates/CopyEnrollment.tsx index 30115cfa3..052dc298e 100644 --- a/frontend/src/components/templates/CopyEnrollment.js +++ b/frontend/src/components/templates/CopyEnrollment.tsx @@ -5,26 +5,33 @@ import { Navigate, useParams } from 'react-router-dom'; import { getErrorMessages } from '../../lib'; import Loader from '../atoms/Loader'; import { Linkify } from '../molecules/Linkify'; -import Alert from '../atoms/Alert'; +import Alert, { AlertType } from '../atoms/Alert'; const CopyEnrollment = () => { - const { enrollmentId } = useParams(); + const { enrollmentId }: { enrollmentId?: string } = useParams(); - const [copyErrorMessage, setCopyErrorMessage] = useState(null); + const [copyErrorMessage, setCopyErrorMessage] = useState<{ + title: string; + message: string; + } | null>(null); const [copiedEnrollmentId, setCopiedEnrollmentId] = useState(null); - const [copiedTargetApi, setCopiedTargetApi] = useState(null); + const [copiedTargetApi, setCopiedTargetApi] = useState(null); - const triggerEnrollmentCopy = async ({ enrollmentId }) => { + const triggerEnrollmentCopy = async ({ + enrollmentId, + }: { + enrollmentId: string; + }) => { try { setCopyErrorMessage(null); const { id, target_api } = await copyEnrollment({ - id: enrollmentId, + id: Number(enrollmentId), }); setCopiedEnrollmentId(id); setCopiedTargetApi(target_api); - } catch (e) { + } catch (e: any) { if (e.response?.data?.title && e.response?.data?.message) { setCopyErrorMessage(e.response.data); } else if (getErrorMessages(e)[0]) { @@ -50,13 +57,8 @@ const CopyEnrollment = () => { if (copiedEnrollmentId && copiedTargetApi) { return ( ); @@ -65,7 +67,7 @@ const CopyEnrollment = () => { if (copyErrorMessage) { return (
- + diff --git a/frontend/src/components/templates/PublicEnrollmentList.js b/frontend/src/components/templates/PublicEnrollmentList.tsx similarity index 83% rename from frontend/src/components/templates/PublicEnrollmentList.js rename to frontend/src/components/templates/PublicEnrollmentList.tsx index f30b1bfab..b91eab9f0 100644 --- a/frontend/src/components/templates/PublicEnrollmentList.js +++ b/frontend/src/components/templates/PublicEnrollmentList.tsx @@ -4,13 +4,18 @@ import { getPublicValidatedEnrollments } from '../../services/enrollments'; import { ScheduleIcon } from '../atoms/icons/fr-fi-icons'; import ListHeader from '../molecules/ListHeader'; import Table from '../organisms/Table'; -import { createColumnHelper } from '@tanstack/react-table'; +import { + Column, + createColumnHelper, + getCoreRowModel, +} from '@tanstack/react-table'; import { useDataProviderConfigurations } from './hooks/use-data-provider-configurations'; import useQueryString from './hooks/use-query-string'; import { debounce } from 'lodash'; import { HIDDEN_DATA_PROVIDER_KEYS } from '../../config/data-provider-configurations'; +import { Enrollment } from './InstructorEnrollmentList'; -const columnHelper = createColumnHelper(); +const columnHelper = createColumnHelper(); const PublicEnrollmentList = () => { const { dataProviderConfigurations } = useDataProviderConfigurations(); @@ -65,26 +70,6 @@ const PublicEnrollmentList = () => { header: 'Intitulé', enableSorting: false, }), - columnHelper.accessor( - ({ - responsable_traitement_given_name: given_name, - responsable_traitement_family_name: family_name, - }) => { - if (!given_name && !family_name) { - return ''; - } - if (!given_name) { - return family_name; - } - return `${given_name} ${family_name}`; - }, - { - enableColumnFilter: false, - enableSorting: false, - header: 'Responsable traitement', - id: 'responsable_traitement_name', - } - ), columnHelper.accessor( ({ target_api }) => dataProviderConfigurations?.[target_api].label, { @@ -114,7 +99,7 @@ const PublicEnrollmentList = () => { [], pageCount: totalPages, state: { columnFilters: filtered, @@ -124,6 +109,7 @@ const PublicEnrollmentList = () => { onColumnFiltersChange: setFiltered, manualPagination: true, manualFiltering: true, + getCoreRowModel: getCoreRowModel(), }} loading={loading} /> diff --git a/frontend/src/components/templates/RedirectToTheRightDataProviderForm.js b/frontend/src/components/templates/RedirectToTheRightDataProviderForm.tsx similarity index 81% rename from frontend/src/components/templates/RedirectToTheRightDataProviderForm.js rename to frontend/src/components/templates/RedirectToTheRightDataProviderForm.tsx index 8476a3bfa..bfdda8820 100644 --- a/frontend/src/components/templates/RedirectToTheRightDataProviderForm.js +++ b/frontend/src/components/templates/RedirectToTheRightDataProviderForm.tsx @@ -2,23 +2,27 @@ import React, { useState, useEffect } from 'react'; import { getUserEnrollment } from '../../services/enrollments'; import { Navigate, useParams } from 'react-router-dom'; import Loader from '../atoms/Loader'; -import Alert from '../atoms/Alert'; +import Alert, { AlertType } from '../atoms/Alert'; import NotFound from '../organisms/NotFound'; const RedirectToTheRightDataProviderForm = () => { const { enrollmentId } = useParams(); const [fetchEnrollmentError, setFetchEnrollmentError] = useState(false); const [fetchEnrollmentNotFound, setFetchEnrollmentNotFound] = useState(false); - const [targetApi, setTargetApi] = useState(null); + const [targetApi, setTargetApi] = useState(null); - const fetchEnrollment = async ({ enrollmentId }) => { + const fetchEnrollment = async ({ + enrollmentId, + }: { + enrollmentId: number; + }) => { try { setFetchEnrollmentError(false); setFetchEnrollmentNotFound(false); const { target_api } = await getUserEnrollment(enrollmentId); setTargetApi(target_api); - } catch (e) { + } catch (e: any) { if (e.response && e.response.status === 404) { setFetchEnrollmentNotFound(true); } else { @@ -29,7 +33,7 @@ const RedirectToTheRightDataProviderForm = () => { useEffect(() => { if (enrollmentId) { - fetchEnrollment({ enrollmentId }); + fetchEnrollment({ enrollmentId: Number(enrollmentId) }); } }, [enrollmentId]); @@ -51,7 +55,7 @@ const RedirectToTheRightDataProviderForm = () => { if (fetchEnrollmentError) { return (
- + Erreur inconnue lors de la récupération de l’habilitation.
diff --git a/frontend/src/components/templates/Stats.js b/frontend/src/components/templates/Stats.tsx similarity index 85% rename from frontend/src/components/templates/Stats.js rename to frontend/src/components/templates/Stats.tsx index dea3a3af6..2ed6717e6 100644 --- a/frontend/src/components/templates/Stats.js +++ b/frontend/src/components/templates/Stats.tsx @@ -18,7 +18,10 @@ import { XAxis, YAxis, } from 'recharts'; -import { HIDDEN_DATA_PROVIDER_KEYS } from '../../config/data-provider-configurations'; +import { + DataProviderConfiguration, + HIDDEN_DATA_PROVIDER_KEYS, +} from '../../config/data-provider-configurations'; import { EnrollmentStatus, STATUS_LABELS, @@ -71,8 +74,24 @@ const USER_STATUS_COLORS = { revoked: '#FF4747', }; +type Stats = { + enrollment_count: number; + validated_enrollment_count: number; + average_processing_time_in_days: number; + go_back_ratio: number; + monthly_enrollment_count: Record[]; + enrollment_by_status: { + name: EnrollmentStatus; + count: number; + }[]; + enrollment_by_target_api: { + name: string; + count: number; + }[]; +}; + export const Stats = () => { - const [stats, setStats] = useState(null); + const [stats, setStats] = useState(null); const { targetApi } = useParams(); const { dataProviderConfigurations } = useDataProviderConfigurations(); @@ -86,8 +105,11 @@ export const Stats = () => { ); }, [dataProviderConfigurations]); - const getApisList = (targetApi, dataProviderConfigurations) => { - const getProvidersKeyByType = (type) => + const getApisList = ( + targetApi: string | undefined, + dataProviderConfigurations: Record | null + ) => { + const getProvidersKeyByType = (type: 'api' | 'service') => Object.keys( pickBy( dataProviderConfigurations, @@ -108,7 +130,7 @@ export const Stats = () => { }; const getTargetAPIList = useCallback( - async function (targetApi) { + async function (targetApi: string | undefined) { return getAPIStats(getApisList(targetApi, dataProviderConfigurations)); }, [dataProviderConfigurations] @@ -240,21 +262,24 @@ export const Stats = () => { /> [ + formatter={(value, name) => [ value, - STATUS_LABELS[name], - props, + STATUS_LABELS[name as EnrollmentStatus], ]} labelFormatter={(value) => moment(value).format('MMM YYYY')} /> - STATUS_LABELS[value]} /> + + STATUS_LABELS[value] + } + /> {Object.keys(EnrollmentStatus).map((status, index, array) => ( {index === array.length - 1 && ( @@ -283,13 +308,14 @@ export const Stats = () => { layout={'vertical'} align={'right'} verticalAlign={'middle'} - formatter={(value) => STATUS_LABELS[value]} + formatter={(value: EnrollmentStatus) => + STATUS_LABELS[value] + } /> [ + formatter={(value, name) => [ value, - STATUS_LABELS[name], - props, + STATUS_LABELS[name as EnrollmentStatus], ]} /> @@ -315,12 +341,11 @@ export const Stats = () => { ))} [ + formatter={(value, name) => [ value, name === 'others' ? 'Autres' - : dataProviderConfigurations?.[name].label, - props, + : (dataProviderConfigurations?.[name]?.label as string), ]} /> { formatter={(value) => (value === 'others' ? 'Autres' - : dataProviderConfigurations?.[value].label + : dataProviderConfigurations + ? dataProviderConfigurations[value].label + : '' ).substring(0, 32) } /> diff --git a/frontend/src/components/templates/enrollmentListStyle.js b/frontend/src/components/templates/enrollmentListStyle.ts similarity index 100% rename from frontend/src/components/templates/enrollmentListStyle.js rename to frontend/src/components/templates/enrollmentListStyle.ts diff --git a/frontend/src/components/templates/hooks/use-data-provider-configurations.ts b/frontend/src/components/templates/hooks/use-data-provider-configurations.ts index 45b6b7c50..12fe6320d 100644 --- a/frontend/src/components/templates/hooks/use-data-provider-configurations.ts +++ b/frontend/src/components/templates/hooks/use-data-provider-configurations.ts @@ -6,9 +6,10 @@ import { import { getCachedDataProviderConfigurations } from '../../../services/data-provider-configurations'; export const useDataProviderConfigurations = () => { - const [configurations, setConfigurations] = useState<{ - [k: string]: DataProviderConfiguration; - } | null>(null); + const [configurations, setConfigurations] = useState | null>(null); useEffect(() => { async function fetchDataProviderConfigurations() {