Skip to content

Commit

Permalink
feat: add particulier flow config et mailing (#79)
Browse files Browse the repository at this point in the history
* feat: add particulier flow

* fix: use brevo template to send emails to communes
  • Loading branch information
MaGOs92 authored May 28, 2024
1 parent 5d37796 commit 0e258be
Show file tree
Hide file tree
Showing 10 changed files with 1,269 additions and 110 deletions.
253 changes: 160 additions & 93 deletions components/bal-widget/bal-widget-config-form.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState, useMemo, useEffect } from "react";
import React, { useState, useMemo, useEffect, useRef } from "react";
import Tabs from "@codegouvfr/react-dsfr/Tabs";
import styled from "styled-components";
import { Input } from "@codegouvfr/react-dsfr/Input";
import { Button } from "@codegouvfr/react-dsfr/Button";
Expand Down Expand Up @@ -31,6 +32,7 @@ const StyledForm = styled.form`
}
.form-controls {
margin-top: 2rem;
display: flex;
align-items: center;
Expand All @@ -46,6 +48,8 @@ export const BALWidgetConfigForm = ({
formData,
setFormData,
}: BALWidgetConfigFormProps) => {
const tabRef = useRef(null);
const [selectedTabId, setSelectedTabId] = useState("communes");
const [apiDepotClients, setApiDepotClients] = useState<ClientApiDepotType[]>(
[]
);
Expand Down Expand Up @@ -76,6 +80,16 @@ export const BALWidgetConfigForm = ({
fetchData();
}, []);

// Add type="button" to all tabs buttons to avoid form submission
useEffect(() => {
if (tabRef.current) {
const tabBtns = tabRef.current.querySelectorAll(".fr-tabs__tab");
tabBtns.forEach((btn) => {
btn.setAttribute("type", "button");
});
}
}, [tabRef]);

const handleEdit =
(section: keyof BALWidgetConfig, property: string) =>
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
Expand Down Expand Up @@ -111,14 +125,14 @@ export const BALWidgetConfigForm = ({

return (
<StyledForm onSubmit={handleSubmit} className="fr-my-4w">
<h3>Configuration du widget</h3>
<h3>Configuration de BAL Widget</h3>
<section>
<h4>Globale</h4>
<Input
label="Titre du widget"
nativeInputProps={{
required: true,
value: formData.global.title,
value: formData.global?.title || "",
onChange: handleEdit("global", "title"),
}}
/>
Expand All @@ -128,109 +142,162 @@ export const BALWidgetConfigForm = ({
{
label: "Cacher le widget",
nativeInputProps: {
checked: formData.global.hideWidget,
checked: formData.global?.hideWidget || false,
onChange: handleToggle("global", "hideWidget"),
},
},
]}
/>
<MultiStringInput
label="Afficher le widget uniquement sur les pages :"
value={formData.global.showOnPages}
value={formData.global?.showOnPages || []}
onChange={(value) =>
handleEdit("global", "showOnPages")({ target: { value } } as any)
}
placeholder="Path de la page autorisée (/programme-bal)"
/>
</section>
<section>
<h4>Aide aux communes</h4>
<Input
label="Titre sur la page d'accueil"
nativeInputProps={{
required: true,
value: formData.communes.welcomeBlockTitle,
onChange: handleEdit("communes", "welcomeBlockTitle"),
}}
/>
<MultiSelectInput
label="Clients API Dépôt caducs"
value={formData.communes.outdatedApiDepotClients}
options={apiDepotClients.map((client) => ({
value: client._id,
label: client.nom,
}))}
placeholder="Sélectionner les clients API Dépôt caducs"
onChange={(value) =>
setFormData((state) => ({
...state,
communes: {
...state.communes,
outdatedApiDepotClients: value,
},
}))
}
/>
<MultiSelectInput
label="Sources moissonnées caduques"
value={formData.communes.outdatedHarvestSources}
options={harvestSources.map((source) => ({
value: source._id,
label: source.title,
}))}
placeholder="Sélectionner les sources moissonnées caduques"
onChange={(value) =>
setFormData((state) => ({
...state,
communes: {
...state.communes,
outdatedHarvestSources: value,
},
}))
}
/>
</section>
<section>
<h4>Gitbook</h4>
<Input
label="Titre sur la page d'accueil"
nativeInputProps={{
required: true,
value: formData.gitbook.welcomeBlockTitle,
onChange: handleEdit("gitbook", "welcomeBlockTitle"),
}}
/>
<MultiLinkInput
label="Articles populaires :"
placeholders={[
"Comment puis-je obtenir une adresse ?",
"Path Gitbook de l'article (/utiliser-la-ban/mon-article)",
]}
value={formData.gitbook.topArticles}
onChange={(value) =>
handleEdit("gitbook", "topArticles")({ target: { value } } as any)
}
/>
</section>
<section>
<h4>Formulaire de contact</h4>
<Input
label="Titre sur la page d'accueil"
nativeInputProps={{
required: true,
value: formData.contactUs.welcomeBlockTitle,
onChange: handleEdit("contactUs", "welcomeBlockTitle"),
}}
/>
<MultiStringInput
label="Sujets du formulaire de contact :"
placeholder="Je souhaite publier une BAL"
value={formData.contactUs.subjects}
onChange={(value) =>
handleEdit("contactUs", "subjects")({ target: { value } } as any)
}
/>
</section>
<Tabs
ref={tabRef}
selectedTabId={selectedTabId}
onTabChange={(e) => setSelectedTabId(e)}
tabs={[
{ tabId: "communes", label: "Communes" },
{ tabId: "particuliers", label: "Particuliers" },
]}
>
{selectedTabId === "communes" && (
<>
<section>
<h4>Aide aux communes</h4>
<Input
label="Titre sur la page d'accueil"
nativeInputProps={{
required: true,
value: formData.communes?.welcomeBlockTitle || "",
onChange: handleEdit("communes", "welcomeBlockTitle"),
}}
/>
<MultiSelectInput
label="Clients API Dépôt caducs"
value={formData.communes?.outdatedApiDepotClients || []}
options={apiDepotClients.map((client) => ({
value: client._id,
label: client.nom,
}))}
placeholder="Sélectionner les clients API Dépôt caducs"
onChange={(value) =>
setFormData((state) => ({
...state,
communes: {
...state.communes,
outdatedApiDepotClients: value,
},
}))
}
/>
<MultiSelectInput
label="Sources moissonnées caduques"
value={formData.communes?.outdatedHarvestSources || []}
options={harvestSources.map((source) => ({
value: source._id,
label: source.title,
}))}
placeholder="Sélectionner les sources moissonnées caduques"
onChange={(value) =>
setFormData((state) => ({
...state,
communes: {
...state.communes,
outdatedHarvestSources: value,
},
}))
}
/>
</section>
<section>
<h4>Gitbook pour les communes</h4>
<Input
label="Titre sur la page d'accueil"
nativeInputProps={{
required: true,
value: formData.gitbookCommunes?.welcomeBlockTitle || "",
onChange: handleEdit("gitbookCommunes", "welcomeBlockTitle"),
}}
/>
<MultiLinkInput
label="Articles populaires :"
placeholders={[
"Comment puis-je obtenir une adresse ?",
"Path Gitbook de l'article (/utiliser-la-ban/mon-article)",
]}
value={formData.gitbookCommunes?.topArticles || []}
onChange={(value) =>
handleEdit(
"gitbookCommunes",
"topArticles"
)({ target: { value } } as any)
}
/>
</section>
<section>
<h4>Formulaire de contact</h4>
<Input
label="Titre sur la page d'accueil"
nativeInputProps={{
required: true,
value: formData.contactUs?.welcomeBlockTitle || "",
onChange: handleEdit("contactUs", "welcomeBlockTitle"),
}}
/>
<MultiStringInput
label="Sujets du formulaire de contact :"
placeholder="Je souhaite publier une BAL"
value={formData.contactUs?.subjects || []}
onChange={(value) =>
handleEdit(
"contactUs",
"subjects"
)({ target: { value } } as any)
}
/>
</section>
</>
)}
{selectedTabId === "particuliers" && (
<>
<section>
<h4>Gitbook pour les particuliers</h4>
<Input
label="Titre sur la page d'accueil"
nativeInputProps={{
required: true,
value: formData.gitbookParticuliers?.welcomeBlockTitle || "",
onChange: handleEdit(
"gitbookParticuliers",
"welcomeBlockTitle"
),
}}
/>
<MultiLinkInput
label="Articles populaires :"
placeholders={[
"Comment puis-je obtenir une adresse ?",
"Path Gitbook de l'article (/utiliser-la-ban/mon-article)",
]}
value={formData.gitbookParticuliers?.topArticles || []}
onChange={(value) =>
handleEdit(
"gitbookParticuliers",
"topArticles"
)({ target: { value } } as any)
}
/>
</section>
</>
)}
</Tabs>

<div className="form-controls">
<Button disabled={!canPublish} type="submit" iconId="fr-icon-save-line">
Publier
Expand Down
27 changes: 18 additions & 9 deletions components/bal-widget/bal-widget-iframe.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import { useState, useEffect, useRef } from "react";
import { BALWidgetConfig } from "types/bal-widget";
import styled from "styled-components";

const BAL_WIDGET_URL = process.env.NEXT_PUBLIC_BAL_WIDGET_URL;

interface BALWidgetIFrameProps {
config: BALWidgetConfig;
}

const StyledIFrame = styled.iframe<{ $isOpen: boolean }>`
position: fixed;
bottom: 40px;
right: 40px;
z-index: 999;
${({ $isOpen }) =>
$isOpen ? "height: 600px; width: 450px;" : "height: 60px; width: 60px;"}
@media screen and (max-width: 450px) {
bottom: 10px;
right: 10px;
${({ $isOpen }) => $isOpen && "width: calc(100% - 20px);"}
}
`;

function BALWidgetIFrame({ config }: BALWidgetIFrameProps) {
const balWidgetRef = useRef<HTMLIFrameElement>(null);
const [isBalWidgetOpen, setIsBalWidgetOpen] = useState(false);
Expand Down Expand Up @@ -52,17 +68,10 @@ function BALWidgetIFrame({ config }: BALWidgetIFrameProps) {
}, [isBalWidgetOpen]);

return (
<iframe
<StyledIFrame
ref={balWidgetRef}
src={BAL_WIDGET_URL}
width={isBalWidgetOpen ? 450 : 60}
height={isBalWidgetOpen ? 800 : 60}
style={{
position: "fixed",
bottom: 40,
right: 40,
zIndex: 999,
}}
$isOpen={isBalWidgetOpen}
/>
);
}
Expand Down
6 changes: 5 additions & 1 deletion pages/bal-widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@ const defaultConfig: BALWidgetConfig = {
outdatedApiDepotClients: [],
outdatedHarvestSources: [],
},
gitbook: {
gitbookCommunes: {
welcomeBlockTitle: "Ces articles pourraient vous aider",
topArticles: [],
},
contactUs: {
welcomeBlockTitle: "Nous contacter",
subjects: [],
},
gitbookParticuliers: {
welcomeBlockTitle: "Ces articles pourraient vous aider",
topArticles: [],
},
};

const BALWidgetPage = ({ config: baseConfig }: BALWidgetPageProps) => {
Expand Down
10 changes: 10 additions & 0 deletions server/lib/bal-widget/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,14 @@ BALWidgetRoutes.post("/send-mail", async (req, res) => {
}
});

BALWidgetRoutes.post("/send-mail-to-commune", async (req, res) => {
try {
await MailerService.sendSignalementToCommune(req.body);
res.json(true);
} catch (err) {
console.error(err);
res.status(500).json({ error: err.message });
}
});

module.exports = BALWidgetRoutes;
Loading

0 comments on commit 0e258be

Please sign in to comment.