diff --git a/src/front/Api/LeCoffreApi/Admin/Roles/Roles.ts b/src/front/Api/LeCoffreApi/Admin/Roles/Roles.ts index af2a0ea7..50770418 100644 --- a/src/front/Api/LeCoffreApi/Admin/Roles/Roles.ts +++ b/src/front/Api/LeCoffreApi/Admin/Roles/Roles.ts @@ -2,21 +2,32 @@ import { Role } from "le-coffre-resources/dist/Admin"; import BaseAdmin from "../BaseAdmin"; -// TODO Type get query params -> Where + inclue + orderby -export interface IGetRolesParams { +export type IGetRolesParams = { where?: {}; include?: {}; select?: {}; -} +}; + +export type IPutRoleParams = { + rules: Role["rules"]; +}; export default class Roles extends BaseAdmin { - public static instance: Roles = new this(); + private static instance: Roles; private readonly baseURl = this.namespaceUrl.concat("/roles"); private constructor() { super(); } + public static getInstance() { + if (!this.instance) { + return new Roles(); + } else { + return this.instance; + } + } + public async get(q: IGetRolesParams): Promise { const url = new URL(this.baseURl); const query = { q }; @@ -39,4 +50,14 @@ export default class Roles extends BaseAdmin { return Promise.reject(err); } } + + public async put(uid: string, body: IPutRoleParams): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + try { + return await this.putRequest(url, body); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } } diff --git a/src/front/Api/LeCoffreApi/Admin/Rules/Rules.ts b/src/front/Api/LeCoffreApi/Admin/Rules/Rules.ts new file mode 100644 index 00000000..f8d79d90 --- /dev/null +++ b/src/front/Api/LeCoffreApi/Admin/Rules/Rules.ts @@ -0,0 +1,49 @@ +import { Rule } from "le-coffre-resources/dist/Admin"; + +import BaseAdmin from "../BaseAdmin"; + +export type IGetRulesParams = { + where?: {}; + include?: {}; + select?: {}; +}; + +export default class Rules extends BaseAdmin { + private static instance: Rules; + private readonly baseURl = this.namespaceUrl.concat("/rules"); + + private constructor() { + super(); + } + + public static getInstance() { + if (!this.instance) { + return new Rules(); + } else { + return this.instance; + } + } + + public async get(q: IGetRulesParams): Promise { + const url = new URL(this.baseURl); + const query = { q }; + Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async getByUid(uid: string, q?: any): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Components/DesignSystem/CheckBox/index.tsx b/src/front/Components/DesignSystem/CheckBox/index.tsx index 36d5d001..4935ca95 100644 --- a/src/front/Components/DesignSystem/CheckBox/index.tsx +++ b/src/front/Components/DesignSystem/CheckBox/index.tsx @@ -9,13 +9,29 @@ type IProps = { name?: string; option: IOption; toolTip?: string; + onChange?: (e: React.ChangeEvent) => void; + checked: boolean; }; -export default class CheckBox extends React.Component { +type IState = { + checked: boolean; +}; + +export default class CheckBox extends React.Component { static defaultProps = { toolTip: "", + checked: false, }; + constructor(props: IProps) { + super(props); + this.state = { + checked: this.props.checked ?? false, + }; + + this.onChange = this.onChange.bind(this); + } + public override render(): JSX.Element { return ( @@ -24,6 +40,8 @@ export default class CheckBox extends React.Component { type="checkbox" name={this.props.name ?? (this.props.option.value as string)} value={this.props.option.value as string} + onChange={this.onChange} + checked={this.state.checked} /> {this.props.option.label} {this.props.toolTip && } @@ -31,4 +49,20 @@ export default class CheckBox extends React.Component { ); } + + public override componentDidUpdate(prevProps: Readonly): void { + if (prevProps.checked !== this.props.checked) { + this.setState({ + checked: this.props.checked, + }); + } + } + + private onChange(e: React.ChangeEvent) { + this.setState({ + checked: !this.state.checked, + }); + + this.props.onChange && this.props.onChange(e); + } } diff --git a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx index 768ecb39..96842071 100644 --- a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx @@ -20,9 +20,7 @@ export default function RoleListContainer(props: IProps) { const filterRoles = useCallback( (input: string) => { const filteredUsers = props.roles.filter((role) => { - return ( - role.name?.toLowerCase().includes(input.toLowerCase()) - ); + return role.name?.toLowerCase().includes(input.toLowerCase()); }); setFilteredUsers(filteredUsers); }, @@ -32,7 +30,7 @@ export default function RoleListContainer(props: IProps) { const onSelectedBlock = useCallback( (block: IBlock) => { props.onCloseLeftSide && props.onCloseLeftSide(); - const redirectPath = Module.getInstance().get().modules.pages.Collaborators.pages.CollaboratorInformations.props.path; + const redirectPath = Module.getInstance().get().modules.pages.Roles.pages.RolesInformations.props.path; router.push(redirectPath.replace("[uid]", block.id)); }, [props, router], diff --git a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx index 64266376..e7898b31 100644 --- a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx @@ -85,27 +85,14 @@ export default class DefaultRoleDashboard extends React.Component this.onResize(window)); - // const query: IGetRolesParams = { - // include: { rules: true }, - // }; + const query: IGetRolesParams = { + include: { rules: true }, + }; - // const roles = await Roles.instance.get(query); - const roles: Role[] = [ - Role.hydrate({ - name: "Notaire", - uid: "1", - }), - Role.hydrate({ - name: "Clerc de notaire", - uid: "2", - }), - Role.hydrate({ - name: "Collaborateur", - uid: "3", - }), - ]; + const roles = await Roles.getInstance().get(query); this.setState({ roles }); } + public override componentWillUnmount() { this.onWindowResize(); } diff --git a/src/front/Components/Layouts/Roles/RolesInformations/classes.module.scss b/src/front/Components/Layouts/Roles/RolesInformations/classes.module.scss index d04c1ba8..1765fdf9 100644 --- a/src/front/Components/Layouts/Roles/RolesInformations/classes.module.scss +++ b/src/front/Components/Layouts/Roles/RolesInformations/classes.module.scss @@ -1,45 +1,26 @@ @import "@Themes/constants.scss"; .root { - .user-infos { - background-color: var(--grey-soft); - display: flex; - justify-content: space-between; - padding: 24px; - + .subtitle { margin-top: 32px; + } - @media (max-width: $screen-l) { + .rights-container { + margin-top: 32px; + padding: 32px 16px; + border: 1px solid gray; + .select-all-container { + margin-top: 32px; + } + + .rights { + margin-top: 32px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 32px; } - @media (max-width: $screen-s) { - grid-template-columns: repeat(1, 1fr); - } - - .user-infos-row { - display: flex; - flex-direction: column; - gap: 12px; - } - } - - .role-container { - padding: 32px 16px; - border: 1px solid var(--grey); - - margin-top: 32px; - - .first-line { - display: flex; - justify-content: space-between; - } - .second-line { - margin-top: 32px; - } - .third-line { + .save-container { margin-top: 32px; } } diff --git a/src/front/Components/Layouts/Roles/RolesInformations/index.tsx b/src/front/Components/Layouts/Roles/RolesInformations/index.tsx index 685986c5..eafa2e48 100644 --- a/src/front/Components/Layouts/Roles/RolesInformations/index.tsx +++ b/src/front/Components/Layouts/Roles/RolesInformations/index.tsx @@ -1,100 +1,115 @@ -import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users"; -import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; -import DefaultCollaboratorDashboard from "@Front/Components/LayoutTemplates/DefaultCollaboratorDashboard"; -import User from "le-coffre-resources/dist/Notary"; -import { useRouter } from "next/router"; -import { useEffect, useState } from "react"; -import classes from "./classes.module.scss"; -import Link from "next/link"; -import SelectField from "@Front/Components/DesignSystem/Form/SelectField"; +import Roles from "@Front/Api/LeCoffreApi/Admin/Roles/Roles"; +import Rules from "@Front/Api/LeCoffreApi/Admin/Rules/Rules"; +import Button from "@Front/Components/DesignSystem/Button"; import CheckBox from "@Front/Components/DesignSystem/CheckBox"; -import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import ChevronIcon from "@Assets/Icons/chevron.svg"; -type IProps = {}; -export default function CollaboratorInformations(props: IProps) { - const router = useRouter(); - let { collaboratorUid } = router.query; +import Form from "@Front/Components/DesignSystem/Form"; +import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography"; +import DefaultRoleDashboard from "@Front/Components/LayoutTemplates/DefaultRoleDashboard"; +import { Role, Rule } from "le-coffre-resources/dist/Admin"; +import { useRouter } from "next/router"; +import { useCallback, useEffect, useState } from "react"; - const [userSelected, setUserSelected] = useState(null); +import classes from "./classes.module.scss"; + +type IProps = {}; +type RuleCheckbox = Rule & { + checked: boolean; +}; +export default function RolesInformations(props: IProps) { + const router = useRouter(); + let { roleUid } = router.query; + + const [roleSelected, setRoleSelected] = useState(null); + const [rulesCheckboxes, setRulesCheckboxes] = useState([]); useEffect(() => { async function getUser() { - if (!collaboratorUid) return; - const user = await Users.getInstance().getByUid(collaboratorUid as string, { + if (!roleUid) return; + const role = await Roles.getInstance().getByUid(roleUid as string, { q: { - contact: true, + rules: true, }, }); - if (!user) return; - setUserSelected(user); + + const rules = await Rules.getInstance().get({}); + if (!role) return; + setRoleSelected(role); + if (!role.rules) return; + const rulesCheckboxes = rules + .map((rule) => { + if (role.rules?.find((r) => r.uid === rule.uid)) { + return { ...rule, checked: true }; + } + return { ...rule, checked: false }; + }) + .sort((rule) => (rule.checked ? -1 : 1)); + setRulesCheckboxes(rulesCheckboxes); } getUser(); - }, [collaboratorUid]); + }, [roleUid]); + + const handleSelectAllChange = useCallback( + (e: React.ChangeEvent) => { + const checked = e.target.checked; + rulesCheckboxes.forEach((rule) => (rule.checked = checked)); + setRulesCheckboxes([...rulesCheckboxes]); + }, + [rulesCheckboxes], + ); + + const onSubmitHandler = useCallback( + async (e: React.FormEvent | null, values: { [key: string]: string }) => { + if (!roleSelected || !roleSelected.uid) return; + const rules = rulesCheckboxes.filter((rule) => rule.checked)?.map((rule) => Rule.hydrate(rule)); + const role = await Roles.getInstance().put(roleSelected.uid, { + rules, + }); + if (!role) return; + setRoleSelected(role); + if (!role.rules) return; + setRulesCheckboxes(role.rules.map((rule) => ({ ...rule, checked: false }))); + }, + [roleSelected, rulesCheckboxes], + ); - const mockedRole = { value: "1", label: "Clerc de notaire" }; return ( - +
-
- {userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name} +
+ Gestion des rôles
-
-
- - Nom - - {userSelected?.contact?.first_name} -
-
- - Prénom - - {userSelected?.contact?.last_name} -
-
- - Numéro de téléphone - - {userSelected?.contact?.phone_number} -
-
- - Email - - {userSelected?.contact?.email} -
+
+ {roleSelected?.name}
- -
-
- Modifier le rôle -
- - - -
+
+
+ Modifier les droits
-
- -
-
+
+
+
+ {rulesCheckboxes.map((rule) => ( +
+ +
+ ))} +
+
+ +
+
- + ); } diff --git a/src/pages/roles/[roleUid]/index.tsx b/src/pages/roles/[roleUid]/index.tsx new file mode 100644 index 00000000..9dd7e651 --- /dev/null +++ b/src/pages/roles/[roleUid]/index.tsx @@ -0,0 +1,5 @@ +import RolesInformations from "@Front/Components/Layouts/Roles/RolesInformations"; + +export default function Route() { + return ; +}