From a25e4664c6ebaba5e6e23c93791a695dbc455f75 Mon Sep 17 00:00:00 2001 From: Lea Renaux Date: Fri, 3 May 2024 15:25:08 +0200 Subject: [PATCH] add SU address data in createContact dialog --- src/pages/CreateContactPage.tsx | 63 ++--- src/pages/Search/SearchContacts.tsx | 22 +- src/ui/Contact/ContactFormDialog.tsx | 176 ++++-------- src/ui/Contact/ContactRightsDialogs.tsx | 7 +- .../CreateContact/CreateContactDialog.tsx | 261 ++++++++++++++++++ .../CreateContact/InformationsForm.tsx | 59 +++- .../CreateContact/RightsManagementForm.tsx | 20 +- src/ui/Form/AddressFormFields.tsx | 2 +- src/ui/Form/Field.tsx | 44 ++- src/ui/SurveyUnit/SurveyUnitContacts.tsx | 8 +- src/ui/SurveyUnit/SurveyUnitFormDialog.tsx | 2 +- 11 files changed, 488 insertions(+), 176 deletions(-) create mode 100644 src/ui/Contact/CreateContact/CreateContactDialog.tsx diff --git a/src/pages/CreateContactPage.tsx b/src/pages/CreateContactPage.tsx index 980d647..8ea5f20 100644 --- a/src/pages/CreateContactPage.tsx +++ b/src/pages/CreateContactPage.tsx @@ -1,9 +1,6 @@ import Stack from "@mui/material/Stack"; -import { useForm } from "../hooks/useForm"; -import { schema } from "../ui/Contact/ContactFormDialog"; -import { useRef, useState } from "react"; +import { useState } from "react"; import { Row } from "../ui/Row"; -import Button from "@mui/material/Button"; import PersonAddAltOutlinedIcon from "@mui/icons-material/PersonAddAltOutlined"; import Typography from "@mui/material/Typography"; import { Step, StepLabel, Stepper, Divider, Card } from "@mui/material"; @@ -11,24 +8,13 @@ import { InformationsForm } from "../ui/Contact/CreateContact/InformationsForm"; import { RightsManagementForm } from "../ui/Contact/CreateContact/RightsManagementForm"; import { Breadcrumbs } from "../ui/Breadcrumbs"; -// const steps = ["Informations du contact", "Adresse du contact", "Gestion des droits"]; - const steps = ["Informations du contact", "Gestion des droits"]; export const CreateContactPage = () => { - const { register, control, errors } = useForm(schema); const [activeStep, setActiveStep] = useState(0); + const [contactData, setContactData] = useState(); - const data = useRef(new FormData()); - - const onSubmitStep = async (event: React.FormEvent) => { - event.preventDefault(); - const newData = new FormData(event.currentTarget); - console.log("new data", { newData }); - for (let [name, value] of newData) { - data.current.append(name, value); - } - }; + const [rights, setRights] = useState(); const handleNext = () => { setActiveStep(prevActiveStep => prevActiveStep + 1); @@ -38,8 +24,15 @@ export const CreateContactPage = () => { setActiveStep(prevActiveStep => prevActiveStep - 1); }; - const handleSubmitStep = async (event: React.FormEvent) => { - onSubmitStep(event); + const handleSubmitStep = async (data: any) => { + if (activeStep === 0) { + setContactData(data); + } + + if (activeStep === 1) { + setRights(data); + } + handleNext(); }; @@ -50,7 +43,7 @@ export const CreateContactPage = () => { ]; return ( - + @@ -72,27 +65,17 @@ export const CreateContactPage = () => { -
- {activeStep === 0 && ( - - )} - {/* {activeStep === 1 && } */} - {activeStep === 1 && } - - + {activeStep === 0 && ( + + )} - - - + {activeStep === 1 && ( + + )}
diff --git a/src/pages/Search/SearchContacts.tsx b/src/pages/Search/SearchContacts.tsx index e7d92ba..0d6a541 100644 --- a/src/pages/Search/SearchContacts.tsx +++ b/src/pages/Search/SearchContacts.tsx @@ -1,4 +1,4 @@ -import { CardActionArea, CircularProgress, Stack } from "@mui/material"; +import { Button, CardActionArea, CircularProgress, Stack } from "@mui/material"; import { Row } from "../../ui/Row"; import { useInfiniteFetchQuery } from "../../hooks/useFetchQuery.ts"; import ToggleButtonGroup from "@mui/material/ToggleButtonGroup"; @@ -10,6 +10,7 @@ import { type APIResponse } from "../../types/api.ts"; import { type ItemOf } from "../../types/utils.ts"; import Card from "@mui/material/Card"; import { Link } from "react-router-dom"; +import { Link as CustomLink } from "../../ui/Link"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; import { TextWithLeftIcon } from "../../ui/TextWithLeftIcon.tsx"; @@ -19,6 +20,7 @@ import EmailIcon from "@mui/icons-material/Email"; import DesktopWindowsOutlinedIcon from "@mui/icons-material/DesktopWindowsOutlined"; import { useSearchFilterParams } from "../../hooks/useSearchFilter.ts"; import { ContactCardTitle } from "../../ui/SurveyUnit/SurveyUnitContacts.tsx"; +import EditIcon from "@mui/icons-material/Edit"; const endpoint = "/api/contacts/search" as const; type Item = ItemOf>["content"]>; @@ -67,6 +69,24 @@ export const SearchContacts = () => { ))} {hasNextPage && } +
); }; diff --git a/src/ui/Contact/ContactFormDialog.tsx b/src/ui/Contact/ContactFormDialog.tsx index 0c0412e..772f720 100644 --- a/src/ui/Contact/ContactFormDialog.tsx +++ b/src/ui/Contact/ContactFormDialog.tsx @@ -1,14 +1,4 @@ -import { - Box, - Button, - Checkbox, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - Divider, - FormControlLabel, -} from "@mui/material"; +import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Divider } from "@mui/material"; import { Schema, z } from "zod"; import { useForm } from "../../hooks/useForm.ts"; import { APISchemas } from "../../types/api.ts"; @@ -33,40 +23,45 @@ export const addressSchema = z repetitionIndex: z .string() .nullable() - .transform(val => (val === null ? "" : val)) + .transform(val => val ?? "") .optional(), streetType: z .string() .nullable() - .transform(val => (val === null ? "" : val)) + .transform(val => val ?? "") .optional(), - streetName: z.string().optional(), + streetName: z + .string() + .optional() + .transform(val => val ?? ""), addressSupplement: z .string() .nullable() - .transform(val => (val === null ? "" : val)) + .transform(val => val ?? "") .optional(), specialDistribution: z .string() .nullable() - .transform(val => (val === null ? "" : val)) + .transform(val => val ?? "") .optional(), cedexName: z .string() + .optional() .nullable() - .transform(val => (val === null ? "" : val)), + .transform(val => val ?? ""), cedexCode: z .string() + .optional() .nullable() - .transform(val => (val === null ? "" : val)), + .transform(val => val ?? ""), cityName: z .string() .nullable() - .transform(val => (val === null ? "" : val)), + .transform(val => val ?? ""), zipCode: z .string() .nullable() - .transform(val => (val === null ? "" : val)), + .transform(val => val ?? ""), countryName: z.string().optional().or(z.literal("")), }) .superRefine(({ cedexCode, zipCode, cityName, cedexName }, refinementContext) => { @@ -135,7 +130,7 @@ export const schema = z.object({ phone: z .string() .nullable() - .transform(val => (val === null ? "" : val)) + .transform(val => val ?? "") .optional(), secondPhone: z.string().optional().or(z.literal("")), identificationName: z.string().optional(), @@ -143,7 +138,7 @@ export const schema = z.object({ address: addressSchema, }); -const civilities = [ +export const civilities = [ { label: "Madame", value: "Female" }, { label: "Monsieur", value: "Male" }, ]; @@ -163,7 +158,7 @@ export const styles = { export const ContactFormDialog = ({ open, onClose, contact, onSave }: Props) => { const defaultValues = contact.address?.countryName ? contact - : { ...contact, address: { ...contact.address, countryName: "France" } }; + : { ...contact, address: { ...contact.address, countryName: "FRANCE" } }; const { register, control, errors, handleSubmit, reset } = useForm(schema, { defaultValues: defaultValues, }); @@ -190,47 +185,18 @@ export const ContactFormDialog = ({ open, onClose, contact, onSave }: Props) => Modification des coordonnées - - - - - - - - - - - - - - - + - + + + @@ -246,65 +212,45 @@ export const ContactFormDialog = ({ open, onClose, contact, onSave }: Props) => ); }; -type FormContentProps = { +type ContactInformationFormProps = { errors: any; register: UseFormRegister>; - control?: UseFormReturn["control"]; - contact?: APISchemas["ContactFirstLoginDto"]; + control: UseFormReturn["control"]; }; -export const FormContent = ({ errors, register, control, contact }: FormContentProps) => { +export const ContactInformationForm = ({ errors, register, control }: ContactInformationFormProps) => { return ( - - + + + + + + + - - - - - - - - - - - - - - - - {contact === undefined && ( - } - label="L’adresse du contact est identique à l’adresse de l’unité enquêtée" - /> - )} - + + + - - + + + ); }; diff --git a/src/ui/Contact/ContactRightsDialogs.tsx b/src/ui/Contact/ContactRightsDialogs.tsx index 3476510..4935097 100644 --- a/src/ui/Contact/ContactRightsDialogs.tsx +++ b/src/ui/Contact/ContactRightsDialogs.tsx @@ -8,6 +8,8 @@ import RadioGroup from "@mui/material/RadioGroup"; import FormControlLabel from "@mui/material/FormControlLabel"; import Radio from "@mui/material/Radio"; import { APISchemas } from "../../types/api"; +import { useToggle } from "react-use"; +import { CreateContactDialog } from "./CreateContact/CreateContactDialog"; export type CommonContactRightsProps = { open: boolean; @@ -218,11 +220,11 @@ export const EditSecondaryToPrimaryDialog = ({ export const EditPrimaryWithoutSecondaryDialog = ({ open, onClose }: CommonContactRightsProps) => { const navigate = useNavigate(); + const [hasDialog, toggleDialog] = useToggle(false); const goToCreateContactForm: FormEventHandler = e => { e.preventDefault(); - onClose(); - navigate("/contacts/createContact"); + toggleDialog(); }; return ( @@ -237,6 +239,7 @@ export const EditPrimaryWithoutSecondaryDialog = ({ open, onClose }: CommonConta Une enquête doit avoir un contact principal. Voulez vous créer un nouveau contact principal ? + ); }; diff --git a/src/ui/Contact/CreateContact/CreateContactDialog.tsx b/src/ui/Contact/CreateContact/CreateContactDialog.tsx new file mode 100644 index 0000000..fc91f70 --- /dev/null +++ b/src/ui/Contact/CreateContact/CreateContactDialog.tsx @@ -0,0 +1,261 @@ +import Dialog from "@mui/material/Dialog"; +import { useForm } from "../../../hooks/useForm"; +import { APISchemas } from "../../../types/api"; +import { + ContactInformationForm, + repetitionIndexEnum, + schema, + streetTypeEnum, + styles, +} from "../ContactFormDialog"; +import DialogTitle from "@mui/material/DialogTitle"; +import DialogContent from "@mui/material/DialogContent"; +import DialogActions from "@mui/material/DialogActions"; +import Button from "@mui/material/Button"; +import { UseFormRegister, UseFormReturn } from "react-hook-form"; +import { Schema, z } from "zod"; +import { useState } from "react"; +import Box from "@mui/material/Box"; +import Divider from "@mui/material/Divider"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Checkbox from "@mui/material/Checkbox"; +import { Field } from "../../Form/Field"; +import { countries } from "../../../constants/countries"; +import Stack from "@mui/material/Stack"; +import { Row } from "../../Row"; + +type Props = { + open: boolean; + onClose: () => void; + surveyUnit?: APISchemas["SurveyUnitDto"]; +}; + +export const CreateContactDialog = ({ open, onClose, surveyUnit }: Props) => { + const defaultValues = { + firstName: "", + lastName: "", + email: "", + function: "", + phone: "", + address: { countryName: "FRANCE" }, + }; + + const { register, control, errors, reset, handleSubmit, setValue } = useForm(schema, { + defaultValues: defaultValues, + }); + + const onAddressChecked = (e: React.ChangeEvent) => { + setValue("usualCompanyName", surveyUnit?.identificationName); + setValue("address", { + cedexCode: "", + cedexName: "", + cityName: "", + zipCode: "", + streetName: "", + ...surveyUnit?.address, + }); + }; + + const handleClose = () => { + reset(defaultValues); + onClose(); + }; + + const onSubmit = handleSubmit(data => { + console.log(data); + handleClose(); + }); + + return ( + +
+ Informations du contact + + + + + + + +
+
+ ); +}; + +type FormContentProps = { + errors: any; + register: UseFormRegister>; + control: UseFormReturn["control"]; + contact?: Omit; + surveyUnitId?: string; + onAddressChecked?: (e: React.ChangeEvent) => void; +}; + +export const FormContent = ({ + errors, + register, + control, + contact, + surveyUnitId, + onAddressChecked, +}: FormContentProps) => { + const [country, setCountry] = useState(contact?.address?.countryName ?? "FRANCE"); + return ( + + + + + {surveyUnitId !== undefined && ( + } + label="L’adresse du contact est identique à l’adresse de l’unité enquêtée" + /> + )} + + + + { + setCountry(e.target.value as string); + }} + /> + + + + + + + + + {country === "FRANCE" ? ( + + ) : ( + + )} + + + {country === "FRANCE" ? ( + + ) : ( + + )} + + + + + + + + + + + + + + + + ); +}; diff --git a/src/ui/Contact/CreateContact/InformationsForm.tsx b/src/ui/Contact/CreateContact/InformationsForm.tsx index 77e5c14..b0109ca 100644 --- a/src/ui/Contact/CreateContact/InformationsForm.tsx +++ b/src/ui/Contact/CreateContact/InformationsForm.tsx @@ -1,22 +1,63 @@ -import { Stack } from "@mui/material"; +import { Box, Button, Divider, Stack } from "@mui/material"; import Typography from "@mui/material/Typography"; -import { UseFormRegister, UseFormReturn } from "react-hook-form"; -import { Schema, z } from "zod"; -import { FormContent } from "../ContactFormDialog"; +import { ContactInformationForm, schema, styles } from "../ContactFormDialog"; +import { useForm } from "../../../hooks/useForm"; +import { Row } from "../../Row"; + +import { APISchemas } from "../../../types/api"; +import { AddressFormFields } from "../../Form/AddressFormFields"; type Props = { - errors: any; - register: UseFormRegister>; - control?: UseFormReturn["control"]; + handleSubmitStep: (data: any) => void; + handleBack: () => void; + contact?: Omit; }; -export const InformationsForm = ({ errors, register, control }: Props) => { +export const InformationsForm = ({ handleSubmitStep, handleBack, contact }: Props) => { + const defaultValues = + contact?.address?.countryName && contact.address.countryName !== "" + ? contact + : { ...contact, address: { ...contact?.address, countryName: "FRANCE" } }; + + const { register, control, errors, handleSubmit } = useForm(schema, { + defaultValues: defaultValues, + }); + + const onSubmit = handleSubmit(data => { + handleSubmitStep(data); + }); + return ( Informations du contact - +
+ + + + + + + + + + + + + +
); }; diff --git a/src/ui/Contact/CreateContact/RightsManagementForm.tsx b/src/ui/Contact/CreateContact/RightsManagementForm.tsx index 610548b..56b5008 100644 --- a/src/ui/Contact/CreateContact/RightsManagementForm.tsx +++ b/src/ui/Contact/CreateContact/RightsManagementForm.tsx @@ -2,9 +2,14 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import { Row } from "../../Row"; -import { InputLabel, TextField } from "@mui/material"; +import { Button, InputLabel, TextField } from "@mui/material"; -export const RightsManagementForm = () => { +type Props = { + handleSubmitStep: (event: React.FormEvent) => void; + handleBack: () => void; +}; + +export const RightsManagementForm = ({ handleSubmitStep, handleBack }: Props) => { return ( @@ -17,7 +22,7 @@ export const RightsManagementForm = () => { période est nécessaire pour l’ajout de droits -
+ { + + + + +
); diff --git a/src/ui/Form/AddressFormFields.tsx b/src/ui/Form/AddressFormFields.tsx index 6607055..1b6e687 100644 --- a/src/ui/Form/AddressFormFields.tsx +++ b/src/ui/Form/AddressFormFields.tsx @@ -33,7 +33,7 @@ export const AddressFormFields = ({ countryValue, type = "surveyUnit", }: Props) => { - const [country, setCountry] = useState(countryValue); + const [country, setCountry] = useState(countryValue ?? "FRANCE"); return ( diff --git a/src/ui/Form/Field.tsx b/src/ui/Form/Field.tsx index 03ad722..a980472 100644 --- a/src/ui/Form/Field.tsx +++ b/src/ui/Form/Field.tsx @@ -122,7 +122,49 @@ export function uncontrolledField(props: Props, ref: any) { ); } -export function controlledField({ type, name, options, error }: Props, field: any) { +export function controlledField( + { type, name, options, error, label, selectoptions }: Props, + field: any, +) { + if (!type || type === "text") { + return ( + + ); + } + if (type === "select" && selectoptions) { + const labelId = `label-${name}`; + + return ( + + + {label} + + + + ); + } if (type === "switch") { return ; } diff --git a/src/ui/SurveyUnit/SurveyUnitContacts.tsx b/src/ui/SurveyUnit/SurveyUnitContacts.tsx index cd35a4a..56dc9f2 100644 --- a/src/ui/SurveyUnit/SurveyUnitContacts.tsx +++ b/src/ui/SurveyUnit/SurveyUnitContacts.tsx @@ -25,6 +25,7 @@ import SearchIcon from "@mui/icons-material/Search"; import useToggle from "react-use/lib/useToggle"; import { useDebouncedState } from "../../hooks/useDebouncedState"; import { Link } from "../Link"; +import { CreateContactDialog } from "../Contact/CreateContact/CreateContactDialog"; type Props = { surveyUnit: APISchemas["SurveyUnitDto"]; @@ -33,6 +34,7 @@ type Props = { export const SurveyUnitContacts = ({ surveyUnit }: Props) => { const [search, setSearch] = useDebouncedState("", 500); const [isFilteredOpened, toggle] = useToggle(false); + const [hasDialog, toggleDialog] = useToggle(false); const { data: contacts, isLoading } = useFetchQuery("/api/survey-units/{id}/contacts", { urlParams: { @@ -114,15 +116,15 @@ export const SurveyUnitContacts = ({ surveyUnit }: Props) => { typography: "titleSmall", fontWeight: "500", }} + onClick={toggleDialog} size="large" fullWidth={false} variant="contained" endIcon={} > - - Créer un nouveau contact - + Créer un nouveau contact + ); }; diff --git a/src/ui/SurveyUnit/SurveyUnitFormDialog.tsx b/src/ui/SurveyUnit/SurveyUnitFormDialog.tsx index b8245bb..0bc89bf 100644 --- a/src/ui/SurveyUnit/SurveyUnitFormDialog.tsx +++ b/src/ui/SurveyUnit/SurveyUnitFormDialog.tsx @@ -23,7 +23,7 @@ const schema = z.object({ export const SurveyUnitFormDialog = ({ open, onClose, surveyUnit, onSave }: Props) => { const defaultValues = surveyUnit.address?.countryName ? surveyUnit - : { ...surveyUnit, address: { ...surveyUnit.address, countryName: "France" } }; + : { ...surveyUnit, address: { ...surveyUnit.address, countryName: "FRANCE" } }; const { register, errors, handleSubmit } = useForm(schema, { defaultValues: defaultValues, });