🔨 email reminder

This commit is contained in:
Max S 2024-08-27 12:15:41 +02:00
parent 1e4ab173ee
commit 62b51b4047
10 changed files with 105 additions and 33 deletions

View File

@ -4,11 +4,11 @@ import Tooltip from "../ToolTip";
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"; import classNames from "classnames";
import { IOptionOld } from "../Form/SelectFieldOld"; import { IOption } from "../Form/SelectFieldOld";
type IProps = { type IProps = {
name?: string; name?: string;
option: IOptionOld; option: IOption;
toolTip?: string; toolTip?: string;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void; onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
checked: boolean; checked: boolean;

View File

@ -10,9 +10,9 @@ import classes from "./classes.module.scss";
import { NextRouter, useRouter } from "next/router"; import { NextRouter, useRouter } from "next/router";
type IProps = { type IProps = {
selectedOption?: IOptionOld; selectedOption?: IOption;
onChange?: (selectedOption: IOptionOld) => void; onChange?: (selectedOption: IOption) => void;
options: IOptionOld[]; options: IOption[];
hasBorderRightCollapsed?: boolean; hasBorderRightCollapsed?: boolean;
placeholder?: string; placeholder?: string;
className?: string; className?: string;
@ -21,7 +21,7 @@ type IProps = {
errors?: ValidationError; errors?: ValidationError;
}; };
export type IOptionOld = { export type IOption = {
value: unknown; value: unknown;
label: string; label: string;
icon?: ReactNode; icon?: ReactNode;
@ -32,7 +32,7 @@ type IState = {
isOpen: boolean; isOpen: boolean;
listWidth: number; listWidth: number;
listHeight: number; listHeight: number;
selectedOption: IOptionOld | null; selectedOption: IOption | null;
errors: ValidationError | null; errors: ValidationError | null;
}; };
@ -187,7 +187,7 @@ class SelectFieldClass extends React.Component<IPropsClass, IState> {
}); });
} }
private onSelect(option: IOptionOld, e: React.MouseEvent<HTMLLIElement, MouseEvent>) { private onSelect(option: IOption, e: React.MouseEvent<HTMLLIElement, MouseEvent>) {
if (this.props.disabled) return; if (this.props.disabled) return;
this.props.onChange && this.props.onChange(option); this.props.onChange && this.props.onChange(option);
this.setState({ this.setState({

View File

@ -13,14 +13,14 @@ import React, { useCallback, useEffect, useState } from "react";
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import ParameterDocuments from "./ParameterDocuments"; import ParameterDocuments from "./ParameterDocuments";
import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld";
import backgroundImage from "@Assets/images/background_refonte.svg"; import backgroundImage from "@Assets/images/background_refonte.svg";
export default function AskDocuments() { export default function AskDocuments() {
const router = useRouter(); const router = useRouter();
let { folderUid, customerUid } = router.query; let { folderUid, customerUid } = router.query;
const [isCreateDocumentModalVisible, setIsCreateDocumentModalVisible] = useState<boolean>(false); const [isCreateDocumentModalVisible, setIsCreateDocumentModalVisible] = useState<boolean>(false);
const [documentTypes, setDocumentTypes] = useState<IOptionOld[]>([]); const [documentTypes, setDocumentTypes] = useState<IOption[]>([]);
const [folder, setFolder] = useState<OfficeFolder | null>(null); const [folder, setFolder] = useState<OfficeFolder | null>(null);
const closeModal = () => setIsCreateDocumentModalVisible(false); const closeModal = () => setIsCreateDocumentModalVisible(false);
@ -62,7 +62,7 @@ export default function AskDocuments() {
); );
const getAvailableDocuments = useCallback( const getAvailableDocuments = useCallback(
async (folder: OfficeFolder): Promise<IOptionOld[]> => { async (folder: OfficeFolder): Promise<IOption[]> => {
// Getting already asked documents UIDs in an array // Getting already asked documents UIDs in an array
const userDocumentTypesUids = folder const userDocumentTypesUids = folder
.documents!.filter((document) => document.depositor!.uid! === customerUid!) .documents!.filter((document) => document.depositor!.uid! === customerUid!)
@ -81,7 +81,7 @@ export default function AskDocuments() {
if (!documentTypes) return []; if (!documentTypes) return [];
// Else, return an array document types formatted as IOPtions // Else, return an array document types formatted as IOPtions
const documentTypesOptions: IOptionOld[] = documentTypes.map((documentType) => { const documentTypesOptions: IOption[] = documentTypes.map((documentType) => {
return { return {
label: documentType!.name!, label: documentType!.name!,
value: documentType!.uid!, value: documentType!.uid!,

View File

@ -1,5 +1,7 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: flex;
flex-direction: column;
gap: var(--spacing-md, 16px);
} }

View File

@ -1,7 +1,10 @@
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
import { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld";
import Modal from "@Front/Components/DesignSystem/Modal"; import Modal from "@Front/Components/DesignSystem/Modal";
import Separator, { ESeperatorColor } from "@Front/Components/DesignSystem/Separator";
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
import Customer from "le-coffre-resources/dist/Customer"; import Customer from "le-coffre-resources/dist/Customer";
import React, { useCallback } from "react"; import React, { useCallback, useMemo, useState } from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
@ -14,11 +17,52 @@ type IProps = {
export default function ReminderModal(props: IProps) { export default function ReminderModal(props: IProps) {
const { isOpen, onClose, onRemindSuccess, customer } = props; const { isOpen, onClose, onRemindSuccess, customer } = props;
const [selectedOptions, setSelectedOptions] = useState<IOption[]>([]);
const [isAllSelected, setIsAllSelected] = useState(false);
const onRemind = useCallback(() => { const onRemind = useCallback(() => {
console.log("selectedOptions", selectedOptions);
onRemindSuccess(); onRemindSuccess();
onClose?.(); onClose?.();
}, [onClose, onRemindSuccess]); }, [onClose, onRemindSuccess, selectedOptions]);
const documentsOptions: IOption[] = useMemo(
() =>
customer.documents?.map((document) => {
return {
label: document.document_type?.name ?? "",
value: document.document_type?.uid ?? "",
};
}) ?? [],
[customer],
);
const handleOnChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const { value, checked } = e.target;
const optionSelected = documentsOptions.find((option) => option.value === value);
if (checked && optionSelected) {
setSelectedOptions((prev) => [...prev, optionSelected]);
} else {
setSelectedOptions((prev) => prev.filter((option) => option.value !== value));
}
},
[documentsOptions],
);
const handleSelectAll = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const { checked } = e.target;
if (checked) {
setSelectedOptions(documentsOptions);
setIsAllSelected(true);
} else {
setSelectedOptions([]);
setIsAllSelected(false);
}
},
[documentsOptions],
);
return ( return (
<Modal <Modal
@ -31,6 +75,21 @@ export default function ReminderModal(props: IProps) {
<Typography typo={ETypo.TEXT_MD_LIGHT}> <Typography typo={ETypo.TEXT_MD_LIGHT}>
Sélectionnez le(s) document(s) pour lequel vous souhaitez relancer le client. Sélectionnez le(s) document(s) pour lequel vous souhaitez relancer le client.
</Typography> </Typography>
<CheckBox
option={{ label: "Tous les documents", value: "all-documents" }}
checked={isAllSelected}
onChange={handleSelectAll}
/>
<Separator color={ESeperatorColor.LIGHT} />
{documentsOptions.map((option) => (
<CheckBox
key={option.value as string}
option={option}
onChange={handleOnChange}
checked={isAllSelected}
disabled={isAllSelected}
/>
))}
</div> </div>
</Modal> </Modal>
); );

View File

@ -13,10 +13,12 @@ import Link from "next/link";
type IProps = { type IProps = {
customer: Customer; customer: Customer;
doesCustomerHaveDocument: boolean;
isAnchored: boolean;
}; };
export default function EmailReminder(props: IProps) { export default function EmailReminder(props: IProps) {
const { customer } = props; const { customer, doesCustomerHaveDocument, isAnchored } = props;
const { isOpen, open, close } = useOpenable(); const { isOpen, open, close } = useOpenable();
const router = useRouter(); const router = useRouter();
@ -24,14 +26,17 @@ export default function EmailReminder(props: IProps) {
return ( return (
<div className={classes["root"]}> <div className={classes["root"]}>
<Button {!isAnchored && (
onClick={open} <Button
rightIcon={<EnvelopeIcon />} onClick={open}
variant={EButtonVariant.PRIMARY} rightIcon={<EnvelopeIcon />}
styletype={EButtonstyletype.OUTLINED} variant={EButtonVariant.PRIMARY}
fullwidth> styletype={EButtonstyletype.OUTLINED}
Relancer par mail fullwidth
</Button> disabled={doesCustomerHaveDocument}>
Relancer par mail
</Button>
)}
<div className={classes["reminder-info"]}> <div className={classes["reminder-info"]}>
<Link <Link
title={"Voir l'historique des relances"} title={"Voir l'historique des relances"}
@ -41,11 +46,13 @@ export default function EmailReminder(props: IProps) {
<IconButton icon={<ClockIcon />} variant={EIconButtonVariant.NEUTRAL} /> <IconButton icon={<ClockIcon />} variant={EIconButtonVariant.NEUTRAL} />
</Link> </Link>
<div className={classes["info"]}> <div className={classes["info"]}>
{/* TODO: mettre la date de la dernière relance */}
<Typography typo={ETypo.TEXT_XS_REGULAR} color={ETypoColor.TEXT_SECONDARY}> <Typography typo={ETypo.TEXT_XS_REGULAR} color={ETypoColor.TEXT_SECONDARY}>
Dernière relance: todo Dernière relance: -
</Typography> </Typography>
{/* TODO: mettre le nombre de relance */}
<Typography typo={ETypo.TEXT_XS_REGULAR} color={ETypoColor.TEXT_SECONDARY}> <Typography typo={ETypo.TEXT_XS_REGULAR} color={ETypoColor.TEXT_SECONDARY}>
Nombre de relance: todo Nombre de relance: -
</Typography> </Typography>
</div> </div>
</div> </div>

View File

@ -35,7 +35,7 @@ $mobile-breakpoint: 664px;
.button-container { .button-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--spacing-lg, 24px); gap: var(--spacing-md, 16px);
} }
@media screen and (max-width: $screen-s) { @media screen and (max-width: $screen-s) {

View File

@ -115,7 +115,11 @@ export default function ClientView(props: IProps) {
</Button> </Button>
</Link> </Link>
)} )}
<EmailReminder customer={customer} /> <EmailReminder
customer={customer}
doesCustomerHaveDocument={!doesCustomerHaveDocument}
isAnchored={anchorStatus !== AnchorStatus.NOT_ANCHORED}
/>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form"; import Form from "@Front/Components/DesignSystem/Form";
import Select, { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld";
import TextField from "@Front/Components/DesignSystem/Form/TextField"; import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow"; import BackArrow from "@Front/Components/Elements/BackArrow";
@ -81,7 +81,7 @@ export default function UpdateFolderMetadata() {
const deedOption = { const deedOption = {
label: selectedFolder?.deed?.deed_type?.name, label: selectedFolder?.deed?.deed_type?.name,
value: selectedFolder?.deed?.deed_type?.uid, value: selectedFolder?.deed?.deed_type?.uid,
} as IOptionOld; } as IOption;
const openingDate = new Date(selectedFolder?.created_at ?? ""); const openingDate = new Date(selectedFolder?.created_at ?? "");
if (!selectedFolder?.created_at) return <></>; if (!selectedFolder?.created_at) return <></>;
const defaultValue = openingDate.toISOString().split("T")[0]; const defaultValue = openingDate.toISOString().split("T")[0];

View File

@ -1,6 +1,6 @@
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form"; import Form from "@Front/Components/DesignSystem/Form";
import Select, { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld";
import TextField from "@Front/Components/DesignSystem/Form/TextField"; import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow"; import BackArrow from "@Front/Components/Elements/BackArrow";
@ -18,7 +18,7 @@ type IProps = {
}; };
type IState = { type IState = {
selectedFolder: OfficeFolder | null; selectedFolder: OfficeFolder | null;
selectedOption?: IOptionOld; selectedOption?: IOption;
}; };
class UpdateFolderMetadataClass extends BasePage<IProps, IState> { class UpdateFolderMetadataClass extends BasePage<IProps, IState> {
constructor(props: IProps) { constructor(props: IProps) {
@ -74,7 +74,7 @@ class UpdateFolderMetadataClass extends BasePage<IProps, IState> {
); );
} }
private onSelectedOption(option: IOptionOld) { private onSelectedOption(option: IOption) {
this.setState({ this.setState({
selectedOption: option, selectedOption: option,
}); });