Skip to content

Commit

Permalink
Merge branch 'main' into 3670-fiche-sanitaire
Browse files Browse the repository at this point in the history
  • Loading branch information
C2Chandelier authored Nov 28, 2024
2 parents aad490a + 52c3447 commit 105ff98
Show file tree
Hide file tree
Showing 79 changed files with 469 additions and 7,179 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ node_modules
out/
coverage/

dump
*.bson.gz
*.json.gz
1 change: 1 addition & 0 deletions admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@swc/plugin-styled-components": "1.5.111",
"@tanstack/react-query": "^5.29.2",
"@uidotdev/usehooks": "^2.4.1",
"axios": "1.7.8",
"bootstrap": "4.6.2",
"browser-image-resizer": "^2.4.1",
"chart.js": "^4.2.1",
Expand Down
38 changes: 18 additions & 20 deletions admin/src/scenes/classe/header/VerifClassButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { HiOutlineCheck } from "react-icons/hi";
import { IoWarningOutline } from "react-icons/io5";

import { ModalConfirmation, Button } from "@snu/ds/admin";
import { translate, ClassesRoutes } from "snu-lib";
import { capture } from "@/sentry";
import api from "@/services/api";
import { ClassesRoutes, HttpError, translateStatusClasse } from "snu-lib";
import { apiv2 } from "@/services/apiv2";
import { ClasseService } from "@/services/classeService";

