refactor: filters modal with context

This commit is contained in:
2025-09-04 14:54:20 +04:00
parent a5afb03be6
commit 7694b4ae03
4 changed files with 118 additions and 95 deletions

View File

@ -8,7 +8,7 @@ import ToolPanelAction from "@/app/deals/components/desktop/ToolPanelAction/Tool
import ViewSelector from "@/app/deals/components/desktop/ViewSelector/ViewSelector"; import ViewSelector from "@/app/deals/components/desktop/ViewSelector/ViewSelector";
import { useDealsContext } from "@/app/deals/contexts/DealsContext"; import { useDealsContext } from "@/app/deals/contexts/DealsContext";
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext"; import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
import DealsTableFiltersModal from "@/app/deals/modals/DealsTableFiltersModal/DealsTableFiltersModal"; import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters";
import ProjectSelect from "@/components/selects/ProjectSelect/ProjectSelect"; import ProjectSelect from "@/components/selects/ProjectSelect/ProjectSelect";
import { useDrawersContext } from "@/drawers/DrawersContext"; import { useDrawersContext } from "@/drawers/DrawersContext";
import useIsMobile from "@/hooks/utils/useIsMobile"; import useIsMobile from "@/hooks/utils/useIsMobile";
@ -49,6 +49,21 @@ const TopToolPanel: FC<Props> = ({ view, setView }) => {
}); });
}; };
const onFiltersClick = () => {
modals.openContextModal({
modal: "dealsFiltersModal",
title: "Фильтры",
withCloseButton: true,
innerProps: {
value: dealsFiltersForm.values,
onChange: (values: DealsFiltersForm) =>
dealsFiltersForm.setValues(values),
project: selectedProject,
boardAndStatusEnabled: view === "table",
},
});
};
return ( return (
<Group justify={"space-between"}> <Group justify={"space-between"}>
<ViewSelector <ViewSelector
@ -59,22 +74,15 @@ const TopToolPanel: FC<Props> = ({ view, setView }) => {
wrap={"nowrap"} wrap={"nowrap"}
align={"center"} align={"center"}
gap={"sm"}> gap={"sm"}>
<DealsTableFiltersModal <Indicator
getOpener={onFiltersClick => ( zIndex={100}
<Indicator disabled={!isChangedFilters}
zIndex={100} offset={3}
disabled={!isChangedFilters} size={8}>
offset={3} <ToolPanelAction onClick={onFiltersClick}>
size={8}> <IconFilter />
<ToolPanelAction onClick={onFiltersClick}> </ToolPanelAction>
<IconFilter /> </Indicator>
</ToolPanelAction>
</Indicator>
)}
filtersForm={dealsFiltersForm}
selectedProject={selectedProject}
boardAndStatusEnabled={view === "table"}
/>
<ToolPanelAction onClick={onEditClick}> <ToolPanelAction onClick={onEditClick}>
<IconEdit /> <IconEdit />
</ToolPanelAction> </ToolPanelAction>

View File

@ -0,0 +1,91 @@
"use client";
import {
Button,
Flex,
NumberInput,
rem,
Space,
Text,
TextInput,
} from "@mantine/core";
import { useForm } from "@mantine/form";
import { ContextModalProps } from "@mantine/modals";
import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters";
import BoardSelect from "@/components/selects/BoardSelect/BoardSelect";
import StatusSelect from "@/components/selects/StatusSelect/StatusSelect";
import { ProjectSchema } from "@/lib/client";
type Props = {
value: DealsFiltersForm;
onChange: (values: DealsFiltersForm) => void;
project: ProjectSchema | null;
boardAndStatusEnabled: boolean;
};
const DealsFiltersModal = ({
id,
context,
innerProps,
}: ContextModalProps<Props>) => {
const filtersForm = useForm({
initialValues: innerProps.value,
});
const onSubmit = (values: DealsFiltersForm) => {
innerProps.onChange(values);
context.closeModal(id);
};
return (
<form onSubmit={filtersForm.onSubmit(onSubmit)}>
<Flex
gap={rem(10)}
direction={"column"}>
<NumberInput
label={"ID"}
placeholder={"Введите ID"}
{...filtersForm.getInputProps("id")}
value={filtersForm.values.id ?? ""}
onChange={value =>
typeof value === "number"
? filtersForm.setFieldValue("id", Number(value))
: filtersForm.setFieldValue("id", null)
}
hideControls
min={1}
/>
<TextInput
label={"Название"}
placeholder={"Введите название"}
{...filtersForm.getInputProps("name")}
/>
{innerProps.boardAndStatusEnabled && (
<>
<BoardSelect
label={"Доска"}
{...filtersForm.getInputProps("board")}
projectId={innerProps.project?.id}
clearable
/>
<StatusSelect
label={"Статус"}
{...filtersForm.getInputProps("status")}
boardId={filtersForm.values.board?.id}
clearable
clearOnBoardChange
/>
</>
)}
<Space />
<Button
variant={"default"}
type={"submit"}>
<Text>Сохранить</Text>
</Button>
</Flex>
</form>
);
};
export default DealsFiltersModal;

View File

@ -1,78 +0,0 @@
"use client";
import { ReactNode } from "react";
import { Flex, Modal, NumberInput, rem, TextInput } from "@mantine/core";
import { UseFormReturnType } from "@mantine/form";
import { useDisclosure } from "@mantine/hooks";
import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters";
import BoardSelect from "@/components/selects/BoardSelect/BoardSelect";
import StatusSelect from "@/components/selects/StatusSelect/StatusSelect";
import { ProjectSchema } from "@/lib/client";
type Props = {
filtersForm: UseFormReturnType<DealsFiltersForm>;
selectedProject: ProjectSchema | null;
boardAndStatusEnabled: boolean;
getOpener: (open: () => void) => ReactNode;
};
const DealsTableFiltersModal = ({
filtersForm,
selectedProject,
boardAndStatusEnabled,
getOpener,
}: Props) => {
const [opened, { open, close }] = useDisclosure();
return (
<>
{getOpener(open)}
<Modal
title={"Фильтры"}
opened={opened}
onClose={close}>
<Flex
gap={rem(10)}
direction={"column"}>
<NumberInput
label={"ID"}
placeholder={"Введите ID"}
{...filtersForm.getInputProps("id")}
value={filtersForm.values.id ?? ""}
onChange={value =>
typeof value === "number"
? filtersForm.setFieldValue("id", Number(value))
: filtersForm.setFieldValue("id", null)
}
hideControls
min={1}
/>
<TextInput
label={"Название"}
placeholder={"Введите название"}
{...filtersForm.getInputProps("name")}
/>
{boardAndStatusEnabled && (
<>
<BoardSelect
label={"Доска"}
{...filtersForm.getInputProps("board")}
projectId={selectedProject?.id}
clearable
/>
<StatusSelect
label={"Статус"}
{...filtersForm.getInputProps("status")}
boardId={filtersForm.values.board?.id}
clearable
clearOnBoardChange
/>
</>
)}
</Flex>
</Modal>
</>
);
};
export default DealsTableFiltersModal;

View File

@ -1,5 +1,7 @@
import DealsFiltersModal from "@/app/deals/modals/DealsFiltersModal/DealsFiltersModal";
import EnterNameModal from "@/modals/EnterNameModal/EnterNameModal"; import EnterNameModal from "@/modals/EnterNameModal/EnterNameModal";
export const modals = { export const modals = {
enterNameModal: EnterNameModal, enterNameModal: EnterNameModal,
dealsFiltersModal: DealsFiltersModal,
}; };