Skip to content

Commit

Permalink
Merge pull request #54 from fga-eps-mds/task/editionModal
Browse files Browse the repository at this point in the history
Adição da funcionalidade de editar etapa
  • Loading branch information
zpeniel09 authored Jul 14, 2023
2 parents b5ff98a + 0941239 commit 3dca6d8
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/components/DataTable/ActionButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function ActionButton({
color="gray.600"
onClick={action}
isDisabled={disabled}
aria-label={label}
>
{icon}
</Button>
Expand Down
130 changes: 130 additions & 0 deletions src/pages/Stages/EditionModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { useEffect } from "react";
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
ModalFooter,
chakra,
Button,
useToast,
} from "@chakra-ui/react";
import * as yup from "yup";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";

import { updateStage } from "services/stages";
import { Input } from "components/FormFields";
import { useLoading } from "hooks/useLoading";

type FormValues = {
name: string;
duration: number;
};

const validationSchema = yup.object({
name: yup.string().required("Dê um nome à etapa"),
duration: yup.number().required().typeError("Dê uma duração para esta etapa"),
});

interface EditionModalProps {
stage: Stage;
isOpen: boolean;
onClose: () => void;
afterSubmission: () => void;
}

export function EditionModal({
stage,
isOpen,
onClose,
afterSubmission,
}: EditionModalProps) {
const toast = useToast();
const { handleLoading } = useLoading();

const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm<FormValues>({
resolver: yupResolver(validationSchema),
reValidateMode: "onChange",
});

const onSubmit = handleSubmit(async (formData) => {
handleLoading(true);
const res = await updateStage({
...formData,
idStage: stage.idStage,
});

onClose();
afterSubmission();

if (res.type === "success") {
handleLoading(false);

toast({
id: "edit-stage-success",
title: "Sucesso!",
description: "A etapa foi editada.",
status: "success",
});
return;
}

handleLoading(false);
toast({
id: "edit-stage-error",
title: "Erro ao editar etapa",
description: res.error?.message,
status: "error",
isClosable: true,
});
});

useEffect(() => {
reset();
}, [isOpen]);

return (
<Modal isOpen={isOpen} onClose={onClose} size={["full", "xl"]}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Editar etapa</ModalHeader>
<ModalCloseButton />
<chakra.form onSubmit={onSubmit}>
<ModalBody display="flex" flexDir="column" gap="3">
<Input
type="text"
label="Nome"
placeholder="Nome da etapa"
errors={errors.name}
defaultValue={stage.name}
{...register("name")}
/>
<Input
type="number"
label="Duração (em dias)"
placeholder="Duração da etapa"
errors={errors.duration}
{...register("duration")}
/>
</ModalBody>
<ModalFooter gap="2">
<Button variant="ghost" onClick={onClose} size="sm">
Cancelar
</Button>
<Button colorScheme="green" type="submit" size="sm">
Salvar
</Button>
</ModalFooter>
</chakra.form>
</ModalContent>
</Modal>
);
}
29 changes: 28 additions & 1 deletion src/pages/Stages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
chakra,
} from "@chakra-ui/react";
import { AddIcon, Icon, SearchIcon } from "@chakra-ui/icons";
import { MdDelete } from "react-icons/md";
import { MdDelete, MdEdit } from "react-icons/md";
import { createColumnHelper } from "@tanstack/react-table";
import { useAuth } from "hooks/useAuth";
import { PrivateLayout } from "layouts/Private";
Expand All @@ -20,6 +20,7 @@ import { Pagination } from "components/Pagination";
import { getStages } from "../../services/stages";
import { CreationModal } from "./CreationModal";
import { DeletionModal } from "./DeletionModal";
import { EditionModal } from "./EditionModal";

