Merge branch 'staging' into preprod

This commit is contained in:
Vins 2024-02-16 15:01:34 +01:00
commit 7482e06ea6
21 changed files with 522 additions and 977 deletions

View File

@ -24,9 +24,6 @@ COPY --from=deps leCoffre-front/package.json package.json
COPY tsconfig.json tsconfig.json COPY tsconfig.json tsconfig.json
COPY next.config.js next.config.js COPY next.config.js next.config.js
COPY src src COPY src src
COPY sentry.client.config.ts sentry.client.config.ts
COPY sentry.edge.config.ts sentry.edge.config.ts
COPY sentry.server.config.ts sentry.server.config.ts
RUN npm run build RUN npm run build

View File

@ -55,45 +55,3 @@ const nextConfig = {
}; };
module.exports = nextConfig; module.exports = nextConfig;
// Injected content via Sentry wizard below
const { withSentryConfig } = require("@sentry/nextjs");
module.exports = withSentryConfig(
module.exports,
{
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options
// Suppresses source map uploading logs during build
silent: true,
org: "smart-chain-nh",
project: "lecoffre",
},
{
// For all available options, see:
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
// Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true,
// Transpiles SDK to be compatible with IE11 (increases bundle size)
transpileClientSDK: true,
// Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
tunnelRoute: "/monitoring",
// Hides source maps from generated client bundles
hideSourceMaps: true,
// Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true,
// Enables automatic instrumentation of Vercel Cron Monitors.
// See the following for more information:
// https://docs.sentry.io/product/crons/
// https://vercel.com/docs/cron-jobs
automaticVercelMonitors: true,
},
);

1178
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,6 @@
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6", "@emotion/styled": "^11.10.6",
"@mui/material": "^5.11.13", "@mui/material": "^5.11.13",
"@sentry/nextjs": "^7.90.0",
"@types/node": "18.15.1", "@types/node": "18.15.1",
"@types/react": "18.0.28", "@types/react": "18.0.28",
"@types/react-dom": "18.0.11", "@types/react-dom": "18.0.11",
@ -25,7 +24,7 @@
"eslint-config-next": "13.2.4", "eslint-config-next": "13.2.4",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.106", "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.108",
"next": "13.2.4", "next": "13.2.4",
"prettier": "^2.8.7", "prettier": "^2.8.7",
"react": "18.2.0", "react": "18.2.0",

View File

@ -1,34 +0,0 @@
// This file configures the initialization of Sentry on the client.
// The config you add here will be used whenever a users loads a page in their browser.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
console.log("Client config");
Sentry.init({
dsn: "https://ca6a89e8b480c814e1b5828b8412c681@o4506382103281664.ingest.sentry.io/4506399972130816",
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1,
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
replaysOnErrorSampleRate: 1.0,
// This sets the sample rate to be 10%. You may want this to be 100% while
// in development and sample at a lower rate in production
replaysSessionSampleRate: 0.1,
// You can remove this option if you're not planning to use the Sentry Session Replay feature:
integrations: [
new Sentry.Replay({
// Additional Replay configuration goes in here, for example:
maskAllText: true,
blockAllMedia: true,
}),
],
});
Sentry.setTag("service", "leCoffre-front");

View File

@ -1,20 +0,0 @@
// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).
// The config you add here will be used whenever one of the edge features is loaded.
// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
console.log("Edge config");
Sentry.init({
dsn: "https://ca6a89e8b480c814e1b5828b8412c681@o4506382103281664.ingest.sentry.io/4506399972130816",
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1,
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
});
Sentry.setTag("service", "leCoffre-front");

View File

@ -1,19 +0,0 @@
// This file configures the initialization of Sentry on the server.
// The config you add here will be used whenever the server handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
console.log("Server config");
Sentry.init({
dsn: "https://ca6a89e8b480c814e1b5828b8412c681@o4506382103281664.ingest.sentry.io/4506399972130816",
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1,
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
});
Sentry.setTag("service", "leCoffre-front");

View File

@ -7,13 +7,13 @@
resize: none; resize: none;
height: auto; height: auto;
box-sizing: border-box; box-sizing: border-box;
font-family: "Inter"; font-family: "Inter", sans-serif;
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
&:read-only{ &:read-only {
cursor: not-allowed; cursor: not-allowed;
} }
z-index: 1; z-index: 1;

