diff --git a/src/client/package.json b/src/client/package.json index b063719d..0ca49abe 100644 --- a/src/client/package.json +++ b/src/client/package.json @@ -48,6 +48,7 @@ "react-scrollspy": "^3.4.2", "react-select": "^5.8.0", "react-toggle": "^4.1.1", + "react-top-loading-bar": "^2.3.1", "react-transition-group": "^4.4.1", "redux": "^4.0.5", "redux-persist": "^6.0.0", @@ -56,6 +57,7 @@ "sass": "^1.79.1", "smoothscroll-polyfill": "^0.4.3", "ua-parser-js": "^0.7.21", + "xlsx": "^0.18.5", "zod": "^3.13.4" }, "scripts": { diff --git a/src/client/src/components/App/App.js b/src/client/src/components/App/App.js index 4f90918b..421904c6 100644 --- a/src/client/src/components/App/App.js +++ b/src/client/src/components/App/App.js @@ -26,6 +26,7 @@ import Search from "../../containers/Search"; import SetMatomo from "../../helpers/Matomo/SetMatomo.js"; import Auth from "../../services/Auth/Auth.js"; import Config from "../../services/Config"; +import { useIsNotFound } from "../../services/Elastic/elastic.js"; import { apolloClient } from "../../services/GraphQL/GraphQL"; import CustomLayout from "../../services/PrivateRoute/CustomLayout.jsx"; import configureStore from "../../services/Store"; @@ -259,10 +260,18 @@ const App = () => { const EnterpriseWrapper = () => { const { siren } = useParams(); const siret = getSirenFromSiret(siren); + const { isNotFound, loading } = useIsNotFound(siret, siren); + return ( - + @@ -273,10 +282,18 @@ const EnterpriseWrapper = () => { const EstablishmentWrapper = () => { const { siret } = useParams(); const siren = getSirenFromSiret(siret); + const { isNotFound, loading } = useIsNotFound(siret, siren); + return ( - + @@ -286,10 +303,17 @@ const EstablishmentWrapper = () => { const ListEstablishmentsWrapper = () => { const { siren } = useParams(); + const { isNotFound, loading } = useIsNotFound("", siren); + return ( - + diff --git a/src/client/src/components/App/Layout.js b/src/client/src/components/App/Layout.js index 1f07089b..2994046a 100644 --- a/src/client/src/components/App/Layout.js +++ b/src/client/src/components/App/Layout.js @@ -13,12 +13,12 @@ const Layout = ({ hasSharedButton = false, children, displayMessage = false, + isNotFound = false, }) => { const isActiveMaintenanceMode = Config.get("maintenanceMode"); - return ( <> - {hasLandingHeader ? ( + {!isNotFound && hasLandingHeader ? (
) : ( <> @@ -42,6 +42,7 @@ Layout.propTypes = { displayMessage: PropTypes.bool, hasLandingHeader: PropTypes.bool, hasSharedButton: PropTypes.bool, + isNotFound: PropTypes.bool, }; export default Layout; diff --git a/src/client/src/components/App/app.scss b/src/client/src/components/App/app.scss index b28ccc34..67877360 100644 --- a/src/client/src/components/App/app.scss +++ b/src/client/src/components/App/app.scss @@ -67,6 +67,10 @@ a { &--nowrap a { white-space: nowrap; } + &--sm-cell { + font-size: 0.5rem !important; + align-items: center !important; + } } } diff --git a/src/client/src/components/DataSheets/NotFound/NotFound.jsx b/src/client/src/components/DataSheets/NotFound/NotFound.jsx new file mode 100644 index 00000000..087d07ad --- /dev/null +++ b/src/client/src/components/DataSheets/NotFound/NotFound.jsx @@ -0,0 +1,17 @@ +import "./notFound.scss"; + +import React from "react"; + +const NotFound = () => { + return ( +
+
+
+
0 entreprise correspond à votre requête
+
+
+
+ ); +}; + +export default NotFound; diff --git a/src/client/src/components/DataSheets/NotFound/notFound.scss b/src/client/src/components/DataSheets/NotFound/notFound.scss new file mode 100644 index 00000000..036ae221 --- /dev/null +++ b/src/client/src/components/DataSheets/NotFound/notFound.scss @@ -0,0 +1,7 @@ +.notFound { + display: flex; + justify-content: center; + align-items: center; + font-size: 22px; + font-weight: bold; +} diff --git a/src/client/src/components/DataSheets/Sections/Establishment/Establishment.js b/src/client/src/components/DataSheets/Sections/Establishment/Establishment.js index 527c6f06..2907ffda 100644 --- a/src/client/src/components/DataSheets/Sections/Establishment/Establishment.js +++ b/src/client/src/components/DataSheets/Sections/Establishment/Establishment.js @@ -14,6 +14,7 @@ import Controles from "./Direccte/Controles"; import Header from "./Header"; import Helps from "./Helps"; import ListEstablishment from "./ListEtablishments/ListEstablishment.jsx"; +import MarchesPublic from "./MarchesPublic/MarchesPublic.jsx"; import Muteco from "./Muteco"; import Relationship from "./Relationship"; @@ -37,9 +38,8 @@ const Establishment = ({ siret }) => { - {siren && ( - - )}{" "} + + diff --git a/src/client/src/components/DataSheets/Sections/Establishment/MarchesPublic/MarchesPublic.jsx b/src/client/src/components/DataSheets/Sections/Establishment/MarchesPublic/MarchesPublic.jsx new file mode 100644 index 00000000..7741e6d1 --- /dev/null +++ b/src/client/src/components/DataSheets/Sections/Establishment/MarchesPublic/MarchesPublic.jsx @@ -0,0 +1,343 @@ +import PropTypes from "prop-types"; +import React, { useState } from "react"; +import Select from "react-select"; + +import Source from "../../../../../containers/Source/Source.js"; +import { + convertirMoisEnAnnees, + joinNoFalsy, +} from "../../../../../helpers/utils/utils.js"; +import { formatChiffre } from "../../../../../utils/donnees-ecofi/donnees-ecofi.js"; +import { formatUpperCase } from "../../../../../utils/entreprise/entreprise.js"; +import { + getCity, + getCodePostal, +} from "../../../../../utils/establishment/establishment"; +import { selectCustomStyles } from "../../../../Search/Filters/customStyles"; +import Download from "../../../../shared/Icons/Download.jsx"; +import LoadableContent from "../../../../shared/LoadableContent/LoadableContent.js"; +import Value from "../../../../shared/Value/index.js"; +import BlocTitle from "../../SharedComponents/BlocTitle/BlocTitle.jsx"; +import { + getAcheteur, + useSortableData, +} from "../../SharedComponents/NonBorderedTable/hooks.js"; +import NonBorderedTable from "../../SharedComponents/NonBorderedTable/NonBorderedTable.js"; +import SortableButton from "../../SharedComponents/NonBorderedTable/SortableButton.jsx"; +import SeeDetailsLink from "../../SharedComponents/SeeDetailsLink/SeeDetailsLink.js"; +import Subcategory from "../../SharedComponents/Subcategory/index.js"; +import { exportToXLSX } from "./hooks.js"; +import { useMarchesPublicWithEtablissements } from "./marchesPublic.gql.js"; + +const MarchesPublic = ({ siret }) => { + const { enrichedMarches, loading, error } = + useMarchesPublicWithEtablissements(siret); + + const [accordionOpen, setAccordionOpen] = useState(true); + const { items, requestSort, sortConfig } = useSortableData(enrichedMarches, { + direction: "descending", + key: "dateNotification", + }); + const columnsOption = [ + { idDefault: true, isFixed: true, label: "Acheteur", value: "acheteur" }, + { idDefault: true, isFixed: true, label: "Département", value: "city" }, + { idDefault: true, label: "Objet", value: "objet" }, + { label: "CPV", value: "cpv_libelle" }, + { label: "Procédure", value: "procedure" }, + { idDefault: true, label: "Montant", value: "montant" }, + { idDefault: true, label: "Notifié le", value: "dateNotification" }, + { idDefault: true, label: "Durée", value: "dureeMois" }, + ]; + const [selectedColumns, setSelectedColumns] = useState( + columnsOption.filter((col) => col.idDefault) + ); + if (error || !siret) { + return null; + } + + const handleExport = () => { + exportToXLSX(items, `commandes_publiques${siret}.xlsx`); + }; + + const handleColumnChange = (selectedOptions) => { + const fixedColumns = columnsOption.filter((col) => col.isFixed); // Récupérer les colonnes fixes + + // Ajouter les colonnes fixes même si elles sont "désélectionnées" + const newSelectedColumns = [ + ...fixedColumns, + ...selectedOptions.filter((option) => !option.isFixed), + ]; + + setSelectedColumns(newSelectedColumns); + }; + + return ( +
+ setAccordionOpen(!accordionOpen)} + text={" Commandes publiques"} + /> + + {accordionOpen && ( +
+ +
+ +
+ +
+ {items?.length > 0 && ( + <> + +
+
+