(null);
+
+ const copyToClipboard = (text: string) => {
+ navigator.clipboard.writeText(text).then(() => {
+ setCopiedId(text);
+ setTimeout(() => setCopiedId(null), 2000);
+ });
+ };
+
+ return (
+ <>
+ {data.emails.map((email, index) => {
+ const link = generateLink(
+ email.collectionName,
+ email.fromApplication,
+ email.contributionId
+ );
+
+ const sentDate = new Date(email.sentAt);
+ const formattedDate = sentDate.toLocaleDateString("fr-FR");
+ const formattedTime = sentDate.toLocaleTimeString("fr-FR", {
+ hour: "2-digit",
+ minute: "2-digit",
+ });
+
+ return (
+
+
+
+ {collectionNameMapping[email.collectionName]}
+
+
+ {email.fromApplication && (
+
+ {email.fromApplication}
+
+ )}
+
+
+
+
+ Réponse de {email.selectedProfile} à{" "}
+
+ {email?.name} ({email?.to})
+
+
+
+
+ {email?.contributionId}
+
+
+
+
+
+ Envoyé le {formattedDate} à {formattedTime}
+
+
+
{email.userResponse}
+
+
+ );
+ })}
+ >
+ );
+};
+
+export default LastMailsSentItem;
diff --git a/client/src/pages/last-mails-sent/components/selectors.tsx b/client/src/pages/last-mails-sent/components/selectors.tsx
new file mode 100644
index 0000000..c642e68
--- /dev/null
+++ b/client/src/pages/last-mails-sent/components/selectors.tsx
@@ -0,0 +1,24 @@
+import { Col } from "@dataesr/dsfr-plus";
+
+const Selectors = ({ uniqueProfiles, setStatus }) => {
+ const handleProfileChange = (event) => {
+ setStatus(event.target.value);
+ };
+
+ return (
+
+
+
+
+
+ );
+};
+
+export default Selectors;
diff --git a/client/src/pages/last-mails-sent/components/styles.scss b/client/src/pages/last-mails-sent/components/styles.scss
new file mode 100644
index 0000000..bfb36be
--- /dev/null
+++ b/client/src/pages/last-mails-sent/components/styles.scss
@@ -0,0 +1,6 @@
+.email-item {
+ background-color: #f1f4f8;
+ padding: 1.5rem;
+ border-radius: 8px;
+ margin-top: 1rem;
+}
diff --git a/client/src/pages/last-mails-sent/components/utils.tsx b/client/src/pages/last-mails-sent/components/utils.tsx
new file mode 100644
index 0000000..7c12841
--- /dev/null
+++ b/client/src/pages/last-mails-sent/components/utils.tsx
@@ -0,0 +1,42 @@
+const collectionNameMapping: { [key: string]: string } = {
+ contribute: "Contribution par objets",
+ contacts: "Formulaire de contact",
+ contribute_productions: "Lier des publications",
+ "remove-user": "Retirer de la base de données",
+ "update-user-data": "Changement de nom",
+};
+
+export default collectionNameMapping;
+// utils/generateLink.ts
+export function generateLink(
+ collectionName: string,
+ fromApplication?: string,
+ id?: string
+): string {
+ const basePathMap: { [key: string]: { [key: string]: string } | string } = {
+ contacts: {
+ scanr: "/scanr-contact",
+ paysage: "/paysage-contact",
+ bso: "/bso-contact",
+ curiexplore: "/curiexplore-contact",
+ "works-magnet": "/works-magnet-contact",
+ datasupr: "/datasupr-contact",
+ },
+ contribute_production: "/scanr-apioperations",
+ "remove-user": "/scanr-removeuser",
+ "update-user-data": "/scanr-namechange",
+ contribute: "/scanr-contributionPage",
+ };
+
+ let basePath = "";
+
+ if (collectionName === "contacts" && fromApplication) {
+ basePath = basePathMap[collectionName][fromApplication] || "";
+ } else {
+ basePath = (basePathMap[collectionName] as string) || "";
+ }
+
+ return id
+ ? `${basePath}?page=1&query=${id}&searchInMessage=false&sort=DESC&status=choose`
+ : basePath;
+}
diff --git a/client/src/pages/last-mails-sent/index.tsx b/client/src/pages/last-mails-sent/index.tsx
new file mode 100644
index 0000000..8015574
--- /dev/null
+++ b/client/src/pages/last-mails-sent/index.tsx
@@ -0,0 +1,93 @@
+import { useState, useEffect } from "react";
+import { useLocation } from "react-router-dom";
+import { Col, Container, Row, Text, Title } from "@dataesr/dsfr-plus";
+import { Contribution } from "../../types";
+import BottomPaginationButtons from "../../components/pagination/bottom-buttons";
+import TopPaginationButtons from "../../components/pagination/top-buttons";
+import useSentEmails from "../../api/contribution-api/getSentMails";
+import LastMailsSentItem from "./components/item";
+import Selectors from "./components/selectors";
+
+const LastMailsSent: React.FC = () => {
+ const location = useLocation();
+ const [sort, setSort] = useState("DESC");
+ const [status, setStatus] = useState("choose");
+ const [query, setQuery] = useState([]);
+ const [page, setPage] = useState(1);
+ const [searchInMessage, setSearchInMessage] = useState(false);
+
+ const { data, isLoading, isError } = useSentEmails();
+ const sentEmails: Contribution[] = data ? data.emails : [];
+ const maxPage = Math.ceil((data?.emails.length || 0) / 10);
+
+ const uniqueProfiles = Array.from(
+ new Set(sentEmails.map((email) => email.selectedProfile))
+ );
+
+ useEffect(() => {
+ const params = new URLSearchParams(location.search);
+ setPage(parseInt(params.get("page") || "1"));
+ setSearchInMessage(params.get("searchInMessage") === "true");
+ const queryParam = params.get("query") || "";
+ setQuery(queryParam ? queryParam.split(",") : []);
+ setSort(params.get("sort") || "DESC");
+ }, [location.search]);
+
+ useEffect(() => {
+ const newSearchParams = new URLSearchParams();
+ newSearchParams.set("page", page.toString());
+ newSearchParams.set("query", query.join(","));
+ newSearchParams.set("searchInMessage", searchInMessage.toString());
+ newSearchParams.set("sort", sort);
+ if (status !== "choose") {
+ newSearchParams.set("status", status);
+ }
+ const newURL = `${window.location.pathname}?${newSearchParams.toString()}`;
+ window.history.pushState({}, "", newURL);
+ }, [page, query, searchInMessage, sort, status]);
+
+ if (isLoading)
+ return (
+
+ Chargement...
+
+ );
+
+ if (isError)
+ return (
+
+ Erreur lors du chargement des emails envoyés.
+
+ );
+
+ return (
+
+ Derniers mails envoyés
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default LastMailsSent;
diff --git a/client/src/types/index.ts b/client/src/types/index.ts
index d6f7df4..22d6efc 100644
--- a/client/src/types/index.ts
+++ b/client/src/types/index.ts
@@ -17,6 +17,10 @@ export interface Contribution {
threads?: Thread[];
fromApplication: string;
}
+
+export interface LastMailsSentProps {
+ data: Contribution;
+}
export interface ContributorSummaryProps {
contributions: Contribution[];
onSelectContribution: (id: string) => void;
diff --git a/server/index.ts b/server/index.ts
index d06df82..c378e01 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -11,6 +11,7 @@ import updateUserDataRoutes from "./routes/update-user-data";
import contactsRoutes from "./routes/contacts";
import sendMail from "./routes/reply/replyRoutes";
import { fetchEmails } from "./routes/receive-email";
+import getLastMailsSentRoutes from "./routes/last-mails-sent";
dotenv.config();
@@ -62,6 +63,7 @@ app
app.use(removeUserRoutes);
app.use(updateUserDataRoutes);
app.use(sendMail);
+ app.use(getLastMailsSentRoutes);
return app;
})
.use(
diff --git a/server/routes/last-mails-sent/get/index.ts b/server/routes/last-mails-sent/get/index.ts
new file mode 100644
index 0000000..c3d6dfc
--- /dev/null
+++ b/server/routes/last-mails-sent/get/index.ts
@@ -0,0 +1,39 @@
+import { Elysia } from "elysia";
+import { MongoClient } from "mongodb";
+import { errorSchema } from "../../../schemas/errors/errorSchema";
+
+const MONGO_URI = process.env.MONGO_URI || "";
+const DB_NAME = process.env.MONGO_DATABASE || "";
+
+const client = new MongoClient(MONGO_URI);
+await client.connect();
+const db = client.db(DB_NAME);
+
+const lastSentMail = new Elysia();
+
+lastSentMail.get(
+ "/get-sent-emails",
+ async () => {
+ const sentEmailsCollection = db.collection("sent_emails");
+
+ const sentEmails = await sentEmailsCollection.find().toArray();
+
+ return {
+ emails: sentEmails,
+ };
+ },
+ {
+ response: {
+ 401: errorSchema,
+ 500: errorSchema,
+ },
+ detail: {
+ summary: "Récupérer les emails envoyés",
+ description:
+ "Cette route permet de récupérer la liste des emails envoyés et enregistrés dans la collection 'sent_emails' de MongoDB.",
+ tags: ["Emails"],
+ },
+ }
+);
+
+export default lastSentMail;
diff --git a/server/routes/last-mails-sent/index.ts b/server/routes/last-mails-sent/index.ts
new file mode 100644
index 0000000..ee54412
--- /dev/null
+++ b/server/routes/last-mails-sent/index.ts
@@ -0,0 +1,8 @@
+import { Elysia } from "elysia";
+import lastSentMail from "./get";
+
+export const getLastMailsSentRoutes = new Elysia();
+
+getLastMailsSentRoutes.use(lastSentMail);
+
+export default getLastMailsSentRoutes;
diff --git a/server/routes/reply/replyRoutes.ts b/server/routes/reply/replyRoutes.ts
index fce71e3..fa5ee2c 100644
--- a/server/routes/reply/replyRoutes.ts
+++ b/server/routes/reply/replyRoutes.ts
@@ -92,6 +92,32 @@ sendMail.post(
error: `Erreur d'envoi: ${response.statusText}`,
};
}
+
+ let fromApplication = null;
+ if (collectionName === "contacts") {
+ const contactDoc = await db.collection("contacts").findOne({
+ _id: new ObjectId(contributionId),
+ });
+ if (contactDoc && contactDoc.fromApplication) {
+ fromApplication = contactDoc.fromApplication;
+ }
+ }
+
+ const sentEmailsCollection = db.collection("sent_emails");
+ await sentEmailsCollection.insertOne({
+ to,
+ name,
+ subject,
+ userResponse,
+ selectedProfile,
+ message,
+ sentAt: new Date(),
+ contributionId,
+ collectionName,
+ status: "sent",
+ ...(fromApplication && { fromApplication }),
+ });
+
const collection = db.collection(collectionName);
const existingDoc = await collection.findOne({
_id: new ObjectId(contributionId),
@@ -127,7 +153,8 @@ sendMail.post(
return {
success: true,
- message: "E-mail envoyé et réponse enregistrée",
+ message:
+ "E-mail envoyé, réponse enregistrée et email loggé dans sent_emails",
collection: collectionName,
};
},
@@ -139,7 +166,7 @@ sendMail.post(
detail: {
summary: "Envoi d'un e-mail",
description:
- "Cette route permet d'envoyer un e-mail à un destinataire et d'enregistrer la réponse dans MongoDB dans une collection spécifique",
+ "Cette route permet d'envoyer un e-mail à un destinataire et d'enregistrer la réponse dans MongoDB dans une collection spécifique. Elle log également les emails envoyés dans une nouvelle collection 'sent_emails'.",
tags: ["Envoi de mails"],
},
}
diff --git a/server/schemas/get/lastMailsSent.ts b/server/schemas/get/lastMailsSent.ts
new file mode 100644
index 0000000..09714de
--- /dev/null
+++ b/server/schemas/get/lastMailsSent.ts
@@ -0,0 +1,17 @@
+import { t } from "elysia";
+
+export const lastMailsSentSchema = t.Object(
+ {
+ id: t.String(),
+ name: t.String(),
+ subject: t.String(),
+ userResponse: t.String(),
+ selectedProfile: t.String(),
+ message: t.String(),
+ sentAt: t.Date(),
+ contributionId: t.String(),
+ collectionName: t.String(),
+ status: t.String(),
+ },
+ { additionalProperties: true }
+);