View File

@ -21,7 +21,7 @@
margin-left: 8px; margin-left: 8px;
padding: 24px 0; padding: 24px 0;
width: 100%; width: 100%;
font-family: "Inter"; font-family: "Inter", sans-serif;
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;

View File

@ -15,7 +15,9 @@
} }
.folderlist-container { .folderlist-container {
max-height: calc(100vh - 215px);
height: 100%; height: 100%;
border-right: 1px solid var(--grey-medium); border-right: 1px solid var(--grey-medium);
overflow: auto;
} }
} }

View File

@ -6,6 +6,8 @@
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
position: relative;
.header { .header {
flex: 1; flex: 1;
} }
@ -15,9 +17,16 @@
} }
.folderlist-container { .folderlist-container {
max-height: calc(100vh - 290px); max-height: calc(100vh - 215px);
height: calc(100vh - 290px); height: calc(100vh - 215px);
overflow: auto; overflow: auto;
border-right: 1px solid var(--grey-medium); border-right: 1px solid var(--grey-medium);
} }
.create-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
} }

View File

@ -59,7 +59,7 @@ export default function DeedListContainer(props: IProps) {
/> />
</div> </div>
</div> </div>
<div> <div className={classes["create-container"]}>
<Link href={Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path}> <Link href={Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path}>
<Button fullwidth={true}>Créer un type d'acte</Button> <Button fullwidth={true}>Créer un type d'acte</Button>
</Link> </Link>

View File

@ -15,8 +15,8 @@
} }
.folderlist-container { .folderlist-container {
max-height: calc(100vh - 290px); max-height: calc(100vh - 215px);
height: calc(100vh - 290px); height: calc(100vh - 215px);
overflow: auto; overflow: auto;
border-right: 1px solid var(--grey-medium); border-right: 1px solid var(--grey-medium);
} }

View File

@ -6,6 +6,8 @@
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
position: relative;
.header { .header {
flex: 1; flex: 1;
} }
@ -15,9 +17,16 @@
} }
.folderlist-container { .folderlist-container {
max-height: calc(100vh - 290px); max-height: calc(100vh - 215px);
height: calc(100vh - 290px); height: calc(100vh - 215px);
overflow: auto; overflow: auto;
border-right: 1px solid var(--grey-medium); border-right: 1px solid var(--grey-medium);
} }
.create-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
} }

View File