interface Props {
classe: NonNullable<ClassesRoutes["GetOne"]["response"]["data"]>;
Expand Down Expand Up @@ -41,24 +41,22 @@ export default function VerifClassButton({ classe, setClasse, isLoading, setLoad
};

const verifyClasse = async () => {
try {
setLoading(true);

const { ok, code, data } = await api.put(`/cle/classe/${classe?._id}/verify`, classe);

if (!ok) {
toastr.error("Oups, une erreur est survenue lors de la vérification de la classe", translate(code));
return setLoading(false);
} else {
setLoading(true);
await apiv2
.post<ClassesRoutes["GetOne"]["response"]["data"]>(`/classe/${classe?._id}/verify`, classe)
.then((updatedClasse) => {
toastr.success("Opération réussie", "La classe a bien été vérifiée");
}
setClasse(data);
} catch (e) {
capture(e);
toastr.error("Oups, une erreur est survenue lors de la vérification de la classe", e);
} finally {
setLoading(false);
}
const classeView = ClasseService.mapDtoToView(updatedClasse);
setClasse(classeView);
})
.catch((error: HttpError) => {
if (error?.statusCode === 422) {
toastr.error("Oups, une erreur est survenue lors de la vérification de la classe", `${translateStatusClasse(error.message)} - Erreur : ${error.correlationId}`);
}
})
.finally(() => {
setLoading(false);
});
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,24 @@ import React, { useEffect, useState } from "react";
import ModalContacts from "../modal/ModalContacts";
import API from "@/services/api";
import { capture } from "@/sentry";
import { CohortDto, ContactDto } from "snu-lib";

export default function CardContacts({ contacts, idServiceDep, getService }) {
export default function CardContacts({ contacts, idServiceDep, getService }: { contacts: ContactDto[]; idServiceDep: string; getService: () => Promise<any> }) {
const [isOpen, setIsOpen] = useState(false);
const [sortedContacts, setSortedContacts] = useState({});
const [nbCohorts, setNbCohorts] = useState(0);
const [cohorts, setCohorts] = useState([]);
const [sessions2023, setSessions2023] = useState([]);
const [cohorts, setCohorts] = useState<string[]>([]);
const [sessions, setSessions] = useState<CohortDto[]>([]);

const [contactsFromCohort, setContactsFromCohort] = useState([]);
const [contactsFromCohort, setContactsFromCohort] = useState<ContactDto[]>([]);

async function cohortsInit() {
try {
const result = await API.get("/cohort");
if (result.status === 401) {
return;
}
if (!result?.ok) {
capture("Unable to load global cohorts data :" + JSON.stringify(result));
} else {
setSessions2023(result.data);
}
if (result.status === 401) return;
if (!result?.ok) capture("Unable to load global cohorts data :" + JSON.stringify(result));

setSessions(result.data);
} catch (err) {
capture(err);
}
Expand All @@ -40,16 +37,17 @@ export default function CardContacts({ contacts, idServiceDep, getService }) {
}, []);

useEffect(() => {
if (contacts && sessions2023.length > 0) {
let existCohort = [];
let tempContact = {};
if (contacts && sessions.length > 0) {
const existCohort: string[] = [];
const tempContact = {};

//TODO update this when we will have the new cohort or change completely this part
const newCohorts = sessions2023.filter((cohort) => cohort.name.match(/^(?!.*CLE).*2024/)).map((cohort) => cohort.name);
// We include only CLE from 2025
const newCohorts = sessions.filter((cohort: CohortDto) => cohort.name.match(/^(?!.*CLE).*2025/)).map((cohort) => cohort.name);
setCohorts(newCohorts);

contacts.forEach((contact) => {
if (!existCohort.includes(contact.cohort) && newCohorts.includes(contact.cohort)) {
contacts.forEach((contact: ContactDto) => {
if (contact.cohort && !existCohort.includes(contact.cohort) && newCohorts.includes(contact.cohort)) {
existCohort.push(contact.cohort);
}
});
Expand All @@ -60,9 +58,9 @@ export default function CardContacts({ contacts, idServiceDep, getService }) {
});
setNbCohorts(existCohort.length);
setSortedContacts(tempContact);
setContactsFromCohort(contacts.filter((contact) => newCohorts.includes(contact.cohort)));
setContactsFromCohort(contacts.filter((contact) => contact.cohort && newCohorts.includes(contact.cohort)));
}
}, [contacts, sessions2023]);
}, [contacts, sessions]);

const handleShowModal = () => setIsOpen(true);

Expand All @@ -77,12 +75,14 @@ export default function CardContacts({ contacts, idServiceDep, getService }) {
</div>
<div className="mt-4 flex flex-row -space-x-2">
{contactsFromCohort.map((contact, index) => {
if (index < 6)
if (index < 6) {
return (
<div key={index} className={`flex h-8 w-8 items-center justify-center rounded-full border-2 border-white bg-gray-100 text-xs text-indigo-600`}>
{getInitials(contact.contactName)}
</div>
);
}
return null;
})}
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions admin/src/services/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fetchRetry from "fetch-retry";
import { capture } from "../sentry";
import { apiURL } from "../config";
import { createFormDataForFileUpload, ERRORS } from "snu-lib";
import { apiv2 } from "./apiv2";

let fetch = window.fetch;

Expand All @@ -22,6 +23,7 @@ class api {

setToken(token) {
this.token = token;
apiv2.setToken(token);
}

checkToken(shouldRefresh) {
Expand Down
77 changes: 77 additions & 0 deletions admin/src/services/apiv2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from "axios";
import { toastr } from "react-redux-toastr";

import { HttpError } from "snu-lib";

import { apiv2URL } from "@/config";
import { capture } from "@/sentry";
export interface IApiV2 {
get<T>(path: string): Promise<T>;
post<T>(path: string, payload: unknown): Promise<T>;
remove<T>(path: string): Promise<T>;
put<T>(path: string, payload: unknown): Promise<T>;
patch<T>(path: string, payload: unknown): Promise<T>;
}
class Apiv2 implements IApiV2 {
private token: string;
private axios: AxiosInstance;

constructor() {
this.axios = axios.create({
baseURL: apiv2URL,
});
this.initInterceptor();
}

setToken(token: string) {
this.token = token;
}

async get<T>(path: string): Promise<T> {
return this.axios.get<T, T>(path);
}

async post<T>(path: string, payload: unknown): Promise<T> {
return this.axios.post<T, T>(path, payload);
}

async remove<T>(path: string): Promise<T> {
return this.axios.delete<T, T>(path);
}

async put<T>(path: string, payload: unknown): Promise<T> {
return this.axios.put<T, T>(path, payload);
}

async patch<T>(path: string, payload: unknown): Promise<T> {
return this.axios.patch<T, T>(path, payload);
}

initInterceptor() {
this.axios.interceptors.request.use((request: InternalAxiosRequestConfig) => {
request.headers.set({ "x-user-timezone": new Date().getTimezoneOffset(), Authorization: `JWT ${this.token}` });
request.headers.setContentType("application/json");
return request;
});

this.axios.interceptors.response.use(
(response: AxiosResponse) => response.data,
(error: AxiosError<HttpError>) => {
if (error.response?.status === 401) {
if (window?.location?.pathname !== "/auth") {
window.location.href = "/auth?disconnected=1";
return Promise.reject();
}
} else if (error.response?.status === 422) {
capture(error);
return Promise.reject(error.response.data);
}
capture(error);
toastr.error("Oups, une erreur est survenue", `Code d'erreur: ${error.response?.data.correlationId}`);
return Promise.reject();
},
);
}
}

export const apiv2 = new Apiv2();
37 changes: 37 additions & 0 deletions admin/src/services/classeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,43 @@ const ClasseService = {
}
return classe;
},

mapDtoToView: (classeDto): NonNullable<ClassesRoutes["GetOne"]["response"]["data"]> => {
return {
_id: classeDto.id,
name: classeDto.nom,
cohort: classeDto.sessionNom,
department: classeDto.departement,
status: classeDto.statut,
region: classeDto.region,
etablissementId: classeDto.etablissementId,
schoolYear: classeDto.anneeScolaire,
statusPhase1: classeDto.statutPhase1,
estimatedSeats: classeDto.placesEstimees,
totalSeats: classeDto.placesTotal,
uniqueKey: classeDto.uniqueKey,
uniqueKeyAndId: classeDto.uniqueKeyAndId,
academy: classeDto.academie,
referentClasseIds: classeDto.referentClasseIds,
sessionId: classeDto.sessionId,
uniqueId: classeDto.uniqueId,
seatsTaken: classeDto.placesPrises,
grade: classeDto.niveau,
grades: classeDto.niveaux,
cohesionCenterId: classeDto.centreCohesionId,
ligneId: classeDto.ligneId,
pointDeRassemblementId: classeDto.pointDeRassemblementId,
comments: classeDto.commentaires,
trimester: classeDto.trimestre,
type: classeDto.type,
filiere: classeDto.filiere,
coloration: classeDto.coloration,
metadata: classeDto.metadata,
createdAt: classeDto.createdAt,
updatedAt: classeDto.updatedAt,
deletedAt: classeDto.deletedAt,
};
},
};

export { ClasseService };
16 changes: 14 additions & 2 deletions admin/src/utils/buildRequest.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import { BasicRoute, buildRequestPath, buildRequestQueryString } from "snu-lib";

import api from "@/services/api";
import apiv1 from "@/services/api";
import { apiv2 } from "@/services/apiv2";

export function buildRequest<Route extends BasicRoute>({ params, payload, path, method, query }: Omit<Route, "response">): () => Promise<Route["response"]> {
export type TargetType = "API" | "API_V2" | undefined;

export function buildRequest<Route extends BasicRoute>({
params,
payload,
path,
method,
query,
target,
}: Omit<Route, "response"> & { target?: TargetType }): () => Promise<Route["response"]> {
const finalPath = buildRequestPath(path, params);
const queryString = buildRequestQueryString(query);

const url = `${finalPath}${queryString}`;

const api = target === "API_V2" ? apiv2 : apiv1;

switch (method) {
case "GET":
return async () => api.get(url);
Expand Down
1 change: 0 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"@fast-csv/format": "^5.0.0",
"@fast-csv/parse": "^5.0.0",
"@godaddy/terminus": "^4.12.1",
"@selego/mongoose-elastic": "1.7.5",
"@sentry/node": "^8.25.0",
"@sentry/profiling-node": "^8.25.0",
"archiver": "^7.0.1",
Expand Down
2 changes: 0 additions & 2 deletions api/src/__tests__/helpers/es.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export const mockEsClient = (results: { [key: string]: any[] } = {}) => {
jest.mock("@selego/mongoose-elastic", () => () => jest.fn());

const mock = jest.mock("../../es", () => ({
search: async (params: { index: string; scroll: "1m"; size: 1000; body: { query: any; _source: "*" } }) => {
return {
Expand Down
3 changes: 1 addition & 2 deletions api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const config = {
ADMIN_URL: _env(envStr, "ADMIN_URL", "http://localhost:8082"),
SENTRY_TRACING_SAMPLE_RATE: _env(envFloat, "SENTRY_TRACING_SAMPLE_RATE", 1),
SENTRY_PROFILE_SAMPLE_RATE: _env(envFloat, "SENTRY_PROFILE_SAMPLE_RATE", 1),
MONGO_URL: _env(envStr, "MONGO_URL", "mongodb://localhost:27017/snu_dev"),
MONGO_URL: _env(envStr, "MONGO_URL", "mongodb://localhost:27017/snu_dev?directConnection=true"),
JWT_SECRET: _env(envStr, "JWT_SECRET", "my-secret"),
SUPPORT_URL: _env(envStr, "SUPPORT_URL", "http://localhost:8084"),
SUPPORT_FRONT_URL: _env(envStr, "SUPPORT_FRONT_URL", "http://localhost:8083"),
Expand Down Expand Up @@ -94,5 +94,4 @@ export const config = {
ENABLE_2FA: _env(envBool, "ENABLE_2FA", false),
LOG_LEVEL: _env(envStr, "LOG_LEVEL", "debug"), // error, warn, info, http, debug
DO_MIGRATION: _env(envBool, "DO_MIGRATION", false),
ENABLE_MONGOOSE_ELASTIC: _env(envBool, "ENABLE_MONGOOSE_ELASTIC", false),
};
7 changes: 0 additions & 7 deletions api/src/models/PlanDeTransport/ligneBus.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { config } from "../../config";
import mongoose, { Schema, InferSchemaType } from "mongoose";
import mongooseElastic from "@selego/mongoose-elastic";
import patchHistory from "mongoose-patch-history";

import { InterfaceExtended, LigneBusSchema, LigneBusTeamSchema } from "snu-lib";

import esClient from "../../es";
import anonymize from "../../anonymization/PlanDeTransport/ligneBus";
import { DocumentExtended, CustomSaveParams, UserExtension, UserSaved } from "../types";

Expand Down Expand Up @@ -47,10 +44,6 @@ schema.plugin(patchHistory, {
excludes: ["/updatedAt"],
});

if (config.ENABLE_MONGOOSE_ELASTIC) {
schema.plugin(mongooseElastic(esClient), MODELNAME);
}

schema.index({ cohort: 1 });
schema.index({ cohort: 1, busId: 1 }, { unique: true });

Expand Down
7 changes: 0 additions & 7 deletions api/src/models/PlanDeTransport/ligneToPoint.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { config } from "../../config";
import mongoose, { Schema, InferSchemaType } from "mongoose";
import patchHistory from "mongoose-patch-history";
import mongooseElastic from "@selego/mongoose-elastic";

import { InterfaceExtended, LigneToPointSchema } from "snu-lib";

import esClient from "../../es";
import { DocumentExtended, CustomSaveParams, UserExtension, UserSaved } from "../types";

const MODELNAME = "lignetopoint";
Expand Down Expand Up @@ -36,10 +33,6 @@ schema.plugin(patchHistory, {
excludes: ["/updatedAt"],
});

if (config.ENABLE_MONGOOSE_ELASTIC) {
schema.plugin(mongooseElastic(esClient), MODELNAME);
}

type LigneToPointType = InterfaceExtended<InferSchemaType<typeof schema>>;
export type LigneToPointDocument<T = {}> = DocumentExtended<LigneToPointType & T>;
type SchemaExtended = LigneToPointDocument & UserExtension;
Expand Down
Loading

0 comments on commit 105ff98

Please sign in to comment.