diff --git a/server/controllers/statistics.ts b/server/controllers/statistics.ts index 95a7eda8f..aa57358f1 100644 --- a/server/controllers/statistics.ts +++ b/server/controllers/statistics.ts @@ -1,55 +1,55 @@ -import type { Request } from 'express'; - -import { - getClassroomsInfos, - getConnectedClassroomsCount, - getContributedClassroomsCount, - getRegisteredClassroomsCount, -} from '../stats/classroomStats'; -import { - getAverageConnections, - getAverageDuration, - getMaxConnections, - getMaxDuration, - getMedianConnections, - getMedianDuration, - getMinConnections, - getMinDuration, -} from '../stats/sessionStats'; -import { getChildrenCodesCount, getFamilyAccountsCount, getConnectedFamiliesCount } from '../stats/villageStats'; -import { Controller } from './controller'; - -export const statisticsController = new Controller('/statistics'); - -statisticsController.get({ path: '/sessions/:phase' }, async (req: Request, res) => { - const phase = req.params.phase ? parseInt(req.params.phase) : null; - - res.sendJSON({ - minDuration: await getMinDuration(), // TODO - add phase - maxDuration: await getMaxDuration(), // TODO - add phase - averageDuration: await getAverageDuration(), // TODO - add phase - medianDuration: await getMedianDuration(), // TODO - add phase - minConnections: await getMinConnections(), // TODO - add phase - maxConnections: await getMaxConnections(), // TODO - add phase - averageConnections: await getAverageConnections(), // TODO - add phase - medianConnections: await getMedianConnections(), // TODO - add phase - registeredClassroomsCount: await getRegisteredClassroomsCount(), - connectedClassroomsCount: await getConnectedClassroomsCount(), // TODO - add phase - contributedClassroomsCount: await getContributedClassroomsCount(phase), - }); -}); - -statisticsController.get({ path: '/classrooms' }, async (_req, res) => { - res.sendJSON({ - classrooms: await getClassroomsInfos(), - }); -}); - -statisticsController.get({ path: '/villages/:villageId' }, async (_req, res) => { - const villageId = parseInt(_req.params.villageId); - res.sendJSON({ - familyAccountsCount: await getFamilyAccountsCount(villageId), - childrenCodesCount: await getChildrenCodesCount(villageId), - connectedFamiliesCount: await getConnectedFamiliesCount(villageId), - }); -}); +import type { Request } from 'express'; + +import { + getClassroomsInfos, + getConnectedClassroomsCount, + getContributedClassroomsCount, + getRegisteredClassroomsCount, +} from '../stats/classroomStats'; +import { + getAverageConnections, + getAverageDuration, + getMaxConnections, + getMaxDuration, + getMedianConnections, + getMedianDuration, + getMinConnections, + getMinDuration, +} from '../stats/sessionStats'; +import { getChildrenCodesCount, getFamilyAccountsCount, getConnectedFamiliesCount } from '../stats/villageStats'; +import { Controller } from './controller'; + +export const statisticsController = new Controller('/statistics'); + +statisticsController.get({ path: '/sessions/:phase' }, async (req: Request, res) => { + const phase = req.params.phase ? parseInt(req.params.phase) : null; + + res.sendJSON({ + minDuration: await getMinDuration(), // TODO - add phase + maxDuration: await getMaxDuration(), // TODO - add phase + averageDuration: await getAverageDuration(), // TODO - add phase + medianDuration: await getMedianDuration(), // TODO - add phase + minConnections: await getMinConnections(), // TODO - add phase + maxConnections: await getMaxConnections(), // TODO - add phase + averageConnections: await getAverageConnections(), // TODO - add phase + medianConnections: await getMedianConnections(), // TODO - add phase + registeredClassroomsCount: await getRegisteredClassroomsCount(), + connectedClassroomsCount: await getConnectedClassroomsCount(), // TODO - add phase + contributedClassroomsCount: await getContributedClassroomsCount(phase), + }); +}); + +statisticsController.get({ path: '/classrooms' }, async (_req, res) => { + res.sendJSON({ + classrooms: await getClassroomsInfos(), + }); +}); + +statisticsController.get({ path: '/villages/:villageId' }, async (_req, res) => { + const villageId = parseInt(_req.params.villageId); + res.sendJSON({ + familyAccountsCount: await getFamilyAccountsCount(villageId), + childrenCodesCount: await getChildrenCodesCount(villageId), + connectedFamiliesCount: await getConnectedFamiliesCount(villageId), + }); +}); diff --git a/server/controllers/village.ts b/server/controllers/village.ts index 5a2aaec57..94e8654f3 100644 --- a/server/controllers/village.ts +++ b/server/controllers/village.ts @@ -2,7 +2,7 @@ import type { JSONSchemaType } from 'ajv'; import type { NextFunction, Request, Response } from 'express'; import { UserType } from '../entities/user'; -import { Village } from '../entities/village'; +import { Village, VillagePhase } from '../entities/village'; import { createVillagesFromPLM } from '../legacy-plm/api'; import { AppError, ErrorCode } from '../middlewares/handleErrors'; import { valueOrDefault } from '../utils'; @@ -15,17 +15,22 @@ const villageController = new Controller('/villages'); //--- Get all villages --- villageController.get({ path: '', userType: UserType.OBSERVATOR }, async (_req: Request, res: Response) => { const countryIsoCode = _req.query.countryIsoCode as string; + const phase = _req.query.phase as string; try { - // Fetch villages based on countryIsoCode if it's provided const villageRepository = AppDataSource.getRepository(Village); - const villages = countryIsoCode - ? await villageRepository - .createQueryBuilder('village') - .where('village.countryCodes LIKE :countryIsoCode', { countryIsoCode: `%${countryIsoCode.toUpperCase()}%` }) - .getMany() - : await villageRepository // Fetch all villages if no countryIsoCode is provided - .createQueryBuilder('student') - .getMany(); + let query; + if (countryIsoCode && phase) { + query = villageRepository.createQueryBuilder('village'); + query.where('village.countryCodes LIKE :countryIsoCode', { countryIsoCode: `%${countryIsoCode.toUpperCase()}%` }); + + if (Object.values(VillagePhase).includes(+phase)) { + query.andWhere('village.activePhase = :phase', { phase }); + } + } else { + query = villageRepository.createQueryBuilder('student'); + } + + const villages = await query.getMany(); res.sendJSON(villages); } catch (e) { console.error(e); diff --git a/server/stats/villageStats.ts b/server/stats/villageStats.ts index 633e6e7fb..76724b303 100644 --- a/server/stats/villageStats.ts +++ b/server/stats/villageStats.ts @@ -1,39 +1,39 @@ -import { Student } from '../entities/student'; -import { User } from '../entities/user'; -import { AppDataSource } from '../utils/data-source'; - -const userRepository = AppDataSource.getRepository(User); -const studentRepository = AppDataSource.getRepository(Student); - -export const getChildrenCodesCount = async (villageId: number) => { - const childrenCodeCount = await studentRepository - .createQueryBuilder('student') - .innerJoin('student.classroom', 'classroom') - .innerJoin('classroom.village', 'village') - .where('classroom.villageId = :villageId', { villageId }) - .getCount(); - return childrenCodeCount; -}; - -export const getFamilyAccountsCount = async (villageId: number) => { - const familyAccountsCount = await userRepository - .createQueryBuilder('user') - .innerJoin('user.village', 'village') - .innerJoin('classroom', 'classroom', 'classroom.villageId = village.id') - .innerJoin('student', 'student', 'student.classroomId = classroom.id') - .where('classroom.villageId = :villageId', { villageId }) - .groupBy('user.id') - .getCount(); - return familyAccountsCount; -}; - -export const getConnectedFamiliesCount = async (villageId: number) => { - const connectedFamiliesCount = await studentRepository - .createQueryBuilder('student') - .innerJoin('classroom', 'classroom', 'classroom.id = student.classroomId') - .where('classroom.villageId = :villageId', { villageId }) - .andWhere('student.numLinkedAccount >= 1') - .getCount(); - - return connectedFamiliesCount; -}; +import { Student } from '../entities/student'; +import { User } from '../entities/user'; +import { AppDataSource } from '../utils/data-source'; + +const userRepository = AppDataSource.getRepository(User); +const studentRepository = AppDataSource.getRepository(Student); + +export const getChildrenCodesCount = async (villageId: number) => { + const childrenCodeCount = await studentRepository + .createQueryBuilder('student') + .innerJoin('student.classroom', 'classroom') + .innerJoin('classroom.village', 'village') + .where('classroom.villageId = :villageId', { villageId }) + .getCount(); + return childrenCodeCount; +}; + +export const getFamilyAccountsCount = async (villageId: number) => { + const familyAccountsCount = await userRepository + .createQueryBuilder('user') + .innerJoin('user.village', 'village') + .innerJoin('classroom', 'classroom', 'classroom.villageId = village.id') + .innerJoin('student', 'student', 'student.classroomId = classroom.id') + .where('classroom.villageId = :villageId', { villageId }) + .groupBy('user.id') + .getCount(); + return familyAccountsCount; +}; + +export const getConnectedFamiliesCount = async (villageId: number) => { + const connectedFamiliesCount = await studentRepository + .createQueryBuilder('student') + .innerJoin('classroom', 'classroom', 'classroom.id = student.classroomId') + .where('classroom.villageId = :villageId', { villageId }) + .andWhere('student.numLinkedAccount >= 1') + .getCount(); + + return connectedFamiliesCount; +}; diff --git a/src/api/statistics/statistics.get.ts b/src/api/statistics/statistics.get.ts index a2a7318bf..e2c81c6e3 100644 --- a/src/api/statistics/statistics.get.ts +++ b/src/api/statistics/statistics.get.ts @@ -1,48 +1,48 @@ -import { useQuery } from 'react-query'; - -import { axiosRequest } from 'src/utils/axiosRequest'; -import type { ClassroomsStats, SessionsStats, VillageStats } from 'types/statistics.type'; - -async function getSessionsStats(phase: number | null): Promise { - return ( - await axiosRequest({ - method: 'GET', - baseURL: '/api', - url: `/statistics/sessions/${phase}`, - }) - ).data; -} - -async function getVillagesStats(villageId: number | null): Promise { - return ( - await axiosRequest({ - method: 'GET', - baseURL: '/api', - url: `/statistics/villages/${villageId}`, - }) - ).data; -} - -export const useGetSessionsStats = (phase: number | null) => { - return useQuery(['sessions-stats'], () => getSessionsStats(phase)); -}; - -export const useGetVillagesStats = (villageId: number | null) => { - return useQuery(['villages-stats', villageId], () => getVillagesStats(villageId), { - enabled: villageId !== null, - }); -}; - -async function getClassroomsStats(): Promise { - return ( - await axiosRequest({ - method: 'GET', - baseURL: '/api', - url: '/statistics/classrooms', - }) - ).data; -} - -export const useGetClassroomsStats = () => { - return useQuery(['classrooms-stats'], () => getClassroomsStats()); -}; +import { useQuery } from 'react-query'; + +import { axiosRequest } from 'src/utils/axiosRequest'; +import type { ClassroomsStats, SessionsStats, VillageStats } from 'types/statistics.type'; + +async function getSessionsStats(phase: number | null): Promise { + return ( + await axiosRequest({ + method: 'GET', + baseURL: '/api', + url: `/statistics/sessions/${phase}`, + }) + ).data; +} + +async function getVillagesStats(villageId: number | null): Promise { + return ( + await axiosRequest({ + method: 'GET', + baseURL: '/api', + url: `/statistics/villages/${villageId}`, + }) + ).data; +} + +export const useGetSessionsStats = (phase: number | null) => { + return useQuery(['sessions-stats'], () => getSessionsStats(phase)); +}; + +export const useGetVillagesStats = (villageId: number | null) => { + return useQuery(['villages-stats', villageId], () => getVillagesStats(villageId), { + enabled: villageId !== null, + }); +}; + +async function getClassroomsStats(): Promise { + return ( + await axiosRequest({ + method: 'GET', + baseURL: '/api', + url: '/statistics/classrooms', + }) + ).data; +} + +export const useGetClassroomsStats = () => { + return useQuery(['classrooms-stats'], () => getClassroomsStats()); +}; diff --git a/src/components/admin/dashboard-statistics/VillageStats.tsx b/src/components/admin/dashboard-statistics/VillageStats.tsx index a12b9d34f..34ac4c58a 100644 --- a/src/components/admin/dashboard-statistics/VillageStats.tsx +++ b/src/components/admin/dashboard-statistics/VillageStats.tsx @@ -1,105 +1,110 @@ -import React, { useState } from 'react'; - -import Box from '@mui/material/Box'; -import Tab from '@mui/material/Tab'; -import Tabs from '@mui/material/Tabs'; -import Typography from '@mui/material/Typography'; - -import StatsCard from './cards/StatsCard/StatsCard'; -import CountriesDropdown from './filters/CountriesDropdown'; -import PhaseDropdown from './filters/PhaseDropdown'; -import VillageDropdown from './filters/VillageDropdown'; -import { PelicoCard } from './pelico-card'; -import styles from './styles/charts.module.css'; -import { useGetVillagesStats } from 'src/api/statistics/statistics.get'; -import { useCountries } from 'src/services/useCountries'; -import { useVillages } from 'src/services/useVillages'; - -const VillageStats = () => { - const [selectedCountry, setSelectedCountry] = useState(''); - const [selectedVillage, setSelectedVillage] = useState(''); - - const pelicoMessage = 'Merci de sélectionner un village-monde pour analyser ses statistiques '; - - const { countries } = useCountries(); - - const { villages } = useVillages(selectedCountry); - const villagesStats = useGetVillagesStats(+selectedVillage); - - const handleCountryChange = (country: string) => { - setSelectedCountry(country); - setSelectedVillage(''); - }; - - const handleVillageChange = (village: string) => { - setSelectedVillage(village); - }; - - interface TabPanelProps { - children?: React.ReactNode; - index: number; - value: number; - } - - function a11yProps(index: number) { - return { - id: `simple-tab-${index}`, - 'aria-controls': `simple-tabpanel-${index}`, - }; - } - const [value, setValue] = React.useState(0); - const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => { - setValue(newValue); - }; - - function CustomTabPanel(props: TabPanelProps) { - const { children, value, index, ...other } = props; - - return ( - - ); - } - - return ( - <> -
-
- -
-
- -
-
- -
-
-

Tableau à venir

- - - - - -

Statistiques - En classe

-
- - {!selectedVillage ? ( - - ) : ( -
- Nombre de profs ayant créé des comptes famille - Nombre de codes enfant créés - Nombre de familles connectées -
- )} -
- - ); -}; - -export default VillageStats; +import React, { useState } from 'react'; + +import Box from '@mui/material/Box'; +import Tab from '@mui/material/Tab'; +import Tabs from '@mui/material/Tabs'; +import Typography from '@mui/material/Typography'; + +import StatsCard from './cards/StatsCard/StatsCard'; +import CountriesDropdown from './filters/CountriesDropdown'; +import PhaseDropdown from './filters/PhaseDropdown'; +import VillageDropdown from './filters/VillageDropdown'; +import { PelicoCard } from './pelico-card'; +import styles from './styles/charts.module.css'; +import { useGetVillagesStats } from 'src/api/statistics/statistics.get'; +import { useCountries } from 'src/services/useCountries'; +import { useVillages } from 'src/services/useVillages'; + +const VillageStats = () => { + const [selectedCountry, setSelectedCountry] = useState(''); + const [selectedVillage, setSelectedVillage] = useState(''); + const [selectedPhase, setSelectedPhase] = useState('4'); + + const pelicoMessage = 'Merci de sélectionner un village-monde pour analyser ses statistiques '; + + const { countries } = useCountries(); + + const { villages } = useVillages(selectedCountry, selectedPhase); + const villagesStats = useGetVillagesStats(+selectedVillage); + + const handleCountryChange = (country: string) => { + setSelectedCountry(country); + setSelectedVillage(''); + }; + + const handleVillageChange = (village: string) => { + setSelectedVillage(village); + }; + + const handlePhaseChange = (phase: string) => { + setSelectedPhase(phase); + }; + + interface TabPanelProps { + children?: React.ReactNode; + index: number; + value: number; + } + + function a11yProps(index: number) { + return { + id: `simple-tab-${index}`, + 'aria-controls': `simple-tabpanel-${index}`, + }; + } + const [value, setValue] = React.useState(0); + const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => { + setValue(newValue); + }; + + function CustomTabPanel(props: TabPanelProps) { + const { children, value, index, ...other } = props; + + return ( + + ); + } + + return ( + <> +
+
+ +
+
+ +
+
+ +
+
+

Tableau à venir

+ + + + + +

Statistiques - En classe

+
+ + {!selectedVillage ? ( + + ) : ( +
+ Nombre de profs ayant créé des comptes famille + Nombre de codes enfant créés + Nombre de familles connectées +
+ )} +
+ + ); +}; + +export default VillageStats; diff --git a/src/components/admin/dashboard-statistics/filters/PhaseDropdown.tsx b/src/components/admin/dashboard-statistics/filters/PhaseDropdown.tsx index d65fa6a4c..d530893e0 100644 --- a/src/components/admin/dashboard-statistics/filters/PhaseDropdown.tsx +++ b/src/components/admin/dashboard-statistics/filters/PhaseDropdown.tsx @@ -7,11 +7,17 @@ import MenuItem from '@mui/material/MenuItem'; import type { SelectChangeEvent } from '@mui/material/Select'; import Select from '@mui/material/Select'; -export default function PhaseDropdown() { - const [phase, setPhase] = React.useState(''); +interface PhaseDropdownProps { + onPhaseChange: (phase: string) => void; +} + +export default function PhaseDropdown({ onPhaseChange }: PhaseDropdownProps) { + const [phase, setPhase] = React.useState('4'); const handleChange = (event: SelectChangeEvent) => { - setPhase(event.target.value as string); + const selectedPhase = event.target.value as string; + setPhase(selectedPhase); + onPhaseChange(selectedPhase); }; return ( @@ -19,10 +25,12 @@ export default function PhaseDropdown() { Phase diff --git a/src/services/useVillages.ts b/src/services/useVillages.ts index ad2ad4da2..17bb43fe7 100644 --- a/src/services/useVillages.ts +++ b/src/services/useVillages.ts @@ -1,151 +1,161 @@ -import { useSnackbar } from 'notistack'; -import React from 'react'; -import type { QueryFunction } from 'react-query'; -import { useQueryClient, useQuery } from 'react-query'; - -import { axiosRequest } from 'src/utils/axiosRequest'; -import type { Village } from 'types/village.type'; - -export const useVillages = (countryIsoCode?: string): { villages: Village[]; setVillages(newVillages: Village[]): void } => { - const queryClient = useQueryClient(); - - // The query function for fetching villages, memoized with useCallback - const getVillages: QueryFunction = React.useCallback(async () => { - const response = await axiosRequest({ - method: 'GET', - url: countryIsoCode ? `/villages?countryIsoCode=${countryIsoCode}` : '/villages', - }); - if (response.error) { - return []; - } - return response.data; - }, [countryIsoCode]); - - // Notice that we include `countryIsoCode` in the query key so that the query is refetched - const { data, isLoading, error } = useQuery( - ['villages', countryIsoCode], // Include countryIsoCode in the query key to trigger refetching - getVillages, - ); - - const setVillages = React.useCallback( - (newVillages: Village[]) => { - queryClient.setQueryData(['villages', countryIsoCode], newVillages); // Ensure that the query key includes countryIsoCode - }, - [queryClient, countryIsoCode], - ); - - return { - villages: isLoading || error ? [] : data || [], - setVillages, - }; -}; - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export const useVillageRequests = () => { - const queryClient = useQueryClient(); - const { enqueueSnackbar } = useSnackbar(); - - const addVillage = React.useCallback( - async (newVillage: Pick) => { - const response = await axiosRequest({ - method: 'POST', - url: '/villages', - data: { - name: newVillage.name, - countries: newVillage.countries.map((c) => c.isoCode), - }, - }); - if (response.error) { - enqueueSnackbar('Une erreur est survenue...', { - variant: 'error', - }); - return null; - } - enqueueSnackbar('Village créé avec succès!', { - variant: 'success', - }); - queryClient.invalidateQueries('villages'); - return response.data as Village; - }, - [queryClient, enqueueSnackbar], - ); - - const editVillage = React.useCallback( - async (updatedVillage: Partial) => { - const { id, ...rest } = updatedVillage; - const response = await axiosRequest({ - method: 'PUT', - url: `/villages/${id}`, - data: { - activePhase: rest.activePhase, - countries: rest.countries?.map((c) => c.isoCode) || undefined, - name: rest.name, - anthemId: rest.anthemId, - }, - }); - if (response.error) { - enqueueSnackbar('Une erreur est survenue...', { - variant: 'error', - }); - return null; - } - enqueueSnackbar('Village modifié avec succès!', { - variant: 'success', - }); - queryClient.invalidateQueries('villages'); - return response.data as Village; - }, - [queryClient, enqueueSnackbar], - ); - - const deleteVillage = React.useCallback( - async (id: number) => { - const response = await axiosRequest({ - method: 'DELETE', - url: `/villages/${id}`, - }); - if (response.error) { - enqueueSnackbar('Une erreur est survenue...', { - variant: 'error', - }); - return; - } - enqueueSnackbar('Village supprimé avec succès!', { - variant: 'success', - }); - queryClient.invalidateQueries('villages'); - }, - [queryClient, enqueueSnackbar], - ); - - const importVillages = React.useCallback(async () => { - const response = await axiosRequest({ - method: 'POST', - url: '/villages/import/plm', - }); - if (response.error) { - enqueueSnackbar('Une erreur est survenue...', { - variant: 'error', - }); - return; - } - enqueueSnackbar( - response.data.count === 0 - ? 'Aucun nouveau village importé!' - : response.data.count === 1 - ? '1 village importé avec succès!' - : `${response.data.count} villages importés avec succès!`, - { - variant: 'success', - }, - ); - queryClient.invalidateQueries('villages'); - }, [queryClient, enqueueSnackbar]); - - return { - addVillage, - editVillage, - deleteVillage, - importVillages, - }; -}; +import { useSnackbar } from 'notistack'; +import React from 'react'; +import type { QueryFunction } from 'react-query'; +import { useQueryClient, useQuery } from 'react-query'; + +import { axiosRequest } from 'src/utils/axiosRequest'; +import type { Village } from 'types/village.type'; + +export const useVillages = (countryIsoCode: string, phase: string): { villages: Village[]; setVillages(newVillages: Village[]): void } => { + const queryClient = useQueryClient(); + const buildUrl = () => { + if (!countryIsoCode && !phase) return '/villages'; + const queryParams = []; + + if (countryIsoCode) queryParams.push(`countryIsoCode=${countryIsoCode}`); + if (phase) queryParams.push(`phase=${phase}`); + + return queryParams.length ? `/villages?${queryParams.join('&')}` : '/villages'; + }; + + const url = buildUrl(); + // The query function for fetching villages, memoized with useCallback + const getVillages: QueryFunction = React.useCallback(async () => { + const response = await axiosRequest({ + method: 'GET', + url, + }); + if (response.error) { + return []; + } + return response.data; + }, [url]); + + // Notice that we include `countryIsoCode` in the query key so that the query is refetched + const { data, isLoading, error } = useQuery( + ['villages', countryIsoCode, phase], // Include countryIsoCode in the query key to trigger refetching + getVillages, + ); + + const setVillages = React.useCallback( + (newVillages: Village[]) => { + queryClient.setQueryData(['villages', countryIsoCode, phase], newVillages); // Ensure that the query key includes countryIsoCode + }, + [queryClient, countryIsoCode, phase], + ); + + return { + villages: isLoading || error ? [] : data || [], + setVillages, + }; +}; + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export const useVillageRequests = () => { + const queryClient = useQueryClient(); + const { enqueueSnackbar } = useSnackbar(); + + const addVillage = React.useCallback( + async (newVillage: Pick) => { + const response = await axiosRequest({ + method: 'POST', + url: '/villages', + data: { + name: newVillage.name, + countries: newVillage.countries.map((c) => c.isoCode), + }, + }); + if (response.error) { + enqueueSnackbar('Une erreur est survenue...', { + variant: 'error', + }); + return null; + } + enqueueSnackbar('Village créé avec succès!', { + variant: 'success', + }); + queryClient.invalidateQueries('villages'); + return response.data as Village; + }, + [queryClient, enqueueSnackbar], + ); + + const editVillage = React.useCallback( + async (updatedVillage: Partial) => { + const { id, ...rest } = updatedVillage; + const response = await axiosRequest({ + method: 'PUT', + url: `/villages/${id}`, + data: { + activePhase: rest.activePhase, + countries: rest.countries?.map((c) => c.isoCode) || undefined, + name: rest.name, + anthemId: rest.anthemId, + }, + }); + if (response.error) { + enqueueSnackbar('Une erreur est survenue...', { + variant: 'error', + }); + return null; + } + enqueueSnackbar('Village modifié avec succès!', { + variant: 'success', + }); + queryClient.invalidateQueries('villages'); + return response.data as Village; + }, + [queryClient, enqueueSnackbar], + ); + + const deleteVillage = React.useCallback( + async (id: number) => { + const response = await axiosRequest({ + method: 'DELETE', + url: `/villages/${id}`, + }); + if (response.error) { + enqueueSnackbar('Une erreur est survenue...', { + variant: 'error', + }); + return; + } + enqueueSnackbar('Village supprimé avec succès!', { + variant: 'success', + }); + queryClient.invalidateQueries('villages'); + }, + [queryClient, enqueueSnackbar], + ); + + const importVillages = React.useCallback(async () => { + const response = await axiosRequest({ + method: 'POST', + url: '/villages/import/plm', + }); + if (response.error) { + enqueueSnackbar('Une erreur est survenue...', { + variant: 'error', + }); + return; + } + enqueueSnackbar( + response.data.count === 0 + ? 'Aucun nouveau village importé!' + : response.data.count === 1 + ? '1 village importé avec succès!' + : `${response.data.count} villages importés avec succès!`, + { + variant: 'success', + }, + ); + queryClient.invalidateQueries('villages'); + }, [queryClient, enqueueSnackbar]); + + return { + addVillage, + editVillage, + deleteVillage, + importVillages, + }; +};