From 7b61ccd2fedfd8d3a457bd925f2f3a9132043221 Mon Sep 17 00:00:00 2001 From: DyferHerioss Date: Thu, 6 Aug 2026 17:07:06 +0300 Subject: [PATCH 1/7] feat: archive fee --- .../common/components/ArchiveWithConfirm.tsx | 93 +++++++++++++++++++ src/operations/common/components/index.jsx | 1 + .../fees/components/FeesActions.tsx | 30 ++++++ .../fees/components/ManagerFeeList.jsx | 58 +++++------- src/providers/feeProvider.ts | 2 +- 5 files changed, 150 insertions(+), 34 deletions(-) create mode 100644 src/operations/common/components/ArchiveWithConfirm.tsx create mode 100644 src/operations/fees/components/FeesActions.tsx diff --git a/src/operations/common/components/ArchiveWithConfirm.tsx b/src/operations/common/components/ArchiveWithConfirm.tsx new file mode 100644 index 000000000..7954d6200 --- /dev/null +++ b/src/operations/common/components/ArchiveWithConfirm.tsx @@ -0,0 +1,93 @@ +import ArchiveIcon from "@mui/icons-material/Archive"; +import {Button, ButtonProps} from "@mui/material"; +import {FC, useState} from "react"; +import { + Confirm, + RaRecord, + useNotify, + useRecordContext, + useRedirect, +} from "react-admin"; +import {useToggle} from "../../../hooks"; + +export const ArchiveWithConfirm: FC<{ + text?: string; + confirmTitle: string; + confirmContent: string; + redirect?: string; + buttonProps?: ButtonProps; + onArchive: (record: RaRecord) => Promise; +}> = ({ + text = "Archiver", + confirmTitle, + confirmContent, + redirect, + buttonProps = {}, + onArchive, +}) => { + const record = useRecordContext(); + const [showConfirm, , toggleShowConfirm] = useToggle(); + const [pending, setPending] = useState(false); + const notify = useNotify(); + const doRedirect = useRedirect(); + + const toggleView = (event: React.MouseEvent) => { + event.stopPropagation(); + toggleShowConfirm(); + }; + + const doArchive = async () => { + toggleShowConfirm(); + + if (!record) { + notify("Impossible de récupérer l'élément à archiver.", { + type: "error", + }); + return; + } + + setPending(true); + try { + await onArchive(record); + notify("Frais archivé avec succès."); + if (redirect) { + doRedirect(redirect); + } + } catch (error) { + console.error(error); + notify("Une erreur s'est produite lors de l'archivage.", { + type: "error", + }); + } finally { + setPending(false); + } + }; + + return ( +
+ + +
+ ); +}; diff --git a/src/operations/common/components/index.jsx b/src/operations/common/components/index.jsx index b17de2b25..603acb291 100644 --- a/src/operations/common/components/index.jsx +++ b/src/operations/common/components/index.jsx @@ -1,3 +1,4 @@ +export {ArchiveWithConfirm} from "./ArchiveWithConfirm"; export * from "./ChipRadio"; export * from "./Create"; export {DeleteWithConfirm} from "./DeleteWithConfirm"; diff --git a/src/operations/fees/components/FeesActions.tsx b/src/operations/fees/components/FeesActions.tsx new file mode 100644 index 000000000..93545ff95 --- /dev/null +++ b/src/operations/fees/components/FeesActions.tsx @@ -0,0 +1,30 @@ +import feeProvider from "@/providers/feeProvider"; +import {ImportButton} from "@/ui/haToolbar"; +import {Box} from "lucide-react"; +import {CreateButton} from "react-admin"; +import { + minimalFeesHeaders, + optionalFeesHeaders, + transformFeesData, + valideFeesData, +} from "../importConf"; +import {FeesFilters} from "./FeesFilter"; + +const FeesActions = (id: string) => { + return ( + + + transformFeesData(data, id)} + /> + + + ); +}; + +export default FeesActions; diff --git a/src/operations/fees/components/ManagerFeeList.jsx b/src/operations/fees/components/ManagerFeeList.jsx index 3c3ef2412..3e4623519 100644 --- a/src/operations/fees/components/ManagerFeeList.jsx +++ b/src/operations/fees/components/ManagerFeeList.jsx @@ -1,20 +1,16 @@ -import {DeleteWithConfirm} from "@/operations/common/components"; +import { + ArchiveWithConfirm, + DeleteWithConfirm, +} from "@/operations/common/components"; import {DateField} from "@/operations/common/components/fields"; import {renderMoney} from "@/operations/common/utils/money"; -import {FeesFilters} from "@/operations/fees/components/FeesFilter"; -import { - minimalFeesHeaders, - optionalFeesHeaders, - transformFeesData, - valideFeesData, -} from "@/operations/fees/importConf"; import {PSP_COLORS, PSP_VALUES, rowStyle} from "@/operations/fees/utils"; import {commentFunctionRenderer} from "@/operations/utils"; -import feeProvider from "@/providers/feeProvider"; +import {payingApi} from "@/providers/api"; +import {toApiIds} from "@/providers/feeProvider"; import {useRole} from "@/security/hooks"; import {EMPTY_TEXT} from "@/ui/constants"; import {HaList} from "@/ui/haList/HaList"; -import {CreateButton, ImportButton} from "@/ui/haToolbar"; import {formatDate} from "@/utils/date"; import {WarningOutlined} from "@mui/icons-material"; import {Box, Chip} from "@mui/material"; @@ -109,31 +105,27 @@ export const ManagerFeeList = ({studentId, studentRef}) => { emptyText={EMPTY_TEXT} /> {!role.isMonitor() && ( - + <> + + { + const {feeId} = toApiIds(record?.id); + return payingApi().archiveStudentFee(studentId, feeId, { + method: "PATCH", + }); + }} + /> + )} ); }; - -function FeesActions({studentId}) { - return ( - - - transformFeesData(data, studentId)} - /> - - - ); -} diff --git a/src/providers/feeProvider.ts b/src/providers/feeProvider.ts index 36d1145e1..63ac66cd4 100644 --- a/src/providers/feeProvider.ts +++ b/src/providers/feeProvider.ts @@ -83,7 +83,7 @@ const feeProvider: HaDataProviderType = { })); }, - saveOrUpdate: async (resources) => { + saveOrUpdate: async (resources, raId) => { const payload = resources[0]; const role = authProvider.getCachedRole(); From e2dbc70835ce880ef20a3c15e295d48240face53 Mon Sep 17 00:00:00 2001 From: DyferHerioss Date: Fri, 7 Aug 2026 00:11:32 +0300 Subject: [PATCH 2/7] feat: show all transaction and credits --- package-lock.json | 103 +++++--- src/conf.js | 1 + .../common/components/ArchiveWithConfirm.tsx | 14 +- .../common/components/DeleteWithConfirm.tsx | 2 +- .../common/components/ProfileLayout.tsx | 80 +++++- .../profilContent/InformationContent.tsx | 9 + .../Credits/CreditTransactionList.tsx | 67 +++++ .../fees/components/FeesActions.tsx | 2 +- .../fees/components/ManagerFeeList.jsx | 60 +++-- src/operations/payments/PaymentCreate.jsx | 245 +++++++++++++++++- src/providers/dataProvider.ts | 2 + src/providers/studentCreditProvider.tsx | 42 +++ 12 files changed, 551 insertions(+), 76 deletions(-) create mode 100644 src/operations/fees/components/Credits/CreditTransactionList.tsx create mode 100644 src/providers/studentCreditProvider.tsx diff --git a/package-lock.json b/package-lock.json index 17b920a93..d334ea3a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4118,21 +4118,12 @@ "license": "MIT" }, "node_modules/@haapi-b0fc7615/typescript-client": { - "version": "1.164.0", - "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/@haapi-b0fc7615/typescript-client/-/typescript-client-1.164.0.tgz", - "integrity": "sha512-OLMXx9vbhvfKnjbJl6frffRego6yREMp2CQ6cun9ON+SMbXc6YkXSTluZEvi1jiFuZ23+f/ezKL9KdSqWtk1hA==", + "version": "1.166.0", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/@haapi-b0fc7615/typescript-client/-/typescript-client-1.166.0.tgz", + "integrity": "sha512-k1djyc+Q8TExbbhtSX+erOX1Xv9v5AuqB50LxFPAChgsNOMQ2axpRBxkN0yZYDX+wB+ntw5QyP3hlNKbFoil6w==", "license": "Unlicense", "peerDependencies": { - "axios": "^1.6.1" - } - }, - "node_modules/@haapi/typescript-client": { - "version": "1.110.0", - "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/@haapi/typescript-client/-/typescript-client-1.110.0.tgz", - "integrity": "sha512-0ZVynotc6roCCSjlxQqnPIHePhx2Mv2M76o41Vkd7bvsRVheRSrg+Be6AnfnEFvvVfb2SEh1pC/SjxSX6hjMsg==", - "license": "Unlicense", - "peerDependencies": { - "axios": "^1.6.1" + "axios": "1.18.1" } }, "node_modules/@haapi/typescript-client": { @@ -6862,6 +6853,18 @@ "node": ">=0.8" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -7229,14 +7232,15 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.18.1", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/axios/-/axios-1.18.1.tgz", + "integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" } }, "node_modules/babel-loader": { @@ -9315,6 +9319,21 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/es6-error/-/es6-error-4.1.1.tgz", @@ -10047,9 +10066,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.16.0", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -10119,14 +10138,16 @@ } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.6", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -10606,9 +10627,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -10706,6 +10727,19 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "1.1.1", "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/human-signals/-/human-signals-1.1.1.tgz", @@ -13409,10 +13443,13 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://npm-hei-school-088312068315.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/public-encrypt": { "version": "4.0.3", diff --git a/src/conf.js b/src/conf.js index 21bd5c8df..3b30c4578 100644 --- a/src/conf.js +++ b/src/conf.js @@ -8,4 +8,5 @@ export const paymentTypes = [ {name: "Virement Bancaire", id: PaymentTypeEnum.BANK_TRANSFER}, {name: "Mobile money", id: PaymentTypeEnum.MOBILE_MONEY}, {name: "Cash", id: PaymentTypeEnum.CASH}, + {name: "Crédit", id: PaymentTypeEnum.CREDIT}, ]; diff --git a/src/operations/common/components/ArchiveWithConfirm.tsx b/src/operations/common/components/ArchiveWithConfirm.tsx index 7954d6200..d5d7c7c9d 100644 --- a/src/operations/common/components/ArchiveWithConfirm.tsx +++ b/src/operations/common/components/ArchiveWithConfirm.tsx @@ -1,6 +1,6 @@ import ArchiveIcon from "@mui/icons-material/Archive"; import {Button, ButtonProps} from "@mui/material"; -import {FC, useState} from "react"; +import {FC} from "react"; import { Confirm, RaRecord, @@ -18,7 +18,7 @@ export const ArchiveWithConfirm: FC<{ buttonProps?: ButtonProps; onArchive: (record: RaRecord) => Promise; }> = ({ - text = "Archiver", + text, confirmTitle, confirmContent, redirect, @@ -27,7 +27,6 @@ export const ArchiveWithConfirm: FC<{ }) => { const record = useRecordContext(); const [showConfirm, , toggleShowConfirm] = useToggle(); - const [pending, setPending] = useState(false); const notify = useNotify(); const doRedirect = useRedirect(); @@ -46,20 +45,20 @@ export const ArchiveWithConfirm: FC<{ return; } - setPending(true); try { await onArchive(record); + notify("Frais archivé avec succès."); + if (redirect) { doRedirect(redirect); } } catch (error) { console.error(error); + notify("Une erreur s'est produite lors de l'archivage.", { type: "error", }); - } finally { - setPending(false); } }; @@ -69,13 +68,14 @@ export const ArchiveWithConfirm: FC<{ color="warning" size="small" data-testid="archive-button-confirm" - disabled={pending} + disabled={record?.is_archived === true} startIcon={} onClick={toggleView} {...buttonProps} > {text} + void; }> = ({ resourceType, - text = "Supprimer", + text, confirmTitle, confirmContent, id, diff --git a/src/operations/common/components/ProfileLayout.tsx b/src/operations/common/components/ProfileLayout.tsx index 755825955..cab30a7f0 100644 --- a/src/operations/common/components/ProfileLayout.tsx +++ b/src/operations/common/components/ProfileLayout.tsx @@ -1,12 +1,12 @@ -import {useShowContext} from "react-admin"; - import {Box, Typography, useMediaQuery} from "@mui/material"; +import {FC} from "react"; +import {useGetOne, useShowContext} from "react-admin"; +import defaultCoverPicture from "@/assets/banner.jpg"; import {PALETTE_COLORS} from "@/haTheme"; -import defaultCoverPicture from "@/assets/banner.jpg"; import {Group, RoleEnum} from "@haapi-b0fc7615/typescript-client"; -import {FC} from "react"; + import {Informations} from "./profilContent/InformationContent"; import {ProfileCardAvatar} from "./profilContent/ProfilCardAvatar"; @@ -28,14 +28,24 @@ export const ProfileLayout: FC<{ }) => { const {record: profile = {}} = useShowContext(); const isLarge = useMediaQuery("(min-width:1700px)"); + const {groups = []} = profile; + const {data: credit} = useGetOne( + "credits", + {id: profile.id}, + { + enabled: isStudentProfile && !!profile.id, + } + ); + return ( + {/* Cover */} + /> + + {profile.first_name} {profile.last_name} + {profile.ref} + {isStudentProfile && ( - {actions} + + {isStudentProfile && credit?.amount > 0 && ( + + + + Solde actuel + + + + {credit.amount.toLocaleString("fr-FR")} Ar + + + + )} + {actions} + , }, + { + id: "credit-transactions", + label: "Crédits", + show: + isStudentProfile && + (role.isManager() || role.isAdmin() || role.isMonitor()), + content: , + }, { id: "monitor-students", label: "Étudiants liés", diff --git a/src/operations/fees/components/Credits/CreditTransactionList.tsx b/src/operations/fees/components/Credits/CreditTransactionList.tsx new file mode 100644 index 000000000..a0ea6151e --- /dev/null +++ b/src/operations/fees/components/Credits/CreditTransactionList.tsx @@ -0,0 +1,67 @@ +import {renderMoney} from "@/operations/common/utils/money"; +import {HaList} from "@/ui/haList/HaList"; +import AccountBalanceWalletOutlined from "@mui/icons-material/AccountBalanceWalletOutlined"; +import {Box} from "@mui/material"; +import {FunctionField} from "react-admin"; + +interface CreditTransactionListProps { + studentId: string; +} + +export const CreditTransactionList = ({ + studentId, +}: CreditTransactionListProps) => { + return ( + + } + title="Transactions de crédit" + actions={null} + resource="credits" + filterIndicator={false} + listProps={{ + filterDefaultValues: { + studentId, + }, + storeKey: `student-${studentId}-credit-transactions`, + }} + > + { + if (record.movement === "DEPOSIT") { + return "Dépôt"; + } + + if (record.movement === "WITHDRAWAL") { + return "Retrait"; + } + + return "Non défini"; + }} + /> + + renderMoney(record.amount)} + /> + + record.fee?.comment ?? "Non défini"} + /> + + { + if (!record.date_time) { + return "Non définie"; + } + + return new Date(record.date_time).toLocaleString("fr-FR"); + }} + /> + + + ); +}; diff --git a/src/operations/fees/components/FeesActions.tsx b/src/operations/fees/components/FeesActions.tsx index 93545ff95..97a6e000b 100644 --- a/src/operations/fees/components/FeesActions.tsx +++ b/src/operations/fees/components/FeesActions.tsx @@ -20,7 +20,7 @@ const FeesActions = (id: string) => { validateData={valideFeesData} optionalHeaders={optionalFeesHeaders} minimalHeaders={minimalFeesHeaders} - transformData={(data) => transformFeesData(data, id)} + transformData={(data: any) => transformFeesData(data, id)} /> diff --git a/src/operations/fees/components/ManagerFeeList.jsx b/src/operations/fees/components/ManagerFeeList.jsx index 3e4623519..729289611 100644 --- a/src/operations/fees/components/ManagerFeeList.jsx +++ b/src/operations/fees/components/ManagerFeeList.jsx @@ -4,6 +4,7 @@ import { } from "@/operations/common/components"; import {DateField} from "@/operations/common/components/fields"; import {renderMoney} from "@/operations/common/utils/money"; +import FeesActions from "@/operations/fees/components/FeesActions"; import {PSP_COLORS, PSP_VALUES, rowStyle} from "@/operations/fees/utils"; import {commentFunctionRenderer} from "@/operations/utils"; import {payingApi} from "@/providers/api"; @@ -14,7 +15,7 @@ import {HaList} from "@/ui/haList/HaList"; import {formatDate} from "@/utils/date"; import {WarningOutlined} from "@mui/icons-material"; import {Box, Chip} from "@mui/material"; -import {FunctionField} from "react-admin"; +import {FunctionField, WrapperField} from "react-admin"; export const ManagerFeeList = ({studentId, studentRef}) => { const role = useRole(); @@ -24,7 +25,7 @@ export const ManagerFeeList = ({studentId, studentRef}) => { } title={`Frais de ${studentRef}`} - resource={"fees"} + resource="fees" filterIndicator={false} actions={ role.isManager() || role.isAdmin() ? ( @@ -50,20 +51,24 @@ export const ManagerFeeList = ({studentId, studentRef}) => { label="Limite de paiement du frais" showTime={false} /> + + renderMoney(record.remaining_amount)} /> + fee?.mpbs?.at(-1)?.psp_id} label="Référence de la transaction" emptyText={EMPTY_TEXT} /> + fee.mpbs ? ( @@ -78,11 +83,13 @@ export const ManagerFeeList = ({studentId, studentRef}) => { label="Type de transaction" emptyText={EMPTY_TEXT} /> + formatDate(fee?.mpbs?.at(-1)?.creation_datetime)} label="Ajout de la référence de transaction" emptyText={EMPTY_TEXT} /> + formatDate(fee?.mpbs?.at(-1)?.last_datetime_verification) @@ -90,6 +97,7 @@ export const ManagerFeeList = ({studentId, studentRef}) => { label="Dernière vérification par HEI" emptyText={EMPTY_TEXT} /> + formatDate(fee?.mpbs?.at(-1)?.psp_own_datetime_verification) @@ -97,6 +105,7 @@ export const ManagerFeeList = ({studentId, studentRef}) => { label="Vérification par PSP" emptyText={EMPTY_TEXT} /> + formatDate(fee?.mpbs?.at(-1)?.successfully_verified_on) @@ -104,26 +113,37 @@ export const ManagerFeeList = ({studentId, studentRef}) => { label="Vérification réussie" emptyText={EMPTY_TEXT} /> + {!role.isMonitor() && ( - <> - - { - const {feeId} = toApiIds(record?.id); - return payingApi().archiveStudentFee(studentId, feeId, { - method: "PATCH", - }); + + - + > + + + { + const {feeId} = toApiIds(record.id); + + return payingApi().archiveStudentFee(studentId, feeId, { + method: "PATCH", + }); + }} + /> + + )} diff --git a/src/operations/payments/PaymentCreate.jsx b/src/operations/payments/PaymentCreate.jsx index 94bdd3dc5..a9a7d2e6c 100644 --- a/src/operations/payments/PaymentCreate.jsx +++ b/src/operations/payments/PaymentCreate.jsx @@ -1,8 +1,201 @@ +// import {paymentTypes} from "@/conf"; +// import {useToggle} from "@/hooks/useToggle"; +// import {studentIdFromRaId} from "@/providers/feeProvider"; +// import { +// MobileMoneyType, +// PaymentTypeEnum, +// } from "@haapi-b0fc7615/typescript-client"; +// import {Box} from "@mui/material"; +// import {Home, Wallet} from "lucide-react"; +// import {useEffect, useState} from "react"; +// import { +// BooleanInput, +// Create, +// DateInput, +// minValue, +// number, +// RadioButtonGroupInput, +// required, +// SelectInput, +// SimpleForm, +// TextInput, +// useDataProvider, +// useNotify, +// } from "react-admin"; +// import {Link as RouterLink, useParams} from "react-router-dom"; +// import {pspIdValidationContraints} from "../utils"; +// import CustomBreadcrumbs from "../utils/CustomBreadcrumbs"; + +// const PaymentCreate = (props) => { +// const params = useParams(); +// const notify = useNotify(); +// const dataProvider = useDataProvider(); +// const [studentRef, setStudentRef] = useState("..."); +// const [paymentChoice, setPaymentChoice] = useState( +// PaymentTypeEnum.BANK_TRANSFER +// ); +// const [notSpecifiedDate, setSpecifyDate] = useToggle(true); + +// const feeId = params.feeId; +// const studentId = studentIdFromRaId(feeId); +// const isMobileMoney = paymentChoice === PaymentTypeEnum.MOBILE_MONEY; +// const isCommentNecessary = +// isMobileMoney || paymentChoice === PaymentTypeEnum.BANK_TRANSFER; + +// useEffect(() => { +// const doEffect = async () => { +// const student = await dataProvider.getOne("students", {id: studentId}); +// setStudentRef(student.data.ref); +// }; +// doEffect(); +// }, [studentId, dataProvider]); + +// const breadcrumbItems = [ +// { +// label: "Étudiant", +// component: RouterLink, +// to: `/students/${studentId}/show`, +// icon: , +// }, +// { +// label: "Frais", +// component: RouterLink, +// to: `/fees/${feeId}/show`, +// icon: , +// }, +// { +// label: "Créer un paiement", +// }, +// ]; + +// const notifyError = (error) => { +// let message = "Une erreur s`'est produite"; +// if (error.response && error.response.status === 400) { +// if (error.response.message.startsWith("Payment amount")) +// message = "Le paiement dépasse le montant restant du frais"; +// else message = "Paiement pour date future non autorisé"; +// } +// notify(message, {type: "error", autoHideDuration: 2500}); +// }; +// const paymentConfToPaymentApi = ({ +// ref, +// type, +// amount, +// comment, +// creation_datetime, +// psp_id, +// psp_type, +// status +// }) => { +// const getDatetimeValue = () => { +// if (notSpecifiedDate) { +// const currentDate = new Date(); +// currentDate.setSeconds(0); +// return currentDate.toISOString(); +// } +// return new Date(creation_datetime).toISOString(); +// }; +// return [ +// { +// feeId, +// type, +// amount, +// comment, +// ref, +// psp_id, +// psp_type, +// creation_datetime: getDatetimeValue(), +// }, +// ]; +// }; + +// return ( +// +// +// `fees/${feeId}/show`} +// transform={paymentConfToPaymentApi} +// {...props} +// > +// +// setPaymentChoice(event.target.value)} +// /> +// {paymentChoice === PaymentTypeEnum.BANK_TRANSFER && ( +// +// )} +// {isMobileMoney && ( +// +// )} +// {isMobileMoney && ( +// +// )} +// +// +// setSpecifyDate(checked)} +// /> +// {!notSpecifiedDate && ( +// +// )} +// +// +// +// ); +// }; + +// export default PaymentCreate; import {paymentTypes} from "@/conf"; import {useToggle} from "@/hooks/useToggle"; import {studentIdFromRaId} from "@/providers/feeProvider"; +import {useRole} from "@/security/hooks"; import { MobileMoneyType, + PaymentStatus, PaymentTypeEnum, } from "@haapi-b0fc7615/typescript-client"; import {Box} from "@mui/material"; @@ -30,6 +223,8 @@ const PaymentCreate = (props) => { const params = useParams(); const notify = useNotify(); const dataProvider = useDataProvider(); + const role = useRole(); + const [studentRef, setStudentRef] = useState("..."); const [paymentChoice, setPaymentChoice] = useState( PaymentTypeEnum.BANK_TRANSFER @@ -38,15 +233,21 @@ const PaymentCreate = (props) => { const feeId = params.feeId; const studentId = studentIdFromRaId(feeId); + const isMobileMoney = paymentChoice === PaymentTypeEnum.MOBILE_MONEY; + const isCommentNecessary = isMobileMoney || paymentChoice === PaymentTypeEnum.BANK_TRANSFER; useEffect(() => { const doEffect = async () => { - const student = await dataProvider.getOne("students", {id: studentId}); + const student = await dataProvider.getOne("students", { + id: studentId, + }); + setStudentRef(student.data.ref); }; + doEffect(); }, [studentId, dataProvider]); @@ -69,14 +270,22 @@ const PaymentCreate = (props) => { ]; const notifyError = (error) => { - let message = "Une erreur s`'est produite"; + let message = "Une erreur s'est produite"; + if (error.response && error.response.status === 400) { - if (error.response.message.startsWith("Payment amount")) + if (error.response.message.startsWith("Payment amount")) { message = "Le paiement dépasse le montant restant du frais"; - else message = "Paiement pour date future non autorisé"; + } else { + message = "Paiement pour date future non autorisé"; + } } - notify(message, {type: "error", autoHideDuration: 2500}); + + notify(message, { + type: "error", + autoHideDuration: 2500, + }); }; + const paymentConfToPaymentApi = ({ ref, type, @@ -90,10 +299,18 @@ const PaymentCreate = (props) => { if (notSpecifiedDate) { const currentDate = new Date(); currentDate.setSeconds(0); + return currentDate.toISOString(); } + return new Date(creation_datetime).toISOString(); }; + + const status = + role.isManager() || role.isAdmin() + ? PaymentStatus.VALIDATE + : PaymentStatus.CREATED; + return [ { feeId, @@ -103,6 +320,7 @@ const PaymentCreate = (props) => { ref, psp_id, psp_type, + status, creation_datetime: getDatetimeValue(), }, ]; @@ -111,6 +329,7 @@ const PaymentCreate = (props) => { return ( + { defaultValue={PaymentTypeEnum.BANK_TRANSFER} onChange={(event) => setPaymentChoice(event.target.value)} /> + {paymentChoice === PaymentTypeEnum.BANK_TRANSFER && ( { validate={required()} /> )} + {isMobileMoney && ( { validate={pspIdValidationContraints} /> )} + {isMobileMoney && ( )} + + + setSpecifyDate(checked)} /> + {!notSpecifiedDate && ( { + const studentId = filter.studentId as string; + + const result = await payingApi().getCreditTransactionsByStudentId( + studentId, + filter as CreditMovement, + page, + perPage + ); + + return { + data: result.data.map((transaction) => ({ + id: transaction.transaction_id, + transaction_id: transaction.transaction_id, + movement: transaction.movement, + amount: transaction.amount, + date_time: transaction.date_time, + fee: transaction.fee, + credit: transaction.credit, + })), + }; + }, + getOne: async (studentId) => { + return await payingApi() + .getCreditByStudentId(studentId) + .then((result) => result.data); + }, + saveOrUpdate: () => { + throw new Error("Function not implemented."); + }, + + delete: () => { + throw new Error("Function not implemented."); + }, +}; + +export default studentCreditProvider; From db215d8c7e1b45df59cf7d2001c871830e6cbd87 Mon Sep 17 00:00:00 2001 From: DyferHerioss Date: Fri, 7 Aug 2026 16:34:44 +0300 Subject: [PATCH 3/7] feat: credit payment --- .../fees/components/FeesActions.tsx | 15 +++--- src/operations/payments/PaymentCreate.jsx | 40 +++++++++++++--- src/providers/feeProvider.ts | 2 +- tsconfig.node.tsbuildinfo | 1 + tsconfig.tsbuildinfo | 1 + vite.config.d.ts | 2 + vite.config.js | 47 +++++++++++++++++++ 7 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 tsconfig.node.tsbuildinfo create mode 100644 tsconfig.tsbuildinfo create mode 100644 vite.config.d.ts create mode 100644 vite.config.js diff --git a/src/operations/fees/components/FeesActions.tsx b/src/operations/fees/components/FeesActions.tsx index 97a6e000b..e09a088b1 100644 --- a/src/operations/fees/components/FeesActions.tsx +++ b/src/operations/fees/components/FeesActions.tsx @@ -1,7 +1,6 @@ import feeProvider from "@/providers/feeProvider"; -import {ImportButton} from "@/ui/haToolbar"; -import {Box} from "lucide-react"; -import {CreateButton} from "react-admin"; +import { Box } from "@mui/material"; +import {CreateButton, ImportButton} from "@/ui/haToolbar"; import { minimalFeesHeaders, optionalFeesHeaders, @@ -10,17 +9,21 @@ import { } from "../importConf"; import {FeesFilters} from "./FeesFilter"; -const FeesActions = (id: string) => { +type FeesActionsProps= { + studentId: string +} + +const FeesActions = ({studentId}: FeesActionsProps) => { return ( - + transformFeesData(data, id)} + transformData={(data: any) => transformFeesData(data, studentId)} /> diff --git a/src/operations/payments/PaymentCreate.jsx b/src/operations/payments/PaymentCreate.jsx index a9a7d2e6c..c0a2f532d 100644 --- a/src/operations/payments/PaymentCreate.jsx +++ b/src/operations/payments/PaymentCreate.jsx @@ -219,16 +219,32 @@ import {Link as RouterLink, useParams} from "react-router-dom"; import {pspIdValidationContraints} from "../utils"; import CustomBreadcrumbs from "../utils/CustomBreadcrumbs"; +const MINIMUM_CREDIT = 200000; + const PaymentCreate = (props) => { const params = useParams(); const notify = useNotify(); const dataProvider = useDataProvider(); const role = useRole(); + const [credit, setCredit] = useState(null); const [studentRef, setStudentRef] = useState("..."); const [paymentChoice, setPaymentChoice] = useState( PaymentTypeEnum.BANK_TRANSFER ); + + const validateCreditPayment = (amount) => { + if (!credit) return undefined; + + if (credit.amount < MINIMUM_CREDIT) { + return `Votre crédit est inférieur à ${MINIMUM_CREDIT}Ar.`; + } + if (Number(amount) > credit.amount) { + return "Le montant saisi est supérieur à votre crédit actuel."; + } + return undefined; + }; + const [notSpecifiedDate, setSpecifyDate] = useToggle(true); const feeId = params.feeId; @@ -238,14 +254,13 @@ const PaymentCreate = (props) => { const isCommentNecessary = isMobileMoney || paymentChoice === PaymentTypeEnum.BANK_TRANSFER; + + const isCreditPayment = paymentChoice === PaymentTypeEnum.CREDIT; useEffect(() => { const doEffect = async () => { - const student = await dataProvider.getOne("students", { - id: studentId, - }); - - setStudentRef(student.data.ref); + const credit = await dataProvider.getOne("credits", {id: studentId}); + setCredit(credit.data); }; doEffect(); @@ -278,7 +293,7 @@ const PaymentCreate = (props) => { } else { message = "Paiement pour date future non autorisé"; } - } + } notify(message, { type: "error", @@ -306,6 +321,7 @@ const PaymentCreate = (props) => { return new Date(creation_datetime).toISOString(); }; + const status = role.isManager() || role.isAdmin() ? PaymentStatus.VALIDATE @@ -387,7 +403,17 @@ const PaymentCreate = (props) => { source="amount" label="Montant du paiement" fullWidth - validate={[required(), number(), minValue(1)]} + validate={[ + required(), + number(), + minValue(1), + (value) => { + if (!isCreditPayment) { + return undefined; + } + return validateCreditPayment(value); + }, + ]} /> { + saveOrUpdate: async (resources) => { const payload = resources[0]; const role = authProvider.getCachedRole(); diff --git a/tsconfig.node.tsbuildinfo b/tsconfig.node.tsbuildinfo new file mode 100644 index 000000000..c0e76d34c --- /dev/null +++ b/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["../../../../../../usr/lib/node_modules/typescript/lib/lib.es5.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2016.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2018.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2019.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2021.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2022.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2023.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.dom.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.scripthost.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2023.array.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2023.collection.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2023.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.collection.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.object.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.promise.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2024.string.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.collection.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.float16.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.intl.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.iterator.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.promise.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.regexp.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.decorators.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../../../../usr/lib/node_modules/typescript/lib/lib.es2025.full.d.ts","./node_modules/@babel/types/lib/index.d.ts","./node_modules/@types/babel__generator/index.d.ts","./node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/@types/babel__template/index.d.ts","./node_modules/@types/babel__traverse/index.d.ts","./node_modules/@types/babel__core/index.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","../../../../node_modules/buffer/index.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/querystring/decode.d.ts","./node_modules/querystring/encode.d.ts","./node_modules/querystring/index.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/esbuild/lib/main.d.ts","./node_modules/vite/types/metadata.d.ts","./node_modules/vite/types/hmrPayload.d.ts","./node_modules/vite/types/customEvent.d.ts","./node_modules/rollup/dist/rollup.d.ts","./node_modules/vite/types/importGlob.d.ts","./node_modules/source-map-js/source-map.d.ts","./node_modules/postcss/lib/previous-map.d.ts","./node_modules/postcss/lib/input.d.ts","./node_modules/postcss/lib/css-syntax-error.d.ts","./node_modules/postcss/lib/declaration.d.ts","./node_modules/postcss/lib/root.d.ts","./node_modules/postcss/lib/warning.d.ts","./node_modules/postcss/lib/lazy-result.d.ts","./node_modules/postcss/lib/no-work-result.d.ts","./node_modules/postcss/lib/processor.d.ts","./node_modules/postcss/lib/result.d.ts","./node_modules/postcss/lib/document.d.ts","./node_modules/postcss/lib/rule.d.ts","./node_modules/postcss/lib/node.d.ts","./node_modules/postcss/lib/comment.d.ts","./node_modules/postcss/lib/container.d.ts","./node_modules/postcss/lib/at-rule.d.ts","./node_modules/postcss/lib/list.d.ts","./node_modules/postcss/lib/postcss.d.ts","./node_modules/postcss/lib/postcss.d.mts","./node_modules/vite/dist/node/index.d.ts","./node_modules/@vitejs/plugin-react/dist/index.d.mts","./node_modules/vite-plugin-istanbul/dist/index.d.ts","./node_modules/node-stdlib-browser/esm/index.d.ts","./node_modules/vite-plugin-node-polyfills/dist/index.d.ts","./vite.config.ts"],"fileIdsList":[[83,94,141],[94,141],[83,84,85,86,87,94,141],[83,85,94,141],[94,138,141],[94,140,141],[141],[94,141,146,177],[94,141,142,147,152,160,174,185],[94,141,142,143,152,160],[89,90,91,94,141],[94,141,144,186],[94,141,145,146,153,161],[94,141,146,174,182],[94,141,147,149,152,160],[94,140,141,148],[94,141,149,150],[94,141,151,152],[94,140,141,152],[94,141,152,153,154,174,185],[94,141,152,153,154,170,174,177],[94,141,149,152,155,160,174,185],[94,141,152,153,155,156,160,174,182,185],[94,141,155,157,174,182,185],[92,93,94,95,96,97,98,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191],[94,141,152,158],[94,141,159,185,190],[94,141,149,152,160,174],[94,141,161],[94,141,162],[94,140,141,163],[94,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191],[94,141,168],[94,141,169],[94,141,152,170,171],[94,141,170,172,186,188],[94,141,152,174,175,177],[94,141,176,177],[94,141,174,175],[94,141,177],[94,141,178],[94,138,141,174,179],[94,141,152,180,181],[94,141,180,181],[94,141,146,160,174,182],[94,141,183],[94,141,160,184],[94,141,155,169,185],[94,141,146,186],[94,141,174,187],[94,141,159,188],[94,141,189],[94,136,141],[94,141,152,154,163,174,177,185,188,190],[94,141,174,191],[88,94,141,219],[94,141,214],[94,141,212,214],[94,141,203,211,212,213,215],[94,141,201],[94,141,204,209,214,217],[94,141,200,217],[94,141,204,205,208,209,210,217],[94,141,204,205,206,208,209,217],[94,141,201,202,203,204,205,209,210,211,213,214,215,217],[94,141,217],[94,141,199,201,202,203,204,205,206,208,209,210,211,212,213,214,215,216],[94,141,199,217],[94,141,204,206,207,209,210,217],[94,141,208,217],[94,141,209,210,214,217],[94,141,202,212],[94,141,164,165],[94,108,112,141,185],[94,108,141,174,185],[94,103,141],[94,105,108,141,182,185],[94,141,160,182],[94,141,192],[94,103,141,192],[94,105,108,141,160,185],[94,100,101,104,107,141,152,174,185],[94,108,115,141],[94,100,106,141],[94,108,129,130,141],[94,104,108,141,177,185,192],[94,129,141,192],[94,102,103,141,192],[94,108,141],[94,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,141],[94,108,123,141],[94,108,115,116,141],[94,106,108,116,117,141],[94,107,141],[94,100,103,108,141],[94,108,112,116,117,141],[94,112,141],[94,106,108,111,141,185],[94,100,105,108,115,141],[94,141,174],[94,103,108,129,141,190,192],[94,141,219],[94,141,219,222],[94,141,152,153,155,157,160,174,182,185,191,192,193,194,195,196,197,198,218],[94,141,195],[94,141,197],[94,141,162,219,220,221,223]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"1e9332c23e9a907175e0ffc6a49e236f97b48838cc8aec9ce7e4cec21e544b65","impliedFormat":1},{"version":"3753fbc1113dc511214802a2342280a8b284ab9094f6420e7aa171e868679f91","impliedFormat":1},{"version":"999ca32883495a866aa5737fe1babc764a469e4cde6ee6b136a4b9ae68853e4b","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"2a2de5b9459b3fc44decd9ce6100b72f1b002ef523126c1d3d8b2a4a63d74d78","affectsGlobalScope":true,"impliedFormat":1},{"version":"f13f4b465c99041e912db5c44129a94588e1aafee35a50eab51044833f50b4ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bd714129fca875f7d4c477a1a392200b0bcd13fb2e80928cd334b63830ea047","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2c9037ae6cd2c52d80ceef0b3c5ffdb488627d71529cf4f63776daf11161c9a","affectsGlobalScope":true,"impliedFormat":1},{"version":"135d5cf4d345f59f1a9caadfafcd858d3d9cc68290db616cc85797224448cccc","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc238c3f81c2984751932b6aab223cd5b830e0ac6cad76389e5e9d2ffc03287d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4a07f9b76d361f572620927e5735b77d6d2101c23cdd94383eb5b706e7b36357","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4e8dc6ab834cc6baa0227e030606d29e3e8449a9f67cdf5605ea5493c4db29","affectsGlobalScope":true,"impliedFormat":1},{"version":"de7ba0fd02e06cd9a5bd4ab441ed0e122735786e67dde1e849cced1cd8b46b78","affectsGlobalScope":true,"impliedFormat":1},{"version":"6148e4e88d720a06855071c3db02069434142a8332cf9c182cda551adedf3156","affectsGlobalScope":true,"impliedFormat":1},{"version":"d63dba625b108316a40c95a4425f8d4294e0deeccfd6c7e59d819efa19e23409","affectsGlobalScope":true,"impliedFormat":1},{"version":"0568d6befee03dd435bed4fc25c4e46865b24bdcb8c563fdc21f580a2c301904","affectsGlobalScope":true,"impliedFormat":1},{"version":"30d62269b05b584741f19a5369852d5d34895aa2ac4fd948956f886d15f9cc0d","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"ffbe6d7b295306b2ba88030f65b74c107d8d99bdcf596ea99c62a02f606108b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"996fb27b15277369c68a4ba46ed138b4e9e839a02fb4ec756f7997629242fd9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"79b712591b270d4778c89706ca2cfc56ddb8c3f895840e477388f1710dc5eda9","affectsGlobalScope":true,"impliedFormat":1},{"version":"20884846cef428b992b9bd032e70a4ef88e349263f63aeddf04dda837a7dba26","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"e03da518b01b46a4c99a1f88cd727ee98ddf14492c43dae1ae7a63e992971bab","impliedFormat":1},{"version":"03f1d83d61696326ea29c8a1c15cbaccf61e92598d53f2ccae06078531f42448","impliedFormat":1},{"version":"2c8e55457aaf4902941dfdba4061935922e8ee6e120539c9801cd7b400fae050","impliedFormat":1},{"version":"3a9313fe5ace558b8b18e85f931da10b259e738775f411c061e5f15787b138eb","impliedFormat":1},{"version":"670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","impliedFormat":1},{"version":"9e0cf651e8e2c5b9bebbabdff2f7c6f8cedd91b1d9afcc0a854cdff053a88f1b","impliedFormat":1},{"version":"069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"a79e62f1e20467e11a904399b8b18b18c0c6eea6b50c1168bf215356d5bebfaf","affectsGlobalScope":true,"impliedFormat":1},{"version":"49a5a44f2e68241a1d2bd9ec894535797998841c09729e506a7cbfcaa40f2180","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e2e0a2dfc6bfabffacba3cc3395aa8197f30893942a2625bd9923ea34a27a3c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"456fa0c0ab68731564917642b977c71c3b7682240685b118652fb9253c9a6429","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d586db0a09a9495ebb5dece28f54df9684bfbd6e1f568426ca153126dac4a40","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"567b7f607f400873151d7bc63a049514b53c3c00f5f56e9e95695d93b66a138e","affectsGlobalScope":true,"impliedFormat":1},{"version":"823f9c08700a30e2920a063891df4e357c64333fdba6889522acc5b7ae13fc08","impliedFormat":1},{"version":"84c1930e33d1bb12ad01bcbe11d656f9646bd21b2fb2afd96e8e10615a021aef","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4b87f767c7bc841511113c876a6b8bf1fd0cb0b718c888ad84478b372ec486b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d04e3640dd9eb67f7f1e5bd3d0bf96c784666f7aefc8ac1537af6f2d38d4c29","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"2bf469abae4cc9c0f340d4e05d9d26e37f936f9c8ca8f007a6534f109dcc77e4","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"0ada07543808f3b967624645a8e1ccd446f8b01ade47842acf1328aec899fed0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4c21aaa8257d7950a5b75a251d9075b6a371208fc948c9c8402f6690ef3b5b55","impliedFormat":1},{"version":"685657a3ec619ef12aa7f754eee3b28598d3bf9749da89839a72a343fffef5ff","impliedFormat":1},{"version":"54c4f21f578864961efc94e8f42bc893a53509e886370ec7dd602e0151b9266c","impliedFormat":1},{"version":"de735eca2c51dd8b860254e9fdb6d9ec19fe402dfe597c23090841ce3937cfc5","impliedFormat":1},{"version":"4ff41188773cbf465807dd2f7059c7494cbee5115608efc297383832a1150c43","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"5155da3047ef977944d791a2188ff6e6c225f6975cc1910ab7bb6838ab84cede","impliedFormat":1},{"version":"93f437e1398a4f06a984f441f7fa7a9f0535c04399619b5c22e0b87bdee182cb","impliedFormat":1},{"version":"afbe24ab0d74694372baa632ecb28bb375be53f3be53f9b07ecd7fc994907de5","impliedFormat":1},{"version":"e16d218a30f6a6810b57f7e968124eaa08c7bb366133ea34bbf01e7cd6b8c0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ad7e61eca7f2f8bf47e72695f9f6663b75e41d87ef49abdb17c0cb843862f8aa","impliedFormat":1},{"version":"ecba2e44af95b0599c269a92628cec22e752868bce37396740deb51a5c547a26","impliedFormat":1},{"version":"46a9fb41a8f3bc7539eeebc15a6e04b9e55d7537a081615ad3614220d34c3e0f","impliedFormat":1},{"version":"eb8692dea24c27821f77e397272d9ed2eda0b95e4a75beb0fdda31081d15a8ae","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"8145e07aad6da5f23f2fcd8c8e4c5c13fb26ee986a79d03b0829b8fce152d8b2","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"5b6844ad931dcc1d3aca53268f4bd671428421464b1286746027aede398094f2","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"125d792ec6c0c0f657d758055c494301cc5fdb327d9d9d5960b3f129aff76093","impliedFormat":1},{"version":"0225ecb9ed86bdb7a2c7fd01f1556906902929377b44483dc4b83e03b3ef227d","affectsGlobalScope":true,"impliedFormat":1},{"version":"1851a3b4db78664f83901bb9cac9e45e03a37bb5933cc5bf37e10bb7e91ab4eb","impliedFormat":1},{"version":"461e54289e6287e8494a0178ba18182acce51a02bca8dea219149bf2cf96f105","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"e31e51c55800014d926e3f74208af49cb7352803619855c89296074d1ecbb524","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"dfb96ba5177b68003deec9e773c47257da5c4c8a74053d8956389d832df72002","affectsGlobalScope":true,"impliedFormat":1},{"version":"92d3070580cf72b4bb80959b7f16ede9a3f39e6f4ef2ac87cfa4561844fdc69f","affectsGlobalScope":true,"impliedFormat":1},{"version":"d3dffd70e6375b872f0b4e152de4ae682d762c61a24881ecc5eb9f04c5caf76f","impliedFormat":1},{"version":"613deebaec53731ff6b74fe1a89f094b708033db6396b601df3e6d5ab0ec0a47","impliedFormat":1},{"version":"d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c","impliedFormat":1},{"version":"e56eb632f0281c9f8210eb8c86cc4839a427a4ffffcfd2a5e40b956050b3e042","affectsGlobalScope":true,"impliedFormat":1},{"version":"e8a979b8af001c9fc2e774e7809d233c8ca955a28756f52ee5dee88ccb0611d2","impliedFormat":1},{"version":"15f884b850ca9b6e07697a0e6b686927b8025edd472b76f2a3149216b18a24b5","impliedFormat":1},{"version":"850040826cfa77593d44f44487133af21917f4f21507258bd4269501b80d32f0","impliedFormat":1},{"version":"8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","impliedFormat":1},{"version":"bcb6ea18f23dae2c48459d7b86d3adccd6898f824fcbf9da08b935f559896580","impliedFormat":1},{"version":"1363ba7d52f2353d0c4306d0ecdaf171bf4509c0148842f9fd8d3986c098a2eb","impliedFormat":1},{"version":"3a24f4a428f24cad90b83fab329a620c4adbace083a8eda62c63365065b79e73","impliedFormat":1},{"version":"739c2c46edc112421fc023c24b4898b1f413f792bb6a02b40ba182c648e56c2f","impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","impliedFormat":1},{"version":"4d979e3c12ffb6497d2b1dc5613130196d986fff764c4526360c0716a162e7e7","impliedFormat":1},{"version":"e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","impliedFormat":1},{"version":"80781460eca408fe8d2937d9fdbbb780d6aac35f549621e6200c9bee1da5b8fe","impliedFormat":1},{"version":"4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","impliedFormat":1},{"version":"7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","impliedFormat":1},{"version":"b9261ac3e9944d3d72c5ee4cf888ad35d9743a5563405c6963c4e43ee3708ca4","impliedFormat":1},{"version":"c84fd54e8400def0d1ef1569cafd02e9f39a622df9fa69b57ccc82128856b916","impliedFormat":1},{"version":"a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","impliedFormat":1},{"version":"2ed6489ef46eb61442d067c08e87e3db501c0bfb2837eee4041a27bf3e792bb0","impliedFormat":1},{"version":"644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","impliedFormat":1},{"version":"d60fe6d59d4e19ecc65359490b8535e359ca4b760d2cdb56897ca75d09d41ba3","impliedFormat":1},{"version":"f45a2a8b1777ecb50ed65e1a04bb899d4b676529b7921bd5d69b08573a00c832","impliedFormat":1},{"version":"774b783046ba3d473948132d28a69f52a295b2f378f2939304118ba571b1355e","impliedFormat":1},{"version":"b5734e05c787a40e4f9efe71f16683c5f7dc3bdb0de7c04440c855bd000f8fa7","impliedFormat":1},{"version":"14ba97f0907144771331e1349fdccb5a13526eba0647e6b447e572376d811b6f","impliedFormat":1},{"version":"2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","impliedFormat":1},{"version":"7165050eddaed878c2d2cd3cafcaf171072ac39e586a048c0603712b5555f536","impliedFormat":1},{"version":"26e629be9bbd94ea1d465af83ce5a3306890520695f07be6eb016f8d734d02be","impliedFormat":99},{"version":"77b411edffb8d1fa25c07b5c3232e214f5f54b1fbb5e3e9eefcc9fd915bea582","impliedFormat":99},{"version":"f5e8546cfe500116aba8a6cb7ee171774b14a6db30d4bcd6e0aa5073e919e739","impliedFormat":99},{"version":"b6458d77bf5d1cfbe7db91eecb33cd0f11dd2358178fb81d33829dd8d7c9f1ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"816ad2333292d54fb1b764ee3ac7cc86c84f10333d6591d8e5b9b0e82af4c781","impliedFormat":99},{"version":"ca859c194937779fddd72780f4cf0d88369cbf0f40c49900a3cab6234a3a23a7","impliedFormat":99},{"version":"d690a798f45cba3b8d861d0210f2caed837508edf6e3246100a4ee8fbeb6e016","signature":"f1a1b21a223c18a29308ebff0b002317e4bb8aa5e350164f8c8c3b8bde33a535"}],"root":[224],"options":{"allowSyntheticDefaultImports":true,"composite":true,"module":99,"skipLibCheck":true},"referencedMap":[[85,1],[83,2],[88,3],[84,1],[86,4],[87,1],[138,5],[139,5],[140,6],[94,7],[141,8],[142,9],[143,10],[89,2],[92,11],[90,2],[91,2],[144,12],[145,13],[146,14],[147,15],[148,16],[149,17],[150,17],[151,18],[152,19],[153,20],[154,21],[95,2],[93,2],[155,22],[156,23],[157,24],[192,25],[158,26],[159,27],[160,28],[161,29],[162,30],[163,31],[167,32],[168,33],[169,34],[170,35],[171,35],[172,36],[173,2],[174,37],[176,38],[175,39],[177,40],[178,41],[179,42],[180,43],[181,44],[182,45],[183,46],[184,47],[185,48],[186,49],[187,50],[188,51],[189,52],[96,2],[97,2],[98,2],[137,53],[190,54],[191,55],[220,56],[193,2],[222,2],[215,57],[213,58],[214,59],[202,60],[203,58],[210,61],[201,62],[206,63],[216,2],[207,64],[212,65],[218,66],[217,67],[200,68],[208,69],[209,70],[204,71],[211,57],[205,72],[164,2],[165,2],[166,73],[197,2],[199,2],[115,74],[125,75],[114,74],[135,76],[106,77],[105,78],[134,79],[128,80],[133,81],[108,82],[122,83],[107,84],[131,85],[103,86],[102,79],[132,87],[104,88],[109,89],[110,2],[113,89],[100,2],[136,90],[126,91],[117,92],[118,93],[120,94],[116,95],[119,96],[129,79],[111,97],[112,98],[121,99],[101,100],[124,91],[123,89],[127,2],[130,101],[221,102],[223,103],[219,104],[196,105],[195,2],[198,2],[194,106],[224,107],[99,2],[80,2],[81,2],[15,2],[13,2],[14,2],[19,2],[18,2],[2,2],[20,2],[21,2],[22,2],[23,2],[24,2],[25,2],[26,2],[27,2],[3,2],[28,2],[29,2],[4,2],[30,2],[34,2],[31,2],[32,2],[33,2],[35,2],[36,2],[37,2],[5,2],[38,2],[39,2],[40,2],[41,2],[6,2],[45,2],[42,2],[43,2],[44,2],[46,2],[7,2],[47,2],[52,2],[53,2],[48,2],[49,2],[50,2],[51,2],[8,2],[57,2],[54,2],[55,2],[56,2],[58,2],[9,2],[59,2],[60,2],[61,2],[63,2],[62,2],[64,2],[65,2],[10,2],[66,2],[67,2],[68,2],[11,2],[69,2],[70,2],[71,2],[72,2],[73,2],[74,2],[12,2],[75,2],[82,2],[76,2],[77,2],[78,2],[79,2],[1,2],[17,2],[16,2]],"latestChangedDtsFile":"./vite.config.d.ts","version":"6.0.3"} \ No newline at end of file diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo new file mode 100644 index 000000000..93b8d59cc --- /dev/null +++ b/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/App.jsx","./src/conf.js","./src/haTheme.js","./src/main.tsx","./src/vite-env.d.ts","./src/config/axios.ts","./src/config/env.ts","./src/hooks/index.js","./src/hooks/useNotify.ts","./src/hooks/useStudentRef.js","./src/hooks/useTabManager.ts","./src/hooks/useToggle.ts","./src/operations/CourseAssignments/AssignedTeachersList.tsx","./src/operations/CourseAssignments/CourseAssignmentsCreate.tsx","./src/operations/CourseAssignments/TeacherCourseList.tsx","./src/operations/CourseAssignments/index.tsx","./src/operations/announcements/AnnouncementCreate.tsx","./src/operations/announcements/AnnouncementList.tsx","./src/operations/announcements/AnnouncementShow.tsx","./src/operations/announcements/index.ts","./src/operations/announcements/components/AnnoucementCard.tsx","./src/operations/announcements/components/AnnouncementsFilter.tsx","./src/operations/announcements/components/EmailField.tsx","./src/operations/announcements/components/SelectGroup.tsx","./src/operations/announcements/components/SelectScope.tsx","./src/operations/announcements/components/index.ts","./src/operations/announcements/utils/getBgImg.tsx","./src/operations/announcements/utils/constants/announcementsScopes.tsx","./src/operations/comments/CommentCreate.jsx","./src/operations/comments/CommentList.jsx","./src/operations/comments/StudentComments.tsx","./src/operations/comments/index.js","./src/operations/comments/utils.jsx","./src/operations/common/components/ArchiveWithConfirm.tsx","./src/operations/common/components/ChipRadio.tsx","./src/operations/common/components/ColorInput.tsx","./src/operations/common/components/Create.jsx","./src/operations/common/components/DeleteWithConfirm.tsx","./src/operations/common/components/Edit.jsx","./src/operations/common/components/EmptyList.tsx","./src/operations/common/components/EmptyListComponent.tsx","./src/operations/common/components/FileDownloader.tsx","./src/operations/common/components/FileUploadDialog.tsx","./src/operations/common/components/FloatingActionButton.tsx","./src/operations/common/components/GeoLocalisation.jsx","./src/operations/common/components/HaDateField.tsx","./src/operations/common/components/ListHeader.tsx","./src/operations/common/components/Loader.tsx","./src/operations/common/components/PdfViewer.jsx","./src/operations/common/components/ProfileLayout.tsx","./src/operations/common/components/Show.jsx","./src/operations/common/components/StudentListWithBulkActions.tsx","./src/operations/common/components/SuspendedStudentAlert.tsx","./src/operations/common/components/Title.tsx","./src/operations/common/components/hexToRgba.ts","./src/operations/common/components/index.jsx","./src/operations/common/components/fields/BirthDateField.jsx","./src/operations/common/components/fields/DateField.jsx","./src/operations/common/components/fields/DateTimeField.tsx","./src/operations/common/components/fields/FieldLabel.jsx","./src/operations/common/components/fields/HaField.jsx","./src/operations/common/components/fields/index.jsx","./src/operations/common/components/profilContent/AbsenceDetailDialog.tsx","./src/operations/common/components/profilContent/ContactDetails.tsx","./src/operations/common/components/profilContent/InformationContent.tsx","./src/operations/common/components/profilContent/PersonalDetails.tsx","./src/operations/common/components/profilContent/PersonalInfos.tsx","./src/operations/common/components/profilContent/ProfilCardAvatar.tsx","./src/operations/common/components/profilContent/StudentParticipationList.tsx","./src/operations/common/components/profilContent/utils.ts","./src/operations/common/components/resource-flows/InsertButton.tsx","./src/operations/common/components/resource-flows/LeaveButton.tsx","./src/operations/common/components/resource-flows/MigrateButton.tsx","./src/operations/common/components/resource-flows/ResourceFlowsContext.tsx","./src/operations/common/components/resource-flows/index.tsx","./src/operations/common/components/resource-flows/useResourceFlowsContext.tsx","./src/operations/common/components/resource-flows/components/DialogActions.tsx","./src/operations/common/components/resource-flows/components/FlowsDialog.tsx","./src/operations/common/components/resource-flows/components/index.tsx","./src/operations/common/utils/commonListHeaderContent.jsx","./src/operations/common/utils/money.ts","./src/operations/common/utils/strinfigy-obj.ts","./src/operations/common/utils/types.ts","./src/operations/common/utils/typo_util.js","./src/operations/cor/CorCreate.tsx","./src/operations/cor/CorDetails.tsx","./src/operations/cor/CorEditButton.tsx","./src/operations/cor/CorFields.tsx","./src/operations/cor/CorList.tsx","./src/operations/cor/CorStudentList.tsx","./src/operations/cor/index.ts","./src/operations/cor/index2.ts","./src/operations/cor/components/AddCorComment.tsx","./src/operations/cor/components/CorButtonAction.tsx","./src/operations/cor/components/CustomAutocompleteArrayInput.tsx","./src/operations/cor/components/StatusChip.tsx","./src/operations/cor/components/StudentAutocompleteInput.tsx","./src/operations/cor/utils/constants.ts","./src/operations/course/CourseCreate.tsx","./src/operations/course/CourseEditButton.tsx","./src/operations/course/CourseList.tsx","./src/operations/course/CourseShow.jsx","./src/operations/course/index.tsx","./src/operations/course/components/CourseListFilter.tsx","./src/operations/course/components/index.tsx","./src/operations/course/utils/constants.ts","./src/operations/dashboard/Dashboard.tsx","./src/operations/dashboard/components/AdminWelcome.tsx","./src/operations/dashboard/components/common/CommentContent.tsx","./src/operations/dashboard/components/common/RecentLetters.tsx","./src/operations/dashboard/components/common/WelcomingCard.tsx","./src/operations/docs/components/DocCreateDialog.jsx","./src/operations/docs/components/DocList.tsx","./src/operations/docs/components/DocShow.tsx","./src/operations/docs/components/SelectWorkStatus.jsx","./src/operations/docs/components/SelectWorkType.jsx","./src/operations/docs/hooks/useViewType.js","./src/operations/docs/staffs/DocShow.tsx","./src/operations/docs/staffs/DockList.tsx","./src/operations/docs/staffs/index.ts","./src/operations/docs/students/DocList.jsx","./src/operations/docs/students/DocShow.jsx","./src/operations/docs/students/index.jsx","./src/operations/docs/teachers/DocList.tsx","./src/operations/docs/teachers/DocShow.tsx","./src/operations/docs/teachers/index.ts","./src/operations/docs/types/OwnerType.ts","./src/operations/docs/types/index.jsx","./src/operations/docs/utils/doc-list-title.ts","./src/operations/events/EventCalendar.tsx","./src/operations/events/EventCreate.tsx","./src/operations/events/EventEditDialog.tsx","./src/operations/events/EventList.tsx","./src/operations/events/EventMissingList.tsx","./src/operations/events/EventParticipantList.tsx","./src/operations/events/index.ts","./src/operations/events/utils.ts","./src/operations/events/components/AbsenceDetailDialogForStaff.tsx","./src/operations/events/components/Actions.tsx","./src/operations/events/components/AddGroup.tsx","./src/operations/events/components/EventCard.tsx","./src/operations/events/components/EventJustificateModal.tsx","./src/operations/events/components/EventListAction.tsx","./src/operations/events/components/EventLoaderCalendar.tsx","./src/operations/events/components/EventMissingFilter.tsx","./src/operations/events/components/EventParticipantsFilter.tsx","./src/operations/events/components/ImportStatusDialog.tsx","./src/operations/events/components/ListContent.tsx","./src/operations/events/components/MultiCheckBoxFilter.tsx","./src/operations/events/components/SelectClassrroom.tsx","./src/operations/events/components/SelectCourse.tsx","./src/operations/events/components/SelectIsOnline.tsx","./src/operations/events/components/SelectPlanner.tsx","./src/operations/events/components/Stats.tsx","./src/operations/events/components/index.ts","./src/operations/exams/ExamCreate.tsx","./src/operations/exams/ExamEdit.tsx","./src/operations/exams/ExamList.tsx","./src/operations/exams/index.ts","./src/operations/exams/components/index.ts","./src/operations/exams/components/cards/ExamCard.tsx","./src/operations/exams/components/cards/index.ts","./src/operations/exams/components/dialogs/index.ts","./src/operations/exams/components/dialogs/ExamEditDialog/index.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/CoefficientSection.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/CourseAssignmentSection.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/ExamDetailsSection.tsx","./src/operations/exams/components/filters/ExamFilter.tsx","./src/operations/exams/components/filters/index.ts","./src/operations/exams/components/selectors/SelectCourseAssignment.tsx","./src/operations/exams/components/selectors/SelectTeacher.tsx","./src/operations/exams/components/selectors/index.ts","./src/operations/exams/hooks/index.ts","./src/operations/exams/hooks/useExamEdit.ts","./src/operations/exams/utils/constants.ts","./src/operations/exams/utils/index.ts","./src/operations/exams/utils/validation.ts","./src/operations/fees/ByStatusFeeList.tsx","./src/operations/fees/FeeCreate.jsx","./src/operations/fees/FeeEdit.tsx","./src/operations/fees/FeeList.jsx","./src/operations/fees/FeeShow.tsx","./src/operations/fees/MultipleStudentFeesCreate.tsx","./src/operations/fees/TransactionFeeList.tsx","./src/operations/fees/constants.ts","./src/operations/fees/importConf.js","./src/operations/fees/index.jsx","./src/operations/fees/types.ts","./src/operations/fees/components/FeeInputs.tsx","./src/operations/fees/components/FeeStatsHeader.tsx","./src/operations/fees/components/FeeStatsTable.tsx","./src/operations/fees/components/FeesActions.tsx","./src/operations/fees/components/FeesDialog.tsx","./src/operations/fees/components/FeesFilter.tsx","./src/operations/fees/components/FeesListHeader.tsx","./src/operations/fees/components/ManagerFeeList.jsx","./src/operations/fees/components/OrangeMoneyHeader.tsx","./src/operations/fees/components/SelectDueDatetime.jsx","./src/operations/fees/components/SelectPredefinedType.jsx","./src/operations/fees/components/StatsStatus.tsx","./src/operations/fees/components/StatusFilterButtons.tsx","./src/operations/fees/components/StudentFeeList.tsx","./src/operations/fees/components/StyleFeeStat.ts","./src/operations/fees/components/index.jsx","./src/operations/fees/components/letterIcon.jsx","./src/operations/fees/components/pspIcon.tsx","./src/operations/fees/components/useFeeStatistics.ts","./src/operations/fees/components/Credits/CreditTransactionList.tsx","./src/operations/fees/utils/DateRangePopover.tsx","./src/operations/fees/utils/FeeFilterChips.tsx","./src/operations/fees/utils/FeeImportDialog.tsx","./src/operations/fees/utils/FeeStatsUtils.ts","./src/operations/fees/utils/FeesExport.tsx","./src/operations/fees/utils/MonthToFilter.tsx","./src/operations/fees/utils/StatusIcon.jsx","./src/operations/fees/utils/commonStyle.js","./src/operations/fees/utils/feeFactory.js","./src/operations/fees/utils/gridStyle.tsx","./src/operations/fees/utils/index.js","./src/operations/fees/utils/pspValues.tsx","./src/operations/fees/utils/remedialCostsConf.js","./src/operations/feesTemplates/FeesTemplateCreate.tsx","./src/operations/feesTemplates/FeesTemplatesEdit.tsx","./src/operations/feesTemplates/FeesTemplatesList.jsx","./src/operations/feesTemplates/index.jsx","./src/operations/grades/ExamParticipantList.tsx","./src/operations/grades/GradesDashboard.tsx","./src/operations/grades/index.js","./src/operations/grades/components/CoursesListView.tsx","./src/operations/grades/components/ExamDetailChip.tsx","./src/operations/grades/components/ExamDetails.tsx","./src/operations/grades/components/ExamGradeListActions.jsx","./src/operations/grades/components/ExamHeader.tsx","./src/operations/grades/components/ExamLoadError.jsx","./src/operations/grades/components/GlobalSummaryView.tsx","./src/operations/grades/components/GradeEditButton.tsx","./src/operations/grades/components/GradeEditForm.tsx","./src/operations/grades/components/GradeHistoryDialog.tsx","./src/operations/grades/components/GradeHistoryItem.tsx","./src/operations/grades/components/GradesDetails.tsx","./src/operations/grades/components/ImportResultDialog.tsx","./src/operations/grades/components/ParticipantsDataGrid.tsx","./src/operations/grades/components/ResultTimeline.tsx","./src/operations/grades/components/TranscriptOverview.tsx","./src/operations/grades/components/UploadGradeResponse.tsx","./src/operations/grades/components/YearlyView.tsx","./src/operations/grades/components/index.js","./src/operations/grades/components/utils.tsx","./src/operations/grades/types/types.ts","./src/operations/grades/utils/StatusChip.ts","./src/operations/grades/utils/TableMessageRow.tsx","./src/operations/grades/utils/constants.js","./src/operations/grades/utils/getGradeColor.ts","./src/operations/grades/utils/getStatusChipProps.tsx","./src/operations/grades/utils/helpers.js","./src/operations/grades/utils/index.js","./src/operations/grades/utils/utils.tsx","./src/operations/groups/GroupCreate.tsx","./src/operations/groups/GroupEdit.tsx","./src/operations/groups/GroupList.jsx","./src/operations/groups/GroupShow.tsx","./src/operations/groups/index.jsx","./src/operations/groups/components/GroupFilters.jsx","./src/operations/groups/components/GroupFlowCreate.jsx","./src/operations/groups/components/GroupStudentFilters.jsx","./src/operations/groups/components/GroupStudentList.jsx","./src/operations/groups/components/MigrateStudent.jsx","./src/operations/letters/CreateLetters.tsx","./src/operations/letters/LetterShow.tsx","./src/operations/letters/LettersList.tsx","./src/operations/letters/UserLettersList.tsx","./src/operations/letters/types.tsx","./src/operations/letters/components/AcceptWithConfirm.tsx","./src/operations/letters/components/BulkActions.tsx","./src/operations/letters/components/HeaderLetterList.tsx","./src/operations/letters/components/LetterItem.tsx","./src/operations/letters/components/LetterListView.tsx","./src/operations/letters/components/LettersFilter.tsx","./src/operations/letters/components/RefuseButton.tsx","./src/operations/letters/components/index.ts","./src/operations/monitors/MonitorCreate.tsx","./src/operations/monitors/MonitorList.tsx","./src/operations/monitors/MonitorListContent.tsx","./src/operations/monitors/MonitorShow.jsx","./src/operations/monitors/MonitorTabs.tsx","./src/operations/monitors/UnlinkedStudentsList.tsx","./src/operations/monitors/index.jsx","./src/operations/monitors/component/InsertStudentToMonitor.jsx","./src/operations/monitors/component/LinkActions.tsx","./src/operations/monitors/component/MonitorStudentList.tsx","./src/operations/monitors/component/index.jsx","./src/operations/payments/PaymentCreate.jsx","./src/operations/payments/PaymentList.jsx","./src/operations/payments/index.jsx","./src/operations/profile/ProfileEdit.tsx","./src/operations/profile/ProfileShow.tsx","./src/operations/profile/index.jsx","./src/operations/profile/components/GenerateReceiptDialog.tsx","./src/operations/profile/components/ProfileFilters.jsx","./src/operations/promotions/PromotionCreate.tsx","./src/operations/promotions/PromotionEditButton.tsx","./src/operations/promotions/PromotionList.tsx","./src/operations/promotions/PromotionShow.tsx","./src/operations/promotions/index.tsx","./src/operations/promotions/components/PromotionGroupList.tsx","./src/operations/promotions/components/PromotionListFilter.tsx","./src/operations/promotions/components/index.ts","./src/operations/promotions/utils/constant.ts","./src/operations/public/Calendar.tsx","./src/operations/public/index.tsx","./src/operations/public/utils/dateFormats.ts","./src/operations/public/utils/dayPropGetter.ts","./src/operations/public/utils/eventStyleGetter.ts","./src/operations/public/utils/frenchMessage.ts","./src/operations/public/utils/index.ts","./src/operations/public/utils/transformApiDataToCalendarEvents.ts","./src/operations/retakeExamCourses/index.ts","./src/operations/retakeExamCourses/retakeExamCourseList.tsx","./src/operations/retakeExamParticipants/RetakeExamParticipantShow.tsx","./src/operations/retakeExamParticipants/components/CourseInfo.tsx","./src/operations/retakeExamParticipants/components/RetakeExamParticipantList.tsx","./src/operations/retakeExamParticipants/components/index.ts","./src/operations/retakeExamSessions/RetakeExamSessionCreate.tsx","./src/operations/retakeExamSessions/RetakeExamSessionEdit.tsx","./src/operations/retakeExamSessions/RetakeExamSessionList.tsx","./src/operations/retakeExamSessions/RetakeExamSessionShow.tsx","./src/operations/retakeExamSessions/index.ts","./src/operations/retakeExamSessions/components/ListeRetakeExamForSpecificStudentBar.tsx","./src/operations/retakeExamSessions/components/PendingCancellationBar.tsx","./src/operations/retakeExamSessions/components/RetakeExamSessionActions.tsx","./src/operations/retakeExamSessions/components/RetakeExamSessionForm.tsx","./src/operations/retakeExamSessions/components/RoleBasedEditButton.tsx","./src/operations/retakeExamSessions/components/RoleBasedShowButton.tsx","./src/operations/retakeExamSessions/components/index.ts","./src/operations/retakeExams/CancellationRetakeExam.tsx","./src/operations/retakeExams/ListRetakeExamsForStudentSpecific.tsx","./src/operations/retakeExams/RetakeExamListShow.tsx","./src/operations/retakeExams/index.ts","./src/operations/retakeExams/components/RetakeExamButtonStatus.tsx","./src/operations/retakeExams/components/RetakeExamButtons.tsx","./src/operations/retakeExams/components/index.ts","./src/operations/retakeExams/components/useButtonActions.tsx","./src/operations/staffMembers/StaffCreate.tsx","./src/operations/staffMembers/StaffList.tsx","./src/operations/staffMembers/StaffShow.tsx","./src/operations/staffMembers/index.tsx","./src/operations/students/StudentCreate.jsx","./src/operations/students/StudentList.tsx","./src/operations/students/StudentShow.jsx","./src/operations/students/constants.ts","./src/operations/students/importConf.jsx","./src/operations/students/index.jsx","./src/operations/students/components/DocMenu.jsx","./src/operations/students/components/GetCertificate.tsx","./src/operations/students/components/GetReceipt.jsx","./src/operations/students/components/SelectSpecialization.jsx","./src/operations/students/components/index.jsx","./src/operations/students/utils/StudentFilterExport.tsx","./src/operations/students/utils/isOver18.ts","./src/operations/students/utils/studentFactory.js","./src/operations/studentsResultOverviews/PromotionOverviewList.tsx","./src/operations/studentsResultOverviews/StudentsResultOvergviewList.tsx","./src/operations/studentsResultOverviews/index.ts","./src/operations/teachers/TeacherCreate.jsx","./src/operations/teachers/TeacherList.tsx","./src/operations/teachers/TeacherShow.tsx","./src/operations/teachers/index.jsx","./src/operations/utils/CustomAutoComplete.jsx","./src/operations/utils/CustomBreadcrumbs.tsx","./src/operations/utils/CustomCommentTextField.jsx","./src/operations/utils/EditToolBar.jsx","./src/operations/utils/IconButtonWithTooltip.tsx","./src/operations/utils/SexRadioButton.jsx","./src/operations/utils/UserStatusRadioButton.jsx","./src/operations/utils/commentRenderer.ts","./src/operations/utils/exporter.js","./src/operations/utils/importer.js","./src/operations/utils/index.jsx","./src/operations/utils/paymentTypeRenderer.js","./src/operations/utils/pspIdValidationContraints.tsx","./src/operations/utils/typography.jsx","./src/operations/utils/userImportConf.js","./src/providers/HaDataProviderType.ts","./src/providers/announcementProvider.ts","./src/providers/api.js","./src/providers/authProvider.ts","./src/providers/aws-config.js","./src/providers/commentProvider.ts","./src/providers/constants.js","./src/providers/corProvider.ts","./src/providers/corStudentProvider.ts","./src/providers/correctGradeProvider.ts","./src/providers/courseAssignementbyTeacher.ts","./src/providers/courseAssignmentsProvider.ts","./src/providers/courseProvider.ts","./src/providers/createGradeProvider.ts","./src/providers/dataProvider.ts","./src/providers/docsProvider.ts","./src/providers/eventParticipantProvider.ts","./src/providers/eventProvider.ts","./src/providers/examGradeProvider.ts","./src/providers/examProvider.ts","./src/providers/exportEventParticipantProvider.ts","./src/providers/exportGroupProvider.ts","./src/providers/exportPromotionProvider.ts","./src/providers/exportStudentProvider.ts","./src/providers/exportTeacherProvider.ts","./src/providers/feeProvider.ts","./src/providers/feesExportProvider.ts","./src/providers/feesTemplatesProvider.ts","./src/providers/gradeImportProvider.ts","./src/providers/gradeProvider.ts","./src/providers/gradesDetailsProvider.ts","./src/providers/groupFlowProvider.ts","./src/providers/groupProvider.ts","./src/providers/groupStudentProvider.ts","./src/providers/heiDocsProvider.ts","./src/providers/letterStatsProvider.ts","./src/providers/lettersProvider.ts","./src/providers/missingListProvider.ts","./src/providers/monitorProvider.ts","./src/providers/monitorStudentProvider.ts","./src/providers/mpbsVerifyProvider.ts","./src/providers/paymentProvider.ts","./src/providers/profilePicProvider.ts","./src/providers/profileProvider.ts","./src/providers/promotionFlowProvider.ts","./src/providers/promotionGroupsProvider.ts","./src/providers/promotionProvider.ts","./src/providers/receiptProvider.ts","./src/providers/resultSummaryProvider.ts","./src/providers/retakeExamCoursesProvider.ts","./src/providers/retakeExamParticipantProvider.ts","./src/providers/retakeExamProvider.ts","./src/providers/retakeExamSessionProvider.ts","./src/providers/searchProvider.ts","./src/providers/staffExportProvider.ts","./src/providers/staffProvider.ts","./src/providers/statsProvider.ts","./src/providers/studentCreditProvider.tsx","./src/providers/studentImportProvider.ts","./src/providers/studentParticipationProvider.ts","./src/providers/studentProvider.ts","./src/providers/studentRetakeExamsProvider.ts","./src/providers/studentsResultOverviewsProvider.ts","./src/providers/teacherProvider.ts","./src/providers/types.ts","./src/providers/unlinkedStudentProvider.ts","./src/providers/usersLettersProvider.ts","./src/providers/utils.js","./src/security/CasdoorAuth.tsx","./src/security/CasdoorLoginButton.tsx","./src/security/CasdoorLoginCard.tsx","./src/security/LoginPage.jsx","./src/security/casdoorSetting.js","./src/security/permissions.ts","./src/security/utils.jsx","./src/security/hooks/index.js","./src/security/hooks/useRole.js","./src/security/waf/AwsWafCaptchaHandler.tsx","./src/security/waf/HumanVerification.tsx","./src/security/waf/conf.ts","./src/security/waf/index.js","./src/types/dom-to-image-more.d.ts","./src/ui/components/AlertBar.tsx","./src/ui/components/Dialog.tsx","./src/ui/components/EmptyList.tsx","./src/ui/components/ResponsiveGrid.tsx","./src/ui/components/index.tsx","./src/ui/components/inputs/Autocomplete.tsx","./src/ui/components/inputs/AutocompleteArrayInput.tsx","./src/ui/components/inputs/AutocompleteInput.tsx","./src/ui/components/inputs/MultipleAutocomplete.tsx","./src/ui/components/inputs/index.tsx","./src/ui/constants/common_styles.js","./src/ui/constants/index.js","./src/ui/constants/typography.js","./src/ui/haLayout/HaLayout.jsx","./src/ui/haLayout/index.jsx","./src/ui/haLayout/appBar/GlobalSearch.tsx","./src/ui/haLayout/appBar/HaAppBar.jsx","./src/ui/haLayout/appBar/UserInfo.tsx","./src/ui/haLayout/appBar/index.jsx","./src/ui/haLayout/appBar/component/ProfilePicture.tsx","./src/ui/haLayout/appBar/component/SearchBarStyles.ts","./src/ui/haLayout/appBar/component/SearchComponents.tsx","./src/ui/haLayout/appBar/component/index.ts","./src/ui/haLayout/appBar/component/useGlobalSearch.ts","./src/ui/haLayout/appBar/utils/searchUtils.ts","./src/ui/haLayout/menu/AdminMenu.tsx","./src/ui/haLayout/menu/HaMenuContent.jsx","./src/ui/haLayout/menu/ManagerMenu.tsx","./src/ui/haLayout/menu/MonitorMenu.tsx","./src/ui/haLayout/menu/OrganizerMenu.tsx","./src/ui/haLayout/menu/StaffMenu.jsx","./src/ui/haLayout/menu/StudentMenu.tsx","./src/ui/haLayout/menu/TeacherMenu.jsx","./src/ui/haLayout/menu/common/HeiListMenuItem.tsx","./src/ui/haLayout/menu/common/index.ts","./src/ui/haLayout/menu/utils/HaMenu.tsx","./src/ui/haLayout/menu/utils/ListMenu.jsx","./src/ui/haLayout/menu/utils/ListMenuItem.tsx","./src/ui/haLayout/menu/utils/SingleMenu.tsx","./src/ui/haLayout/menu/utils/index.jsx","./src/ui/haList/HaList.jsx","./src/ui/haList/HaListTitle.jsx","./src/ui/haList/HaMainSearch.jsx","./src/ui/haList/PrevNextPagination.tsx","./src/ui/haList/index.jsx","./src/ui/haList/useHaListContext.tsx","./src/ui/haToolbar/AutocompleteFilter.jsx","./src/ui/haToolbar/Button.jsx","./src/ui/haToolbar/DataTimeFilter.tsx","./src/ui/haToolbar/FilterForm.jsx","./src/ui/haToolbar/FilterFormContent.jsx","./src/ui/haToolbar/Filters.jsx","./src/ui/haToolbar/LiveFilter.jsx","./src/ui/haToolbar/SelectFilter.jsx","./src/ui/haToolbar/index.jsx","./src/ui/haToolbar/useHaToolbarContext.jsx","./src/ui/haToolbar/importButton/ImportButton.jsx","./src/ui/haToolbar/importButton/ImportDialog.jsx","./src/ui/haToolbar/importButton/ImportInputFile.jsx","./src/ui/haToolbar/importButton/NewImportButton.tsx","./src/ui/haToolbar/importButton/index.jsx","./src/ui/haToolbar/importButton/utils.js","./src/ui/haToolbar/utils/Items.jsx","./src/utils/constants.js","./src/utils/date.js","./src/utils/files.js","./src/utils/formatDateToTimeZone.ts","./src/utils/getObjValue.ts","./src/utils/gtm.js","./src/utils/index.js","./src/utils/mapToChoices.ts","./src/utils/noop.js","./src/utils/stringify.ts","./cypress/e2e/admin.docs.cy.tsx","./cypress/e2e/admin.staff.cy.ts","./cypress/e2e/admin.welcome.cy.tsx","./cypress/e2e/authentification.cy.tsx","./cypress/e2e/certificate.cy.tsx","./cypress/e2e/comments.cy.tsx","./cypress/e2e/cor.manager.cy.ts","./cypress/e2e/download.cy.tsx","./cypress/e2e/event.manager.cy.tsx","./cypress/e2e/event.student.cy.tsx","./cypress/e2e/event.teacher.cy.tsx","./cypress/e2e/exam.card.cy.tsx","./cypress/e2e/exam.participant.list.cy.tsx","./cypress/e2e/function.cy.ts","./cypress/e2e/grade-overview.cy.ts","./cypress/e2e/grades.components.cy.tsx","./cypress/e2e/helpers.cy.ts","./cypress/e2e/importConf.cy.ts","./cypress/e2e/letter.event.cy.tsx","./cypress/e2e/letters.manager.cy.tsx","./cypress/e2e/letters.users.cy.tsx","./cypress/e2e/manager.announcements.cy.tsx","./cypress/e2e/manager.course.cy.tsx","./cypress/e2e/manager.cy.tsx","./cypress/e2e/manager.docs.cy.tsx","./cypress/e2e/manager.fees.cy.tsx","./cypress/e2e/manager.fees.import.cy.tsx","./cypress/e2e/manager.fees.mpbs.cy.tsx","./cypress/e2e/manager.fees.templates.cy.tsx","./cypress/e2e/manager.groups.cy.tsx","./cypress/e2e/manager.monitor.cy.tsx","./cypress/e2e/manager.payments.cy.tsx","./cypress/e2e/manager.promotions.cy.tsx","./cypress/e2e/manager.students.cy.tsx","./cypress/e2e/manager.teachers.cy.tsx","./cypress/e2e/manager.teachers.import.cy.tsx","./cypress/e2e/monitor.cy.tsx","./cypress/e2e/notification.cy.tsx","./cypress/e2e/profil.picture.cy.tsx","./cypress/e2e/profile.cy.tsx","./cypress/e2e/public-link.cy.tsx","./cypress/e2e/receipt.cy.tsx","./cypress/e2e/student.announcements.cy.tsx","./cypress/e2e/student.cy.tsx","./cypress/e2e/student.docs.cy.tsx","./cypress/e2e/student.fees.letter.tsx","./cypress/e2e/student.fees.mpbs.cy.tsx","./cypress/e2e/teacher.announcements.cy.tsx","./cypress/e2e/teacher.course.cy.tsx","./cypress/e2e/teacher.cy.tsx","./cypress/e2e/utils.tsx","./cypress/fixtures/api_mocks/admins-mock.ts","./cypress/fixtures/api_mocks/advanceStats-mocks.ts","./cypress/fixtures/api_mocks/announcement-mocks.ts","./cypress/fixtures/api_mocks/authentification-mocks.ts","./cypress/fixtures/api_mocks/calendar-mock.ts","./cypress/fixtures/api_mocks/comment-mocks.ts","./cypress/fixtures/api_mocks/cor-mock.ts","./cypress/fixtures/api_mocks/course-assignment-mocks.ts","./cypress/fixtures/api_mocks/course-mocks.ts","./cypress/fixtures/api_mocks/docs-mocks.ts","./cypress/fixtures/api_mocks/event-mocks.ts","./cypress/fixtures/api_mocks/exam-grade-mocks.ts","./cypress/fixtures/api_mocks/exam-mocks.ts","./cypress/fixtures/api_mocks/fees-mocks.ts","./cypress/fixtures/api_mocks/fees-stats.ts","./cypress/fixtures/api_mocks/fees-templates-mocks.ts","./cypress/fixtures/api_mocks/grades-mocks.ts","./cypress/fixtures/api_mocks/groups-mocks.ts","./cypress/fixtures/api_mocks/letters-mocks.ts","./cypress/fixtures/api_mocks/managers-mocks.ts","./cypress/fixtures/api_mocks/missing-participants-mock.ts","./cypress/fixtures/api_mocks/monitors-mock.ts","./cypress/fixtures/api_mocks/organizers-mock.ts","./cypress/fixtures/api_mocks/payments-mocks.ts","./cypress/fixtures/api_mocks/profil-mocks.ts","./cypress/fixtures/api_mocks/promotions-mocks.ts","./cypress/fixtures/api_mocks/staffs-mock.ts","./cypress/fixtures/api_mocks/students-mocks.ts","./cypress/fixtures/api_mocks/summary-result-mocks.ts","./cypress/fixtures/api_mocks/teachers-mocks.ts","./cypress/support/commands.ts","./cypress/support/component.ts","./cypress/support/e2e.ts","./cypress/support/global.d.ts"],"errors":true,"version":"6.0.3"} \ No newline at end of file diff --git a/vite.config.d.ts b/vite.config.d.ts new file mode 100644 index 000000000..089eeef96 --- /dev/null +++ b/vite.config.d.ts @@ -0,0 +1,2 @@ +declare const _default: import("vite").UserConfigFnObject; +export default _default; diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 000000000..496768a16 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,47 @@ +import react from "@vitejs/plugin-react"; +import path from "path"; +import { defineConfig, loadEnv } from "vite"; +import istanbul from "vite-plugin-istanbul"; +import { nodePolyfills } from "vite-plugin-node-polyfills"; +// https://vitejs.dev/config/ +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ""); + return { + plugins: [ + react(), + nodePolyfills({ include: ["crypto", "os", "path", "stream", "vm"] }), + istanbul({ + requireEnv: false, + cypress: true, + include: "src/*", + exclude: ["node_modules", "cypress", "src/**/*.cy.*"], + extension: [".js", ".jsx", ".ts", ".tsx"], + }), + ], + define: { + "process.env": env, + }, + optimizeDeps: { + entries: ["cypress/**/*", "src/**/*"], + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + build: { + outDir: "build", + sourcemap: true, + rollupOptions: { + output: { + sourcemap: false, + }, + }, + }, + server: { + watch: { + ignored: ["**/coverage/**"], + }, + }, + }; +}); From c31132591bbb464743315d91aea35476f6c0d1b8 Mon Sep 17 00:00:00 2001 From: DyferHerioss Date: Tue, 11 Aug 2026 21:16:34 +0300 Subject: [PATCH 4/7] feat: list credit payment --- cypress/e2e/manager.payments.credit.cy.tsx | 198 ++++++++++++++++++ .../api_mocks/credit-payments-mocks.ts | 47 +++++ src/App.jsx | 6 + .../dashboard/components/AdminWelcome.tsx | 2 + .../common/PendingCreditPayments.tsx | 95 +++++++++ .../fees/components/StudentFeeList.tsx | 113 +++++++++- src/operations/fees/constants.ts | 8 + src/operations/payments/CreditPaymentList.tsx | 73 +++++++ src/operations/payments/PaymentCreate.jsx | 39 +--- src/operations/payments/PaymentList.jsx | 6 + .../components/CreditPaymentActions.tsx | 117 +++++++++++ .../CreditPaymentStatusFilterButtons.tsx | 47 +++++ .../payments/components/PaymentStatusIcon.tsx | 43 ++++ src/operations/payments/index.jsx | 2 + .../payments/utils/validateCredit.ts | 67 ++++++ src/providers/creditPaymentProvider.ts | 132 ++++++++++++ src/providers/dataProvider.ts | 2 + src/providers/studentParticipationProvider.ts | 21 +- .../studentsResultOverviewsProvider.ts | 12 +- src/ui/haLayout/menu/AdminMenu.tsx | 7 + src/ui/haLayout/menu/ManagerMenu.tsx | 6 + src/ui/haList/HaList.jsx | 2 + src/ui/haList/HaListTitle.jsx | 2 + tsconfig.tsbuildinfo | 2 +- 24 files changed, 988 insertions(+), 61 deletions(-) create mode 100644 cypress/e2e/manager.payments.credit.cy.tsx create mode 100644 cypress/fixtures/api_mocks/credit-payments-mocks.ts create mode 100644 src/operations/dashboard/components/common/PendingCreditPayments.tsx create mode 100644 src/operations/payments/CreditPaymentList.tsx create mode 100644 src/operations/payments/components/CreditPaymentActions.tsx create mode 100644 src/operations/payments/components/CreditPaymentStatusFilterButtons.tsx create mode 100644 src/operations/payments/components/PaymentStatusIcon.tsx create mode 100644 src/operations/payments/utils/validateCredit.ts create mode 100644 src/providers/creditPaymentProvider.ts diff --git a/cypress/e2e/manager.payments.credit.cy.tsx b/cypress/e2e/manager.payments.credit.cy.tsx new file mode 100644 index 000000000..efe0e8bfa --- /dev/null +++ b/cypress/e2e/manager.payments.credit.cy.tsx @@ -0,0 +1,198 @@ +import {PaymentStatus} from "@haapi-b0fc7615/typescript-client"; +import { + creditPaymentPendingMock, + creditPaymentRejectedMock, + creditPaymentValidatedMock, + creditPaymentsByStatusMock, + studentCreditMock, +} from "../fixtures/api_mocks/credit-payments-mocks"; +import {fee1Mock, feesMock} from "../fixtures/api_mocks/fees-mocks"; +import { + createPaymentMock, + createPaymentWithAmountMock, +} from "../fixtures/api_mocks/payments-mocks"; +import {student1Mock, studentsMock} from "../fixtures/api_mocks/students-mocks"; + +const amount = 1 + Math.floor(Math.random() * 100_000); +const createPayment = createPaymentWithAmountMock(amount); + +describe("Manager.Payments.Flow", () => { + beforeEach(() => { + cy.mockLogin({role: "MANAGER"}); + cy.visit("/profile"); + cy.intercept("GET", `/students?page=1&page_size=10`, studentsMock).as( + "getStudents" + ); + cy.intercept( + "GET", + `/students?page=1&page_size=10&first_name=${student1Mock.first_name}`, + [student1Mock] + ).as("getStudentsByFirstName"); + cy.intercept("GET", `/students/${student1Mock.id}`, student1Mock); + cy.intercept("GET", `/students/${student1Mock.id}/level`, "L1").as( + "getStudentLevel" + ); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=1&page_size=10`, + feesMock + ).as("getFees"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=2&page_size=10`, + feesMock + ).as("getFees2"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/credit`, + studentCreditMock + ).as("getStudentCredit"); + + cy.getByTestid("students-menu").click(); + cy.get('a[href="/students"]').click(); + cy.wait("@getStudents"); + cy.getByTestid("menu-list-action").click(); + cy.getByTestid("add-filter").click(); + cy.getByTestid("filter-profile-first_name").type(student1Mock.first_name); + cy.getByTestid("apply-filter").click(); + cy.contains(student1Mock.first_name).click(); + }); + + it("can show a fee's detail and its list of payments", () => { + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}`, + fee1Mock + ).as("getFee1"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}/payments?page=1&page_size=10`, + createPaymentMock(fee1Mock) + ).as("getPayments"); + + cy.getByTestid("fees-tab").click(); + cy.wait("@getFees"); + cy.get( + ".manager-fee-list .RaDatagrid-clickableRow.MuiTableRow-root:nth-child(1)" + ).click(); + cy.wait("@getFee1"); + + cy.get("#main-content") + .should("contain", `${fee1Mock.remaining_amount} Ar`) + .and("contain", `${fee1Mock.total_amount} Ar`) + .and("contain", fee1Mock.comment) + .and("contain", "Paiements"); + + cy.wait("@getPayments"); + cy.get("table").contains("Comment"); + }); + + it("can create a cash payment for a fee", () => { + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}`, + fee1Mock + ).as("getFee1"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}/payments?page=1&page_size=10`, + [] + ).as("getPayments"); + cy.intercept( + "POST", + `/students/${student1Mock.id}/fees/${fee1Mock.id}/payments`, + [createPayment] + ).as("createPayment"); + + cy.getByTestid("fees-tab").click(); + cy.wait("@getFees"); + cy.get( + ".manager-fee-list .RaDatagrid-clickableRow.MuiTableRow-root:nth-child(1)" + ).click(); + cy.wait("@getFee1"); + cy.wait("@getPayments"); + + cy.contains("Créer").click(); + cy.wait("@getStudentCredit"); + + cy.get("#type_CASH").click(); + cy.get("#amount").click().type(createPayment.amount!.toString()); + cy.get("#comment").click().type(createPayment.comment!); + cy.contains("Enregistrer").click(); + + cy.wait("@createPayment"); + cy.contains("Élément créé"); + }); +}); + +describe("Manager.CreditPayments", () => { + beforeEach(() => { + cy.mockLogin({role: "MANAGER"}); + cy.visit("/profile"); + + cy.intercept("GET", `/fees?page=1&page_size=500`, { + data: [{...fee1Mock, student_ref: student1Mock.ref}], + }).as("getFeesForEnrichment"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/credit`, + studentCreditMock + ).as("getStudentCredit"); + + Object.values(PaymentStatus).forEach((status) => { + cy.intercept( + "GET", + `/students/credit-payments?status=${status}&page=1&page_size=500`, + creditPaymentsByStatusMock[status] + ).as(`getAllCreditPayments_${status}`); + cy.intercept( + "GET", + `/students/credit-payments?status=${status}&page=1&page_size=10`, + creditPaymentsByStatusMock[status] + ).as(`getFilteredCreditPayments_${status}`); + }); + + cy.getByTestid("students-menu").click(); + cy.get('a[href="/credit-payments"]').click(); + }); + + it("lists credit payments with the most recent first when no filter is applied", () => { + cy.wait("@getAllCreditPayments_CREATED"); + cy.wait("@getAllCreditPayments_VALIDATE"); + cy.wait("@getAllCreditPayments_INVALIDATE"); + + cy.get("table tbody tr") + .eq(0) + .should("contain", creditPaymentPendingMock.comment); + cy.get("table tbody tr") + .eq(1) + .should("contain", creditPaymentValidatedMock.comment); + cy.get("table tbody tr") + .eq(2) + .should("contain", creditPaymentRejectedMock.comment); + }); + + it("can filter credit payments by status", () => { + cy.contains("button", "En attente").click(); + cy.wait("@getFilteredCreditPayments_CREATED"); + cy.contains(creditPaymentPendingMock.comment!); + cy.contains(creditPaymentValidatedMock.comment!).should("not.exist"); + cy.contains(creditPaymentRejectedMock.comment!).should("not.exist"); + + cy.contains("button", "Validés").click(); + cy.wait("@getFilteredCreditPayments_VALIDATE"); + cy.contains(creditPaymentValidatedMock.comment!); + cy.contains(creditPaymentPendingMock.comment!).should("not.exist"); + + cy.contains("button", "Rejetés").click(); + cy.wait("@getFilteredCreditPayments_INVALIDATE"); + cy.contains(creditPaymentRejectedMock.comment!); + cy.contains(creditPaymentValidatedMock.comment!).should("not.exist"); + + cy.contains("button", "Tous").click(); + cy.wait("@getAllCreditPayments_CREATED"); + cy.contains(creditPaymentPendingMock.comment!); + cy.contains(creditPaymentValidatedMock.comment!); + cy.contains(creditPaymentRejectedMock.comment!); + }); +}); diff --git a/cypress/fixtures/api_mocks/credit-payments-mocks.ts b/cypress/fixtures/api_mocks/credit-payments-mocks.ts new file mode 100644 index 000000000..af529fd34 --- /dev/null +++ b/cypress/fixtures/api_mocks/credit-payments-mocks.ts @@ -0,0 +1,47 @@ +import { + Payment, + PaymentStatus, + PaymentTypeEnum, +} from "@haapi-b0fc7615/typescript-client"; +import {fee1Mock} from "./fees-mocks"; + +export const creditPaymentPendingMock: Payment = { + id: "credit_payment_pending_id", + fee_id: fee1Mock.id, + creation_datetime: new Date("2024-01-10T08:00:00Z"), + type: PaymentTypeEnum.CREDIT, + status: PaymentStatus.CREATED, + amount: 50000, + comment: "Paiement par crédit en attente", +}; + +export const creditPaymentValidatedMock: Payment = { + id: "credit_payment_validated_id", + fee_id: fee1Mock.id, + creation_datetime: new Date("2024-01-05T08:00:00Z"), + type: PaymentTypeEnum.CREDIT, + status: PaymentStatus.VALIDATE, + amount: 80000, + comment: "Paiement par crédit validé", +}; + +export const creditPaymentRejectedMock: Payment = { + id: "credit_payment_rejected_id", + fee_id: fee1Mock.id, + creation_datetime: new Date("2024-01-01T08:00:00Z"), + type: PaymentTypeEnum.CREDIT, + status: PaymentStatus.INVALIDATE, + amount: 30000, + comment: "Paiement par crédit rejeté", +}; + +export const creditPaymentsByStatusMock: Record = { + [PaymentStatus.CREATED]: [creditPaymentPendingMock], + [PaymentStatus.VALIDATE]: [creditPaymentValidatedMock], + [PaymentStatus.INVALIDATE]: [creditPaymentRejectedMock], +}; + +export const studentCreditMock = { + id: "credit1_id", + amount: 500000, +}; diff --git a/src/App.jsx b/src/App.jsx index 7cd694364..397a9057c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -125,6 +125,12 @@ function AppBase() { element={} /> + } + /> + { + = ({animate}) => { + const role = useRole(); + + const {data: pendingPayments} = useGetList( + "credit-payments", + { + filter: {status: PaymentStatus.CREATED}, + pagination: {page: 1, perPage: 500}, + }, + { + enabled: role.isManager() || role.isAdmin(), + } + ); + + const pendingCount = pendingPayments?.length ?? 0; + + return ( + + + + + + Paiements par crédit à valider + + + + + + + + + + + + + ); +}; diff --git a/src/operations/payments/components/CreditPaymentStatusFilterButtons.tsx b/src/operations/payments/components/CreditPaymentStatusFilterButtons.tsx new file mode 100644 index 000000000..5c570d09b --- /dev/null +++ b/src/operations/payments/components/CreditPaymentStatusFilterButtons.tsx @@ -0,0 +1,47 @@ +import {PaymentStatus} from "@haapi-b0fc7615/typescript-client"; +import {Button, ButtonProps, Stack} from "@mui/material"; +import {useListContext} from "react-admin"; + +const STATUS_FILTERS: { + label: string; + value?: PaymentStatus; + color: ButtonProps["color"]; +}[] = [ + {label: "Tous", color: "primary"}, + {label: "En attente", value: PaymentStatus.CREATED, color: "warning"}, + {label: "Validés", value: PaymentStatus.VALIDATE, color: "success"}, + {label: "Rejetés", value: PaymentStatus.INVALIDATE, color: "error"}, +]; + +export const CreditPaymentStatusFilterButtons = () => { + const {filterValues, setFilters} = useListContext(); + + return ( + + {STATUS_FILTERS.map((filter) => { + const onClick = () => { + const nextFilters = {...filterValues, status: filter.value}; + if (!filter.value) { + delete nextFilters.status; + } + setFilters(nextFilters, {}); + }; + + return ( + + ); + })} + + ); +}; diff --git a/src/operations/payments/components/PaymentStatusIcon.tsx b/src/operations/payments/components/PaymentStatusIcon.tsx new file mode 100644 index 000000000..d8f66e976 --- /dev/null +++ b/src/operations/payments/components/PaymentStatusIcon.tsx @@ -0,0 +1,43 @@ +import {mapToChoices} from "@/utils/mapToChoices"; +import {PaymentStatus} from "@haapi-b0fc7615/typescript-client"; +import {Cancel, CheckCircle, HourglassEmpty} from "@mui/icons-material"; +import {IconButton, Tooltip} from "@mui/material"; +import {useRecordContext} from "react-admin"; + +export const PAYMENT_STATUS_ICON: Record = { + [PaymentStatus.CREATED]: , + [PaymentStatus.VALIDATE]: , + [PaymentStatus.INVALIDATE]: , +}; + +export const PAYMENT_STATUS_LABEL: Record = { + [PaymentStatus.CREATED]: "Paiement en attente de validation", + [PaymentStatus.VALIDATE]: "Paiement validé", + [PaymentStatus.INVALIDATE]: "Paiement rejeté", +}; + +export const PAYMENT_STATUS_CHOICES = mapToChoices( + PAYMENT_STATUS_LABEL, + "id", + "name" +); + +export const PaymentStatusIcon = () => { + const record = useRecordContext(); + const status = record?.status as PaymentStatus | undefined; + + return ( + + + {status ? ( + PAYMENT_STATUS_ICON[status] + ) : ( + + )} + + + ); +}; diff --git a/src/operations/payments/index.jsx b/src/operations/payments/index.jsx index 95f273140..ce437aa22 100644 --- a/src/operations/payments/index.jsx +++ b/src/operations/payments/index.jsx @@ -1,9 +1,11 @@ import {AttachMoney} from "@mui/icons-material"; +import CreditPaymentList from "./CreditPaymentList"; import PaymentCreate from "./PaymentCreate"; import PaymentList from "./PaymentList"; const payments = { list: PaymentList, + listCreditPayments: CreditPaymentList, create: PaymentCreate, icon: AttachMoney, options: {label: "Paiements"}, diff --git a/src/operations/payments/utils/validateCredit.ts b/src/operations/payments/utils/validateCredit.ts new file mode 100644 index 000000000..c960d1cfd --- /dev/null +++ b/src/operations/payments/utils/validateCredit.ts @@ -0,0 +1,67 @@ +import {useCallback, useEffect, useState} from "react"; +import {useDataProvider} from "react-admin"; +import {Credit} from "@haapi-b0fc7615/typescript-client"; + +export const MINIMUM_CREDIT = 200000; + +export const hasEnoughCredit = (credit: Credit | null | undefined): boolean => { + return !!credit && (credit.amount ?? 0) >= MINIMUM_CREDIT; +}; + +export const validateAmountAgainstCredit = ( + amount: number | string, + credit: Credit | null | undefined +): string | undefined => { + if (!credit) { + return undefined; + } + + if (!hasEnoughCredit(credit)) { + return `Votre crédit est inférieur à ${MINIMUM_CREDIT}Ar.`; + } + + if (Number(amount) > (credit.amount ?? 0)) { + return "Le montant saisi est supérieur à votre crédit actuel."; + } + + return undefined; +}; + +export const useStudentCredit = (studentId: string | number) => { + const dataProvider = useDataProvider(); + + const [credit, setCredit] = useState(null); + + const getStudentCredit = useCallback(async () => { + if (!studentId) { + setCredit(null); + return null; + } + + const result = await dataProvider.getOne("credits", { + id: studentId, + }); + + const studentCredit = result.data as Credit; + + setCredit(studentCredit); + + return studentCredit; + }, [studentId, dataProvider]); + + useEffect(() => { + getStudentCredit(); + }, [getStudentCredit]); + + const canPayByCredit = hasEnoughCredit(credit); + + const validateCreditPayment = (amount: number | string) => + validateAmountAgainstCredit(amount, credit); + + return { + credit, + canPayByCredit, + getStudentCredit, + validateCreditPayment, + }; +}; \ No newline at end of file diff --git a/src/providers/creditPaymentProvider.ts b/src/providers/creditPaymentProvider.ts new file mode 100644 index 000000000..1146dab97 --- /dev/null +++ b/src/providers/creditPaymentProvider.ts @@ -0,0 +1,132 @@ +import {Payment, PaymentStatus} from "@haapi-b0fc7615/typescript-client"; +import {payingApi} from "./api"; +import {HaDataProviderType} from "./HaDataProviderType"; + +const ALL_STATUSES = Object.values(PaymentStatus); +const FETCH_ALL_PAGE_SIZE = 500; + +const sortByCreationDateDesc = (payments: Payment[]): Payment[] => + [...payments].sort( + (a, b) => + new Date(b.creation_datetime ?? 0).getTime() - + new Date(a.creation_datetime ?? 0).getTime() + ); + +const fetchAllCreditPayments = async (): Promise => { + const resultsByStatus = await Promise.all( + ALL_STATUSES.map((status) => + payingApi().getCreditPaymentsByStatus(status, 1, FETCH_ALL_PAGE_SIZE) + ) + ); + + return sortByCreationDateDesc( + resultsByStatus.flatMap((result) => result.data) + ); +}; + +type StudentInfo = {student_ref?: string; student_credit?: number}; + +const findStudentInfoByPayment = async ( + payments: Payment[] +): Promise> => { + const feesResult = await payingApi().getFees( + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + 1, + FETCH_ALL_PAGE_SIZE + ); + const fees = feesResult.data.data ?? []; + const feeById = new Map(fees.map((fee) => [fee.id, fee])); + + const studentIds = [ + ...new Set( + payments + .map((payment) => feeById.get(payment.fee_id!)?.student_id) + .filter((studentId): studentId is string => !!studentId) + ), + ]; + + const credits = await Promise.all( + studentIds.map((studentId) => payingApi().getCreditByStudentId(studentId)) + ); + + const creditByStudentId = new Map( + studentIds.map((studentId, index) => [ + studentId, + credits[index].data.amount, + ]) + ); + + return new Map( + payments.map((payment) => { + const fee = feeById.get(payment.fee_id!); + return [ + payment.id!, + { + student_ref: fee?.student_ref, + student_credit: fee?.student_id + ? creditByStudentId.get(fee.student_id) + : undefined, + }, + ]; + }) + ); +}; + +const enrichWithStudentInfo = async ( + payments: Payment[] +): Promise<(Payment & StudentInfo)[]> => { + if (!payments.length) { + return []; + } + + const studentInfoByPaymentId = await findStudentInfoByPayment(payments); + + return payments.map((payment) => ({ + ...payment, + ...studentInfoByPaymentId.get(payment.id!), + })); +}; + +const creditPaymentProvider: HaDataProviderType = { + getList: async ( + page: number, + perPage: number, + filter: {status?: PaymentStatus} = {} + ) => { + if (filter.status) { + const result = await payingApi().getCreditPaymentsByStatus( + filter.status, + page, + perPage + ); + + return { + data: await enrichWithStudentInfo(sortByCreationDateDesc(result.data)), + }; + } + + const allPayments = await fetchAllCreditPayments(); + const start = (page - 1) * perPage; + const pagePayments = allPayments.slice(start, start + perPage); + + return { + data: await enrichWithStudentInfo(pagePayments), + }; + }, + getOne: () => { + throw new Error("Function not implemented."); + }, + saveOrUpdate: () => { + throw new Error("Function not implemented."); + }, + delete: () => { + throw new Error("Function not implemented."); + }, +}; + +export default creditPaymentProvider; diff --git a/src/providers/dataProvider.ts b/src/providers/dataProvider.ts index 4fd71c2cd..1ea8b5b23 100644 --- a/src/providers/dataProvider.ts +++ b/src/providers/dataProvider.ts @@ -6,6 +6,7 @@ import corStudentProvider from "@/providers/corStudentProvider"; import {courseAssignmentsByTeacherProvider} from "@/providers/courseAssignementbyTeacher"; import CourseAssignmentsProvider from "@/providers/courseAssignmentsProvider"; import courseProvider from "@/providers/courseProvider"; +import creditPaymentProvider from "@/providers/creditPaymentProvider"; import docsProvider from "@/providers/docsProvider"; import eventParticipantProvider from "@/providers/eventParticipantProvider"; import eventProvider from "@/providers/eventProvider"; @@ -66,6 +67,7 @@ const providerMap = { "students-export": exportStudentProvider, "fees": feeProvider, "payments": paymentProvider, + "credit-payments": creditPaymentProvider, "teachers": teacherProvider, "export-teachers": exportTeacherProvider, "docs": docsProvider, diff --git a/src/providers/studentParticipationProvider.ts b/src/providers/studentParticipationProvider.ts index 173192a35..c3b8b9b55 100644 --- a/src/providers/studentParticipationProvider.ts +++ b/src/providers/studentParticipationProvider.ts @@ -1,20 +1,11 @@ -import {AttendanceStatus} from "@haapi-b0fc7615/typescript-client"; +import { + AttendanceStatus, + StudentGlobalAttendance, +} from "@haapi-b0fc7615/typescript-client"; import {attendanceApi} from "./api"; import {HaDataProviderType} from "./HaDataProviderType"; -type AttendanceRecord = { - id?: string; - _id?: string; - attendance_status: AttendanceStatus; - begin_datetime: string; - end_datetime: string; - event_type: string; - title: string; - description?: string; - location?: string; -}; - const StudentParticipationProvider: HaDataProviderType = { getList: async ( _page: number, @@ -34,8 +25,8 @@ const StudentParticipationProvider: HaDataProviderType = { return attendanceApi() .getStudentAttendance(from, to, id, attendanceStatus, titleParam) .then(({data}) => ({ - data: data.map((record: AttendanceRecord, index: number) => ({ - id: record.id ?? record._id ?? `${record.begin_datetime}-${index}`, + data: data.map((record: StudentGlobalAttendance, index: number) => ({ + id: record.id ?? `${record.begin_datetime}-${index}`, attendanceStatus: record.attendance_status, beginDatetime: record.begin_datetime, endDatetime: record.end_datetime, diff --git a/src/providers/studentsResultOverviewsProvider.ts b/src/providers/studentsResultOverviewsProvider.ts index d840f08d2..c601a3057 100644 --- a/src/providers/studentsResultOverviewsProvider.ts +++ b/src/providers/studentsResultOverviewsProvider.ts @@ -1,4 +1,7 @@ -import {ResultOverviewStatus} from "@haapi-b0fc7615/typescript-client"; +import { + ResultOverviewStatus, + StudentResultOverview, +} from "@haapi-b0fc7615/typescript-client"; import {usersApi} from "./api"; import {HaDataProviderType} from "./HaDataProviderType"; @@ -13,12 +16,9 @@ const studentsResultOverviewProvider: HaDataProviderType = { .getStudentsResultOverviewsByStatus(promotionId, status, page, perPage) .then((response) => ({ data: response.data.map( - ( - item: {id: string; _id: string; studentId: string}, - index: number - ) => ({ + (item: StudentResultOverview, index: number) => ({ ...item, - id: item.id ?? item._id ?? item.studentId ?? index, + id: item.student?.id ?? item.student?.ref ?? index, }) ), })); diff --git a/src/ui/haLayout/menu/AdminMenu.tsx b/src/ui/haLayout/menu/AdminMenu.tsx index 6cb3523db..df50ee70a 100644 --- a/src/ui/haLayout/menu/AdminMenu.tsx +++ b/src/ui/haLayout/menu/AdminMenu.tsx @@ -3,6 +3,7 @@ import {HeiListMenuItem} from "@/ui/haLayout/menu/common"; import {ListMenu, ListMenuItem, SingleMenu} from "@/ui/haLayout/menu/utils"; import {trackNavClick} from "@/utils/gtm"; import { + AccountBalanceWallet as CreditPaymentsIcon, Newspaper as AnnouncementIcon, Inventory as DocsIcon, EditCalendar, @@ -54,6 +55,12 @@ function AdminMenu() { to="/students" onClick={() => trackNavClick("students_list", role)} /> + } + to="/credit-payments" + onClick={() => trackNavClick("payments_list", role)} + /> } diff --git a/src/ui/haLayout/menu/ManagerMenu.tsx b/src/ui/haLayout/menu/ManagerMenu.tsx index 308af3c8d..0d1ecae14 100644 --- a/src/ui/haLayout/menu/ManagerMenu.tsx +++ b/src/ui/haLayout/menu/ManagerMenu.tsx @@ -2,6 +2,7 @@ import {HeiListMenuItem} from "@/ui/haLayout/menu/common"; import {ListMenu, ListMenuItem, SingleMenu} from "@/ui/haLayout/menu/utils"; import { Newspaper as AnnouncementIcon, + AccountBalanceWallet as CreditPaymentsIcon, SafetyDivider as CorIcon, Inventory as DocsIcon, EditCalendar, @@ -46,6 +47,11 @@ function ManagerMenu() { icon={} to="/transactions" /> + } + to="/credit-payments" + /> } diff --git a/src/ui/haList/HaList.jsx b/src/ui/haList/HaList.jsx index 78cad056d..3dbd68f09 100644 --- a/src/ui/haList/HaList.jsx +++ b/src/ui/haList/HaList.jsx @@ -54,6 +54,7 @@ export function HaList({ datagridProps = {}, mainSearch = {source: "", label: ""}, filterIndicator = true, + filterButtons = /** @type {import("react").ReactNode} */ (null), }) { return ( @@ -77,6 +78,7 @@ export function HaList({ title={title} icon={icon} mainSearch={mainSearch} + filterButtons={filterButtons} /> {hasDatagrid ? ( diff --git a/src/ui/haList/HaListTitle.jsx b/src/ui/haList/HaListTitle.jsx index cece14178..0b04e8147 100644 --- a/src/ui/haList/HaListTitle.jsx +++ b/src/ui/haList/HaListTitle.jsx @@ -32,6 +32,7 @@ export function HaListTitle({ actions, mainSearch, filterIndicator, + filterButtons = /** @type {import("react").ReactNode} */ (null), }) { const [showAction, setShowAction] = useState(null); const {filterValues} = useListFilterContext(); @@ -61,6 +62,7 @@ export function HaListTitle({ {title} + {filterButtons && {filterButtons}} {mainSearch.source !== "" && ( diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo index 93b8d59cc..0bd93067e 100644 --- a/tsconfig.tsbuildinfo +++ b/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/App.jsx","./src/conf.js","./src/haTheme.js","./src/main.tsx","./src/vite-env.d.ts","./src/config/axios.ts","./src/config/env.ts","./src/hooks/index.js","./src/hooks/useNotify.ts","./src/hooks/useStudentRef.js","./src/hooks/useTabManager.ts","./src/hooks/useToggle.ts","./src/operations/CourseAssignments/AssignedTeachersList.tsx","./src/operations/CourseAssignments/CourseAssignmentsCreate.tsx","./src/operations/CourseAssignments/TeacherCourseList.tsx","./src/operations/CourseAssignments/index.tsx","./src/operations/announcements/AnnouncementCreate.tsx","./src/operations/announcements/AnnouncementList.tsx","./src/operations/announcements/AnnouncementShow.tsx","./src/operations/announcements/index.ts","./src/operations/announcements/components/AnnoucementCard.tsx","./src/operations/announcements/components/AnnouncementsFilter.tsx","./src/operations/announcements/components/EmailField.tsx","./src/operations/announcements/components/SelectGroup.tsx","./src/operations/announcements/components/SelectScope.tsx","./src/operations/announcements/components/index.ts","./src/operations/announcements/utils/getBgImg.tsx","./src/operations/announcements/utils/constants/announcementsScopes.tsx","./src/operations/comments/CommentCreate.jsx","./src/operations/comments/CommentList.jsx","./src/operations/comments/StudentComments.tsx","./src/operations/comments/index.js","./src/operations/comments/utils.jsx","./src/operations/common/components/ArchiveWithConfirm.tsx","./src/operations/common/components/ChipRadio.tsx","./src/operations/common/components/ColorInput.tsx","./src/operations/common/components/Create.jsx","./src/operations/common/components/DeleteWithConfirm.tsx","./src/operations/common/components/Edit.jsx","./src/operations/common/components/EmptyList.tsx","./src/operations/common/components/EmptyListComponent.tsx","./src/operations/common/components/FileDownloader.tsx","./src/operations/common/components/FileUploadDialog.tsx","./src/operations/common/components/FloatingActionButton.tsx","./src/operations/common/components/GeoLocalisation.jsx","./src/operations/common/components/HaDateField.tsx","./src/operations/common/components/ListHeader.tsx","./src/operations/common/components/Loader.tsx","./src/operations/common/components/PdfViewer.jsx","./src/operations/common/components/ProfileLayout.tsx","./src/operations/common/components/Show.jsx","./src/operations/common/components/StudentListWithBulkActions.tsx","./src/operations/common/components/SuspendedStudentAlert.tsx","./src/operations/common/components/Title.tsx","./src/operations/common/components/hexToRgba.ts","./src/operations/common/components/index.jsx","./src/operations/common/components/fields/BirthDateField.jsx","./src/operations/common/components/fields/DateField.jsx","./src/operations/common/components/fields/DateTimeField.tsx","./src/operations/common/components/fields/FieldLabel.jsx","./src/operations/common/components/fields/HaField.jsx","./src/operations/common/components/fields/index.jsx","./src/operations/common/components/profilContent/AbsenceDetailDialog.tsx","./src/operations/common/components/profilContent/ContactDetails.tsx","./src/operations/common/components/profilContent/InformationContent.tsx","./src/operations/common/components/profilContent/PersonalDetails.tsx","./src/operations/common/components/profilContent/PersonalInfos.tsx","./src/operations/common/components/profilContent/ProfilCardAvatar.tsx","./src/operations/common/components/profilContent/StudentParticipationList.tsx","./src/operations/common/components/profilContent/utils.ts","./src/operations/common/components/resource-flows/InsertButton.tsx","./src/operations/common/components/resource-flows/LeaveButton.tsx","./src/operations/common/components/resource-flows/MigrateButton.tsx","./src/operations/common/components/resource-flows/ResourceFlowsContext.tsx","./src/operations/common/components/resource-flows/index.tsx","./src/operations/common/components/resource-flows/useResourceFlowsContext.tsx","./src/operations/common/components/resource-flows/components/DialogActions.tsx","./src/operations/common/components/resource-flows/components/FlowsDialog.tsx","./src/operations/common/components/resource-flows/components/index.tsx","./src/operations/common/utils/commonListHeaderContent.jsx","./src/operations/common/utils/money.ts","./src/operations/common/utils/strinfigy-obj.ts","./src/operations/common/utils/types.ts","./src/operations/common/utils/typo_util.js","./src/operations/cor/CorCreate.tsx","./src/operations/cor/CorDetails.tsx","./src/operations/cor/CorEditButton.tsx","./src/operations/cor/CorFields.tsx","./src/operations/cor/CorList.tsx","./src/operations/cor/CorStudentList.tsx","./src/operations/cor/index.ts","./src/operations/cor/index2.ts","./src/operations/cor/components/AddCorComment.tsx","./src/operations/cor/components/CorButtonAction.tsx","./src/operations/cor/components/CustomAutocompleteArrayInput.tsx","./src/operations/cor/components/StatusChip.tsx","./src/operations/cor/components/StudentAutocompleteInput.tsx","./src/operations/cor/utils/constants.ts","./src/operations/course/CourseCreate.tsx","./src/operations/course/CourseEditButton.tsx","./src/operations/course/CourseList.tsx","./src/operations/course/CourseShow.jsx","./src/operations/course/index.tsx","./src/operations/course/components/CourseListFilter.tsx","./src/operations/course/components/index.tsx","./src/operations/course/utils/constants.ts","./src/operations/dashboard/Dashboard.tsx","./src/operations/dashboard/components/AdminWelcome.tsx","./src/operations/dashboard/components/common/CommentContent.tsx","./src/operations/dashboard/components/common/RecentLetters.tsx","./src/operations/dashboard/components/common/WelcomingCard.tsx","./src/operations/docs/components/DocCreateDialog.jsx","./src/operations/docs/components/DocList.tsx","./src/operations/docs/components/DocShow.tsx","./src/operations/docs/components/SelectWorkStatus.jsx","./src/operations/docs/components/SelectWorkType.jsx","./src/operations/docs/hooks/useViewType.js","./src/operations/docs/staffs/DocShow.tsx","./src/operations/docs/staffs/DockList.tsx","./src/operations/docs/staffs/index.ts","./src/operations/docs/students/DocList.jsx","./src/operations/docs/students/DocShow.jsx","./src/operations/docs/students/index.jsx","./src/operations/docs/teachers/DocList.tsx","./src/operations/docs/teachers/DocShow.tsx","./src/operations/docs/teachers/index.ts","./src/operations/docs/types/OwnerType.ts","./src/operations/docs/types/index.jsx","./src/operations/docs/utils/doc-list-title.ts","./src/operations/events/EventCalendar.tsx","./src/operations/events/EventCreate.tsx","./src/operations/events/EventEditDialog.tsx","./src/operations/events/EventList.tsx","./src/operations/events/EventMissingList.tsx","./src/operations/events/EventParticipantList.tsx","./src/operations/events/index.ts","./src/operations/events/utils.ts","./src/operations/events/components/AbsenceDetailDialogForStaff.tsx","./src/operations/events/components/Actions.tsx","./src/operations/events/components/AddGroup.tsx","./src/operations/events/components/EventCard.tsx","./src/operations/events/components/EventJustificateModal.tsx","./src/operations/events/components/EventListAction.tsx","./src/operations/events/components/EventLoaderCalendar.tsx","./src/operations/events/components/EventMissingFilter.tsx","./src/operations/events/components/EventParticipantsFilter.tsx","./src/operations/events/components/ImportStatusDialog.tsx","./src/operations/events/components/ListContent.tsx","./src/operations/events/components/MultiCheckBoxFilter.tsx","./src/operations/events/components/SelectClassrroom.tsx","./src/operations/events/components/SelectCourse.tsx","./src/operations/events/components/SelectIsOnline.tsx","./src/operations/events/components/SelectPlanner.tsx","./src/operations/events/components/Stats.tsx","./src/operations/events/components/index.ts","./src/operations/exams/ExamCreate.tsx","./src/operations/exams/ExamEdit.tsx","./src/operations/exams/ExamList.tsx","./src/operations/exams/index.ts","./src/operations/exams/components/index.ts","./src/operations/exams/components/cards/ExamCard.tsx","./src/operations/exams/components/cards/index.ts","./src/operations/exams/components/dialogs/index.ts","./src/operations/exams/components/dialogs/ExamEditDialog/index.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/CoefficientSection.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/CourseAssignmentSection.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/ExamDetailsSection.tsx","./src/operations/exams/components/filters/ExamFilter.tsx","./src/operations/exams/components/filters/index.ts","./src/operations/exams/components/selectors/SelectCourseAssignment.tsx","./src/operations/exams/components/selectors/SelectTeacher.tsx","./src/operations/exams/components/selectors/index.ts","./src/operations/exams/hooks/index.ts","./src/operations/exams/hooks/useExamEdit.ts","./src/operations/exams/utils/constants.ts","./src/operations/exams/utils/index.ts","./src/operations/exams/utils/validation.ts","./src/operations/fees/ByStatusFeeList.tsx","./src/operations/fees/FeeCreate.jsx","./src/operations/fees/FeeEdit.tsx","./src/operations/fees/FeeList.jsx","./src/operations/fees/FeeShow.tsx","./src/operations/fees/MultipleStudentFeesCreate.tsx","./src/operations/fees/TransactionFeeList.tsx","./src/operations/fees/constants.ts","./src/operations/fees/importConf.js","./src/operations/fees/index.jsx","./src/operations/fees/types.ts","./src/operations/fees/components/FeeInputs.tsx","./src/operations/fees/components/FeeStatsHeader.tsx","./src/operations/fees/components/FeeStatsTable.tsx","./src/operations/fees/components/FeesActions.tsx","./src/operations/fees/components/FeesDialog.tsx","./src/operations/fees/components/FeesFilter.tsx","./src/operations/fees/components/FeesListHeader.tsx","./src/operations/fees/components/ManagerFeeList.jsx","./src/operations/fees/components/OrangeMoneyHeader.tsx","./src/operations/fees/components/SelectDueDatetime.jsx","./src/operations/fees/components/SelectPredefinedType.jsx","./src/operations/fees/components/StatsStatus.tsx","./src/operations/fees/components/StatusFilterButtons.tsx","./src/operations/fees/components/StudentFeeList.tsx","./src/operations/fees/components/StyleFeeStat.ts","./src/operations/fees/components/index.jsx","./src/operations/fees/components/letterIcon.jsx","./src/operations/fees/components/pspIcon.tsx","./src/operations/fees/components/useFeeStatistics.ts","./src/operations/fees/components/Credits/CreditTransactionList.tsx","./src/operations/fees/utils/DateRangePopover.tsx","./src/operations/fees/utils/FeeFilterChips.tsx","./src/operations/fees/utils/FeeImportDialog.tsx","./src/operations/fees/utils/FeeStatsUtils.ts","./src/operations/fees/utils/FeesExport.tsx","./src/operations/fees/utils/MonthToFilter.tsx","./src/operations/fees/utils/StatusIcon.jsx","./src/operations/fees/utils/commonStyle.js","./src/operations/fees/utils/feeFactory.js","./src/operations/fees/utils/gridStyle.tsx","./src/operations/fees/utils/index.js","./src/operations/fees/utils/pspValues.tsx","./src/operations/fees/utils/remedialCostsConf.js","./src/operations/feesTemplates/FeesTemplateCreate.tsx","./src/operations/feesTemplates/FeesTemplatesEdit.tsx","./src/operations/feesTemplates/FeesTemplatesList.jsx","./src/operations/feesTemplates/index.jsx","./src/operations/grades/ExamParticipantList.tsx","./src/operations/grades/GradesDashboard.tsx","./src/operations/grades/index.js","./src/operations/grades/components/CoursesListView.tsx","./src/operations/grades/components/ExamDetailChip.tsx","./src/operations/grades/components/ExamDetails.tsx","./src/operations/grades/components/ExamGradeListActions.jsx","./src/operations/grades/components/ExamHeader.tsx","./src/operations/grades/components/ExamLoadError.jsx","./src/operations/grades/components/GlobalSummaryView.tsx","./src/operations/grades/components/GradeEditButton.tsx","./src/operations/grades/components/GradeEditForm.tsx","./src/operations/grades/components/GradeHistoryDialog.tsx","./src/operations/grades/components/GradeHistoryItem.tsx","./src/operations/grades/components/GradesDetails.tsx","./src/operations/grades/components/ImportResultDialog.tsx","./src/operations/grades/components/ParticipantsDataGrid.tsx","./src/operations/grades/components/ResultTimeline.tsx","./src/operations/grades/components/TranscriptOverview.tsx","./src/operations/grades/components/UploadGradeResponse.tsx","./src/operations/grades/components/YearlyView.tsx","./src/operations/grades/components/index.js","./src/operations/grades/components/utils.tsx","./src/operations/grades/types/types.ts","./src/operations/grades/utils/StatusChip.ts","./src/operations/grades/utils/TableMessageRow.tsx","./src/operations/grades/utils/constants.js","./src/operations/grades/utils/getGradeColor.ts","./src/operations/grades/utils/getStatusChipProps.tsx","./src/operations/grades/utils/helpers.js","./src/operations/grades/utils/index.js","./src/operations/grades/utils/utils.tsx","./src/operations/groups/GroupCreate.tsx","./src/operations/groups/GroupEdit.tsx","./src/operations/groups/GroupList.jsx","./src/operations/groups/GroupShow.tsx","./src/operations/groups/index.jsx","./src/operations/groups/components/GroupFilters.jsx","./src/operations/groups/components/GroupFlowCreate.jsx","./src/operations/groups/components/GroupStudentFilters.jsx","./src/operations/groups/components/GroupStudentList.jsx","./src/operations/groups/components/MigrateStudent.jsx","./src/operations/letters/CreateLetters.tsx","./src/operations/letters/LetterShow.tsx","./src/operations/letters/LettersList.tsx","./src/operations/letters/UserLettersList.tsx","./src/operations/letters/types.tsx","./src/operations/letters/components/AcceptWithConfirm.tsx","./src/operations/letters/components/BulkActions.tsx","./src/operations/letters/components/HeaderLetterList.tsx","./src/operations/letters/components/LetterItem.tsx","./src/operations/letters/components/LetterListView.tsx","./src/operations/letters/components/LettersFilter.tsx","./src/operations/letters/components/RefuseButton.tsx","./src/operations/letters/components/index.ts","./src/operations/monitors/MonitorCreate.tsx","./src/operations/monitors/MonitorList.tsx","./src/operations/monitors/MonitorListContent.tsx","./src/operations/monitors/MonitorShow.jsx","./src/operations/monitors/MonitorTabs.tsx","./src/operations/monitors/UnlinkedStudentsList.tsx","./src/operations/monitors/index.jsx","./src/operations/monitors/component/InsertStudentToMonitor.jsx","./src/operations/monitors/component/LinkActions.tsx","./src/operations/monitors/component/MonitorStudentList.tsx","./src/operations/monitors/component/index.jsx","./src/operations/payments/PaymentCreate.jsx","./src/operations/payments/PaymentList.jsx","./src/operations/payments/index.jsx","./src/operations/profile/ProfileEdit.tsx","./src/operations/profile/ProfileShow.tsx","./src/operations/profile/index.jsx","./src/operations/profile/components/GenerateReceiptDialog.tsx","./src/operations/profile/components/ProfileFilters.jsx","./src/operations/promotions/PromotionCreate.tsx","./src/operations/promotions/PromotionEditButton.tsx","./src/operations/promotions/PromotionList.tsx","./src/operations/promotions/PromotionShow.tsx","./src/operations/promotions/index.tsx","./src/operations/promotions/components/PromotionGroupList.tsx","./src/operations/promotions/components/PromotionListFilter.tsx","./src/operations/promotions/components/index.ts","./src/operations/promotions/utils/constant.ts","./src/operations/public/Calendar.tsx","./src/operations/public/index.tsx","./src/operations/public/utils/dateFormats.ts","./src/operations/public/utils/dayPropGetter.ts","./src/operations/public/utils/eventStyleGetter.ts","./src/operations/public/utils/frenchMessage.ts","./src/operations/public/utils/index.ts","./src/operations/public/utils/transformApiDataToCalendarEvents.ts","./src/operations/retakeExamCourses/index.ts","./src/operations/retakeExamCourses/retakeExamCourseList.tsx","./src/operations/retakeExamParticipants/RetakeExamParticipantShow.tsx","./src/operations/retakeExamParticipants/components/CourseInfo.tsx","./src/operations/retakeExamParticipants/components/RetakeExamParticipantList.tsx","./src/operations/retakeExamParticipants/components/index.ts","./src/operations/retakeExamSessions/RetakeExamSessionCreate.tsx","./src/operations/retakeExamSessions/RetakeExamSessionEdit.tsx","./src/operations/retakeExamSessions/RetakeExamSessionList.tsx","./src/operations/retakeExamSessions/RetakeExamSessionShow.tsx","./src/operations/retakeExamSessions/index.ts","./src/operations/retakeExamSessions/components/ListeRetakeExamForSpecificStudentBar.tsx","./src/operations/retakeExamSessions/components/PendingCancellationBar.tsx","./src/operations/retakeExamSessions/components/RetakeExamSessionActions.tsx","./src/operations/retakeExamSessions/components/RetakeExamSessionForm.tsx","./src/operations/retakeExamSessions/components/RoleBasedEditButton.tsx","./src/operations/retakeExamSessions/components/RoleBasedShowButton.tsx","./src/operations/retakeExamSessions/components/index.ts","./src/operations/retakeExams/CancellationRetakeExam.tsx","./src/operations/retakeExams/ListRetakeExamsForStudentSpecific.tsx","./src/operations/retakeExams/RetakeExamListShow.tsx","./src/operations/retakeExams/index.ts","./src/operations/retakeExams/components/RetakeExamButtonStatus.tsx","./src/operations/retakeExams/components/RetakeExamButtons.tsx","./src/operations/retakeExams/components/index.ts","./src/operations/retakeExams/components/useButtonActions.tsx","./src/operations/staffMembers/StaffCreate.tsx","./src/operations/staffMembers/StaffList.tsx","./src/operations/staffMembers/StaffShow.tsx","./src/operations/staffMembers/index.tsx","./src/operations/students/StudentCreate.jsx","./src/operations/students/StudentList.tsx","./src/operations/students/StudentShow.jsx","./src/operations/students/constants.ts","./src/operations/students/importConf.jsx","./src/operations/students/index.jsx","./src/operations/students/components/DocMenu.jsx","./src/operations/students/components/GetCertificate.tsx","./src/operations/students/components/GetReceipt.jsx","./src/operations/students/components/SelectSpecialization.jsx","./src/operations/students/components/index.jsx","./src/operations/students/utils/StudentFilterExport.tsx","./src/operations/students/utils/isOver18.ts","./src/operations/students/utils/studentFactory.js","./src/operations/studentsResultOverviews/PromotionOverviewList.tsx","./src/operations/studentsResultOverviews/StudentsResultOvergviewList.tsx","./src/operations/studentsResultOverviews/index.ts","./src/operations/teachers/TeacherCreate.jsx","./src/operations/teachers/TeacherList.tsx","./src/operations/teachers/TeacherShow.tsx","./src/operations/teachers/index.jsx","./src/operations/utils/CustomAutoComplete.jsx","./src/operations/utils/CustomBreadcrumbs.tsx","./src/operations/utils/CustomCommentTextField.jsx","./src/operations/utils/EditToolBar.jsx","./src/operations/utils/IconButtonWithTooltip.tsx","./src/operations/utils/SexRadioButton.jsx","./src/operations/utils/UserStatusRadioButton.jsx","./src/operations/utils/commentRenderer.ts","./src/operations/utils/exporter.js","./src/operations/utils/importer.js","./src/operations/utils/index.jsx","./src/operations/utils/paymentTypeRenderer.js","./src/operations/utils/pspIdValidationContraints.tsx","./src/operations/utils/typography.jsx","./src/operations/utils/userImportConf.js","./src/providers/HaDataProviderType.ts","./src/providers/announcementProvider.ts","./src/providers/api.js","./src/providers/authProvider.ts","./src/providers/aws-config.js","./src/providers/commentProvider.ts","./src/providers/constants.js","./src/providers/corProvider.ts","./src/providers/corStudentProvider.ts","./src/providers/correctGradeProvider.ts","./src/providers/courseAssignementbyTeacher.ts","./src/providers/courseAssignmentsProvider.ts","./src/providers/courseProvider.ts","./src/providers/createGradeProvider.ts","./src/providers/dataProvider.ts","./src/providers/docsProvider.ts","./src/providers/eventParticipantProvider.ts","./src/providers/eventProvider.ts","./src/providers/examGradeProvider.ts","./src/providers/examProvider.ts","./src/providers/exportEventParticipantProvider.ts","./src/providers/exportGroupProvider.ts","./src/providers/exportPromotionProvider.ts","./src/providers/exportStudentProvider.ts","./src/providers/exportTeacherProvider.ts","./src/providers/feeProvider.ts","./src/providers/feesExportProvider.ts","./src/providers/feesTemplatesProvider.ts","./src/providers/gradeImportProvider.ts","./src/providers/gradeProvider.ts","./src/providers/gradesDetailsProvider.ts","./src/providers/groupFlowProvider.ts","./src/providers/groupProvider.ts","./src/providers/groupStudentProvider.ts","./src/providers/heiDocsProvider.ts","./src/providers/letterStatsProvider.ts","./src/providers/lettersProvider.ts","./src/providers/missingListProvider.ts","./src/providers/monitorProvider.ts","./src/providers/monitorStudentProvider.ts","./src/providers/mpbsVerifyProvider.ts","./src/providers/paymentProvider.ts","./src/providers/profilePicProvider.ts","./src/providers/profileProvider.ts","./src/providers/promotionFlowProvider.ts","./src/providers/promotionGroupsProvider.ts","./src/providers/promotionProvider.ts","./src/providers/receiptProvider.ts","./src/providers/resultSummaryProvider.ts","./src/providers/retakeExamCoursesProvider.ts","./src/providers/retakeExamParticipantProvider.ts","./src/providers/retakeExamProvider.ts","./src/providers/retakeExamSessionProvider.ts","./src/providers/searchProvider.ts","./src/providers/staffExportProvider.ts","./src/providers/staffProvider.ts","./src/providers/statsProvider.ts","./src/providers/studentCreditProvider.tsx","./src/providers/studentImportProvider.ts","./src/providers/studentParticipationProvider.ts","./src/providers/studentProvider.ts","./src/providers/studentRetakeExamsProvider.ts","./src/providers/studentsResultOverviewsProvider.ts","./src/providers/teacherProvider.ts","./src/providers/types.ts","./src/providers/unlinkedStudentProvider.ts","./src/providers/usersLettersProvider.ts","./src/providers/utils.js","./src/security/CasdoorAuth.tsx","./src/security/CasdoorLoginButton.tsx","./src/security/CasdoorLoginCard.tsx","./src/security/LoginPage.jsx","./src/security/casdoorSetting.js","./src/security/permissions.ts","./src/security/utils.jsx","./src/security/hooks/index.js","./src/security/hooks/useRole.js","./src/security/waf/AwsWafCaptchaHandler.tsx","./src/security/waf/HumanVerification.tsx","./src/security/waf/conf.ts","./src/security/waf/index.js","./src/types/dom-to-image-more.d.ts","./src/ui/components/AlertBar.tsx","./src/ui/components/Dialog.tsx","./src/ui/components/EmptyList.tsx","./src/ui/components/ResponsiveGrid.tsx","./src/ui/components/index.tsx","./src/ui/components/inputs/Autocomplete.tsx","./src/ui/components/inputs/AutocompleteArrayInput.tsx","./src/ui/components/inputs/AutocompleteInput.tsx","./src/ui/components/inputs/MultipleAutocomplete.tsx","./src/ui/components/inputs/index.tsx","./src/ui/constants/common_styles.js","./src/ui/constants/index.js","./src/ui/constants/typography.js","./src/ui/haLayout/HaLayout.jsx","./src/ui/haLayout/index.jsx","./src/ui/haLayout/appBar/GlobalSearch.tsx","./src/ui/haLayout/appBar/HaAppBar.jsx","./src/ui/haLayout/appBar/UserInfo.tsx","./src/ui/haLayout/appBar/index.jsx","./src/ui/haLayout/appBar/component/ProfilePicture.tsx","./src/ui/haLayout/appBar/component/SearchBarStyles.ts","./src/ui/haLayout/appBar/component/SearchComponents.tsx","./src/ui/haLayout/appBar/component/index.ts","./src/ui/haLayout/appBar/component/useGlobalSearch.ts","./src/ui/haLayout/appBar/utils/searchUtils.ts","./src/ui/haLayout/menu/AdminMenu.tsx","./src/ui/haLayout/menu/HaMenuContent.jsx","./src/ui/haLayout/menu/ManagerMenu.tsx","./src/ui/haLayout/menu/MonitorMenu.tsx","./src/ui/haLayout/menu/OrganizerMenu.tsx","./src/ui/haLayout/menu/StaffMenu.jsx","./src/ui/haLayout/menu/StudentMenu.tsx","./src/ui/haLayout/menu/TeacherMenu.jsx","./src/ui/haLayout/menu/common/HeiListMenuItem.tsx","./src/ui/haLayout/menu/common/index.ts","./src/ui/haLayout/menu/utils/HaMenu.tsx","./src/ui/haLayout/menu/utils/ListMenu.jsx","./src/ui/haLayout/menu/utils/ListMenuItem.tsx","./src/ui/haLayout/menu/utils/SingleMenu.tsx","./src/ui/haLayout/menu/utils/index.jsx","./src/ui/haList/HaList.jsx","./src/ui/haList/HaListTitle.jsx","./src/ui/haList/HaMainSearch.jsx","./src/ui/haList/PrevNextPagination.tsx","./src/ui/haList/index.jsx","./src/ui/haList/useHaListContext.tsx","./src/ui/haToolbar/AutocompleteFilter.jsx","./src/ui/haToolbar/Button.jsx","./src/ui/haToolbar/DataTimeFilter.tsx","./src/ui/haToolbar/FilterForm.jsx","./src/ui/haToolbar/FilterFormContent.jsx","./src/ui/haToolbar/Filters.jsx","./src/ui/haToolbar/LiveFilter.jsx","./src/ui/haToolbar/SelectFilter.jsx","./src/ui/haToolbar/index.jsx","./src/ui/haToolbar/useHaToolbarContext.jsx","./src/ui/haToolbar/importButton/ImportButton.jsx","./src/ui/haToolbar/importButton/ImportDialog.jsx","./src/ui/haToolbar/importButton/ImportInputFile.jsx","./src/ui/haToolbar/importButton/NewImportButton.tsx","./src/ui/haToolbar/importButton/index.jsx","./src/ui/haToolbar/importButton/utils.js","./src/ui/haToolbar/utils/Items.jsx","./src/utils/constants.js","./src/utils/date.js","./src/utils/files.js","./src/utils/formatDateToTimeZone.ts","./src/utils/getObjValue.ts","./src/utils/gtm.js","./src/utils/index.js","./src/utils/mapToChoices.ts","./src/utils/noop.js","./src/utils/stringify.ts","./cypress/e2e/admin.docs.cy.tsx","./cypress/e2e/admin.staff.cy.ts","./cypress/e2e/admin.welcome.cy.tsx","./cypress/e2e/authentification.cy.tsx","./cypress/e2e/certificate.cy.tsx","./cypress/e2e/comments.cy.tsx","./cypress/e2e/cor.manager.cy.ts","./cypress/e2e/download.cy.tsx","./cypress/e2e/event.manager.cy.tsx","./cypress/e2e/event.student.cy.tsx","./cypress/e2e/event.teacher.cy.tsx","./cypress/e2e/exam.card.cy.tsx","./cypress/e2e/exam.participant.list.cy.tsx","./cypress/e2e/function.cy.ts","./cypress/e2e/grade-overview.cy.ts","./cypress/e2e/grades.components.cy.tsx","./cypress/e2e/helpers.cy.ts","./cypress/e2e/importConf.cy.ts","./cypress/e2e/letter.event.cy.tsx","./cypress/e2e/letters.manager.cy.tsx","./cypress/e2e/letters.users.cy.tsx","./cypress/e2e/manager.announcements.cy.tsx","./cypress/e2e/manager.course.cy.tsx","./cypress/e2e/manager.cy.tsx","./cypress/e2e/manager.docs.cy.tsx","./cypress/e2e/manager.fees.cy.tsx","./cypress/e2e/manager.fees.import.cy.tsx","./cypress/e2e/manager.fees.mpbs.cy.tsx","./cypress/e2e/manager.fees.templates.cy.tsx","./cypress/e2e/manager.groups.cy.tsx","./cypress/e2e/manager.monitor.cy.tsx","./cypress/e2e/manager.payments.cy.tsx","./cypress/e2e/manager.promotions.cy.tsx","./cypress/e2e/manager.students.cy.tsx","./cypress/e2e/manager.teachers.cy.tsx","./cypress/e2e/manager.teachers.import.cy.tsx","./cypress/e2e/monitor.cy.tsx","./cypress/e2e/notification.cy.tsx","./cypress/e2e/profil.picture.cy.tsx","./cypress/e2e/profile.cy.tsx","./cypress/e2e/public-link.cy.tsx","./cypress/e2e/receipt.cy.tsx","./cypress/e2e/student.announcements.cy.tsx","./cypress/e2e/student.cy.tsx","./cypress/e2e/student.docs.cy.tsx","./cypress/e2e/student.fees.letter.tsx","./cypress/e2e/student.fees.mpbs.cy.tsx","./cypress/e2e/teacher.announcements.cy.tsx","./cypress/e2e/teacher.course.cy.tsx","./cypress/e2e/teacher.cy.tsx","./cypress/e2e/utils.tsx","./cypress/fixtures/api_mocks/admins-mock.ts","./cypress/fixtures/api_mocks/advanceStats-mocks.ts","./cypress/fixtures/api_mocks/announcement-mocks.ts","./cypress/fixtures/api_mocks/authentification-mocks.ts","./cypress/fixtures/api_mocks/calendar-mock.ts","./cypress/fixtures/api_mocks/comment-mocks.ts","./cypress/fixtures/api_mocks/cor-mock.ts","./cypress/fixtures/api_mocks/course-assignment-mocks.ts","./cypress/fixtures/api_mocks/course-mocks.ts","./cypress/fixtures/api_mocks/docs-mocks.ts","./cypress/fixtures/api_mocks/event-mocks.ts","./cypress/fixtures/api_mocks/exam-grade-mocks.ts","./cypress/fixtures/api_mocks/exam-mocks.ts","./cypress/fixtures/api_mocks/fees-mocks.ts","./cypress/fixtures/api_mocks/fees-stats.ts","./cypress/fixtures/api_mocks/fees-templates-mocks.ts","./cypress/fixtures/api_mocks/grades-mocks.ts","./cypress/fixtures/api_mocks/groups-mocks.ts","./cypress/fixtures/api_mocks/letters-mocks.ts","./cypress/fixtures/api_mocks/managers-mocks.ts","./cypress/fixtures/api_mocks/missing-participants-mock.ts","./cypress/fixtures/api_mocks/monitors-mock.ts","./cypress/fixtures/api_mocks/organizers-mock.ts","./cypress/fixtures/api_mocks/payments-mocks.ts","./cypress/fixtures/api_mocks/profil-mocks.ts","./cypress/fixtures/api_mocks/promotions-mocks.ts","./cypress/fixtures/api_mocks/staffs-mock.ts","./cypress/fixtures/api_mocks/students-mocks.ts","./cypress/fixtures/api_mocks/summary-result-mocks.ts","./cypress/fixtures/api_mocks/teachers-mocks.ts","./cypress/support/commands.ts","./cypress/support/component.ts","./cypress/support/e2e.ts","./cypress/support/global.d.ts"],"errors":true,"version":"6.0.3"} \ No newline at end of file +{"root":["./src/App.jsx","./src/conf.js","./src/haTheme.js","./src/main.tsx","./src/vite-env.d.ts","./src/config/axios.ts","./src/config/env.ts","./src/hooks/index.js","./src/hooks/useNotify.ts","./src/hooks/useStudentRef.js","./src/hooks/useTabManager.ts","./src/hooks/useToggle.ts","./src/operations/CourseAssignments/AssignedTeachersList.tsx","./src/operations/CourseAssignments/CourseAssignmentsCreate.tsx","./src/operations/CourseAssignments/TeacherCourseList.tsx","./src/operations/CourseAssignments/index.tsx","./src/operations/announcements/AnnouncementCreate.tsx","./src/operations/announcements/AnnouncementList.tsx","./src/operations/announcements/AnnouncementShow.tsx","./src/operations/announcements/index.ts","./src/operations/announcements/components/AnnoucementCard.tsx","./src/operations/announcements/components/AnnouncementsFilter.tsx","./src/operations/announcements/components/EmailField.tsx","./src/operations/announcements/components/SelectGroup.tsx","./src/operations/announcements/components/SelectScope.tsx","./src/operations/announcements/components/index.ts","./src/operations/announcements/utils/getBgImg.tsx","./src/operations/announcements/utils/constants/announcementsScopes.tsx","./src/operations/comments/CommentCreate.jsx","./src/operations/comments/CommentList.jsx","./src/operations/comments/StudentComments.tsx","./src/operations/comments/index.js","./src/operations/comments/utils.jsx","./src/operations/common/components/ArchiveWithConfirm.tsx","./src/operations/common/components/ChipRadio.tsx","./src/operations/common/components/ColorInput.tsx","./src/operations/common/components/Create.jsx","./src/operations/common/components/DeleteWithConfirm.tsx","./src/operations/common/components/Edit.jsx","./src/operations/common/components/EmptyList.tsx","./src/operations/common/components/EmptyListComponent.tsx","./src/operations/common/components/FileDownloader.tsx","./src/operations/common/components/FileUploadDialog.tsx","./src/operations/common/components/FloatingActionButton.tsx","./src/operations/common/components/GeoLocalisation.jsx","./src/operations/common/components/HaDateField.tsx","./src/operations/common/components/ListHeader.tsx","./src/operations/common/components/Loader.tsx","./src/operations/common/components/PdfViewer.jsx","./src/operations/common/components/ProfileLayout.tsx","./src/operations/common/components/Show.jsx","./src/operations/common/components/StudentListWithBulkActions.tsx","./src/operations/common/components/SuspendedStudentAlert.tsx","./src/operations/common/components/Title.tsx","./src/operations/common/components/hexToRgba.ts","./src/operations/common/components/index.jsx","./src/operations/common/components/fields/BirthDateField.jsx","./src/operations/common/components/fields/DateField.jsx","./src/operations/common/components/fields/DateTimeField.tsx","./src/operations/common/components/fields/FieldLabel.jsx","./src/operations/common/components/fields/HaField.jsx","./src/operations/common/components/fields/index.jsx","./src/operations/common/components/profilContent/AbsenceDetailDialog.tsx","./src/operations/common/components/profilContent/ContactDetails.tsx","./src/operations/common/components/profilContent/InformationContent.tsx","./src/operations/common/components/profilContent/PersonalDetails.tsx","./src/operations/common/components/profilContent/PersonalInfos.tsx","./src/operations/common/components/profilContent/ProfilCardAvatar.tsx","./src/operations/common/components/profilContent/StudentParticipationList.tsx","./src/operations/common/components/profilContent/utils.ts","./src/operations/common/components/resource-flows/InsertButton.tsx","./src/operations/common/components/resource-flows/LeaveButton.tsx","./src/operations/common/components/resource-flows/MigrateButton.tsx","./src/operations/common/components/resource-flows/ResourceFlowsContext.tsx","./src/operations/common/components/resource-flows/index.tsx","./src/operations/common/components/resource-flows/useResourceFlowsContext.tsx","./src/operations/common/components/resource-flows/components/DialogActions.tsx","./src/operations/common/components/resource-flows/components/FlowsDialog.tsx","./src/operations/common/components/resource-flows/components/index.tsx","./src/operations/common/utils/commonListHeaderContent.jsx","./src/operations/common/utils/money.ts","./src/operations/common/utils/strinfigy-obj.ts","./src/operations/common/utils/types.ts","./src/operations/common/utils/typo_util.js","./src/operations/cor/CorCreate.tsx","./src/operations/cor/CorDetails.tsx","./src/operations/cor/CorEditButton.tsx","./src/operations/cor/CorFields.tsx","./src/operations/cor/CorList.tsx","./src/operations/cor/CorStudentList.tsx","./src/operations/cor/index.ts","./src/operations/cor/index2.ts","./src/operations/cor/components/AddCorComment.tsx","./src/operations/cor/components/CorButtonAction.tsx","./src/operations/cor/components/CustomAutocompleteArrayInput.tsx","./src/operations/cor/components/StatusChip.tsx","./src/operations/cor/components/StudentAutocompleteInput.tsx","./src/operations/cor/utils/constants.ts","./src/operations/course/CourseCreate.tsx","./src/operations/course/CourseEditButton.tsx","./src/operations/course/CourseList.tsx","./src/operations/course/CourseShow.jsx","./src/operations/course/index.tsx","./src/operations/course/components/CourseListFilter.tsx","./src/operations/course/components/index.tsx","./src/operations/course/utils/constants.ts","./src/operations/dashboard/Dashboard.tsx","./src/operations/dashboard/components/AdminWelcome.tsx","./src/operations/dashboard/components/common/CommentContent.tsx","./src/operations/dashboard/components/common/PendingCreditPayments.tsx","./src/operations/dashboard/components/common/RecentLetters.tsx","./src/operations/dashboard/components/common/WelcomingCard.tsx","./src/operations/docs/components/DocCreateDialog.jsx","./src/operations/docs/components/DocList.tsx","./src/operations/docs/components/DocShow.tsx","./src/operations/docs/components/SelectWorkStatus.jsx","./src/operations/docs/components/SelectWorkType.jsx","./src/operations/docs/hooks/useViewType.js","./src/operations/docs/staffs/DocShow.tsx","./src/operations/docs/staffs/DockList.tsx","./src/operations/docs/staffs/index.ts","./src/operations/docs/students/DocList.jsx","./src/operations/docs/students/DocShow.jsx","./src/operations/docs/students/index.jsx","./src/operations/docs/teachers/DocList.tsx","./src/operations/docs/teachers/DocShow.tsx","./src/operations/docs/teachers/index.ts","./src/operations/docs/types/OwnerType.ts","./src/operations/docs/types/index.jsx","./src/operations/docs/utils/doc-list-title.ts","./src/operations/events/EventCalendar.tsx","./src/operations/events/EventCreate.tsx","./src/operations/events/EventEditDialog.tsx","./src/operations/events/EventList.tsx","./src/operations/events/EventMissingList.tsx","./src/operations/events/EventParticipantList.tsx","./src/operations/events/index.ts","./src/operations/events/utils.ts","./src/operations/events/components/AbsenceDetailDialogForStaff.tsx","./src/operations/events/components/Actions.tsx","./src/operations/events/components/AddGroup.tsx","./src/operations/events/components/EventCard.tsx","./src/operations/events/components/EventJustificateModal.tsx","./src/operations/events/components/EventListAction.tsx","./src/operations/events/components/EventLoaderCalendar.tsx","./src/operations/events/components/EventMissingFilter.tsx","./src/operations/events/components/EventParticipantsFilter.tsx","./src/operations/events/components/ImportStatusDialog.tsx","./src/operations/events/components/ListContent.tsx","./src/operations/events/components/MultiCheckBoxFilter.tsx","./src/operations/events/components/SelectClassrroom.tsx","./src/operations/events/components/SelectCourse.tsx","./src/operations/events/components/SelectIsOnline.tsx","./src/operations/events/components/SelectPlanner.tsx","./src/operations/events/components/Stats.tsx","./src/operations/events/components/index.ts","./src/operations/exams/ExamCreate.tsx","./src/operations/exams/ExamEdit.tsx","./src/operations/exams/ExamList.tsx","./src/operations/exams/index.ts","./src/operations/exams/components/index.ts","./src/operations/exams/components/cards/ExamCard.tsx","./src/operations/exams/components/cards/index.ts","./src/operations/exams/components/dialogs/index.ts","./src/operations/exams/components/dialogs/ExamEditDialog/index.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/CoefficientSection.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/CourseAssignmentSection.tsx","./src/operations/exams/components/dialogs/ExamEditDialog/sections/ExamDetailsSection.tsx","./src/operations/exams/components/filters/ExamFilter.tsx","./src/operations/exams/components/filters/index.ts","./src/operations/exams/components/selectors/SelectCourseAssignment.tsx","./src/operations/exams/components/selectors/SelectTeacher.tsx","./src/operations/exams/components/selectors/index.ts","./src/operations/exams/hooks/index.ts","./src/operations/exams/hooks/useExamEdit.ts","./src/operations/exams/utils/constants.ts","./src/operations/exams/utils/index.ts","./src/operations/exams/utils/validation.ts","./src/operations/fees/ByStatusFeeList.tsx","./src/operations/fees/FeeCreate.jsx","./src/operations/fees/FeeEdit.tsx","./src/operations/fees/FeeList.jsx","./src/operations/fees/FeeShow.tsx","./src/operations/fees/MultipleStudentFeesCreate.tsx","./src/operations/fees/TransactionFeeList.tsx","./src/operations/fees/constants.ts","./src/operations/fees/importConf.js","./src/operations/fees/index.jsx","./src/operations/fees/types.ts","./src/operations/fees/components/FeeInputs.tsx","./src/operations/fees/components/FeeStatsHeader.tsx","./src/operations/fees/components/FeeStatsTable.tsx","./src/operations/fees/components/FeesActions.tsx","./src/operations/fees/components/FeesDialog.tsx","./src/operations/fees/components/FeesFilter.tsx","./src/operations/fees/components/FeesListHeader.tsx","./src/operations/fees/components/ManagerFeeList.jsx","./src/operations/fees/components/OrangeMoneyHeader.tsx","./src/operations/fees/components/SelectDueDatetime.jsx","./src/operations/fees/components/SelectPredefinedType.jsx","./src/operations/fees/components/StatsStatus.tsx","./src/operations/fees/components/StatusFilterButtons.tsx","./src/operations/fees/components/StudentFeeList.tsx","./src/operations/fees/components/StyleFeeStat.ts","./src/operations/fees/components/index.jsx","./src/operations/fees/components/letterIcon.jsx","./src/operations/fees/components/pspIcon.tsx","./src/operations/fees/components/useFeeStatistics.ts","./src/operations/fees/components/Credits/CreditTransactionList.tsx","./src/operations/fees/utils/DateRangePopover.tsx","./src/operations/fees/utils/FeeFilterChips.tsx","./src/operations/fees/utils/FeeImportDialog.tsx","./src/operations/fees/utils/FeeStatsUtils.ts","./src/operations/fees/utils/FeesExport.tsx","./src/operations/fees/utils/MonthToFilter.tsx","./src/operations/fees/utils/StatusIcon.jsx","./src/operations/fees/utils/commonStyle.js","./src/operations/fees/utils/feeFactory.js","./src/operations/fees/utils/gridStyle.tsx","./src/operations/fees/utils/index.js","./src/operations/fees/utils/pspValues.tsx","./src/operations/fees/utils/remedialCostsConf.js","./src/operations/feesTemplates/FeesTemplateCreate.tsx","./src/operations/feesTemplates/FeesTemplatesEdit.tsx","./src/operations/feesTemplates/FeesTemplatesList.jsx","./src/operations/feesTemplates/index.jsx","./src/operations/grades/ExamParticipantList.tsx","./src/operations/grades/GradesDashboard.tsx","./src/operations/grades/index.js","./src/operations/grades/components/CoursesListView.tsx","./src/operations/grades/components/ExamDetailChip.tsx","./src/operations/grades/components/ExamDetails.tsx","./src/operations/grades/components/ExamGradeListActions.jsx","./src/operations/grades/components/ExamHeader.tsx","./src/operations/grades/components/ExamLoadError.jsx","./src/operations/grades/components/GlobalSummaryView.tsx","./src/operations/grades/components/GradeEditButton.tsx","./src/operations/grades/components/GradeEditForm.tsx","./src/operations/grades/components/GradeHistoryDialog.tsx","./src/operations/grades/components/GradeHistoryItem.tsx","./src/operations/grades/components/GradesDetails.tsx","./src/operations/grades/components/ImportResultDialog.tsx","./src/operations/grades/components/ParticipantsDataGrid.tsx","./src/operations/grades/components/ResultTimeline.tsx","./src/operations/grades/components/TranscriptOverview.tsx","./src/operations/grades/components/UploadGradeResponse.tsx","./src/operations/grades/components/YearlyView.tsx","./src/operations/grades/components/index.js","./src/operations/grades/components/utils.tsx","./src/operations/grades/types/types.ts","./src/operations/grades/utils/StatusChip.ts","./src/operations/grades/utils/TableMessageRow.tsx","./src/operations/grades/utils/constants.js","./src/operations/grades/utils/getGradeColor.ts","./src/operations/grades/utils/getStatusChipProps.tsx","./src/operations/grades/utils/helpers.js","./src/operations/grades/utils/index.js","./src/operations/grades/utils/utils.tsx","./src/operations/groups/GroupCreate.tsx","./src/operations/groups/GroupEdit.tsx","./src/operations/groups/GroupList.jsx","./src/operations/groups/GroupShow.tsx","./src/operations/groups/index.jsx","./src/operations/groups/components/GroupFilters.jsx","./src/operations/groups/components/GroupFlowCreate.jsx","./src/operations/groups/components/GroupStudentFilters.jsx","./src/operations/groups/components/GroupStudentList.jsx","./src/operations/groups/components/MigrateStudent.jsx","./src/operations/letters/CreateLetters.tsx","./src/operations/letters/LetterShow.tsx","./src/operations/letters/LettersList.tsx","./src/operations/letters/UserLettersList.tsx","./src/operations/letters/types.tsx","./src/operations/letters/components/AcceptWithConfirm.tsx","./src/operations/letters/components/BulkActions.tsx","./src/operations/letters/components/HeaderLetterList.tsx","./src/operations/letters/components/LetterItem.tsx","./src/operations/letters/components/LetterListView.tsx","./src/operations/letters/components/LettersFilter.tsx","./src/operations/letters/components/RefuseButton.tsx","./src/operations/letters/components/index.ts","./src/operations/monitors/MonitorCreate.tsx","./src/operations/monitors/MonitorList.tsx","./src/operations/monitors/MonitorListContent.tsx","./src/operations/monitors/MonitorShow.jsx","./src/operations/monitors/MonitorTabs.tsx","./src/operations/monitors/UnlinkedStudentsList.tsx","./src/operations/monitors/index.jsx","./src/operations/monitors/component/InsertStudentToMonitor.jsx","./src/operations/monitors/component/LinkActions.tsx","./src/operations/monitors/component/MonitorStudentList.tsx","./src/operations/monitors/component/index.jsx","./src/operations/payments/CreditPaymentList.tsx","./src/operations/payments/PaymentCreate.jsx","./src/operations/payments/PaymentList.jsx","./src/operations/payments/index.jsx","./src/operations/payments/components/CreditPaymentActions.tsx","./src/operations/payments/components/CreditPaymentStatusFilterButtons.tsx","./src/operations/payments/components/PaymentStatusIcon.tsx","./src/operations/payments/utils/validateCredit.ts","./src/operations/profile/ProfileEdit.tsx","./src/operations/profile/ProfileShow.tsx","./src/operations/profile/index.jsx","./src/operations/profile/components/GenerateReceiptDialog.tsx","./src/operations/profile/components/ProfileFilters.jsx","./src/operations/promotions/PromotionCreate.tsx","./src/operations/promotions/PromotionEditButton.tsx","./src/operations/promotions/PromotionList.tsx","./src/operations/promotions/PromotionShow.tsx","./src/operations/promotions/index.tsx","./src/operations/promotions/components/PromotionGroupList.tsx","./src/operations/promotions/components/PromotionListFilter.tsx","./src/operations/promotions/components/index.ts","./src/operations/promotions/utils/constant.ts","./src/operations/public/Calendar.tsx","./src/operations/public/index.tsx","./src/operations/public/utils/dateFormats.ts","./src/operations/public/utils/dayPropGetter.ts","./src/operations/public/utils/eventStyleGetter.ts","./src/operations/public/utils/frenchMessage.ts","./src/operations/public/utils/index.ts","./src/operations/public/utils/transformApiDataToCalendarEvents.ts","./src/operations/retakeExamCourses/index.ts","./src/operations/retakeExamCourses/retakeExamCourseList.tsx","./src/operations/retakeExamParticipants/RetakeExamParticipantShow.tsx","./src/operations/retakeExamParticipants/components/CourseInfo.tsx","./src/operations/retakeExamParticipants/components/RetakeExamParticipantList.tsx","./src/operations/retakeExamParticipants/components/index.ts","./src/operations/retakeExamSessions/RetakeExamSessionCreate.tsx","./src/operations/retakeExamSessions/RetakeExamSessionEdit.tsx","./src/operations/retakeExamSessions/RetakeExamSessionList.tsx","./src/operations/retakeExamSessions/RetakeExamSessionShow.tsx","./src/operations/retakeExamSessions/index.ts","./src/operations/retakeExamSessions/components/ListeRetakeExamForSpecificStudentBar.tsx","./src/operations/retakeExamSessions/components/PendingCancellationBar.tsx","./src/operations/retakeExamSessions/components/RetakeExamSessionActions.tsx","./src/operations/retakeExamSessions/components/RetakeExamSessionForm.tsx","./src/operations/retakeExamSessions/components/RoleBasedEditButton.tsx","./src/operations/retakeExamSessions/components/RoleBasedShowButton.tsx","./src/operations/retakeExamSessions/components/index.ts","./src/operations/retakeExams/CancellationRetakeExam.tsx","./src/operations/retakeExams/ListRetakeExamsForStudentSpecific.tsx","./src/operations/retakeExams/RetakeExamListShow.tsx","./src/operations/retakeExams/index.ts","./src/operations/retakeExams/components/RetakeExamButtonStatus.tsx","./src/operations/retakeExams/components/RetakeExamButtons.tsx","./src/operations/retakeExams/components/index.ts","./src/operations/retakeExams/components/useButtonActions.tsx","./src/operations/staffMembers/StaffCreate.tsx","./src/operations/staffMembers/StaffList.tsx","./src/operations/staffMembers/StaffShow.tsx","./src/operations/staffMembers/index.tsx","./src/operations/students/StudentCreate.jsx","./src/operations/students/StudentList.tsx","./src/operations/students/StudentShow.jsx","./src/operations/students/constants.ts","./src/operations/students/importConf.jsx","./src/operations/students/index.jsx","./src/operations/students/components/DocMenu.jsx","./src/operations/students/components/GetCertificate.tsx","./src/operations/students/components/GetReceipt.jsx","./src/operations/students/components/SelectSpecialization.jsx","./src/operations/students/components/index.jsx","./src/operations/students/utils/StudentFilterExport.tsx","./src/operations/students/utils/isOver18.ts","./src/operations/students/utils/studentFactory.js","./src/operations/studentsResultOverviews/PromotionOverviewList.tsx","./src/operations/studentsResultOverviews/StudentsResultOvergviewList.tsx","./src/operations/studentsResultOverviews/index.ts","./src/operations/teachers/TeacherCreate.jsx","./src/operations/teachers/TeacherList.tsx","./src/operations/teachers/TeacherShow.tsx","./src/operations/teachers/index.jsx","./src/operations/utils/CustomAutoComplete.jsx","./src/operations/utils/CustomBreadcrumbs.tsx","./src/operations/utils/CustomCommentTextField.jsx","./src/operations/utils/EditToolBar.jsx","./src/operations/utils/IconButtonWithTooltip.tsx","./src/operations/utils/SexRadioButton.jsx","./src/operations/utils/UserStatusRadioButton.jsx","./src/operations/utils/commentRenderer.ts","./src/operations/utils/exporter.js","./src/operations/utils/importer.js","./src/operations/utils/index.jsx","./src/operations/utils/paymentTypeRenderer.js","./src/operations/utils/pspIdValidationContraints.tsx","./src/operations/utils/typography.jsx","./src/operations/utils/userImportConf.js","./src/providers/HaDataProviderType.ts","./src/providers/announcementProvider.ts","./src/providers/api.js","./src/providers/authProvider.ts","./src/providers/aws-config.js","./src/providers/commentProvider.ts","./src/providers/constants.js","./src/providers/corProvider.ts","./src/providers/corStudentProvider.ts","./src/providers/correctGradeProvider.ts","./src/providers/courseAssignementbyTeacher.ts","./src/providers/courseAssignmentsProvider.ts","./src/providers/courseProvider.ts","./src/providers/createGradeProvider.ts","./src/providers/creditPaymentProvider.ts","./src/providers/dataProvider.ts","./src/providers/docsProvider.ts","./src/providers/eventParticipantProvider.ts","./src/providers/eventProvider.ts","./src/providers/examGradeProvider.ts","./src/providers/examProvider.ts","./src/providers/exportEventParticipantProvider.ts","./src/providers/exportGroupProvider.ts","./src/providers/exportPromotionProvider.ts","./src/providers/exportStudentProvider.ts","./src/providers/exportTeacherProvider.ts","./src/providers/feeProvider.ts","./src/providers/feesExportProvider.ts","./src/providers/feesTemplatesProvider.ts","./src/providers/gradeImportProvider.ts","./src/providers/gradeProvider.ts","./src/providers/gradesDetailsProvider.ts","./src/providers/groupFlowProvider.ts","./src/providers/groupProvider.ts","./src/providers/groupStudentProvider.ts","./src/providers/heiDocsProvider.ts","./src/providers/letterStatsProvider.ts","./src/providers/lettersProvider.ts","./src/providers/missingListProvider.ts","./src/providers/monitorProvider.ts","./src/providers/monitorStudentProvider.ts","./src/providers/mpbsVerifyProvider.ts","./src/providers/paymentProvider.ts","./src/providers/profilePicProvider.ts","./src/providers/profileProvider.ts","./src/providers/promotionFlowProvider.ts","./src/providers/promotionGroupsProvider.ts","./src/providers/promotionProvider.ts","./src/providers/receiptProvider.ts","./src/providers/resultSummaryProvider.ts","./src/providers/retakeExamCoursesProvider.ts","./src/providers/retakeExamParticipantProvider.ts","./src/providers/retakeExamProvider.ts","./src/providers/retakeExamSessionProvider.ts","./src/providers/searchProvider.ts","./src/providers/staffExportProvider.ts","./src/providers/staffProvider.ts","./src/providers/statsProvider.ts","./src/providers/studentCreditProvider.tsx","./src/providers/studentImportProvider.ts","./src/providers/studentParticipationProvider.ts","./src/providers/studentProvider.ts","./src/providers/studentRetakeExamsProvider.ts","./src/providers/studentsResultOverviewsProvider.ts","./src/providers/teacherProvider.ts","./src/providers/types.ts","./src/providers/unlinkedStudentProvider.ts","./src/providers/usersLettersProvider.ts","./src/providers/utils.js","./src/security/CasdoorAuth.tsx","./src/security/CasdoorLoginButton.tsx","./src/security/CasdoorLoginCard.tsx","./src/security/LoginPage.jsx","./src/security/casdoorSetting.js","./src/security/permissions.ts","./src/security/utils.jsx","./src/security/hooks/index.js","./src/security/hooks/useRole.js","./src/security/waf/AwsWafCaptchaHandler.tsx","./src/security/waf/HumanVerification.tsx","./src/security/waf/conf.ts","./src/security/waf/index.js","./src/types/dom-to-image-more.d.ts","./src/ui/components/AlertBar.tsx","./src/ui/components/Dialog.tsx","./src/ui/components/EmptyList.tsx","./src/ui/components/ResponsiveGrid.tsx","./src/ui/components/index.tsx","./src/ui/components/inputs/Autocomplete.tsx","./src/ui/components/inputs/AutocompleteArrayInput.tsx","./src/ui/components/inputs/AutocompleteInput.tsx","./src/ui/components/inputs/MultipleAutocomplete.tsx","./src/ui/components/inputs/index.tsx","./src/ui/constants/common_styles.js","./src/ui/constants/index.js","./src/ui/constants/typography.js","./src/ui/haLayout/HaLayout.jsx","./src/ui/haLayout/index.jsx","./src/ui/haLayout/appBar/GlobalSearch.tsx","./src/ui/haLayout/appBar/HaAppBar.jsx","./src/ui/haLayout/appBar/UserInfo.tsx","./src/ui/haLayout/appBar/index.jsx","./src/ui/haLayout/appBar/component/ProfilePicture.tsx","./src/ui/haLayout/appBar/component/SearchBarStyles.ts","./src/ui/haLayout/appBar/component/SearchComponents.tsx","./src/ui/haLayout/appBar/component/index.ts","./src/ui/haLayout/appBar/component/useGlobalSearch.ts","./src/ui/haLayout/appBar/utils/searchUtils.ts","./src/ui/haLayout/menu/AdminMenu.tsx","./src/ui/haLayout/menu/HaMenuContent.jsx","./src/ui/haLayout/menu/ManagerMenu.tsx","./src/ui/haLayout/menu/MonitorMenu.tsx","./src/ui/haLayout/menu/OrganizerMenu.tsx","./src/ui/haLayout/menu/StaffMenu.jsx","./src/ui/haLayout/menu/StudentMenu.tsx","./src/ui/haLayout/menu/TeacherMenu.jsx","./src/ui/haLayout/menu/common/HeiListMenuItem.tsx","./src/ui/haLayout/menu/common/index.ts","./src/ui/haLayout/menu/utils/HaMenu.tsx","./src/ui/haLayout/menu/utils/ListMenu.jsx","./src/ui/haLayout/menu/utils/ListMenuItem.tsx","./src/ui/haLayout/menu/utils/SingleMenu.tsx","./src/ui/haLayout/menu/utils/index.jsx","./src/ui/haList/HaList.jsx","./src/ui/haList/HaListTitle.jsx","./src/ui/haList/HaMainSearch.jsx","./src/ui/haList/PrevNextPagination.tsx","./src/ui/haList/index.jsx","./src/ui/haList/useHaListContext.tsx","./src/ui/haToolbar/AutocompleteFilter.jsx","./src/ui/haToolbar/Button.jsx","./src/ui/haToolbar/DataTimeFilter.tsx","./src/ui/haToolbar/FilterForm.jsx","./src/ui/haToolbar/FilterFormContent.jsx","./src/ui/haToolbar/Filters.jsx","./src/ui/haToolbar/LiveFilter.jsx","./src/ui/haToolbar/SelectFilter.jsx","./src/ui/haToolbar/index.jsx","./src/ui/haToolbar/useHaToolbarContext.jsx","./src/ui/haToolbar/importButton/ImportButton.jsx","./src/ui/haToolbar/importButton/ImportDialog.jsx","./src/ui/haToolbar/importButton/ImportInputFile.jsx","./src/ui/haToolbar/importButton/NewImportButton.tsx","./src/ui/haToolbar/importButton/index.jsx","./src/ui/haToolbar/importButton/utils.js","./src/ui/haToolbar/utils/Items.jsx","./src/utils/constants.js","./src/utils/date.js","./src/utils/files.js","./src/utils/formatDateToTimeZone.ts","./src/utils/getObjValue.ts","./src/utils/gtm.js","./src/utils/index.js","./src/utils/mapToChoices.ts","./src/utils/noop.js","./src/utils/stringify.ts","./cypress/e2e/admin.docs.cy.tsx","./cypress/e2e/admin.staff.cy.ts","./cypress/e2e/admin.welcome.cy.tsx","./cypress/e2e/authentification.cy.tsx","./cypress/e2e/certificate.cy.tsx","./cypress/e2e/comments.cy.tsx","./cypress/e2e/cor.manager.cy.ts","./cypress/e2e/download.cy.tsx","./cypress/e2e/event.manager.cy.tsx","./cypress/e2e/event.student.cy.tsx","./cypress/e2e/event.teacher.cy.tsx","./cypress/e2e/exam.card.cy.tsx","./cypress/e2e/exam.participant.list.cy.tsx","./cypress/e2e/function.cy.ts","./cypress/e2e/grade-overview.cy.ts","./cypress/e2e/grades.components.cy.tsx","./cypress/e2e/helpers.cy.ts","./cypress/e2e/importConf.cy.ts","./cypress/e2e/letter.event.cy.tsx","./cypress/e2e/letters.manager.cy.tsx","./cypress/e2e/letters.users.cy.tsx","./cypress/e2e/manager.announcements.cy.tsx","./cypress/e2e/manager.course.cy.tsx","./cypress/e2e/manager.cy.tsx","./cypress/e2e/manager.docs.cy.tsx","./cypress/e2e/manager.fees.cy.tsx","./cypress/e2e/manager.fees.import.cy.tsx","./cypress/e2e/manager.fees.mpbs.cy.tsx","./cypress/e2e/manager.fees.templates.cy.tsx","./cypress/e2e/manager.groups.cy.tsx","./cypress/e2e/manager.monitor.cy.tsx","./cypress/e2e/manager.payments.credit.cy.tsx","./cypress/e2e/manager.payments.cy.tsx","./cypress/e2e/manager.promotions.cy.tsx","./cypress/e2e/manager.students.cy.tsx","./cypress/e2e/manager.teachers.cy.tsx","./cypress/e2e/manager.teachers.import.cy.tsx","./cypress/e2e/monitor.cy.tsx","./cypress/e2e/notification.cy.tsx","./cypress/e2e/profil.picture.cy.tsx","./cypress/e2e/profile.cy.tsx","./cypress/e2e/public-link.cy.tsx","./cypress/e2e/receipt.cy.tsx","./cypress/e2e/student.announcements.cy.tsx","./cypress/e2e/student.cy.tsx","./cypress/e2e/student.docs.cy.tsx","./cypress/e2e/student.fees.letter.tsx","./cypress/e2e/student.fees.mpbs.cy.tsx","./cypress/e2e/teacher.announcements.cy.tsx","./cypress/e2e/teacher.course.cy.tsx","./cypress/e2e/teacher.cy.tsx","./cypress/e2e/utils.tsx","./cypress/fixtures/api_mocks/admins-mock.ts","./cypress/fixtures/api_mocks/advanceStats-mocks.ts","./cypress/fixtures/api_mocks/announcement-mocks.ts","./cypress/fixtures/api_mocks/authentification-mocks.ts","./cypress/fixtures/api_mocks/calendar-mock.ts","./cypress/fixtures/api_mocks/comment-mocks.ts","./cypress/fixtures/api_mocks/cor-mock.ts","./cypress/fixtures/api_mocks/course-assignment-mocks.ts","./cypress/fixtures/api_mocks/course-mocks.ts","./cypress/fixtures/api_mocks/credit-payments-mocks.ts","./cypress/fixtures/api_mocks/docs-mocks.ts","./cypress/fixtures/api_mocks/event-mocks.ts","./cypress/fixtures/api_mocks/exam-grade-mocks.ts","./cypress/fixtures/api_mocks/exam-mocks.ts","./cypress/fixtures/api_mocks/fees-mocks.ts","./cypress/fixtures/api_mocks/fees-stats.ts","./cypress/fixtures/api_mocks/fees-templates-mocks.ts","./cypress/fixtures/api_mocks/grades-mocks.ts","./cypress/fixtures/api_mocks/groups-mocks.ts","./cypress/fixtures/api_mocks/letters-mocks.ts","./cypress/fixtures/api_mocks/managers-mocks.ts","./cypress/fixtures/api_mocks/missing-participants-mock.ts","./cypress/fixtures/api_mocks/monitors-mock.ts","./cypress/fixtures/api_mocks/organizers-mock.ts","./cypress/fixtures/api_mocks/payments-mocks.ts","./cypress/fixtures/api_mocks/profil-mocks.ts","./cypress/fixtures/api_mocks/promotions-mocks.ts","./cypress/fixtures/api_mocks/staffs-mock.ts","./cypress/fixtures/api_mocks/students-mocks.ts","./cypress/fixtures/api_mocks/summary-result-mocks.ts","./cypress/fixtures/api_mocks/teachers-mocks.ts","./cypress/support/commands.ts","./cypress/support/component.ts","./cypress/support/e2e.ts","./cypress/support/global.d.ts"],"version":"6.0.3"} \ No newline at end of file From 3dd2741cf6494d309a83ff516615100989b5fcbf Mon Sep 17 00:00:00 2001 From: DyferHerioss Date: Wed, 12 Aug 2026 08:07:07 +0300 Subject: [PATCH 5/7] chore: build, coverage, and test --- package-lock.json | 6 +- .../common/components/FileDownloader.tsx | 7 +- .../common/components/ListHeader.tsx | 2 +- .../common/components/fields/HaField.jsx | 1 + .../fees/components/FeesActions.tsx | 8 +- .../fees/components/ManagerFeeList.jsx | 3 - .../fees/components/StudentFeeList.tsx | 4 +- src/operations/fees/constants.ts | 4 +- src/operations/payments/PaymentCreate.jsx | 196 +----------------- .../components/CreditPaymentActions.tsx | 7 +- .../payments/utils/validateCredit.ts | 4 +- .../students/components/GetReceipt.jsx | 12 +- src/providers/studentCreditProvider.tsx | 35 +++- src/ui/haLayout/menu/AdminMenu.tsx | 2 +- src/ui/haLayout/menu/ManagerMenu.tsx | 2 +- vite.config.js | 82 ++++---- 16 files changed, 100 insertions(+), 275 deletions(-) diff --git a/package-lock.json b/package-lock.json index d334ea3a7..b8fc2a48b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4118,9 +4118,9 @@ "license": "MIT" }, "node_modules/@haapi-b0fc7615/typescript-client": { - "version": "1.166.0", - "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/@haapi-b0fc7615/typescript-client/-/typescript-client-1.166.0.tgz", - "integrity": "sha512-k1djyc+Q8TExbbhtSX+erOX1Xv9v5AuqB50LxFPAChgsNOMQ2axpRBxkN0yZYDX+wB+ntw5QyP3hlNKbFoil6w==", + "version": "1.166.1", + "resolved": "https://npm-hei-lab-057045785189.d.codeartifact.eu-west-3.amazonaws.com/npm/hei-store/@haapi-b0fc7615/typescript-client/-/typescript-client-1.166.1.tgz", + "integrity": "sha512-wp0OQFYD5IpUZtxUYltT+8r1wsT4IeG7ZfCe1ZW0cPkFhh/6xsPBSL+m6CIH361PvmTwQaAnWBUABuz73l55cg==", "license": "Unlicense", "peerDependencies": { "axios": "1.18.1" diff --git a/src/operations/common/components/FileDownloader.tsx b/src/operations/common/components/FileDownloader.tsx index 2de54f320..11938dc71 100644 --- a/src/operations/common/components/FileDownloader.tsx +++ b/src/operations/common/components/FileDownloader.tsx @@ -19,7 +19,7 @@ export type FileDownloaderProps = { fileType?: string; buttonProps?: ButtonProps; buttonText: string; -} & Omit; +} & {"data-testid"?: string} & Omit; export const FileDownloader: FC = ({ downloadFunction, @@ -29,6 +29,7 @@ export const FileDownloader: FC = ({ errorMessage, buttonText, fileType = "application/pdf", + "data-testid": dataTestId = "download-button", ...raButtonProps }) => { const [isLoading, setIsLoading] = useState(false); @@ -69,7 +70,7 @@ export const FileDownloader: FC = ({ {isSmall ? ( = ({ {...raButtonProps} disabled={isLoading} onClick={handleDownload} - data-testid="download-button" + data-testid={dataTestId} startIcon={isLoading ? : startIcon} > {buttonText} diff --git a/src/operations/common/components/ListHeader.tsx b/src/operations/common/components/ListHeader.tsx index 0a434cb99..67feb1623 100644 --- a/src/operations/common/components/ListHeader.tsx +++ b/src/operations/common/components/ListHeader.tsx @@ -80,7 +80,7 @@ const CardInfos: FC = ({cardDetails = []}) => { > {cardDetails.map(({icon, total, title}) => ( - + {icon} { return ( diff --git a/src/operations/fees/components/ManagerFeeList.jsx b/src/operations/fees/components/ManagerFeeList.jsx index 729289611..a998b74ac 100644 --- a/src/operations/fees/components/ManagerFeeList.jsx +++ b/src/operations/fees/components/ManagerFeeList.jsx @@ -40,9 +40,6 @@ export const ManagerFeeList = ({studentId, studentRef}) => { datagridProps={{ rowClick: (id) => `/fees/${id}/show`, rowStyle, - rowProps: (record) => ({ - "data-testid": `fee-row-${record.id}`, - }), }} editable={false} > diff --git a/src/operations/fees/components/StudentFeeList.tsx b/src/operations/fees/components/StudentFeeList.tsx index 6561e4637..b336b846f 100644 --- a/src/operations/fees/components/StudentFeeList.tsx +++ b/src/operations/fees/components/StudentFeeList.tsx @@ -10,12 +10,12 @@ import { MpbsStatusIcon, } from "@/operations/fees/utils"; import {CreateLettersDialog} from "@/operations/letters/CreateLetters"; +import {useStudentCredit} from "@/operations/payments/utils/validateCredit"; import { commentFunctionRenderer, IconButtonWithTooltip, pspIdValidationContraints, } from "@/operations/utils"; -import {useStudentCredit} from "@/operations/payments/utils/validateCredit"; import authProvider from "@/providers/authProvider"; import {HaList} from "@/ui/haList/HaList"; import {ButtonBase, HaActionWrapper} from "@/ui/haToolbar"; @@ -43,9 +43,9 @@ import { FormControl, FormControlLabel, FormLabel, + TextField as MuiTextInput, Radio, RadioGroup, - TextField as MuiTextInput, Typography, } from "@mui/material"; import {AxiosError} from "axios"; diff --git a/src/operations/fees/constants.ts b/src/operations/fees/constants.ts index c808399a9..b4638742b 100644 --- a/src/operations/fees/constants.ts +++ b/src/operations/fees/constants.ts @@ -69,7 +69,7 @@ export const ADVANCED_FEE_STATISTICS_TYPE_CHOICES = [ export const PAYMENT_TYPE = { [PaymentTypeEnum.MOBILE_MONEY]: "MOBILE MONEY", - [PaymentTypeEnum.CREDIT]:"CREDIT", + [PaymentTypeEnum.CREDIT]: "CREDIT", } as const; -export const PAYMENT_TYPE_CHOICES = mapToChoices(PAYMENT_TYPE, "id", "name"); \ No newline at end of file +export const PAYMENT_TYPE_CHOICES = mapToChoices(PAYMENT_TYPE, "id", "name"); diff --git a/src/operations/payments/PaymentCreate.jsx b/src/operations/payments/PaymentCreate.jsx index 0b66c758c..332204768 100644 --- a/src/operations/payments/PaymentCreate.jsx +++ b/src/operations/payments/PaymentCreate.jsx @@ -1,198 +1,7 @@ -// import {paymentTypes} from "@/conf"; -// import {useToggle} from "@/hooks/useToggle"; -// import {studentIdFromRaId} from "@/providers/feeProvider"; -// import { -// MobileMoneyType, -// PaymentTypeEnum, -// } from "@haapi-b0fc7615/typescript-client"; -// import {Box} from "@mui/material"; -// import {Home, Wallet} from "lucide-react"; -// import {useEffect, useState} from "react"; -// import { -// BooleanInput, -// Create, -// DateInput, -// minValue, -// number, -// RadioButtonGroupInput, -// required, -// SelectInput, -// SimpleForm, -// TextInput, -// useDataProvider, -// useNotify, -// } from "react-admin"; -// import {Link as RouterLink, useParams} from "react-router-dom"; -// import {pspIdValidationContraints} from "../utils"; -// import CustomBreadcrumbs from "../utils/CustomBreadcrumbs"; - -// const PaymentCreate = (props) => { -// const params = useParams(); -// const notify = useNotify(); -// const dataProvider = useDataProvider(); -// const [studentRef, setStudentRef] = useState("..."); -// const [paymentChoice, setPaymentChoice] = useState( -// PaymentTypeEnum.BANK_TRANSFER -// ); -// const [notSpecifiedDate, setSpecifyDate] = useToggle(true); - -// const feeId = params.feeId; -// const studentId = studentIdFromRaId(feeId); -// const isMobileMoney = paymentChoice === PaymentTypeEnum.MOBILE_MONEY; -// const isCommentNecessary = -// isMobileMoney || paymentChoice === PaymentTypeEnum.BANK_TRANSFER; - -// useEffect(() => { -// const doEffect = async () => { -// const student = await dataProvider.getOne("students", {id: studentId}); -// setStudentRef(student.data.ref); -// }; -// doEffect(); -// }, [studentId, dataProvider]); - -// const breadcrumbItems = [ -// { -// label: "Étudiant", -// component: RouterLink, -// to: `/students/${studentId}/show`, -// icon: , -// }, -// { -// label: "Frais", -// component: RouterLink, -// to: `/fees/${feeId}/show`, -// icon: , -// }, -// { -// label: "Créer un paiement", -// }, -// ]; - -// const notifyError = (error) => { -// let message = "Une erreur s`'est produite"; -// if (error.response && error.response.status === 400) { -// if (error.response.message.startsWith("Payment amount")) -// message = "Le paiement dépasse le montant restant du frais"; -// else message = "Paiement pour date future non autorisé"; -// } -// notify(message, {type: "error", autoHideDuration: 2500}); -// }; -// const paymentConfToPaymentApi = ({ -// ref, -// type, -// amount, -// comment, -// creation_datetime, -// psp_id, -// psp_type, -// status -// }) => { -// const getDatetimeValue = () => { -// if (notSpecifiedDate) { -// const currentDate = new Date(); -// currentDate.setSeconds(0); -// return currentDate.toISOString(); -// } -// return new Date(creation_datetime).toISOString(); -// }; -// return [ -// { -// feeId, -// type, -// amount, -// comment, -// ref, -// psp_id, -// psp_type, -// creation_datetime: getDatetimeValue(), -// }, -// ]; -// }; - -// return ( -// -// -// `fees/${feeId}/show`} -// transform={paymentConfToPaymentApi} -// {...props} -// > -// -// setPaymentChoice(event.target.value)} -// /> -// {paymentChoice === PaymentTypeEnum.BANK_TRANSFER && ( -// -// )} -// {isMobileMoney && ( -// -// )} -// {isMobileMoney && ( -// -// )} -// -// -// setSpecifyDate(checked)} -// /> -// {!notSpecifiedDate && ( -// -// )} -// -// -// -// ); -// }; - -// export default PaymentCreate; import {paymentTypes} from "@/conf"; import {useToggle} from "@/hooks/useToggle"; -import {studentIdFromRaId} from "@/providers/feeProvider"; import {useStudentCredit} from "@/operations/payments/utils/validateCredit"; +import {studentIdFromRaId} from "@/providers/feeProvider"; import {useRole} from "@/security/hooks"; import { MobileMoneyType, @@ -270,7 +79,7 @@ const PaymentCreate = (props) => { } else { message = "Paiement pour date future non autorisé"; } - } + } notify(message, { type: "error", @@ -298,7 +107,6 @@ const PaymentCreate = (props) => { return new Date(creation_datetime).toISOString(); }; - // Les paiements par Mobile Money (Orange Money) sont validés // automatiquement, quel que soit le rôle qui les crée. const status = diff --git a/src/operations/payments/components/CreditPaymentActions.tsx b/src/operations/payments/components/CreditPaymentActions.tsx index 69c8bc042..3b4934177 100644 --- a/src/operations/payments/components/CreditPaymentActions.tsx +++ b/src/operations/payments/components/CreditPaymentActions.tsx @@ -4,11 +4,8 @@ import {PaymentStatus} from "@haapi-b0fc7615/typescript-client"; import {Box, Button} from "@mui/material"; import {Confirm, useNotify, useRecordContext, useRefresh} from "react-admin"; -// TODO: le rejet appelle actuellement le même endpoint que la validation -// (`validateCreditPayments`) car aucun endpoint de rejet/invalidation n'existe -// encore côté API. À corriger dès qu'un endpoint dédié sera disponible. const rejectCreditPayment = (paymentId: string) => - payingApi().validateCreditPayments([paymentId]); + payingApi().rejectCreditPayments([paymentId]); const validateCreditPayment = (paymentId: string) => payingApi().validateCreditPayments([paymentId]); @@ -24,8 +21,6 @@ export const CreditPaymentActions = () => { return null; } - // Un paiement déjà résolu (validé ou rejeté) ne peut plus être rejoué : - // les boutons restent visibles pour garder la colonne lisible, mais désactivés. const isActionable = record.status === PaymentStatus.CREATED; const stopPropagation = (event: React.MouseEvent) => diff --git a/src/operations/payments/utils/validateCredit.ts b/src/operations/payments/utils/validateCredit.ts index c960d1cfd..dec009846 100644 --- a/src/operations/payments/utils/validateCredit.ts +++ b/src/operations/payments/utils/validateCredit.ts @@ -1,6 +1,6 @@ +import {Credit} from "@haapi-b0fc7615/typescript-client"; import {useCallback, useEffect, useState} from "react"; import {useDataProvider} from "react-admin"; -import {Credit} from "@haapi-b0fc7615/typescript-client"; export const MINIMUM_CREDIT = 200000; @@ -64,4 +64,4 @@ export const useStudentCredit = (studentId: string | number) => { getStudentCredit, validateCreditPayment, }; -}; \ No newline at end of file +}; diff --git a/src/operations/students/components/GetReceipt.jsx b/src/operations/students/components/GetReceipt.jsx index 4664cc4fa..5a1f5ab65 100644 --- a/src/operations/students/components/GetReceipt.jsx +++ b/src/operations/students/components/GetReceipt.jsx @@ -1,7 +1,7 @@ import {FileDownloader} from "@/operations/common/components"; import {feeIdFromRaId} from "@/providers/feeProvider"; import {Download} from "@mui/icons-material"; -import {Button, useDataProvider} from "react-admin"; +import {useDataProvider} from "react-admin"; const FILE_NAME = "Reçu_paiement.pdf"; @@ -23,13 +23,9 @@ export const GetReceipt = ({studentId, feeId, paymentId}) => { } - data-testid="get-receipt-btn" - /> - } + buttonText="Reçu" + startIcon={} + data-testid="get-receipt-btn" successMessage="Reçu en cours de téléchargement" errorMessage="Échec de téléchargement. Veuillez réessayer" /> diff --git a/src/providers/studentCreditProvider.tsx b/src/providers/studentCreditProvider.tsx index 588d467f0..b947bdeb9 100644 --- a/src/providers/studentCreditProvider.tsx +++ b/src/providers/studentCreditProvider.tsx @@ -1,7 +1,26 @@ -import {CreditMovement} from "@haapi-b0fc7615/typescript-client"; +import {CreditMovement, PaymentStatus} from "@haapi-b0fc7615/typescript-client"; import {HaDataProviderType} from "./HaDataProviderType"; import {payingApi} from "./api"; +const FETCH_ALL_PAGE_SIZE = 500; + +const getPendingCreditAmount = async (studentId: string): Promise => { + const [studentFees, pendingCreditPayments] = await Promise.all([ + payingApi().getFeesByStudentId(studentId, 1, FETCH_ALL_PAGE_SIZE), + payingApi().getCreditPaymentsByStatus( + PaymentStatus.CREATED, + 1, + FETCH_ALL_PAGE_SIZE + ), + ]); + + const studentFeeIds = new Set(studentFees.data.map((fee) => fee.id)); + + return pendingCreditPayments.data + .filter((payment) => studentFeeIds.has(payment.fee_id)) + .reduce((total, payment) => total + (payment.amount ?? 0), 0); +}; + const studentCreditProvider: HaDataProviderType = { getList: async (page, perPage, filter) => { const studentId = filter.studentId as string; @@ -26,9 +45,17 @@ const studentCreditProvider: HaDataProviderType = { }; }, getOne: async (studentId) => { - return await payingApi() - .getCreditByStudentId(studentId) - .then((result) => result.data); + const [creditResult, pendingCreditAmount] = await Promise.all([ + payingApi().getCreditByStudentId(studentId), + getPendingCreditAmount(studentId), + ]); + + const credit = creditResult.data; + + return { + ...credit, + amount: (credit.amount ?? 0) - pendingCreditAmount, + }; }, saveOrUpdate: () => { throw new Error("Function not implemented."); diff --git a/src/ui/haLayout/menu/AdminMenu.tsx b/src/ui/haLayout/menu/AdminMenu.tsx index df50ee70a..2291c1df3 100644 --- a/src/ui/haLayout/menu/AdminMenu.tsx +++ b/src/ui/haLayout/menu/AdminMenu.tsx @@ -3,8 +3,8 @@ import {HeiListMenuItem} from "@/ui/haLayout/menu/common"; import {ListMenu, ListMenuItem, SingleMenu} from "@/ui/haLayout/menu/utils"; import {trackNavClick} from "@/utils/gtm"; import { - AccountBalanceWallet as CreditPaymentsIcon, Newspaper as AnnouncementIcon, + AccountBalanceWallet as CreditPaymentsIcon, Inventory as DocsIcon, EditCalendar, EventBusy, diff --git a/src/ui/haLayout/menu/ManagerMenu.tsx b/src/ui/haLayout/menu/ManagerMenu.tsx index 0d1ecae14..435787176 100644 --- a/src/ui/haLayout/menu/ManagerMenu.tsx +++ b/src/ui/haLayout/menu/ManagerMenu.tsx @@ -2,8 +2,8 @@ import {HeiListMenuItem} from "@/ui/haLayout/menu/common"; import {ListMenu, ListMenuItem, SingleMenu} from "@/ui/haLayout/menu/utils"; import { Newspaper as AnnouncementIcon, - AccountBalanceWallet as CreditPaymentsIcon, SafetyDivider as CorIcon, + AccountBalanceWallet as CreditPaymentsIcon, Inventory as DocsIcon, EditCalendar, EventBusy, diff --git a/vite.config.js b/vite.config.js index 496768a16..2e5f4a26b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,47 +1,47 @@ import react from "@vitejs/plugin-react"; import path from "path"; -import { defineConfig, loadEnv } from "vite"; +import {defineConfig, loadEnv} from "vite"; import istanbul from "vite-plugin-istanbul"; -import { nodePolyfills } from "vite-plugin-node-polyfills"; +import {nodePolyfills} from "vite-plugin-node-polyfills"; // https://vitejs.dev/config/ -export default defineConfig(({ mode }) => { - const env = loadEnv(mode, process.cwd(), ""); - return { - plugins: [ - react(), - nodePolyfills({ include: ["crypto", "os", "path", "stream", "vm"] }), - istanbul({ - requireEnv: false, - cypress: true, - include: "src/*", - exclude: ["node_modules", "cypress", "src/**/*.cy.*"], - extension: [".js", ".jsx", ".ts", ".tsx"], - }), - ], - define: { - "process.env": env, +export default defineConfig(({mode}) => { + const env = loadEnv(mode, process.cwd(), ""); + return { + plugins: [ + react(), + nodePolyfills({include: ["crypto", "os", "path", "stream", "vm"]}), + istanbul({ + requireEnv: false, + cypress: true, + include: "src/*", + exclude: ["node_modules", "cypress", "src/**/*.cy.*"], + extension: [".js", ".jsx", ".ts", ".tsx"], + }), + ], + define: { + "process.env": env, + }, + optimizeDeps: { + entries: ["cypress/**/*", "src/**/*"], + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + build: { + outDir: "build", + sourcemap: true, + rollupOptions: { + output: { + sourcemap: false, }, - optimizeDeps: { - entries: ["cypress/**/*", "src/**/*"], - }, - resolve: { - alias: { - "@": path.resolve(__dirname, "./src"), - }, - }, - build: { - outDir: "build", - sourcemap: true, - rollupOptions: { - output: { - sourcemap: false, - }, - }, - }, - server: { - watch: { - ignored: ["**/coverage/**"], - }, - }, - }; + }, + }, + server: { + watch: { + ignored: ["**/coverage/**"], + }, + }, + }; }); From 9b14584843a30f22c010251e8618883841a102f6 Mon Sep 17 00:00:00 2001 From: DyferHerioss Date: Wed, 12 Aug 2026 08:25:39 +0300 Subject: [PATCH 6/7] chore: rm unused config --- vite.config.d.ts | 2 -- vite.config.js | 47 ----------------------------------------------- 2 files changed, 49 deletions(-) delete mode 100644 vite.config.d.ts delete mode 100644 vite.config.js diff --git a/vite.config.d.ts b/vite.config.d.ts deleted file mode 100644 index 089eeef96..000000000 --- a/vite.config.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const _default: import("vite").UserConfigFnObject; -export default _default; diff --git a/vite.config.js b/vite.config.js deleted file mode 100644 index 2e5f4a26b..000000000 --- a/vite.config.js +++ /dev/null @@ -1,47 +0,0 @@ -import react from "@vitejs/plugin-react"; -import path from "path"; -import {defineConfig, loadEnv} from "vite"; -import istanbul from "vite-plugin-istanbul"; -import {nodePolyfills} from "vite-plugin-node-polyfills"; -// https://vitejs.dev/config/ -export default defineConfig(({mode}) => { - const env = loadEnv(mode, process.cwd(), ""); - return { - plugins: [ - react(), - nodePolyfills({include: ["crypto", "os", "path", "stream", "vm"]}), - istanbul({ - requireEnv: false, - cypress: true, - include: "src/*", - exclude: ["node_modules", "cypress", "src/**/*.cy.*"], - extension: [".js", ".jsx", ".ts", ".tsx"], - }), - ], - define: { - "process.env": env, - }, - optimizeDeps: { - entries: ["cypress/**/*", "src/**/*"], - }, - resolve: { - alias: { - "@": path.resolve(__dirname, "./src"), - }, - }, - build: { - outDir: "build", - sourcemap: true, - rollupOptions: { - output: { - sourcemap: false, - }, - }, - }, - server: { - watch: { - ignored: ["**/coverage/**"], - }, - }, - }; -}); From 61451deff61c9fc2f89d4dba0521edf298b25fe8 Mon Sep 17 00:00:00 2001 From: DyferHerioss Date: Thu, 13 Aug 2026 10:15:32 +0300 Subject: [PATCH 7/7] chore: increase coverage --- cypress/e2e/admin.welcome.cy.tsx | 16 ++ .../e2e/manager.credit-transactions.cy.tsx | 69 +++++++++ cypress/e2e/manager.fees.archive.cy.tsx | 86 +++++++++++ cypress/e2e/manager.payments.credit.cy.tsx | 143 +++++++++++++++++- cypress/e2e/student.fees.mpbs.cy.tsx | 48 ++++++ .../common/components/ArchiveWithConfirm.tsx | 9 +- src/providers/studentCreditProvider.tsx | 42 +++-- 7 files changed, 393 insertions(+), 20 deletions(-) create mode 100644 cypress/e2e/manager.credit-transactions.cy.tsx create mode 100644 cypress/e2e/manager.fees.archive.cy.tsx diff --git a/cypress/e2e/admin.welcome.cy.tsx b/cypress/e2e/admin.welcome.cy.tsx index 8ceb2bcac..6864a6423 100644 --- a/cypress/e2e/admin.welcome.cy.tsx +++ b/cypress/e2e/admin.welcome.cy.tsx @@ -4,6 +4,7 @@ import {WhoamiRoleEnum} from "@haapi-b0fc7615/typescript-client"; import {advanceStatsMocks} from "../fixtures/api_mocks/advanceStats-mocks"; import {announcementsMock} from "../fixtures/api_mocks/announcement-mocks"; import {commentMocks} from "../fixtures/api_mocks/comment-mocks"; +import {creditPaymentPendingMock} from "../fixtures/api_mocks/credit-payments-mocks"; import {unpaidFeeMock} from "../fixtures/api_mocks/fees-mocks"; import {lettersMocks, statsMocks} from "../fixtures/api_mocks/letters-mocks"; import {studentsMock} from "../fixtures/api_mocks/students-mocks"; @@ -64,6 +65,12 @@ describe("AdminWelcome Page", () => { ).as("getAnnouncements2"); cy.intercept("GET", `/fees**`, {data: [unpaidFeeMock]}).as("getFees"); + + cy.intercept( + "GET", + `/students/credit-payments?status=CREATED&page=*&page_size=*`, + [creditPaymentPendingMock] + ).as("getPendingCreditPayments"); }); it("should display 'Bonjour' greeting in WelcomingCard", () => { @@ -137,6 +144,15 @@ describe("AdminWelcome Page", () => { }); }); + it("should display the pending credit payments widget with the correct count", () => { + cy.wait("@getPendingCreditPayments"); + cy.contains("Paiements par crédit à valider").should("exist"); + cy.contains("1 en attente").should("exist"); + + cy.contains("Voir tous les paiements").click(); + cy.url().should("include", "/credit-payments"); + }); + it("should render radial gradient decorations with radial-gradient in background", () => { cy.viewport(1280, 800); cy.get('[data-testid="welcoming-radial-1"]') diff --git a/cypress/e2e/manager.credit-transactions.cy.tsx b/cypress/e2e/manager.credit-transactions.cy.tsx new file mode 100644 index 000000000..48845f357 --- /dev/null +++ b/cypress/e2e/manager.credit-transactions.cy.tsx @@ -0,0 +1,69 @@ +import {fee1Mock} from "../fixtures/api_mocks/fees-mocks"; +import {student1Mock, studentsMock} from "../fixtures/api_mocks/students-mocks"; + +const creditTransactionsMock = [ + { + transaction_id: "transaction1_id", + movement: "DEPOSIT", + amount: 100000, + date_time: new Date("2024-02-01T10:00:00Z"), + fee: {comment: fee1Mock.comment}, + }, + { + transaction_id: "transaction2_id", + movement: "WITHDRAWAL", + amount: 40000, + date_time: null, + fee: null, + }, +]; + +describe("Manager.Student.CreditTransactions", () => { + beforeEach(() => { + cy.mockLogin({role: "MANAGER"}); + cy.visit("/profile"); + cy.intercept("GET", `/students?page=1&page_size=10`, studentsMock).as( + "getStudents" + ); + cy.intercept( + "GET", + `/students?page=*&page_size=*&first_name=${student1Mock.first_name}`, + [student1Mock] + ).as("getStudentsByFirstName"); + cy.intercept("GET", `/students/${student1Mock.id}`, student1Mock); + cy.intercept("GET", `/students/${student1Mock.id}/level`, "L1").as( + "getStudentLevel" + ); + cy.intercept( + "GET", + `/students/${student1Mock.id}/credit-transactions**`, + creditTransactionsMock + ).as("getCreditTransactions"); + + cy.getByTestid("students-menu").click(); + cy.get('a[href="/students"]').click(); + cy.wait("@getStudents"); + cy.getByTestid("menu-list-action").click(); + cy.getByTestid("add-filter").click(); + cy.getByTestid("filter-profile-first_name").type(student1Mock.first_name); + cy.getByTestid("apply-filter").click(); + cy.contains(student1Mock.first_name).click(); + }); + + it("lists the student's credit transactions", () => { + cy.getByTestid("credit-transactions-tab").click(); + cy.wait("@getCreditTransactions"); + + cy.get("table tbody tr") + .eq(0) + .should("contain", "Dépôt") + .and("contain", "100000 Ar") + .and("contain", fee1Mock.comment); + + cy.get("table tbody tr") + .eq(1) + .should("contain", "Retrait") + .and("contain", "40000 Ar") + .and("contain", "Non défini"); + }); +}); diff --git a/cypress/e2e/manager.fees.archive.cy.tsx b/cypress/e2e/manager.fees.archive.cy.tsx new file mode 100644 index 000000000..f09583517 --- /dev/null +++ b/cypress/e2e/manager.fees.archive.cy.tsx @@ -0,0 +1,86 @@ +import {fee1Mock, feesMock} from "../fixtures/api_mocks/fees-mocks"; +import {student1Mock, studentsMock} from "../fixtures/api_mocks/students-mocks"; + +describe("Manager.Fee.Archive", () => { + beforeEach(() => { + cy.mockLogin({role: "MANAGER"}); + cy.visit("/profile"); + cy.intercept("GET", `/students?page=1&page_size=10`, studentsMock).as( + "getStudents" + ); + cy.intercept( + "GET", + `/students?page=*&page_size=*&first_name=${student1Mock.first_name}`, + [student1Mock] + ).as("getStudentsByFirstName"); + cy.intercept("GET", `/students/${student1Mock.id}`, student1Mock); + cy.intercept("GET", `/students/${student1Mock.id}/level`, "L1").as( + "getStudentLevel" + ); + + cy.getByTestid("students-menu").click(); + cy.get('a[href="/students"]').click(); + cy.wait("@getStudents"); + cy.getByTestid("menu-list-action").click(); + cy.getByTestid("add-filter").click(); + cy.getByTestid("filter-profile-first_name").type(student1Mock.first_name); + cy.getByTestid("apply-filter").click(); + cy.contains(student1Mock.first_name).click(); + }); + + it("can archive a fee", () => { + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=1&page_size=10`, + feesMock + ).as("getFees"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=2&page_size=10`, + feesMock + ).as("getFees2"); + cy.intercept( + "PATCH", + `/students/${student1Mock.id}/fees/${fee1Mock.id}`, + {} + ).as("archiveFee"); + + cy.getByTestid("fees-tab").click(); + cy.wait("@getFees"); + + cy.get( + ".manager-fee-list .RaDatagrid-clickableRow.MuiTableRow-root:nth-child(1)" + ) + .find('[data-testid="archive-button-confirm"]') + .click(); + + cy.get("#alert-dialog-title").should("contain", "Archivage de frais"); + cy.contains("Confirmez-vous l'archivage de ce frais ?"); + cy.get(".ra-confirm").click(); + + cy.wait("@archiveFee"); + cy.contains("Frais archivé avec succès."); + }); + + it("disables the archive button for an already archived fee", () => { + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=1&page_size=10`, + [{...fee1Mock, is_archived: true}, ...feesMock.slice(1)] + ).as("getFeesArchived"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=2&page_size=10`, + feesMock + ).as("getFeesArchived2"); + + cy.getByTestid("fees-tab").click(); + cy.wait("@getFeesArchived"); + + cy.get( + ".manager-fee-list .RaDatagrid-clickableRow.MuiTableRow-root:nth-child(1)" + ) + .find('[data-testid="archive-button-confirm"]') + .should("be.disabled"); + }); +}); diff --git a/cypress/e2e/manager.payments.credit.cy.tsx b/cypress/e2e/manager.payments.credit.cy.tsx index efe0e8bfa..b70496ad2 100644 --- a/cypress/e2e/manager.payments.credit.cy.tsx +++ b/cypress/e2e/manager.payments.credit.cy.tsx @@ -25,7 +25,7 @@ describe("Manager.Payments.Flow", () => { ); cy.intercept( "GET", - `/students?page=1&page_size=10&first_name=${student1Mock.first_name}`, + `/students?page=*&page_size=*&first_name=${student1Mock.first_name}`, [student1Mock] ).as("getStudentsByFirstName"); cy.intercept("GET", `/students/${student1Mock.id}`, student1Mock); @@ -103,6 +103,11 @@ describe("Manager.Payments.Flow", () => { `/students/${student1Mock.id}/fees/${fee1Mock.id}/payments`, [createPayment] ).as("createPayment"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=1&page_size=500`, + [] + ).as("getFeesForCredit"); cy.getByTestid("fees-tab").click(); cy.wait("@getFees"); @@ -114,6 +119,7 @@ describe("Manager.Payments.Flow", () => { cy.contains("Créer").click(); cy.wait("@getStudentCredit"); + cy.wait("@getFeesForCredit"); cy.get("#type_CASH").click(); cy.get("#amount").click().type(createPayment.amount!.toString()); @@ -123,6 +129,86 @@ describe("Manager.Payments.Flow", () => { cy.wait("@createPayment"); cy.contains("Élément créé"); }); + + it("can create a credit payment for a fee within the student's credit", () => { + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}`, + fee1Mock + ).as("getFee1"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}/payments?page=1&page_size=10`, + [] + ).as("getPayments"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=1&page_size=500`, + [] + ).as("getFeesForCredit"); + cy.intercept( + "POST", + `/students/${student1Mock.id}/fees/${fee1Mock.id}/payments`, + [creditPaymentValidatedMock] + ).as("createCreditPayment"); + + cy.getByTestid("fees-tab").click(); + cy.wait("@getFees"); + cy.get( + ".manager-fee-list .RaDatagrid-clickableRow.MuiTableRow-root:nth-child(1)" + ).click(); + cy.wait("@getFee1"); + cy.wait("@getPayments"); + + cy.contains("Créer").click(); + cy.wait("@getStudentCredit"); + cy.wait("@getFeesForCredit"); + + cy.get("#type_CREDIT").click(); + cy.get("#amount").click().type("100000"); + cy.contains("Enregistrer").click(); + + cy.wait("@createCreditPayment"); + cy.contains("Élément créé"); + }); + + it("cannot create a credit payment exceeding the student's credit", () => { + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}`, + fee1Mock + ).as("getFee1"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees/${fee1Mock.id}/payments?page=1&page_size=10`, + [] + ).as("getPayments"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=1&page_size=500`, + [] + ).as("getFeesForCredit"); + + cy.getByTestid("fees-tab").click(); + cy.wait("@getFees"); + cy.get( + ".manager-fee-list .RaDatagrid-clickableRow.MuiTableRow-root:nth-child(1)" + ).click(); + cy.wait("@getFee1"); + cy.wait("@getPayments"); + + cy.contains("Créer").click(); + cy.wait("@getStudentCredit"); + cy.wait("@getFeesForCredit"); + + cy.get("#type_CREDIT").click(); + cy.get("#amount") + .click() + .type((studentCreditMock.amount + 1).toString()); + cy.contains("Enregistrer").click(); + + cy.contains("Le montant saisi est supérieur à votre crédit actuel."); + }); }); describe("Manager.CreditPayments", () => { @@ -142,12 +228,12 @@ describe("Manager.CreditPayments", () => { Object.values(PaymentStatus).forEach((status) => { cy.intercept( "GET", - `/students/credit-payments?status=${status}&page=1&page_size=500`, + `/students/credit-payments?status=${status}&page=*&page_size=500`, creditPaymentsByStatusMock[status] ).as(`getAllCreditPayments_${status}`); cy.intercept( "GET", - `/students/credit-payments?status=${status}&page=1&page_size=10`, + `/students/credit-payments?status=${status}&page=*&page_size=10`, creditPaymentsByStatusMock[status] ).as(`getFilteredCreditPayments_${status}`); }); @@ -163,7 +249,9 @@ describe("Manager.CreditPayments", () => { cy.get("table tbody tr") .eq(0) - .should("contain", creditPaymentPendingMock.comment); + .should("contain", creditPaymentPendingMock.comment) + .and("contain", student1Mock.ref) + .and("contain", `${studentCreditMock.amount} Ar`); cy.get("table tbody tr") .eq(1) .should("contain", creditPaymentValidatedMock.comment); @@ -195,4 +283,51 @@ describe("Manager.CreditPayments", () => { cy.contains(creditPaymentValidatedMock.comment!); cy.contains(creditPaymentRejectedMock.comment!); }); + + it("can validate a pending credit payment", () => { + cy.intercept("PATCH", `/students/payments/validate`, {}).as( + "validatePayment" + ); + + cy.wait("@getAllCreditPayments_CREATED"); + cy.getByTestid(`validate-payment-${creditPaymentPendingMock.id}`).click(); + cy.get("#alert-dialog-title").should("contain", "Valider le paiement"); + cy.get(".ra-confirm").click(); + + cy.wait("@validatePayment") + .its("request.body") + .should("deep.equal", [creditPaymentPendingMock.id]); + cy.contains("Paiement validé avec succès."); + }); + + it("can reject a pending credit payment", () => { + cy.intercept("PATCH", `/students/payments/reject`, {}).as("rejectPayment"); + + cy.wait("@getAllCreditPayments_CREATED"); + cy.getByTestid(`reject-payment-${creditPaymentPendingMock.id}`).click(); + cy.get("#alert-dialog-title").should("contain", "Rejeter le paiement"); + cy.get(".ra-confirm").click(); + + cy.wait("@rejectPayment") + .its("request.body") + .should("deep.equal", [creditPaymentPendingMock.id]); + cy.contains("Paiement rejeté avec succès."); + }); + + it("disables validate and reject actions for already processed payments", () => { + cy.wait("@getAllCreditPayments_CREATED"); + + cy.getByTestid(`validate-payment-${creditPaymentValidatedMock.id}`).should( + "be.disabled" + ); + cy.getByTestid(`reject-payment-${creditPaymentValidatedMock.id}`).should( + "be.disabled" + ); + cy.getByTestid(`validate-payment-${creditPaymentRejectedMock.id}`).should( + "be.disabled" + ); + cy.getByTestid(`reject-payment-${creditPaymentRejectedMock.id}`).should( + "be.disabled" + ); + }); }); diff --git a/cypress/e2e/student.fees.mpbs.cy.tsx b/cypress/e2e/student.fees.mpbs.cy.tsx index 05c0e9d33..7ef9757cf 100644 --- a/cypress/e2e/student.fees.mpbs.cy.tsx +++ b/cypress/e2e/student.fees.mpbs.cy.tsx @@ -1,3 +1,4 @@ +import {studentCreditMock} from "../fixtures/api_mocks/credit-payments-mocks"; import { fee1Mock, fee1MockMpbs, @@ -21,6 +22,16 @@ describe("Mobile payment by student", () => { cy.intercept("GET", `/students/${student1Mock.id}/level`, "L1").as( "getStudentLevel" ); + cy.intercept( + "GET", + `/students/${student1Mock.id}/credit`, + studentCreditMock + ).as("getStudentCredit"); + cy.intercept( + "GET", + `/students/${student1Mock.id}/fees?page=1&page_size=500`, + [] + ).as("getFeesForCredit"); cy.mockLogin({role: "STUDENT"}); cy.get(`[href="/students/${student1Mock.id}/fees"]`).click(); @@ -71,4 +82,41 @@ describe("Mobile payment by student", () => { cy.wait("@getMpbsFees"); }); + + it("can pay a fee by credit when the student has enough credit", () => { + cy.intercept( + "POST", + `/students/${fee1Mock.student_id}/fees/${fee1Mock.id}/payments`, + [{id: "credit_payment_new_id"}] + ).as("createCreditPayment"); + + cy.wait("@getStudentCredit"); + + cy.getByTestid( + `addMobileMoney-${fee1Mock.student_id}--${fee1Mock.id}` + ).click({force: true}); + + cy.contains("Crédit").click(); + cy.get("#amount").click().type("100000"); + cy.contains("Enregistrer").click(); + + cy.contains("Paiement enregistré avec succès"); + cy.wait("@createCreditPayment"); + }); + + it("cannot pay a fee by credit for more than the available credit", () => { + cy.wait("@getStudentCredit"); + + cy.getByTestid( + `addMobileMoney-${fee1Mock.student_id}--${fee1Mock.id}` + ).click({force: true}); + + cy.contains("Crédit").click(); + cy.get("#amount") + .click() + .type((studentCreditMock.amount + 1).toString()); + cy.contains("Enregistrer").click(); + + cy.contains("Le montant saisi est supérieur à votre crédit actuel."); + }); }); diff --git a/src/operations/common/components/ArchiveWithConfirm.tsx b/src/operations/common/components/ArchiveWithConfirm.tsx index d5d7c7c9d..6340b464d 100644 --- a/src/operations/common/components/ArchiveWithConfirm.tsx +++ b/src/operations/common/components/ArchiveWithConfirm.tsx @@ -1,6 +1,5 @@ import ArchiveIcon from "@mui/icons-material/Archive"; import {Button, ButtonProps} from "@mui/material"; -import {FC} from "react"; import { Confirm, RaRecord, @@ -10,21 +9,23 @@ import { } from "react-admin"; import {useToggle} from "../../../hooks"; -export const ArchiveWithConfirm: FC<{ +interface ArchiveWithConfirmProps { text?: string; confirmTitle: string; confirmContent: string; redirect?: string; buttonProps?: ButtonProps; onArchive: (record: RaRecord) => Promise; -}> = ({ +} + +export const ArchiveWithConfirm = ({ text, confirmTitle, confirmContent, redirect, buttonProps = {}, onArchive, -}) => { +}: ArchiveWithConfirmProps) => { const record = useRecordContext(); const [showConfirm, , toggleShowConfirm] = useToggle(); const notify = useNotify(); diff --git a/src/providers/studentCreditProvider.tsx b/src/providers/studentCreditProvider.tsx index b947bdeb9..04bf93d42 100644 --- a/src/providers/studentCreditProvider.tsx +++ b/src/providers/studentCreditProvider.tsx @@ -1,23 +1,41 @@ -import {CreditMovement, PaymentStatus} from "@haapi-b0fc7615/typescript-client"; +import { + CreditMovement, + PaymentStatus, + PaymentTypeEnum, +} from "@haapi-b0fc7615/typescript-client"; import {HaDataProviderType} from "./HaDataProviderType"; import {payingApi} from "./api"; const FETCH_ALL_PAGE_SIZE = 500; +// Computed from the student's own fees/payments (instead of the +// manager/admin-only "all credit payments" endpoint) so it can be used both +// from a manager's view of a student and from the student's own view. const getPendingCreditAmount = async (studentId: string): Promise => { - const [studentFees, pendingCreditPayments] = await Promise.all([ - payingApi().getFeesByStudentId(studentId, 1, FETCH_ALL_PAGE_SIZE), - payingApi().getCreditPaymentsByStatus( - PaymentStatus.CREATED, - 1, - FETCH_ALL_PAGE_SIZE - ), - ]); + const {data: studentFees} = await payingApi().getFeesByStudentId( + studentId, + 1, + FETCH_ALL_PAGE_SIZE + ); - const studentFeeIds = new Set(studentFees.data.map((fee) => fee.id)); + const paymentsByFee = await Promise.all( + studentFees.map((fee) => + payingApi().getStudentPayments( + studentId, + fee.id as string, + 1, + FETCH_ALL_PAGE_SIZE + ) + ) + ); - return pendingCreditPayments.data - .filter((payment) => studentFeeIds.has(payment.fee_id)) + return paymentsByFee + .flatMap((result) => result.data) + .filter( + (payment) => + payment.type === PaymentTypeEnum.CREDIT && + payment.status === PaymentStatus.CREATED + ) .reduce((total, payment) => total + (payment.amount ?? 0), 0); };