Skip to content

Commit

Permalink
feat: mise en place du premier formulaire (description) en mode édition
Browse files Browse the repository at this point in the history
  • Loading branch information
pprev94 committed Oct 15, 2024
1 parent 299b7d5 commit 310dabe
Show file tree
Hide file tree
Showing 22 changed files with 772 additions and 73 deletions.
7 changes: 6 additions & 1 deletion assets/@types/espaceco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export interface CommunityResponseDTO {
/** @format date-time */
creation: string;
grids: Grids[];
logo_url: string;
logo_url: string | null;
keywords?: string[];
}

export interface Grids {
Expand All @@ -27,3 +28,7 @@ export interface Grids {
type: string;
deleted: boolean;
}

export interface CommunityPatchDTO extends Partial<Omit<CommunityResponseDTO, "logo_url">> {
logo: File | null;
}
2 changes: 1 addition & 1 deletion assets/components/Input/AutocompleteSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { symToStr } from "tsafe/symToStr";
interface AutocompleteSelectProps<T> {
id?: string;
label: string;
hintText: string;
hintText?: string;
state?: "default" | "error" | "success";
stateRelatedMessage?: string;
defaultValue?: T[];
Expand Down
22 changes: 21 additions & 1 deletion assets/espaceco/api/community.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ const getAsMember = (queryParams: Record<string, unknown>, signal: AbortSignal)
});
};

const community = { get, searchByName, getAsMember };
const getCommunity = (communityId: number) => {
const url = SymfonyRouting.generate("cartesgouvfr_api_espaceco_community_get_community", { communityId: communityId });
return jsonFetch<CommunityResponseDTO>(url);
};

const updateLogo = (communityId: number, formData: FormData) => {
const url = SymfonyRouting.generate("cartesgouvfr_api_espaceco_community_update_logo", { communityId: communityId });
return jsonFetch<CommunityResponseDTO>(
url,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
},
formData
);
};

const community = { get, getCommunity, searchByName, getAsMember, updateLogo };

