Skip to content

Commit

Permalink
chore: sauvegarde
Browse files Browse the repository at this point in the history
  • Loading branch information
ocruze committed Feb 7, 2025
1 parent 706bf92 commit c042763
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { declareComponentKeys } from "i18nifty";
import { ReactNode } from "react";
import { Translations } from "../../../../i18n/types";

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

const { i18n } = declareComponentKeys<
| { K: "title"; P: { datastoreName?: string }; R: string }
Expand All @@ -13,6 +15,15 @@ const { i18n } = declareComponentKeys<
| { K: "sandbox_datastore_explanation"; R: ReactNode }
| "refresh_datasheet_list"
| { K: "last_refresh_date"; P: { dataUpdatedAt: number }; R: string }
| "filter_label"
| "filter_placeholder"
| { K: "filter_option"; P: { filter: FilterEnum }; R: string }
| "sort_label"
| "sort_placeholder"
| { K: "sort_option"; P: { sort: SortByEnum }; R: string }
| "sort_order_label"
| "sort_order_placeholder"
| { K: "sort_order_option"; P: { sortOrder: SortOrderEnum }; R: string }
>()("DatasheetList");
export type I18n = typeof i18n;

Expand All @@ -32,6 +43,42 @@ export const DatasheetListFrTranslations: Translations<"fr">["DatasheetList"] =
),
refresh_datasheet_list: "Rafraîchir",
last_refresh_date: ({ dataUpdatedAt }) => `Données mises à jour le ${formatDateFromISO(new Date(dataUpdatedAt).toISOString())}`,
filter_label: "Filtrer",
filter_placeholder: "Sélectionner un filtre",
filter_option: ({ filter }) => {
switch (filter) {
case FilterEnum.PUBLISHED:
return "Fiches publiées";
case FilterEnum.NOT_PUBLISHED:
return "Fiches non publiées";
default:
return "Filtre inconnu";
}
},
sort_label: "Trier",
sort_placeholder: "Trier par",
sort_option: ({ sort }) => {
switch (sort) {
case SortByEnum.NAME:
return "Nom";
case SortByEnum.NB_SERVICES:
return "Fiches publiées";
default:
return "Tri inconnu";
}
},
sort_order_label: "Trier",
sort_order_placeholder: "Dans l'ordre",
sort_order_option: ({ sortOrder }) => {
switch (sortOrder) {
case SortOrderEnum.ASCENDING:
return "Croissant";
case SortOrderEnum.DESCENDING:
return "Décroissant";
default:
return "Ordre inconnu";
}
},
};

export const DatasheetListEnTranslations: Translations<"en">["DatasheetList"] = {
Expand All @@ -44,4 +91,13 @@ export const DatasheetListEnTranslations: Translations<"en">["DatasheetList"] =
sandbox_datastore_explanation: undefined,
refresh_datasheet_list: undefined,
last_refresh_date: undefined,
filter_label: undefined,
filter_placeholder: undefined,
filter_option: undefined,
sort_label: undefined,
sort_placeholder: undefined,
sort_option: undefined,
sort_order_label: undefined,
sort_order_placeholder: undefined,
sort_order_option: undefined,
};
180 changes: 174 additions & 6 deletions assets/entrepot/pages/datasheet/DatasheetList/DatasheetList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,65 @@ import { fr } from "@codegouvfr/react-dsfr";
import Alert from "@codegouvfr/react-dsfr/Alert";
import ButtonsGroup from "@codegouvfr/react-dsfr/ButtonsGroup";
import Pagination from "@codegouvfr/react-dsfr/Pagination";
import SearchBar from "@codegouvfr/react-dsfr/SearchBar";
import SelectNext from "@codegouvfr/react-dsfr/SelectNext";
import Tag from "@codegouvfr/react-dsfr/Tag";
import { useQuery } from "@tanstack/react-query";
import { FC, useMemo } from "react";
import { FC, useMemo, useState } from "react";

import { Datasheet, EndpointTypeEnum } from "../../../../@types/app";
import Main from "../../../../components/Layout/Main";
import LoadingIcon from "../../../../components/Utils/LoadingIcon";
import Skeleton from "../../../../components/Utils/Skeleton";
import { useDatastore } from "../../../../contexts/datastore";
import { useTranslation } from "../../../../i18n/i18n";
import RQKeys from "../../../../modules/entrepot/RQKeys";
import { routes, useRoute } from "../../../../router/router";
import api from "../../../api";
import { FilterEnum, Sort, SortByEnum, SortOrderEnum } from "./DatasheetList.types";
import DatasheetListItem from "./DatasheetListItem";
import { useDatastore } from "../../../../contexts/datastore";
import Main from "../../../../components/Layout/Main";

