-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ajout des filtres sur la liste des utilisateurs (#3387)
- Loading branch information
Showing
22 changed files
with
688 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,50 @@ | ||
// récupéré de l'API et adapté pour ne pas avoir certains champs optionnels | ||
export interface UsersPaginated { | ||
pagination: Pagination; | ||
data: User[]; | ||
} | ||
|
||
export interface User { | ||
_id: string; | ||
/** | ||
* Email utilisateur | ||
*/ | ||
account_status: string; | ||
password_updated_at: Date; | ||
created_at: Date; | ||
email: string; | ||
/** | ||
* civilité | ||
*/ | ||
civility: "Madame" | "Monsieur"; | ||
/** | ||
* Le nom de l'utilisateur | ||
*/ | ||
civility: string; | ||
nom: string; | ||
/** | ||
* Le prénom de l'utilisateur | ||
*/ | ||
prenom: string; | ||
/** | ||
* Le téléphone de l'utilisateur | ||
*/ | ||
telephone: string; | ||
/** | ||
* La fonction de l'utilisateur | ||
*/ | ||
fonction: string; | ||
/** | ||
* Date de création du compte | ||
*/ | ||
created_at: string; | ||
telephone: string; | ||
has_accept_cgu_version: string; | ||
organisation_id: string; | ||
organisation: UserOrganisation; | ||
last_connection: string; | ||
} | ||
|
||
export interface UserOrganisation { | ||
_id: string; | ||
created_at: Date; | ||
type: string; | ||
uai: string; | ||
siret: string; | ||
organisme: UserOrganisme; | ||
label: string; | ||
} | ||
|
||
export interface UserOrganisme { | ||
_id: string; | ||
nom: string; | ||
reseaux: any[]; | ||
nature: string; | ||
raison_sociale: string; | ||
adresse?: { | ||
departement?: string; | ||
region?: string; | ||
}; | ||
} | ||
|
||
export interface Pagination { | ||
total: number; | ||
page: number; | ||
limit: number; | ||
lastPage: number; | ||
} |
4 changes: 2 additions & 2 deletions
4
...nismes/filters/OrganismesFilterButton.tsx → ui/components/FilterButton/FilterButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { useRouter } from "next/router"; | ||
import { useMemo } from "react"; | ||
|
||
import { _get, _post, _put } from "@/common/httpClient"; | ||
import { UsersPaginated } from "@/common/internal/User"; | ||
import { UserNormalized, toUserNormalized } from "@/modules/admin/users/models/users"; | ||
import { | ||
UsersFiltersQuery, | ||
filterUsersArrayFromUsersFilters, | ||
parseUsersFiltersFromQuery, | ||
} from "@/modules/admin/users/models/users-filters"; | ||
|
||
export function useUsers() { | ||
const NO_LIMIT = 10_000; | ||
|
||
const { | ||
data: usersPaginated, | ||
refetch: refetchUsers, | ||
isLoading, | ||
} = useQuery<UsersPaginated, any>(["admin/users"], () => | ||
_get("/api/v1/admin/users/", { | ||
params: { | ||
page: 1, | ||
limit: NO_LIMIT, | ||
}, | ||
}) | ||
); | ||
|
||
const allUsers = useMemo(() => { | ||
if (!usersPaginated) return []; | ||
return usersPaginated.data.map((user) => toUserNormalized(user)); | ||
}, [usersPaginated]); | ||
|
||
return { | ||
isLoading, | ||
refetchUsers, | ||
allUsers, | ||
}; | ||
} | ||
|
||
export function useUsersFiltered(users: UserNormalized[]) { | ||
const router = useRouter(); | ||
|
||
const filteredUsers = useMemo(() => { | ||
return users | ||
? filterUsersArrayFromUsersFilters( | ||
users, | ||
parseUsersFiltersFromQuery(router.query as unknown as UsersFiltersQuery) | ||
) | ||
: []; | ||
}, [users, router.query]); | ||
|
||
return { filteredUsers }; | ||
} | ||
|
||
export function useUsersSearched(usersFiltered: UserNormalized[], search: string) { | ||
const searchedUsers = useMemo(() => { | ||
if (!search) return usersFiltered; | ||
return usersFiltered?.filter((user) => { | ||
const searchLower = search.toLowerCase(); | ||
return ( | ||
user.normalizedNomPrenom.includes(searchLower) || | ||
user.normalizedEmail.includes(searchLower) || | ||
user.normalizedOrganismeNom.toLowerCase().includes(searchLower) | ||
); | ||
}); | ||
}, [search, usersFiltered]); | ||
|
||
return { searchedUsers }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { Button, HStack, Stack, Text } from "@chakra-ui/react"; | ||
import { useRouter } from "next/router"; | ||
import { useMemo } from "react"; | ||
|
||
import { | ||
PaginationInfosQuery, | ||
convertPaginationInfosToQuery, | ||
parsePaginationInfosFromQuery, | ||
} from "@/modules/models/pagination"; | ||
|
||
import FiltreUsersAccountStatut from "./filters/FiltreUsersAccountStatut"; | ||
import FiltreUsersDepartment from "./filters/FiltreUsersDepartements"; | ||
import FiltreUsersRegion from "./filters/FiltreUsersRegion"; | ||
import FiltreUsersReseaux from "./filters/FiltreUsersReseaux"; | ||
import FiltreUserTypes from "./filters/FiltreUsersType"; | ||
import { | ||
UsersFilters, | ||
UsersFiltersQuery, | ||
convertUsersFiltersToQuery, | ||
parseUsersFiltersFromQuery, | ||
} from "./models/users-filters"; | ||
|
||
const UsersFiltersPanel = () => { | ||
const router = useRouter(); | ||
|
||
const { usersFilters, sort } = useMemo(() => { | ||
const { pagination, sort } = parsePaginationInfosFromQuery(router.query as unknown as PaginationInfosQuery); | ||
return { | ||
usersFilters: parseUsersFiltersFromQuery(router.query as unknown as UsersFiltersQuery), | ||
pagination: pagination, | ||
sort: sort ?? [{ desc: false, id: "nom" }], | ||
}; | ||
}, [JSON.stringify(router.query)]); | ||
|
||
const updateState = (newParams: Partial<{ [key in keyof UsersFilters]: any }>) => { | ||
void router.push( | ||
{ | ||
pathname: router.pathname, | ||
query: { | ||
...(router.query.organismeId ? { organismeId: router.query.organismeId } : {}), | ||
...convertUsersFiltersToQuery({ ...usersFilters, ...newParams }), | ||
...convertPaginationInfosToQuery({ sort, ...newParams }), | ||
}, | ||
}, | ||
undefined, | ||
{ shallow: true } | ||
); | ||
}; | ||
|
||
const resetFilters = () => { | ||
void router.push( | ||
{ | ||
pathname: router.pathname, | ||
query: { ...(router.query.organismeId ? { organismeId: router.query.organismeId } : {}) }, | ||
}, | ||
undefined, | ||
{ shallow: true } | ||
); | ||
}; | ||
|
||
return ( | ||
<Stack spacing="0.5"> | ||
<Text fontSize="zeta" fontWeight="extrabold"> | ||
FILTRER PAR | ||
</Text> | ||
<HStack> | ||
{/* FILTRE Département */} | ||
<FiltreUsersDepartment | ||
value={usersFilters.departements} | ||
onChange={(departements) => updateState({ departements })} | ||
/> | ||
|
||
{/* FILTRE Région */} | ||
<FiltreUsersRegion value={usersFilters.regions} onChange={(regions) => updateState({ regions })} /> | ||
|
||
{/* FILTRE Type Utilisateur */} | ||
<FiltreUserTypes | ||
value={usersFilters.type_utilisateur} | ||
onChange={(type_utilisateur) => updateState({ type_utilisateur })} | ||
/> | ||
|
||
{/* FILTRE Réseau */} | ||
<FiltreUsersReseaux value={usersFilters.reseaux} onChange={(reseaux) => updateState({ reseaux })} /> | ||
|
||
{/* FILTRE Statut du compte */} | ||
<FiltreUsersAccountStatut | ||
value={usersFilters.account_status} | ||
onChange={(account_status) => updateState({ account_status })} | ||
/> | ||
|
||
{/* FILTRE Période */} | ||
|
||
{/* REINITIALISER */} | ||
<Button variant="link" onClick={resetFilters} fontSize="omega"> | ||
réinitialiser | ||
</Button> | ||
</HStack> | ||
</Stack> | ||
); | ||
}; | ||
|
||
export default UsersFiltersPanel; |
50 changes: 50 additions & 0 deletions
50
ui/modules/admin/users/filters/FiltreUsersAccountStatut.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Checkbox, CheckboxGroup, Stack } from "@chakra-ui/react"; | ||
import { useState } from "react"; | ||
|
||
import { USER_STATUS_LABELS } from "@/common/constants/usersConstants"; | ||
import { FilterButton } from "@/components/FilterButton/FilterButton"; | ||
import SimpleOverlayMenu from "@/modules/dashboard/SimpleOverlayMenu"; | ||
|
||
interface FiltreUsersAccountStatutTypesProps { | ||
value: string[]; | ||
onChange: (statutsCompte: string[]) => void; | ||
} | ||
|
||
function FiltreUsersAccountStatut(props: FiltreUsersAccountStatutTypesProps) { | ||
const [isOpen, setIsOpen] = useState(false); | ||
const statutsCompte = props.value; | ||
|
||
return ( | ||
<div> | ||
<FilterButton | ||
isOpen={isOpen} | ||
setIsOpen={setIsOpen} | ||
buttonLabel="Statut du compte" | ||
badge={statutsCompte?.length} | ||
/> | ||
{isOpen && ( | ||
<SimpleOverlayMenu onClose={() => setIsOpen(false)} width="auto" p="3w"> | ||
<CheckboxGroup | ||
defaultValue={statutsCompte} | ||
size="sm" | ||
onChange={(selectedAccountStatuts: string[]) => props.onChange(selectedAccountStatuts)} | ||
> | ||
<Stack> | ||
<Checkbox iconSize="0.5rem" value="CONFIRMED" key="CONFIRMED"> | ||
{USER_STATUS_LABELS.CONFIRMED} | ||
</Checkbox> | ||
<Checkbox iconSize="0.5rem" value="PENDING_EMAIL_VALIDATION" key="PENDING_EMAIL_VALIDATION"> | ||
{USER_STATUS_LABELS.PENDING_EMAIL_VALIDATION} | ||
</Checkbox> | ||
<Checkbox iconSize="0.5rem" value="PENDING_ADMIN_VALIDATION" key="PENDING_ADMIN_VALIDATION"> | ||
{USER_STATUS_LABELS.PENDING_ADMIN_VALIDATION} | ||
</Checkbox> | ||
</Stack> | ||
</CheckboxGroup> | ||
</SimpleOverlayMenu> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
export default FiltreUsersAccountStatut; |
Oops, something went wrong.