Untitled
unknown
plain_text
a year ago
21 kB
13
Indexable
import React, { useEffect, useState } from "react";
import Breadcrumbs from "../../../stories/components/molecules/Breadcrumbs/Breadcrumbs";
import Text from "../../../stories/components/ions/Text/Text";
import Input from "../../../stories/components/atoms/Input/Input";
import Select from "../../../stories/components/atoms/Select/Select";
import { RadioInput } from "../../../stories/components/atoms/Radio/Radio";
import { FormErrors } from "./interfaces";
import InputImage from "../../../stories/components/organisms/InputFile/InputFile";
import Button from "../../../stories/components/atoms/Button/Button";
import { modelService } from "../../../services/model/model.service";
import { useNavigate, useParams } from "react-router-dom";
import { z } from "zod";
import { AxiosError, AxiosProgressEvent } from "axios";
import "react-toastify/dist/ReactToastify.css";
import { boardService } from "../../../services/board/board.service";
import { IBoardDetails } from "../../../services/board/board.types";
import { IClient, clientService } from "../../../services/client";
import { IModel } from "../../../services/model";
import { UseToast } from "../../../contexts/ToastContext";
import "react-toastify/dist/ReactToastify.css";
import { RadioInputCustom } from "../../../stories/components/atoms/Radio/RadioCustom";
import ProgressBarLine from "../../../stories/components/atoms/ProgressBarLine/ProgressBarLine";
const BoardCreate: React.FC = () => {
const navigate = useNavigate();
const [loading, setLoading] = useState<boolean>(false);
const [uploadProgress, setUploadProgress] = useState<number>(0);
const { id } = useParams();
const [sideOptions, setSideOptions] = React.useState<
{ label: string; value: string }[]
>([
{ label: "Bottom (Lado S)", value: "Bottom" },
{ label: "Top (Lado C)", value: "Top" },
]);
const [isNewRegister] = useState<boolean>(!id);
const [file, setFile] = useState<File | null>(null);
const [models, setModels] = useState<IModel[]>([]);
const [clients, setClients] = useState<IClient[]>([]);
const [clientIdSelected, setClientIdSelected] = useState<string>("");
const [formData, setFormData] = useState({
ClientId: "",
ModelId: "",
ModelBoardName: "",
ProgramName: "",
QRCode: "",
Side: "Bottom",
EstimatedLifetime: 0,
TotalThermocouples: 0,
TotalReservedThermocouples: 0,
Nitrogen: false,
});
const [validationErrors, setValidationErrors] = useState({
file: false,
ClientId: false,
ModelId: false,
ModelBoardName: false,
ProgramName: false,
QRCode: false,
EstimatedLifetime: false,
TotalThermocouples: false,
TotalReservedThermocouples: false,
});
const [errors, setErrors] = useState<FormErrors>({});
const [boardData, setBoardData] = useState<IBoardDetails>();
const labelStyles: string = "mb-1";
const boardCreationSchema = z.object({
ClientId: z.string().min(1, "Seleção obrigatória"),
ModelId: z.string().min(1, "Seleção obrigatória"),
ModelBoardName: z.string().min(1, "Seleção obrigatória"),
QRCode: z.string().min(1, "Campo obrigatório"),
ProgramName: z.string().min(1, "Campo obrigatório"),
Side: z.enum(["Bottom", "Top"]),
EstimatedLifetime: z.number().min(1, "Campo obrigatório"),
TotalThermocouples: z.number().min(1, "Campo obrigatório"),
TotalReservedThermocouples: z.number().min(1, "Campo obrigatório"),
Nitrogen: z.boolean(),
});
const { showToast } = UseToast();
useEffect(() => {
if (id) {
const fetchBoardData = async () => {
const { data } = await boardService.getBoardDetails(id);
const updatedData = {
...data,
qrCode: data.qrCode.length > 0 && isNewRegister ? data.qrCode : "",
};
setBoardData(updatedData);
setFormData({
ClientId: data.clientId,
EstimatedLifetime: data.lifeTime,
ProgramName: data.programName,
QRCode: isNewRegister ? data.qrCode : "",
Side: data.side,
Nitrogen: data.nitrogen,
ModelId: data.modelId,
ModelBoardName: data.modelBoardName,
TotalReservedThermocouples: data.totalReservedThermocouples,
TotalThermocouples: data.totalThermocouples,
});
setSideOptions([
{
label: `${data.side === "Bottom" ? "Bottom (Lado S)" : "Top (Lado S)"}`,
value: data.side,
},
]);
};
fetchBoardData();
}
}, [id, isNewRegister]);
useEffect(() => {
const fetchClients = async () => {
const response = await clientService.listClients();
setClients(response.data);
};
if (clientIdSelected) {
clearModelsList();
const fetchModelsByClientId = async () => {
const response =
await modelService.listModelsByClient(clientIdSelected);
setModels(response.data);
};
fetchModelsByClientId();
}
fetchClients();
}, [clientIdSelected]);
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setLoading(true);
try {
const validatedData = boardCreationSchema.parse(formData);
if (file || id) {
const formData = new FormData();
if (file) {
formData.append("Image", file);
}
formData.append("ClientId", validatedData.ClientId);
formData.append("UserId", "1");
formData.append("ModelId", validatedData.ModelId);
formData.append("ModelBoardName", validatedData.ModelBoardName);
formData.append("ProgramName", validatedData.ProgramName);
formData.append("QRCode", validatedData.QRCode);
formData.append("Side", validatedData.Side);
formData.append("Nitrogen", validatedData.Nitrogen.toString());
formData.append(
"EstimatedLifetime",
validatedData.EstimatedLifetime.toString()
);
formData.append(
"TotalThermocouples",
validatedData.TotalThermocouples.toString()
);
formData.append(
"TotalReservedThermocouples",
validatedData.TotalReservedThermocouples.toString()
);
if (id) {
await boardService.resubscribeBoard(
{ data: formData, id },
(progressEvent: AxiosProgressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total!
);
setUploadProgress(percentCompleted);
}
);
} else {
await boardService.subscribeBoard(
formData,
(progressEvent: AxiosProgressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total!
);
setUploadProgress(percentCompleted);
}
);
}
navigate("/boards", {
state: showToast(
`Placa instrumentalizada ${isNewRegister ? "cadastrada" : "recadastrada"} com sucesso!`,
{
type: "success",
}
),
});
} else {
setLoading(false);
showToast(`Por favor, anexe uma imagem da placa antes de submeter!`, {
type: "warning",
});
}
} catch (error) {
setLoading(false);
if (error instanceof z.ZodError) {
const newErrors: FormErrors = {};
error.errors.forEach((e) => {
if (e.path[0]) {
newErrors[e.path[0] as keyof FormErrors] = e.message;
}
});
setErrors(newErrors);
}
if (error instanceof AxiosError) {
showToast(error.response?.data.message, { type: "error" });
}
} finally {
setLoading(false);
}
};
const handleChange = ({
field,
value,
}: {
field: string;
value: string | number | boolean;
}) => {
if (field === "ClientId" && clientIdSelected !== value) {
setClientIdSelected(String(value));
}
setFormData((prev) => ({ ...prev, [field]: value }));
};
const clearModelsList = async () => {
setModels([]);
setFormData((prev) => ({ ...prev, ModelId: "" }));
};
const clearFileInParent = () => {
setFile(null);
};
const modelSelectIsDisabled = () => {
if (boardData?.boardId || !clientIdSelected) return true;
return false;
};
return (
<>
{loading && uploadProgress > 0 && (
<ProgressBarLine progress={uploadProgress} />
)}
<div className="container">
<header className=" items-center">
<Breadcrumbs
title={
isNewRegister
? "Cadastrar Placa Instrumentalizada"
: "Recadastrar Placa Instrumentalizada"
}
path={[
{
link: "#",
title: "Placas",
},
{
link: "/boards",
title: "Lista de Placas Instrumentalizadas",
},
{
link: "/board-create",
title: id ? "Recadastrar Placa Instrumentalizadas" : "Cadastrar Placa Instrumentalizadas",
},
]}
/>
<Text type="span" fontSize="16px" color="#00000073">
Preencha as informações da Placa Instrumentalizada e faça o upload
da foto da placa. Todos os campos são obrigatórios
</Text>
</header>
{loading && (
<div className="w-full h-screen z-20 bg-white absolute bg-opacity-50"></div>
)}
<form className="justify-between mt-5 " onSubmit={handleSubmit}>
<div id="line1" className="flex ">
<section
id="column1"
className="w-1/2 mr-10 h-full justify-between"
>
<div>
<Select
controlLabel="Cliente"
options={clients.map((item) => ({
label: item.clientName,
value: String(item.id),
}))}
onChange={(value) => {
handleChange({ field: "ClientId", value: String(value) });
setValidationErrors((prev) => ({
...prev,
ClientId: !!value,
}));
}}
classNameLabel={labelStyles}
disabled={boardData?.boardId ? true : false}
initialValue={isNewRegister ? "" : String(boardData?.client)}
testId="clientSelect"
error={
errors.ClientId && !validationErrors.ClientId
? "Seleção obrigatória"
: ""
}
/>
<div className="flex justify-between mt-4">
<article className="w-[25%]">
<Select
controlLabel="Código do Modelo"
options={models.map((item) => ({
label: item.modelName,
value: String(item.id),
}))}
onChange={(value) => {
handleChange({ field: "ModelId", value: String(value) });
setValidationErrors((prev) => ({
...prev,
ModelId: !!value,
}));
}}
classNameLabel={labelStyles}
disabled={modelSelectIsDisabled()}
initialValue={
isNewRegister ? "" : String(boardData?.modelCode)
}
testId="modelSelect"
error={
errors.ModelId && !validationErrors.ModelId
? "Seleção obrigatória"
: ""
}
/>
</article>
<article className="w-2/3 mt-1">
<Input
label="Nome do Modelo"
placeholder="Insira o Nome da Placa"
type="text"
classNameLabel={labelStyles}
onChange={({ target: { value } }) => {
handleChange({ field: "ModelBoardName", value });
setValidationErrors((prev) => ({
...prev,
QRCode: !!value,
}));
}}
initialValue={isNewRegister ? "" : String(boardData?.modelBoardName)}
testId="NomedoProgramaInput"
error={
errors.QRCode && !validationErrors.QRCode
? "Seleção obrigatória"
: ""
}
/>
</article>
</div>
<Input
label="Nome do Programa"
placeholder="Insira o nome do Programa"
type="text"
classNameLabel={labelStyles}
onChange={({ target: { value } }) => {
handleChange({ field: "ProgramName", value });
setValidationErrors((prev) => ({
...prev,
QRCode: !!value,
}));
}}
initialValue={isNewRegister ? "" : String(boardData?.programName)}
testId="NomedoProgramaInput"
error={
errors.QRCode && !validationErrors.QRCode
? "Seleção obrigatória"
: ""
}
/>
<Input
label="QR Code de identificação da Placa"
placeholder="Leia aqui o QR Code ou digite manualmente"
type="text"
classNameLabel={labelStyles}
onChange={({ target: { value } }) => {
handleChange({ field: "QRCode", value });
setValidationErrors((prev) => ({
...prev,
QRCode: !!value,
}));
}}
initialValue={isNewRegister ? "" : String(boardData?.qrCode)}
testId="QrCodeInput"
error={
errors.QRCode && !validationErrors.QRCode
? "Seleção obrigatória"
: ""
}
/>
<div className="flex justify-between">
<article className="w-[45%]">
<RadioInput
label="Lado"
onChange={(value) =>
handleChange({ field: "Side", value })
}
options={sideOptions}
selectedValue={formData.Side}
classNameLabel={labelStyles}
testId="sideInputRadio"
/>
</article>
<article className="w-2/3">
<Input
label="Vida Útil estimada (Ciclos)"
placeholder="Ex: 100"
type="number"
classNameLabel={labelStyles}
onChange={({ target: { value } }) => {
handleChange({
field: "EstimatedLifetime",
value: Number(value),
});
setValidationErrors((prev) => ({
...prev,
EstimatedLifetime: !!value,
}));
}}
initialValue={
isNewRegister ? "" : String(boardData?.lifeTime)
}
testId="LifeEstimatedInput"
error={
errors.EstimatedLifetime &&
!validationErrors.EstimatedLifetime
? "Seleção obrigatória"
: ""
}
/>
</article>
</div>
<div className="flex justify-between">
<div className="w-[45%]">
<Input
label="Qtd. Total de Termopares"
placeholder="Insira um número"
type="number"
classNameLabel={labelStyles}
onChange={({ target: { value } }) => {
handleChange({
field: "TotalThermocouples",
value: Number(value),
});
setValidationErrors((prev) => ({
...prev,
TotalThermocouples: !!value,
}));
}}
initialValue={
isNewRegister
? ""
: String(boardData?.totalThermocouples)
}
testId="QtdThermocouplesInput"
error={
errors.TotalThermocouples &&
!validationErrors.TotalThermocouples
? "Seleção obrigatória"
: ""
}
/>
</div>
<div className="w-1/2">
<Input
label="Qtd. de Termopares Reserva"
placeholder="Insira um número"
type="number"
classNameLabel={labelStyles}
onChange={({ target: { value } }) => {
handleChange({
field: "TotalReservedThermocouples",
value: Number(value),
});
setValidationErrors((prev) => ({
...prev,
TotalReservedThermocouples: !!value,
}));
}}
initialValue={
isNewRegister
? ""
: String(boardData?.totalReservedThermocouples)
}
testId="QtdReservedThermocouplesInput"
error={
errors.TotalReservedThermocouples &&
!validationErrors.TotalReservedThermocouples
? "Seleção obrigatória"
: ""
}
/>
</div>
</div>
<div className="flex">
<RadioInputCustom
label="Nitrogênio"
onChange={(value) =>
handleChange({
field: "Nitrogen",
value: value === String(true) ? true : false,
})
}
options={[
{ label: "Não utiliza", value: String(false) },
{ label: "Utiliza", value: String(true) },
]}
selectedValue={String(formData.Nitrogen)}
classNameLabel={labelStyles}
testId="nitrogenInputRadio"
id={id}
/>
</div>
</div>
</section>
<section id="column2" className="w-1/2">
<InputImage
onUpload={(file) => {
setFile(file);
}}
onFileCleared={clearFileInParent}
labelText="Foto da Placa Instrumentalizada"
initialFile={isNewRegister ? null : boardData?.image}
testId="inputImage"
/>
</section>
</div>
<footer className="mt-10 flex justify-between relative z-20">
<Button
label="Cancelar"
className="py-2 px-4"
type="button"
onClick={() => navigate("/boards")}
testId="cancelButton"
disabled={loading}
/>
<Button
label={isNewRegister ? "Cadastrar" : "Recadastrar"}
className="py-2 px-4"
type="submit"
primary
testId="confirmButton"
loading={loading}
disabled={loading}
/>
</footer>
</form>
</div>
</>
);
};
export default BoardCreate;
Editor is loading...
Leave a Comment