function Stages() {
const toast = useToast();
Expand All @@ -36,6 +37,11 @@ function Stages() {
onOpen: onDeletionOpen,
onClose: onDeletionClose,
} = useDisclosure();
const {
isOpen: isEditionOpen,
onOpen: onEditionOpen,
onClose: onEditionClose,
} = useDisclosure();
const [currentPage, setCurrentPage] = useState(0);
const handlePageChange = (selectedPage: { selected: number }) => {
setCurrentPage(selectedPage.selected);
Expand Down Expand Up @@ -74,6 +80,19 @@ function Stages() {

const tableActions = useMemo(
() => [
{
label: "Editar Etapa",
icon: <Icon as={MdEdit} boxSize={4} />,
action: ({ stage }: { stage: Stage }) => {
selectStage(stage);
onEditionOpen();
},
actionName: "edit-stage",
disabled: !isActionAllowedToUser(
userData?.value?.allowedActions || [],
"edit-stage"
),
},
{
label: "Excluir Etapa",
icon: <Icon as={MdDelete} boxSize={4} />,
Expand Down Expand Up @@ -224,6 +243,14 @@ function Stages() {
refetchStages={refetchStages}
/>
)}
{selectedStage ? (
<EditionModal
stage={selectedStage}
isOpen={isEditionOpen}
onClose={onEditionClose}
afterSubmission={refetchStages}
/>
) : null}
</PrivateLayout>
);
}
Expand Down
44 changes: 35 additions & 9 deletions src/pages/__tests__/Stages.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { describe, expect } from "vitest";
import { act, render, screen, fireEvent } from "@testing-library/react";
import {
act,
render,
screen,
fireEvent,
waitFor,
} from "@testing-library/react";

import { BrowserRouter } from "react-router-dom";
import { rest } from "msw";
Expand Down Expand Up @@ -107,31 +113,51 @@ describe("Stages page", () => {
expect(await screen.queryByText("j")).toBe(null);
});

it("open and closes the edition modal correctly", async () => {
const editStageButton = screen.getAllByLabelText("Editar Etapa");

await act(async () => {
await fireEvent.click(editStageButton[0]);
});

expect(await screen.findAllByText("Editar etapa")).not.toBeNull();

const closeModalButton = await screen.getByText("Cancelar");

await act(async () => {
await fireEvent.click(closeModalButton);
});

await waitFor(() => {
expect(screen.queryByText("Editar etapa")).toBeNull();
});
});

it("filters stages correctly", async () => {
const input = screen.getByPlaceholderText("Pesquisar etapas");
const searchStagesButton = screen.getByPlaceholderText("Pesquisar etapas");

expect(input).not.toBe(null);
expect(searchStagesButton).not.toBe(null);

await act(async () => {
await fireEvent.change(input, {
await fireEvent.change(searchStagesButton, {
target: { value: "a" },
});
await fireEvent.submit(input);
await fireEvent.submit(searchStagesButton);
});

expect(await screen.queryByText("a")).not.toBe(null);
expect(await screen.queryByText("b")).toBe(null);
expect(await screen.queryByText("c")).toBe(null);

const button = screen.getByLabelText("botão de busca");
const searchBarButton = screen.getByLabelText("botão de busca");

expect(button).not.toBe(null);
expect(searchBarButton).not.toBe(null);

await act(async () => {
await fireEvent.change(input, {
await fireEvent.change(searchStagesButton, {
target: { value: "c" },
});
await fireEvent.click(button);
await fireEvent.click(searchBarButton);
});

expect(await screen.queryByText("a")).toBe(null);
Expand Down
23 changes: 23 additions & 0 deletions src/services/stages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,29 @@ export const createStage = async (data: {
}
};

export const updateStage = async (data: {
idStage: number;
name: string;
}): Promise<Result<Stage>> => {
try {
const res = await api.stages.put<Stage>("/updateStage", data);

return {
type: "success",
value: res.data,
};
} catch (error) {
if (error instanceof Error)
return { type: "error", error, value: undefined };

return {
type: "error",
error: new Error("Erro desconhecido"),
value: undefined,
};
}
};

export const deleteStage = async (idStage: number): Promise<Result<Stage>> => {
try {
const res = await api.stages.delete<Stage>(`/deleteStage/${idStage}`);
Expand Down

0 comments on commit 3dca6d8

Please sign in to comment.