Skip to content

Commit

Permalink
feat: add search and pagination on community members page
Browse files Browse the repository at this point in the history
  • Loading branch information
tonai committed Feb 27, 2025
1 parent e8ea54b commit a1e79c6
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 150 deletions.
47 changes: 47 additions & 0 deletions assets/components/Layout/PageTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { fr } from "@codegouvfr/react-dsfr";
import ButtonsGroup, { ButtonsGroupProps } from "@codegouvfr/react-dsfr/ButtonsGroup";
import { ReactNode } from "react";
import { useStyles } from "tss-react";

interface IPageTitleProps {
buttons?: ButtonsGroupProps.Common["buttons"];
children?: ReactNode;
showButtons?: boolean;
title: ReactNode;
}

function PageTitle(props: IPageTitleProps) {
const { buttons, children, showButtons, title } = props;
const { css } = useStyles();

return (
<div className={fr.cx("fr-grid-row")}>
<div className={fr.cx("fr-col-12", "fr-col-lg-8")}>
<h1>{title}</h1>
{children}
</div>
<div
className={fr.cx("fr-col-12", "fr-col-lg-4", "fr-col--top")}
style={{
display: "flex",
alignItems: "center",
}}
>
{showButtons && buttons && (
<div
className={css({
marginLeft: "inherit",
[fr.breakpoints.up("lg")]: {
marginLeft: "auto",
},
})}
>
<ButtonsGroup buttons={buttons} inlineLayoutWhen="sm and up" />
</div>
)}
</div>
</div>
);
}

export default PageTitle;
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ import "../../../../sass/pages/community_members.scss";
import { useCommunity } from "../../../../contexts/community";
import Main from "../../../../components/Layout/Main";
import { useDatastore } from "../../../../contexts/datastore";
import Pagination from "@codegouvfr/react-dsfr/Pagination";
import { usePagination } from "@/hooks/usePagination";
import SearchBar from "@codegouvfr/react-dsfr/SearchBar";
import PageTitle from "@/components/Layout/PageTitle";
import { useSearch } from "@/hooks/useSearch";

type CommunityMembersProps = {
userId?: string;
Expand Down Expand Up @@ -66,7 +71,7 @@ function CommunityMembers({ userId }: CommunityMembersProps) {
const { datastore } = useDatastore();

// Les membres de cette communauté
const { data: communityMembers, isLoading: isLoadingMembers } = useQuery({
const { data: communityMembers, isLoading } = useQuery({
queryKey: RQKeys.community_members(community._id),
queryFn: ({ signal }) => api.community.getMembers(community._id, { signal }),
staleTime: 20000,
Expand Down Expand Up @@ -103,11 +108,14 @@ function CommunityMembers({ userId }: CommunityMembersProps) {
return members;
}, [communityMembers, communitySupervisor, user?.id]);

const { search,searchedItems } = useSearch(members);
const { limit, page, paginatedItems, totalPages } = usePagination(searchedItems);

useEffect(() => {
if (userId && !isLoadingMembers && !communityMemberIds.includes(userId)) {
if (userId && !isLoading && !communityMemberIds.includes(userId)) {
addMemberModal.open();
}
}, [communityMemberIds, isLoadingMembers, userId]);
}, [communityMemberIds, isLoading, userId]);

const queryClient = useQueryClient();

Expand Down Expand Up @@ -172,8 +180,8 @@ function CommunityMembers({ userId }: CommunityMembersProps) {
}}
title="Membres"
>
{isLoadingMembers && <LoadingText />}
{!isLoadingMembers && userId && communityMemberIds.includes(userId) && (
{isLoading && <LoadingText />}
{!isLoading && userId && communityMemberIds.includes(userId) && (
<Alert
className={fr.cx("fr-mb-1w")}
severity={"warning"}
Expand All @@ -184,14 +192,38 @@ function CommunityMembers({ userId }: CommunityMembersProps) {
}}
/>
)}
{!isLoadingMembers && (
{!isLoading && (
<>
<h1>{t("community_members", { communityName: community?.name ?? "" })}</h1>
<div className={fr.cx("fr-grid-row", "fr-grid-row--right")}>
<Button priority={"primary"} iconId={"fr-icon-add-circle-line"} onClick={() => addMemberModal.open()}>
{t("add_user")}
</Button>
<PageTitle
buttons={[
{
children: t("add_user"),
iconId: "fr-icon-add-circle-line",
onClick: () => addMemberModal.open(),
},
]}
showButtons
title={t("community_members", { communityName: community?.name ?? "" })}
/>

<div className={fr.cx("fr-grid-row", "fr-grid-row--gutters", "fr-mt-2v")}>
<div className={fr.cx("fr-col-12", "fr-col-md-8", "fr-col-offset-md-2")}>
<SearchBar
label={tCommon("search")}
onButtonClick={(text) => {
if (!isLoading) {
routes.members_list({ communityId: community._id, userId, search: text }).replace();
}
}}
allowEmptySearch={true}
big
renderInput={({ className, id, placeholder, type }) => (
<input className={className} id={id} placeholder={placeholder} type={type} disabled={isLoading} />
)}
/>
</div>
</div>

<div className={tableContainerClassName}>
<table>
<thead>
Expand All @@ -209,7 +241,7 @@ function CommunityMembers({ userId }: CommunityMembersProps) {
</tr>
</thead>
<tbody>
{members.map((member) => {
{paginatedItems.map((member) => {
return (
<tr key={member.id}>
<td>
Expand Down Expand Up @@ -250,6 +282,16 @@ function CommunityMembers({ userId }: CommunityMembersProps) {
})}
</tbody>
</table>
<div className={fr.cx("fr-grid-row", "fr-grid-row--center", "fr-mt-6v")}>
<Pagination
count={totalPages}
showFirstLast={true}
getPageLinkProps={(pageNumber) => ({
...routes.members_list({ communityId: community._id, userId, page: pageNumber, limit: limit, search }).link,
})}
defaultPage={page}
/>
</div>
</div>
<UserRights />
{(isRemovePending || isModifyPending) && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { ReactNode } from "react";

import { formatDateFromISO } from "@/utils";
import { Translations } from "../../../../i18n/types";
import { FilterEnum, SortByEnum, SortOrderEnum } from "./DatasheetList.types";
import { FilterEnum } from "@/hooks/useFilters";
import { SortOrderEnum } from "@/hooks/useSort";
import { SortByEnum } from "./DatasheetList.types";

const { i18n } = declareComponentKeys<
| { K: "title"; P: { datastoreName?: string }; R: string }
Expand Down Expand Up @@ -42,9 +44,9 @@ export const DatasheetListFrTranslations: Translations<"fr">["DatasheetList"] =
switch (filter) {
case FilterEnum.ALL:
return "Toutes les fiches";
case FilterEnum.PUBLISHED:
case FilterEnum.ENABLED:
return "Fiches publiées";
case FilterEnum.NOT_PUBLISHED:
case FilterEnum.DISABLED:
return "Fiches non publiées";
default:
return "Filtre inconnu";
Expand Down
Loading

0 comments on commit a1e79c6

Please sign in to comment.