const getFilteredList = (list: Datasheet[], filters: FilterEnum[], filterName?: string) => {
if (filterName) {
list = list.filter((d) => d.name.toLowerCase().includes(filterName.toLowerCase()));
}

if (filters.length === 0) {
return list;
}

let filtered: Datasheet[] = [];

if (filters.includes(FilterEnum.PUBLISHED)) {
filtered = [...filtered, ...list.filter((d) => d.nb_publications > 0)];
}

if (filters.includes(FilterEnum.NOT_PUBLISHED)) {
filtered = [...filtered, ...list.filter((d) => d.nb_publications === 0)];
}
return filtered;
};

const getSortedList = (list: Datasheet[], sort: Sort) => {
return list.sort((a, b) => {
switch (sort.by) {
case SortByEnum.NB_SERVICES:
return (a.nb_publications - b.nb_publications) * sort.order;

case SortByEnum.NAME:
default:
return a.name.localeCompare(b.name) * sort.order;
}
});
};

type DatasheetListProps = {
datastoreId: string;
};
const DatasheetList: FC<DatasheetListProps> = ({ datastoreId }) => {
const { t } = useTranslation("DatasheetList");
const { datastore, isFetching } = useDatastore();
const { t: tCommon } = useTranslation("Common");

const { params } = useRoute();
const pagination = {
Expand All @@ -45,10 +84,17 @@ const DatasheetList: FC<DatasheetListProps> = ({ datastoreId }) => {
metadataEndpoint && metadataEndpoint?.quota && metadataEndpoint?.use && metadataEndpoint?.quota <= metadataEndpoint?.use
);

// filtre et tri
const [searchDatasheetName, setSearchDatasheetName] = useState<string | undefined>();
const [filters, setFilters] = useState<FilterEnum[]>([]);
const [sort, setSort] = useState<Sort>({ by: SortByEnum.NAME, order: SortOrderEnum.ASCENDING });

const datasheetList = getSortedList(getFilteredList(datasheetListQuery.data ?? [], filters, searchDatasheetName), sort);

return (
<Main title="Mes données">
<div className={fr.cx("fr-grid-row")}>
<div className={fr.cx("fr-col")}>
<div className={fr.cx("fr-col-12")}>
<h1>
{t("title", { datastoreName: datastore?.name })}
{(isFetching || datasheetListQuery?.isFetching) && <LoadingIcon className={fr.cx("fr-ml-2w")} largeIcon={true} />}
Expand Down Expand Up @@ -98,13 +144,135 @@ const DatasheetList: FC<DatasheetListProps> = ({ datastoreId }) => {
<>
<p>{t("last_refresh_date", { dataUpdatedAt: datasheetListQuery.dataUpdatedAt })}</p>

{datasheetListQuery?.data
<div className={fr.cx("fr-grid-row", "fr-grid-row--gutters")}>
<div className={fr.cx("fr-col-12")}>
<SearchBar
label={tCommon("search")}
onButtonClick={(text) => {
setSearchDatasheetName(text);
routes.datasheet_list({ datastoreId }).replace();
}}
allowEmptySearch={true}
/>
</div>
</div>

{/* <div className={fr.cx("fr-grid-row", "fr-grid-row--gutters")}>
<div className={fr.cx("fr-col-12", "fr-col-md-4")}>
<Chec
</div>
<div className={fr.cx("fr-col-12", "fr-col-md-4")}></div>
</div> */}

<div className={fr.cx("fr-grid-row", "fr-grid-row--gutters")}>
<div className={fr.cx("fr-col-12", "fr-col-md-4")}>
<SelectNext
label={null}
options={[
{
value: FilterEnum.PUBLISHED.toString(),
label: t("filter_option", { filter: FilterEnum.PUBLISHED }),
},
{
value: FilterEnum.NOT_PUBLISHED.toString(),
label: t("filter_option", { filter: FilterEnum.NOT_PUBLISHED }),
},
]}
nativeSelectProps={{
"aria-label": t("filter_label"),
onClick: (e) => {
const selectedFilter = Number(e.currentTarget.value);
if (isNaN(selectedFilter) || selectedFilter === 0) return;

setFilters((prev) => (prev.includes(selectedFilter) ? [...prev] : [...prev, selectedFilter]));
e.currentTarget.value = "";
routes.datasheet_list({ datastoreId }).replace();
},
}}
placeholder={t("filter_placeholder")}
/>
</div>
<div className={fr.cx("fr-col-12", "fr-col-md-8")}>
<ul className={fr.cx("fr-tags-group")}>
{filters.map((filter) => (
<li key={filter}>
<Tag
dismissible
nativeButtonProps={{
onClick: () => {
setFilters((prev) => prev.filter((f) => f !== filter));
routes.datasheet_list({ datastoreId }).replace();
},
}}
>
{t("filter_option", { filter: Number(filter) })}
</Tag>
</li>
))}
</ul>
</div>
</div>
<div className={fr.cx("fr-grid-row", "fr-grid-row--gutters", "fr-grid-row--right", "fr-mb-4v")}>
<div className={fr.cx("fr-col-12", "fr-col-sm-8")}>
<SelectNext
label={null}
options={[
{
label: t("sort_option", { sort: SortByEnum.NAME }),
value: SortByEnum.NAME.toString(),
},
{
label: t("sort_option", { sort: SortByEnum.NB_SERVICES }),
value: SortByEnum.NB_SERVICES.toString(),
},
]}
nativeSelectProps={{
"aria-label": t("sort_label"),
value: sort.by.toString(),
onChange: (e) => {
const selectedSortBy = Number(e.currentTarget.value);

if (isNaN(selectedSortBy) || selectedSortBy === 0) return;
setSort((prev) => ({ ...prev, by: selectedSortBy }));
},
}}
placeholder={t("sort_placeholder")}
/>
</div>
<div className={fr.cx("fr-col-12", "fr-col-sm-4")}>
<SelectNext
label={null}
options={[
{
label: t("sort_order_option", { sortOrder: SortOrderEnum.ASCENDING }),
value: SortOrderEnum.ASCENDING.toString(),
},
{
label: t("sort_order_option", { sortOrder: SortOrderEnum.DESCENDING }),
value: SortOrderEnum.DESCENDING.toString(),
},
]}
nativeSelectProps={{
"aria-label": t("sort_order_label"),
value: sort.order.toString(),
onChange: (e) => {
const selectedSortOrder = Number(e.currentTarget.value);
if (isNaN(selectedSortOrder) || selectedSortOrder === 0) return;
setSort((prev) => ({ ...prev, order: selectedSortOrder }));
},
}}
placeholder={t("sort_order_placeholder")}
/>
</div>
</div>

{datasheetList
?.slice((pagination.page - 1) * pagination.limit, pagination.page * pagination.limit)
.map((datasheet: Datasheet) => <DatasheetListItem key={datasheet.name} datastoreId={datastoreId} datasheet={datasheet} />)}

<div className={fr.cx("fr-grid-row", "fr-grid-row--center", "fr-mt-6v")}>
<Pagination
count={Math.ceil(datasheetListQuery.data?.length / pagination.limit)}
count={Math.ceil(datasheetList.length / pagination.limit)}
showFirstLast={true}
getPageLinkProps={(pageNumber) => ({
...routes.datasheet_list({ datastoreId, page: pageNumber, limit: pagination.limit }).link,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export enum FilterEnum {
PUBLISHED = 1,
NOT_PUBLISHED = 2,
}

export enum SortByEnum {
NAME = 1,
NB_SERVICES = 2,
}

export enum SortOrderEnum {
ASCENDING = 1,
DESCENDING = -1,
}

export type Sort = { by: SortByEnum; order: SortOrderEnum };
6 changes: 6 additions & 0 deletions assets/i18n/Common.locale.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const { i18n } = declareComponentKeys<
| "url_copied"
| "copy_to_clipboard"
| "go_to_content"
| "search"
| "clear"
>()("Common");
export type I18n = typeof i18n;

Expand Down Expand Up @@ -70,6 +72,8 @@ export const commonFrTranslations: Translations<"fr">["Common"] = {
url_copied: "URL copiée",
copy_to_clipboard: "Copier dans le presse-papier",
go_to_content: "Aller au contenu",
search: "Rechercher",
clear: "Effacer",
};

export const commonEnTranslations: Translations<"en">["Common"] = {
Expand Down Expand Up @@ -105,4 +109,6 @@ export const commonEnTranslations: Translations<"en">["Common"] = {
url_copied: "URL copied",
copy_to_clipboard: "Copy to clipboard",
go_to_content: "Go to content",
search: "Search",
clear: "Clear",
};

0 comments on commit c042763

Please sign in to comment.