export default community;
2 changes: 1 addition & 1 deletion assets/espaceco/pages/communities/Communities.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type QueryParamsType = {

const Communities: FC = () => {
const route = useRoute();
const { t } = useTranslation("EspaceCoCommunities");
const { t } = useTranslation("CommunityList");

const filter = useMemo<CommunityListFilter>(() => {
const f = route.params["filter"];
Expand Down
23 changes: 18 additions & 5 deletions assets/espaceco/pages/communities/CommunityListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@ import { useTranslation } from "../../../i18n/i18n";
import placeholder1x1 from "../../../img/placeholder.1x1.png";

import "../../../sass/pages/espaceco/community.scss";
import { routes } from "../../../router/router";

type CommunityListItemProps = {
className?: string;
community: CommunityResponseDTO;
};
const CommunityListItem: FC<CommunityListItemProps> = ({ className, community }) => {
const { t } = useTranslation("EspaceCoCommunities");
const { t } = useTranslation("CommunityList");
const { t: tCommon } = useTranslation("Common");

const [showDescription, toggleShowDescription] = useToggle(false);

return (
<>
<div className={cx(fr.cx("fr-grid-row", "fr-my-2v", "fr-my-2v", "fr-p-2v"), className ?? "")}>
<div className={cx(fr.cx("fr-grid-row", "fr-grid-row--middle", "fr-my-2v", "fr-my-2v", "fr-p-2v"), className ?? "")}>
<div className={fr.cx("fr-col-5")}>
<div className={fr.cx("fr-grid-row", "fr-grid-row--left", "fr-grid-row--middle")}>
<div className={fr.cx("fr-grid-row", "fr-grid-row--middle", "fr-grid-row--left")}>
<Button
iconId={showDescription ? "ri-subtract-fill" : "ri-add-fill"}
size="small"
Expand All @@ -44,8 +46,19 @@ const CommunityListItem: FC<CommunityListItemProps> = ({ className, community })
<span className={fr.cx("fr-ml-2v")}>{community.name}</span>
</div>
</div>
<div className={fr.cx("fr-col-7", "fr-px-2v")}>
<div className={fr.cx("fr-grid-row", "fr-grid-row--middle")} dangerouslySetInnerHTML={{ __html: community.description ?? "" }} />
<div className={fr.cx("fr-col-5", "fr-px-2v")}>
<div dangerouslySetInnerHTML={{ __html: community.description ?? "" }} />
</div>
<div className={fr.cx("fr-grid-row", "fr-grid-row--right", "fr-col-1", "fr-px-2v")}>
<Button
title={tCommon("modify")}
priority="secondary"
iconId="fr-icon-edit-line"
size="small"
onClick={() => {
routes.espaceco_manage_community({ communityId: community.id }).push();
}}
/>
</div>
</div>
{community.detailed_description && <div className={fr.cx("fr-grid-row")} dangerouslySetInnerHTML={{ __html: community.detailed_description }} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export const { i18n } = declareComponentKeys<
| "no_options"
| "loading"
| "show_details"
>()("EspaceCoCommunities");
>()("CommunityList");

export const EspaceCoCommunitiesFrTranslations: Translations<"fr">["EspaceCoCommunities"] = {
export const CommunityListFrTranslations: Translations<"fr">["CommunityList"] = {
title: "Liste des guichets",
filters: "Filtres",
all_public_communities: "Tous les guichets publics",
Expand All @@ -36,7 +36,7 @@ export const EspaceCoCommunitiesFrTranslations: Translations<"fr">["EspaceCoComm
show_details: "Afficher les détails",
};

export const EspaceCoCommunitiesEnTranslations: Translations<"en">["EspaceCoCommunities"] = {
export const CommunityListEnTranslations: Translations<"en">["CommunityList"] = {
title: "List of communities",
filters: "Filters",
all_public_communities: undefined,
Expand Down
85 changes: 85 additions & 0 deletions assets/espaceco/pages/communities/ManageCommunity.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { useQuery } from "@tanstack/react-query";
import { FC, useState } from "react";
import RQKeys from "../../../modules/espaceco/RQKeys";
import api from "../../api";
import { datastoreNavItems } from "../../../config/datastoreNavItems";
import AppLayout from "../../../components/Layout/AppLayout";
import { useTranslation } from "../../../i18n/i18n";
import LoadingText from "../../../components/Utils/LoadingText";
import { fr } from "@codegouvfr/react-dsfr";
import Alert from "@codegouvfr/react-dsfr/Alert";
import Button from "@codegouvfr/react-dsfr/Button";
import { routes } from "../../../router/router";
import Tabs from "@codegouvfr/react-dsfr/Tabs";
import Description from "./management/Description";
import { CommunityResponseDTO } from "../../../@types/espaceco";
import { CartesApiException } from "../../../modules/jsonFetch";

type ManageCommunityProps = {
communityId: number;
};

const navItems = datastoreNavItems();

const ManageCommunity: FC<ManageCommunityProps> = ({ communityId }) => {
const { t } = useTranslation("ManageCommunity");

const communityQuery = useQuery<CommunityResponseDTO, CartesApiException>({
queryKey: RQKeys.community(communityId),
queryFn: () => api.community.getCommunity(communityId),
staleTime: 3600000,
});

const [selectedTabId, setSelectedTabId] = useState("tab1");

return (
<AppLayout navItems={navItems} documentTitle={t("title", { name: communityQuery.data?.name })}>
<h1>{t("title", { name: communityQuery.data?.name })}</h1>
{communityQuery.isLoading ? (
<LoadingText message={t("loading")} />
) : communityQuery.isError ? (
<Alert
severity="error"
closable={false}
title={t("fetch_failed")}
description={
<>
<p>{communityQuery.error?.message}</p>
<Button linkProps={routes.espaceco_community_list().link}>{t("back_to_list")}</Button>
</>
}
/>
) : (
communityQuery.data !== undefined && (
<div className={fr.cx("fr-container", "fr-py-2w")}>
<Tabs
selectedTabId={selectedTabId}
tabs={[
{ tabId: "tab1", label: t("tab1") },
{ tabId: "tab2", label: t("tab2") },
{ tabId: "tab3", label: t("tab3") },
{ tabId: "tab4", label: t("tab4") },
{ tabId: "tab5", label: t("tab5") },
{ tabId: "tab6", label: t("tab6") },
]}
onTabChange={setSelectedTabId}
>
<>
{(() => {
switch (selectedTabId) {
case "tab1":
return <Description community={communityQuery.data} />;
default:
return <p>`Content of ${selectedTabId}`</p>;
}
})()}
</>
</Tabs>
</div>
)
)}
</AppLayout>
);
};

export default ManageCommunity;
95 changes: 95 additions & 0 deletions assets/espaceco/pages/communities/ManageCommunityTr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { declareComponentKeys } from "i18nifty";
import { Translations } from "../../../i18n/i18n";

export type logoAction = "add" | "modify" | "delete";

// traductions
export const { i18n } = declareComponentKeys<
| { K: "title"; P: { name: string | undefined }; R: string }
| "loading"
| "fetch_failed"
| "back_to_list"
| "tab1"
| "tab2"
| "tab3"
| "tab4"
| "tab5"
| "tab6"
| "desc.name"
| "desc.hint_name"
| "desc.description"
| "desc.hint_description"
| "desc.logo"
| "desc.logo.title"
| { K: "logo_action"; P: { action: logoAction }; R: string }
| "logo_confirm_delete_modal.title"
| "modal.logo.title"
| "modal.logo.file_hint"
| "desc.keywords"
>()("ManageCommunity");

export const ManageCommunityFrTranslations: Translations<"fr">["ManageCommunity"] = {
title: ({ name }) => (name === undefined ? "Gérer le guichet" : `Gérer le guichet - ${name}`),
loading: "Recherche du guichet en cours ...",
fetch_failed: "La récupération des informations sur le guichet a échoué",
back_to_list: "Retour à la liste des guichets",
tab1: "Description",
tab2: "Bases de données",
tab3: "Zoom, centrage",
tab4: "Couches de la carte",
tab5: "Outils",
tab6: "Signalements",
"desc.name": "Nom du guichet",
"desc.hint_name": "Donnez un nom clair et compréhensible",
"desc.description": "Description",
"desc.hint_description": "Bref résumé narratif de l'objectif du guichet",
"desc.logo": "Logo (optionnel)",
"desc.logo.title": "Ajouter, modifier ou supprimer le logo du guichet",
logo_action: ({ action }) => {
switch (action) {
case "add":
return "Ajouter un logo";
case "modify":
return "Remplacer le logo";
case "delete":
return "Supprimer le logo";
}
},
"logo_confirm_delete_modal.title": "Êtes-vous sûr de vouloir supprimer le logo de ce guichet ?",
"modal.logo.title": "Logo du guichet",
"modal.logo.file_hint": "Taille maximale : 5 Mo. Formats acceptés : jpg, png",
"desc.keywords": "Mots-clés (optionnel)",
};

export const ManageCommunityEnTranslations: Translations<"en">["ManageCommunity"] = {
title: ({ name }) => (name === undefined ? "Manage front office" : `Manage front office - ${name}`),
loading: undefined,
fetch_failed: undefined,
back_to_list: undefined,
tab1: undefined,
tab2: undefined,
tab3: undefined,
tab4: undefined,
tab5: undefined,
tab6: undefined,
"desc.name": undefined,
"desc.hint_name": undefined,
"desc.description": undefined,
"desc.hint_description": undefined,
"desc.logo": undefined,
"desc.logo.title": undefined,
logo_action: ({ action }) => {
switch (action) {
case "add":
return "Add logo";
case "modify":
return "Replace logo";
case "delete":
return "Delete logo";
}
},
"logo_confirm_delete_modal.title": undefined,
"modal.logo.title": undefined,
"modal.logo.file_hint": undefined,
"desc.keywords": undefined,
};
2 changes: 1 addition & 1 deletion assets/espaceco/pages/communities/SearchCommunity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type SearchCommunityProps = {
};

const SearchCommunity: FC<SearchCommunityProps> = ({ filter, onChange }) => {
const { t } = useTranslation("EspaceCoCommunities");
const { t } = useTranslation("CommunityList");

const [search, setSearch] = useDebounceValue("", 500);

Expand Down
Loading

0 comments on commit 310dabe

Please sign in to comment.