Refacto users super admin

This commit is contained in:
Maxime Lalo 2024-07-29 11:09:56 +02:00
parent 791aeacfc4
commit 6870ffd47c
5 changed files with 67 additions and 196 deletions

View File

@ -16,6 +16,16 @@ export default function DropdownNavigation({ blocks, onSelectedBlock, defaultSel
if (defaultSelectedBlock) setSelectedBlock(defaultSelectedBlock);
}, [defaultSelectedBlock]);
const handleDropDownSelect = (option: IOption) => {
const block = blocks.find((block) => block.id === option.id);
if (block) {
setSelectedBlock(block);
onSelectedBlock
? onSelectedBlock(block)
: console.error("DropdownNavigation: onSelectedBlock prop is required to handle block selection");
}
};
return (
<div className={classes["root"]}>
<Dropdown
@ -28,6 +38,7 @@ export default function DropdownNavigation({ blocks, onSelectedBlock, defaultSel
},
} as IOption;
})}
onSelect={handleDropDownSelect}
selectedOption={selectedBlock ? { id: selectedBlock.id, label: selectedBlock.primaryText } : undefined}
/>
</div>

View File

@ -11,6 +11,7 @@
justify-content: flex-start;
@media (max-width: $screen-m) {
height: auto;
gap: 16px;
padding: var(--spacing-lg, 24px);
width: auto;

View File

@ -1,115 +1,22 @@
@import "@Themes/constants.scss";
@keyframes growWidth {
0% {
width: 100%;
}
100% {
width: 200%;
}
}
.root {
position: relative;
.content {
display: flex;
overflow: hidden;
justify-content: flex-start;
height: calc(100vh - var(--header-height));
.overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--color-generic-white);
opacity: 0.5;
z-index: 2;
transition: all 0.3s $custom-easing;
@media (max-width: $screen-m) {
flex-direction: column;
}
.left-side {
background-color: var(--color-generic-white);
z-index: 3;
display: flex;
width: 336px;
min-width: 336px;
transition: all 0.3s $custom-easing;
overflow: hidden;
@media (max-width: ($screen-m - 1px)) {
width: 56px;
min-width: 56px;
transform: translateX(-389px);
&.opened {
transform: translateX(0px);
width: 336px;
min-width: 336px;
}
}
@media (max-width: $screen-s) {
width: 0px;
min-width: 0px;
&.opened {
width: 100vw;
min-width: 100vw;
}
}
}
.closable-left-side {
position: absolute;
background-color: var(--color-generic-white);
z-index: 0;
display: flex;
justify-content: center;
min-width: 56px;
max-width: 56px;
height: calc(100vh - var(--header-height));
border-right: 1px var(--color-neutral-200 solid);
@media (min-width: $screen-m) {
display: none;
}
.chevron-icon {
margin-top: 21px;
transform: rotate(180deg);
cursor: pointer;
}
@media (max-width: $screen-s) {
display: none;
}
}
.right-side {
min-width: calc(100vw - 389px);
padding: 24px;
min-width: calc(100% - 336px);
overflow-y: auto;
padding: var(--spacing-lg, 24px);
@media (max-width: ($screen-m - 1px)) {
min-width: calc(100vw - 56px);
}
@media (max-width: $screen-s) {
flex: 1;
min-width: unset;
}
.back-arrow-mobile {
display: none;
@media (max-width: $screen-s) {
display: block;
margin-bottom: 24px;
}
}
.back-arrow-desktop {
@media (max-width: $screen-s) {
display: none;
}
@media (max-width: $screen-m) {
width: 100%;
}
}
}

View File

@ -1,115 +1,67 @@
import ChevronIcon from "@Assets/Icons/chevron.svg";
import { ChevronLeftIcon } from "@heroicons/react/20/solid";
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Header from "@Front/Components/DesignSystem/Header";
import Version from "@Front/Components/DesignSystem/Version";
import BackArrow from "@Front/Components/Elements/BackArrow";
import WindowStore from "@Front/Stores/WindowStore";
import classNames from "classnames";
import User from "le-coffre-resources/dist/SuperAdmin";
import Image from "next/image";
import React, { ReactNode } from "react";
import React, { ReactNode, useEffect } from "react";
import classes from "./classes.module.scss";
import UserListContainer from "./UserListContainer";
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
import { useRouter } from "next/router";
import Module from "@Front/Config/Module";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
type IProps = {
title: string;
children?: ReactNode;
onSelectedUser: (user: User) => void;
hasBackArrow: boolean;
hasBackArrow?: boolean;
backArrowUrl?: string;
mobileBackText?: string;
};
type IState = {
users: User[] | null;
isLeftSideOpen: boolean;
leftSideCanBeClosed: boolean;
};
export default class DefaultUserDashboard extends React.Component<IProps, IState> {
private onWindowResize = () => {};
public static defaultProps: Partial<IProps> = {
hasBackArrow: false,
};
public constructor(props: IProps) {
super(props);
this.state = {
users: null,
isLeftSideOpen: false,
leftSideCanBeClosed: typeof window !== "undefined" ? window.innerWidth < 1024 : false,
};
this.onOpenLeftSide = this.onOpenLeftSide.bind(this);
this.onCloseLeftSide = this.onCloseLeftSide.bind(this);
}
public override render(): JSX.Element {
return (
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
{this.state.isLeftSideOpen && <div className={classes["overlay"]} onClick={this.onCloseLeftSide} />}
<div className={classNames(classes["left-side"], this.state.isLeftSideOpen && classes["opened"])}>
{this.state.users && <UserListContainer users={this.state.users} onCloseLeftSide={this.onCloseLeftSide} />}
</div>
<div className={classNames(classes["closable-left-side"])}>
<Image alt="open side menu" src={ChevronIcon} className={classes["chevron-icon"]} onClick={this.onOpenLeftSide} />
</div>
<div className={classes["right-side"]}>
{this.props.hasBackArrow && (
<div className={classes["back-arrow-desktop"]}>
<BackArrow url={this.props.backArrowUrl ?? ""} />
</div>
)}
{this.props.mobileBackText && (
<div className={classes["back-arrow-mobile"]}>
<Button
leftIcon={<ChevronLeftIcon />}
variant={EButtonVariant.PRIMARY}
styletype={EButtonstyletype.TEXT}
onClick={this.onOpenLeftSide}>
{this.props.mobileBackText ?? "Retour"}
</Button>
</div>
)}
{this.props.children}
</div>
</div>
<Version />
</div>
);
}
public override async componentDidMount() {
this.onWindowResize = WindowStore.getInstance().onResize((window) => this.onResize(window));
export default function DefaultUserDashboard(props: IProps) {
const { hasBackArrow, children, backArrowUrl } = props;
const [users, setUsers] = React.useState<User[] | null>(null);
const router = useRouter();
useEffect(() => {
const query: IGetUsersparams = {
include: { contact: true },
};
const users = await Users.getInstance().get(query);
this.setState({ users });
}
public override componentWillUnmount() {
this.onWindowResize();
}
Users.getInstance()
.get(query)
.then((users) => setUsers(users));
}, []);
private onOpenLeftSide() {
this.setState({ isLeftSideOpen: true });
}
const onSelectedBlock = (block: IBlock) => {
router.push(Module.getInstance().get().modules.pages.Users.pages.UsersInformations.props.path.replace("[uid]", block.id));
};
private onCloseLeftSide() {
if (!this.state.leftSideCanBeClosed) return;
this.setState({ isLeftSideOpen: false });
}
private onResize(window: Window) {
if (window.innerWidth > 1023) {
if (!this.state.leftSideCanBeClosed) return;
this.setState({ leftSideCanBeClosed: false });
}
this.setState({ leftSideCanBeClosed: true });
}
return (
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
{users && (
<SearchBlockList
blocks={users.map((user) => {
return {
id: user.uid,
primaryText: user.contact?.first_name + " " + user.contact?.last_name,
secondaryText: user.contact?.email,
} as IBlock;
})}
onSelectedBlock={onSelectedBlock}
/>
)}
<div className={classes["right-side"]}>
{hasBackArrow && (
<div className={classes["back-arrow-desktop"]}>
<BackArrow url={backArrowUrl ?? ""} />
</div>
)}
{children}
</div>
</div>
<Version />
</div>
);
}

View File

@ -9,7 +9,7 @@ type IState = {};
export default class Users extends BasePage<IProps, IState> {
public override render(): JSX.Element {
return (
<DefaultUserDashboard title={"Dossier"} mobileBackText={"Liste des utilisateurs"}>
<DefaultUserDashboard title={"Dossier"}>
<div className={classes["root"]}>
<div className={classes["no-folder-selected"]}>
<Typography typo={ETypo.TITLE_H1}>Informations des utilisateurs</Typography>