@ -64,7 +64,7 @@ export default function RoleListContainer(props: IProps) {
/> />
</div> </div>
</div> </div>
<div> <div className={classes["create-container"]}>
<Link href={Module.getInstance().get().modules.pages.Roles.pages.Create.props.path}> <Link href={Module.getInstance().get().modules.pages.Roles.pages.Create.props.path}>
<Button fullwidth={true}>Créer un rôle</Button> <Button fullwidth={true}>Créer un rôle</Button>
</Link> </Link>

View File

@ -71,12 +71,14 @@ export default function DeedTypesInformations(props: IProps) {
setDeedTypeSelected(deedType); setDeedTypeSelected(deedType);
if (!deedType.document_types) return; if (!deedType.document_types) return;
const documentsOptions: IOption[] = deedType.document_types?.map((documentType) => { const documentsOptions: IOption[] = deedType.document_types
return { ?.map((documentType) => {
label: documentType.name, return {
value: documentType.uid, label: documentType.name,
}; value: documentType.uid,
}); };
})
.sort((a, b) => a.label.localeCompare(b.label));
setSelectedDocuments(documentsOptions); setSelectedDocuments(documentsOptions);
} }
@ -108,12 +110,12 @@ export default function DeedTypesInformations(props: IProps) {
setSelectedDocuments(values as IOption[]); setSelectedDocuments(values as IOption[]);
}, []); }, []);
const formattedOptions: IOption[] = availableDocuments.map((document) => { const formattedOptions: IOption[] = availableDocuments
return { .map((document) => ({
label: document.name, label: document.name,
value: document.uid, value: document.uid,
}; }))
}); .sort((a, b) => a.label.localeCompare(b.label));
return ( return (
<DefaultDeedTypesDashboard mobileBackText={"Liste des types d'actes"}> <DefaultDeedTypesDashboard mobileBackText={"Liste des types d'actes"}>

View File

@ -51,7 +51,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
super(props); super(props);
this.state = { this.state = {
folder_access: "", folder_access: "select_collaborators",
formValues: { formValues: {
folder_number: "", folder_number: "",
entitled: "", entitled: "",
@ -122,10 +122,10 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
Accès au dossier Accès au dossier
</Typography> </Typography>
<div className={classes["radio-container"]}> <div className={classes["radio-container"]}>
<RadioBox name="file_access" defaultChecked onChange={this.radioOnChange} value="whole_office"> <RadioBox name="file_access" onChange={this.radioOnChange} value="whole_office">
Sélectionner tout l'office Sélectionner tout l'office
</RadioBox> </RadioBox>
<RadioBox name="file_access" onChange={this.radioOnChange} value="select_collaborators"> <RadioBox name="file_access" defaultChecked onChange={this.radioOnChange} value="select_collaborators">
Sélectionner certains collaborateurs Sélectionner certains collaborateurs
</RadioBox> </RadioBox>
</div> </div>
@ -149,11 +149,26 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
const collaborators = await Users.getInstance().get({ const collaborators = await Users.getInstance().get({
include: { contact: true }, include: { contact: true },
}); });
const collaboratorsOptions = this.mapUsersOptions(collaborators);
this.setState({ this.setState({
deedTypes, deedTypes,
deedTypesOptions: this.mapDeedOptions(deedTypes), deedTypesOptions: this.mapDeedOptions(deedTypes),
collaborators, collaborators,
collaboratorsOptions: this.mapUsersOptions(collaborators), collaboratorsOptions: collaboratorsOptions,
});
const userId = JwtService.getInstance().decodeJwt()?.userId;
const currentCollaborator = collaboratorsOptions.find(({ value }) => value === userId);
if (!currentCollaborator) return;
this.setState({
formValues: {
...this.state.formValues,
collaborators: [{ label: currentCollaborator.label, value: currentCollaborator.value }],
},
}); });
} }

View File

@ -65,6 +65,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
this.openArchivedModal = this.openArchivedModal.bind(this); this.openArchivedModal = this.openArchivedModal.bind(this);
this.closeArchivedModal = this.closeArchivedModal.bind(this); this.closeArchivedModal = this.closeArchivedModal.bind(this);
this.onArchivedModalAccepted = this.onArchivedModalAccepted.bind(this); this.onArchivedModalAccepted = this.onArchivedModalAccepted.bind(this);
this.onPreventArchiveModalAccepted = this.onPreventArchiveModalAccepted.bind(this);
this.getCompletionNumber = this.getCompletionNumber.bind(this); this.getCompletionNumber = this.getCompletionNumber.bind(this);
this.onArchivedDescriptionInputChange = this.onArchivedDescriptionInputChange.bind(this); this.onArchivedDescriptionInputChange = this.onArchivedDescriptionInputChange.bind(this);
this.deleteFolder = this.deleteFolder.bind(this); this.deleteFolder = this.deleteFolder.bind(this);
@ -198,6 +199,25 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
onChange={this.onArchivedDescriptionInputChange} onChange={this.onArchivedDescriptionInputChange}
/> />
</Confirm> </Confirm>
<Confirm
isOpen={this.state.isPreventArchiveModalOpen}
onAccept={this.onPreventArchiveModalAccepted}
onClose={this.closePreventArchiveModal}
closeBtn
header={"Archiver le dossier"}
cancelText={"Annuler"}
confirmText={"Archiver"}>
<div className={classes["modal-title"]}>
<Typography typo={ITypo.P_16}>
Vous êtes en train darchiver le dossier sans avoir lancré, êtes-vous sûr de vouloir le faire ?
</Typography>
</div>
<TextAreaField
name="archived_description"
placeholder="Description"
onChange={this.onArchivedDescriptionInputChange}
/>
</Confirm>
<Confirm <Confirm
isOpen={this.state.isVerifDeleteModalVisible} isOpen={this.state.isVerifDeleteModalVisible}
onAccept={this.deleteFolder} onAccept={this.deleteFolder}
@ -230,22 +250,6 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
</div> </div>
</div> </div>
)} )}
<Confirm
isOpen={this.state.isPreventArchiveModalOpen}
onAccept={this.closePreventArchiveModal}
onClose={this.closePreventArchiveModal}
closeBtn
header={"Vous devez valider et ancrer un dossier avant de pouvoir l'archiver"}
cancelText={"Annuler"}
confirmText={"J'ai compris"}>
<div className={classes["modal-title"]}>
<Typography typo={ITypo.P_16}>
Pour valider un dossier, toutes les pièces envoyées par vos clients doivent être validées (vert). Si certains
documents sont en attente (orange), alors, veuillez les valider ou les refuser et veillez à ce qu'aucun document
ne soit encore en demandé au client (gris)
</Typography>
</div>
</Confirm>
<Confirm <Confirm
isOpen={this.state.isValidateModalVisible} isOpen={this.state.isValidateModalVisible}
onClose={this.closeModal} onClose={this.closeModal}
@ -423,6 +427,13 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
this.closeArchivedModal(); this.closeArchivedModal();
this.props.router.push(Module.getInstance().get().modules.pages.Folder.props.path); this.props.router.push(Module.getInstance().get().modules.pages.Folder.props.path);
} }
private async onPreventArchiveModalAccepted() {
if (!this.props.selectedFolder) return;
await Folders.getInstance().archive(this.props.selectedFolder.uid ?? "", this.state.inputArchivedDescripton);
this.closePreventArchiveModal();
this.props.router.push(Module.getInstance().get().modules.pages.Folder.props.path);
}
} }
export default function FolderInformation(props: IProps) { export default function FolderInformation(props: IProps) {

View File

@ -62,7 +62,7 @@ a:hover {
.react-select__menu-notice { .react-select__menu-notice {
font-size: 18px; font-size: 18px;
font-family: Inter; font-family: "Inter", sans-serif !important;
} }
.Toastify__toast-body { .Toastify__toast-body {

View File

@ -1,17 +0,0 @@
import * as Sentry from "@sentry/nextjs";
import Error from "next/error";
const CustomErrorComponent = (props) => {
return <Error statusCode={props.statusCode} />;
};
CustomErrorComponent.getInitialProps = async (contextData) => {
// In case this is running in a serverless function, await this in order to give Sentry
// time to send the error before the lambda exits
await Sentry.captureUnderscoreErrorException(contextData);
// This will contain the status code of the response
return Error.getInitialProps(contextData);
};
export default CustomErrorComponent;

View File

@ -3,7 +3,11 @@
"incremental": false, "incremental": false,
"target": "es5", "target": "es5",
"module": "CommonJS", "module": "CommonJS",
"lib": ["dom", "dom.iterable", "esnext"], "lib": [
"dom",
"dom.iterable",
"esnext"
],
"jsx": "preserve", "jsx": "preserve",
"sourceMap": true, "sourceMap": true,
"outDir": "./dist", "outDir": "./dist",
@ -34,14 +38,30 @@
"moduleResolution": "node", "moduleResolution": "node",
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@Api/*": ["src/api/*"], "@Api/*": [
"@Front/*": ["src/front/*"], "src/api/*"
"@Assets/*": ["src/front/Assets/*"], ],
"@Components/*": ["src/front/Components/*"], "@Front/*": [
"@Themes/*": ["src/front/Themes/*"], "src/front/*"
"@Stores/*": ["src/front/Stores/*"], ],
"@FrontServices/*": ["src/front/services/*"], "@Assets/*": [
"@Page/*": ["src/pages/*"] "src/front/Assets/*"
],
"@Components/*": [
"src/front/Components/*"
],
"@Themes/*": [
"src/front/Themes/*"
],
"@Stores/*": [
"src/front/Stores/*"
],
"@FrontServices/*": [
"src/front/services/*"
],
"@Page/*": [
"src/pages/*"
]
}, },
// "rootDirs": [], // "rootDirs": [],
// "typeRoots": [], // "typeRoots": [],
@ -62,6 +82,13 @@
"allowJs": true, "allowJs": true,
"isolatedModules": true "isolatedModules": true
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "src/front/next.config.js"], "include": [
"exclude": ["node_modules"] "next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"src/front/next.config.js",
],
"exclude": [
"node_modules"
]
} }