Skip to content

Commit

Permalink
feat(home): add home page with search bar
Browse files Browse the repository at this point in the history
  • Loading branch information
Mihoub2 committed Nov 14, 2024
1 parent 3ac1de7 commit dd34290
Show file tree
Hide file tree
Showing 13 changed files with 393 additions and 140 deletions.
36 changes: 36 additions & 0 deletions client/src/api/contribution-api/getAllDatas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useQuery } from "@tanstack/react-query";
import { postHeaders } from "../../config/api";

const routes = [
"contacts",
"contribute",
"production",
"remove-user",
"update-user-data",
];

const fetchAllData = async (baseApiUrl) => {
const fetchPromises = routes.map(async (route) => {
const url = `${baseApiUrl}/${route}`;
const response = await fetch(url, {
headers: postHeaders,
});
if (!response.ok) {
throw new Error(`Failed to fetch from ${route}`);
}
return response.json();
});

return Promise.all(fetchPromises);
};

const ContributionAllDatas = (baseApiUrl) => {
const fetchContributions = () => fetchAllData(baseApiUrl);
const { data, isLoading, isError, refetch } = useQuery(
["allContributions"],
fetchContributions
);
return { data, isLoading, isError, refetch };
};

export default ContributionAllDatas;
3 changes: 2 additions & 1 deletion client/src/api/utils/buildURL.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const buildURL = (
const sorted = sort === "ASC" ? "sort=created_at" : "sort=-created_at";

const where: any = {};
if (query.trim() !== "") {
if (typeof query === "string" && query.trim() !== "") {
const isObjectId = /^[0-9a-fA-F]{24}$/.test(query);

if (isObjectId) {
Expand Down Expand Up @@ -57,6 +57,7 @@ export const buildURL = (

return `${baseApiUrl}/${baseUrl}?${sorted}&page=${page}&max_results=${max_results}${whereQuery}${fromAppQuery}`;
};

export const buildStatsURL = (
filter: string,
sort: string = "ASC",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ const SearchSection: React.FC<{
onSearch={(value) => handleSearch(value || "")}
isLarge
buttonLabel="Rechercher"
placeholder="Rechercher par nom ou ID"
placeholder="Rechercher par nom, ID ou mot clé"
/>
<div className="fr-mb-1w">
{query
.filter((item) => item.trim() !== "")
.map((item, index) => (
?.filter((item) => item.trim() !== "")
?.map((item, index) => (
<DismissibleTag
key={index}
color="purple-glycine"
Expand Down
38 changes: 38 additions & 0 deletions client/src/pages/home/components/generate-links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export function generateLinkFromAllDatas(
collectionName: string,
fromApplication?: string,
id?: string,
objectId?: boolean,
productions?: Array<any>
): 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 (productions?.length > 1) {
basePath = "/scanr-apioperations";
} else if (objectId) {
basePath = "/scanr-contributionPage";
} else if (fromApplication) {
basePath = "/scanr-contact";
} else {
basePath = (basePathMap[collectionName] as string) || "";
}

return id
? `${basePath}?page=1&query=${id}&searchInMessage=false&sort=DESC&status=choose`
: basePath;
}
157 changes: 157 additions & 0 deletions client/src/pages/home/components/item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import React, { useState } from "react";
import { Badge, Col, Container, Link, Row, Text } from "@dataesr/dsfr-plus";
import { FaCopy } from "react-icons/fa";
import "./styles.scss";
import { AllContributionsProps } from "../../../types";
import { generateLinkFromAllDatas } from "./generate-links";
import {
BadgeColor,
BadgeStatus,
StatusLabel,
typeIcon,
TypeLabel,
} from "../../../utils";

const AllContributions: React.FC<AllContributionsProps & { query: string }> = ({
data,
query,
}) => {
const [copiedId, setCopiedId] = useState<string | null>(null);

const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text).then(() => {
setCopiedId(text);
setTimeout(() => setCopiedId(null), 2000);
});
};

const highlightQuery = (text: string, query: string) => {
if (!query) return text;
const regex = new RegExp(`(${query})`, "gi");
return text?.replace(regex, '<span class="highlight">$1</span>');
};

return (
<Container>
{data.length === 0 ? (
<p>Pas de résultat</p>
) : (
data?.map((email, index) => {
const link = generateLinkFromAllDatas(
email.collectionName,
email.fromApplication,
email.id,
email.objectId,
email.productions
);
const creationDate = new Date(email.created_at);
const formattedDate = creationDate.toLocaleDateString("fr-FR");
const formattedTime = creationDate.toLocaleTimeString("fr-FR", {
hour: "2-digit",
minute: "2-digit",
});

let badgeContent = "";
if (email.productions?.length > 1) {
badgeContent = "Lier des publications";
} else if (email.objectId && !email.productions) {
badgeContent = "Contribution par objet";
} else badgeContent = "Contact";

return (
<Row gutters key={index} className="email-row">
<Col lg="12" md="10" sm="12" className="email-item fr-mb-2w">
<div className="badges">
{badgeContent && (
<Badge
size="sm"
color="blue-ecume"
className="fr-mr-1w fr-mb-1w"
>
{badgeContent}
</Badge>
)}
{email.fromApplication && (
<Badge
size="sm"
color="blue-ecume"
className="fr-mr-1w fr-mb-1w"
>
{email.fromApplication}
</Badge>
)}
<Badge
size="sm"
color={BadgeStatus({ status: email?.status })}
className="fr-mr-1w fr-mb-1w"
>
{StatusLabel({ status: email.status })}
</Badge>
{email?.type && (
<Badge
size="sm"
icon={typeIcon({ icon: email.type })}
color={BadgeColor({ type: email.type })}
className="fr-mr-1w fr-mb-1w"
>
{TypeLabel({ type: email.type })}
</Badge>
)}
{email?.comment ||
(email?.team?.length > 0 && (
<Badge
size="sm"
color="green-emeraude"
className="fr-mr-1w fr-mb-1w"
>
{`Traité par ${email.team[0]}`}
</Badge>
))}
</div>
<div>
<Text className="fr-mb-0">
Contribution de{" "}
<i>
{email?.name} - {email?.email}
</i>
</Text>
<Text size="sm">
<Link href={link} rel="noopener noreferrer">
Voir la contribution <i>{email?.id}</i>
</Link>
<button
className={`copy-button ${
copiedId === email.id ? "copied" : ""
}`}
onClick={() => copyToClipboard(email.id)}
title="Copier l'ID"
>
{copiedId === email.id && (
<span className="copied-text">Copié</span>
)}
<FaCopy size={14} color="#2196f3" className="copy-icon" />
</button>
</Text>
<Text size="sm">
<i>
Date de la contribution : {formattedDate} à{" "}
{formattedTime}
</i>
</Text>
<Text
size="sm"
dangerouslySetInnerHTML={{
__html: highlightQuery(email?.message, query),
}}
/>
</div>
</Col>
</Row>
);
})
)}
</Container>
);
};

export default AllContributions;
41 changes: 41 additions & 0 deletions client/src/pages/home/components/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.email-item {
background-color: #f1f4f8;
padding: 1.5rem;
border-radius: 8px;
margin-top: 1rem;
}

.email-content {
overflow: hidden;
word-wrap: break-word;
overflow-wrap: break-word;
word-break: break-all;
}

.copy-button {
border: none;
background: none;
cursor: pointer;
}

.copied-text {
color: #4caf50;
margin-right: 0.5rem;
}

@media (max-width: 768px) {
.email-item {
padding: 1rem;
}
.email-content {
font-size: 0.9rem;
}
.copy-icon {
display: inline-block;
margin-left: 0.5rem;
}
}
.highlight {
background-color: yellow;
font-weight: bold;
}
Loading

0 comments on commit dd34290

Please sign in to comment.