responsive information folder section

This commit is contained in:
Max S 2024-08-25 16:14:33 +02:00
parent 84e820b90a
commit 79f965e502
3 changed files with 166 additions and 19 deletions

View File

@ -1,13 +1,15 @@
import React, { useCallback, useEffect, useRef, useState } from "react"; import React, { useCallback, useEffect, useRef, useState } from "react";
import Typography, { ETypo, ETypoColor } from "../Typography"; import Typography, { ETypo, ETypoColor } from "../Typography";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import classNames from "classnames";
type IProps = { type IProps = {
percentage: number; percentage: number;
className?: string;
}; };
export default function CircleProgress(props: IProps) { export default function CircleProgress(props: IProps) {
const { percentage } = props; const { percentage, className } = props;
const [animatedProgress, setAnimatedProgress] = useState(0); const [animatedProgress, setAnimatedProgress] = useState(0);
const requestRef = useRef<number>(); const requestRef = useRef<number>();
@ -41,7 +43,7 @@ export default function CircleProgress(props: IProps) {
const offset = circumference - (animatedProgress / 100) * circumference; const offset = circumference - (animatedProgress / 100) * circumference;
return ( return (
<div className={classes["root"]}> <div className={classNames(classes["root"], className)}>
<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27" viewBox="0 0 27 27" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" width="27" height="27" viewBox="0 0 27 27" fill="none">
<circle className={classes["circleBackground"]} cx="13.5" cy="13.5" r={radius} strokeWidth="3" /> <circle className={classes["circleBackground"]} cx="13.5" cy="13.5" r={radius} strokeWidth="3" />
<circle <circle

View File

@ -1,18 +1,41 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
$mobile-breakpoint: 600px;
.root { .root {
display: flex; display: flex;
gap: var(--spacing-lg, 40px); gap: var(--spacing-lg, 24px);
@media screen and (max-width: $mobile-breakpoint) {
flex-direction: column;
}
.info-box1 { .info-box1 {
display: flex; display: flex;
width: 100%; width: 100%;
flex-direction: column; flex-direction: column;
gap: var(--spacing-sm, 8px); gap: var(--spacing-sm, 8px);
.folder-number-container {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--spacing-lg, 24px);
}
.open-date { .open-date {
display: flex; display: flex;
gap: var(--spacing-sm, 8px); gap: var(--spacing-sm, 8px);
} }
@media screen and (max-width: $screen-s) {
width: 54vw;
}
@media screen and (max-width: $mobile-breakpoint) {
width: 100%;
}
} }
.info-box2 { .info-box2 {
@ -22,22 +45,74 @@
width: 100%; width: 100%;
max-width: 400px; max-width: 400px;
@media screen and (max-width: $mobile-breakpoint) {
max-width: 100%;
}
.progress-container { .progress-container {
width: 100%;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
.icon-container { @media screen and (max-width: $screen-s) {
display: flex; flex-direction: column-reverse;
gap: var(--spacing-md, 8px); gap: var(--spacing-lg, 24px);
}
@media screen and (max-width: $mobile-breakpoint) {
align-items: flex-start;
}
}
}
.icon-container {
display: flex;
gap: var(--spacing-md, 8px);
&.desktop {
display: flex;
@media screen and (max-width: $mobile-breakpoint) {
display: none;
} }
} }
.description-container { &.mobile {
.text { display: none;
max-height: 60px; @media screen and (max-width: $mobile-breakpoint) {
overflow-y: auto; display: flex;
}
}
}
.description-container {
.text {
max-height: 60px;
overflow-y: auto;
white-space: normal;
word-wrap: break-word;
}
&.desktop {
@media screen and (max-width: $screen-s) {
display: none;
}
}
&.ipad {
display: none;
@media screen and (max-width: $screen-s) {
display: block;
}
@media screen and (max-width: $mobile-breakpoint) {
display: none;
}
}
&.mobile {
display: none;
@media screen and (max-width: $mobile-breakpoint) {
display: block;
} }
} }
} }
@ -46,5 +121,10 @@
background-color: var(--separator-stroke-light); background-color: var(--separator-stroke-light);
width: 1px; width: 1px;
align-self: stretch; align-self: stretch;
@media screen and (max-width: $mobile-breakpoint) {
height: 1px;
width: 100%;
}
} }
} }

View File

@ -6,12 +6,13 @@ import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag";
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
import Module from "@Front/Config/Module"; import Module from "@Front/Config/Module";
import { ArchiveBoxIcon, EllipsisHorizontalIcon, PaperAirplaneIcon, PencilSquareIcon, UsersIcon } from "@heroicons/react/24/outline"; import { ArchiveBoxIcon, EllipsisHorizontalIcon, PaperAirplaneIcon, PencilSquareIcon, UsersIcon } from "@heroicons/react/24/outline";
import classNames from "classnames";
import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { OfficeFolder } from "le-coffre-resources/dist/Notary";
import Link from "next/link";
import { useMemo } from "react"; import { useMemo } from "react";
import { AnchorStatus } from ".."; import { AnchorStatus } from "..";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import Link from "next/link";
type IProps = { type IProps = {
folder: OfficeFolder | null; folder: OfficeFolder | null;
@ -24,7 +25,7 @@ type IProps = {
export default function InformationSection(props: IProps) { export default function InformationSection(props: IProps) {
const { folder, progress, onArchive, anchorStatus, isArchived } = props; const { folder, progress, onArchive, anchorStatus, isArchived } = props;
const menuItems = useMemo(() => { const menuItemsDekstop = useMemo(() => {
let elements: IItem[] = []; let elements: IItem[] = [];
// Creating the three elements and adding them conditionnally // Creating the three elements and adding them conditionnally
@ -48,17 +49,71 @@ export default function InformationSection(props: IProps) {
// If the folder is not anchored, we can modify the collaborators and the informations // If the folder is not anchored, we can modify the collaborators and the informations
if (anchorStatus === AnchorStatus.NOT_ANCHORED) { if (anchorStatus === AnchorStatus.NOT_ANCHORED) {
elements.push(modifyCollaboratorsElement); elements.push(modifyCollaboratorsElement);
elements.push(modifyInformationsElement); elements.push(modifyInformationsElement);
} }
return elements; return elements;
}, [anchorStatus, folder?.uid]); }, [anchorStatus, folder?.uid]);
const menuItemsMobile = useMemo(() => {
let elements: IItem[] = [];
// Creating the three elements and adding them conditionnally
const modifyCollaboratorsElement = {
icon: <UsersIcon />,
text: "Modifier les collaborateurs",
link: Module.getInstance()
.get()
.modules.pages.Folder.pages.EditCollaborators.props.path.replace("[folderUid]", folder?.uid ?? ""),
hasSeparator: true,
};
const modifyInformationsElement = {
icon: <PencilSquareIcon />,
text: "Modifier les informations du dossier",
link: Module.getInstance()
.get()
.modules.pages.Folder.pages.EditInformations.props.path.replace("[folderUid]", folder?.uid ?? ""),
hasSeparator: true,
};
// If the folder is not anchored, we can modify the collaborators and the informations
if (anchorStatus === AnchorStatus.NOT_ANCHORED) {
elements.push(modifyCollaboratorsElement);
elements.push(modifyInformationsElement);
}
elements.push({
icon: <PaperAirplaneIcon />,
text: "Envoyer des documents",
link: Module.getInstance()
.get()
.modules.pages.Folder.pages.SendDocuments.props.path.replace("[folderUid]", folder?.uid ?? ""),
hasSeparator: !isArchived,
});
if (!isArchived) {
elements.push({
icon: <ArchiveBoxIcon />,
text: "Archiver le dossier",
onClick: onArchive,
hasSeparator: false,
});
}
return elements;
}, [anchorStatus, folder?.uid, isArchived, onArchive]);
return ( return (
<section className={classes["root"]}> <section className={classes["root"]}>
<div className={classes["info-box1"]}> <div className={classes["info-box1"]}>
<div> <div>
<Typography typo={ETypo.TEXT_MD_REGULAR}>{folder?.folder_number}</Typography> <div className={classes["folder-number-container"]}>
<Typography typo={ETypo.TEXT_MD_REGULAR}>{folder?.folder_number}</Typography>
<div className={classNames(classes["icon-container"], classes["mobile"])}>
<Menu items={menuItemsMobile}>
<IconButton icon={<EllipsisHorizontalIcon />} variant={EIconButtonVariant.NEUTRAL} />
</Menu>
</div>
</div>
<Typography typo={ETypo.TITLE_H4}>{folder?.name}</Typography> <Typography typo={ETypo.TITLE_H4}>{folder?.name}</Typography>
</div> </div>
@ -69,13 +124,22 @@ export default function InformationSection(props: IProps) {
{folder?.created_at ? new Date(folder.created_at).toLocaleDateString() : ""} {folder?.created_at ? new Date(folder.created_at).toLocaleDateString() : ""}
</Typography> </Typography>
</div> </div>
<div className={classNames(classes["description-container"], classes["ipad"])}>
<Typography typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.COLOR_NEUTRAL_700}>
Note du dossier
</Typography>
<Typography typo={ETypo.TEXT_LG_REGULAR} className={classes["text"]}>
{folder?.description}
</Typography>
</div>
</div> </div>
<div className={classes["separator"]} /> <div className={classes["separator"]} />
<div className={classes["info-box2"]}> <div className={classes["info-box2"]}>
<div className={classes["progress-container"]}> <div className={classes["progress-container"]}>
<CircleProgress percentage={progress} /> <CircleProgress percentage={progress} />
<div className={classes["icon-container"]}> <div className={classNames(classes["icon-container"], classes["desktop"])}>
<Link <Link
href={Module.getInstance() href={Module.getInstance()
.get() .get()
@ -83,13 +147,14 @@ export default function InformationSection(props: IProps) {
title="Envoyer des documents"> title="Envoyer des documents">
<IconButton icon={<PaperAirplaneIcon />} variant={EIconButtonVariant.NEUTRAL} /> <IconButton icon={<PaperAirplaneIcon />} variant={EIconButtonVariant.NEUTRAL} />
</Link> </Link>
<Menu items={menuItems}>
<Menu items={menuItemsDekstop}>
<IconButton icon={<EllipsisHorizontalIcon />} variant={EIconButtonVariant.NEUTRAL} /> <IconButton icon={<EllipsisHorizontalIcon />} variant={EIconButtonVariant.NEUTRAL} />
</Menu> </Menu>
{!isArchived && <IconButton onClick={onArchive} icon={<ArchiveBoxIcon />} variant={EIconButtonVariant.ERROR} />} {!isArchived && <IconButton onClick={onArchive} icon={<ArchiveBoxIcon />} variant={EIconButtonVariant.ERROR} />}
</div> </div>
</div> </div>
<div className={classes["description-container"]}> <div className={classNames(classes["description-container"], classes["desktop"], classes["mobile"])}>
<Typography typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.COLOR_NEUTRAL_700}> <Typography typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.COLOR_NEUTRAL_700}>
Note du dossier Note du dossier
</Typography> </Typography>