refactor: modals refactored

This commit is contained in:
2025-09-05 14:25:36 +04:00
parent 7694b4ae03
commit d0c734d481
24 changed files with 292 additions and 97 deletions

View File

@ -9,14 +9,8 @@ import { useDrawersContext } from "@/drawers/DrawersContext";
import { DealSchema } from "@/lib/client";
const DealsTable: FC = () => {
const {
deals,
paginationInfo,
page,
setPage,
dealsFiltersForm,
dealsCrud,
} = useDealsContext();
const { deals, paginationInfo, page, setPage, sortingForm, dealsCrud } =
useDealsContext();
const { selectedProject } = useProjectsContext();
const { openDrawer } = useDrawersContext();
@ -40,20 +34,20 @@ const DealsTable: FC = () => {
return (
<Stack
gap={"xs"}
h={"calc(100vh - 125px)"}>
h={"calc(100vh - var(--mantine-spacing-xl) * 4)"}>
<BaseTable
records={[...deals]}
columns={columns}
sortStatus={{
columnAccessor: dealsFiltersForm.values.sortingField ?? "",
direction: dealsFiltersForm.values.sortingDirection,
columnAccessor: sortingForm.values.sortingField ?? "",
direction: sortingForm.values.sortingDirection,
}}
onSortStatusChange={sorting => {
dealsFiltersForm.setFieldValue(
sortingForm.setFieldValue(
"sortingField",
sorting.columnAccessor
);
dealsFiltersForm.setFieldValue(
sortingForm.setFieldValue(
"sortingDirection",
sorting.direction
);

View File

@ -35,7 +35,7 @@ const TopToolPanel: FC<Props> = ({ view, setView }) => {
title: "Создание проекта",
withCloseButton: true,
innerProps: {
onComplete: projectsCrud.onCreate,
onChange: values => projectsCrud.onCreate(values.name),
},
});
};
@ -49,9 +49,15 @@ const TopToolPanel: FC<Props> = ({ view, setView }) => {
});
};
const viewFiltersModalMap = {
table: "dealsTableFiltersModal",
board: "dealsBoardFiltersModal",
schedule: "dealsScheduleFiltersModal",
};
const onFiltersClick = () => {
modals.openContextModal({
modal: "dealsFiltersModal",
modal: viewFiltersModalMap[view],
title: "Фильтры",
withCloseButton: true,
innerProps: {

View File

@ -29,8 +29,8 @@ const Board: FC<Props> = ({ board }) => {
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}>
<InPlaceInput
defaultValue={board.name}
onComplete={value =>
value={board.name}
onChange={value =>
boardsCrud.onUpdate(board.id, { name: value })
}
inputStyles={{

View File

@ -11,7 +11,7 @@ const CreateBoardButton = () => {
<Flex style={{ borderBottom: "2px solid gray" }}>
<InPlaceInput
placeholder={"Название доски"}
onComplete={boardsCrud.onCreate}
onChange={boardsCrud.onCreate}
getChildren={startEditing => (
<Box
onClick={startEditing}

View File

@ -17,7 +17,7 @@ const CreateStatusButton = () => {
className={styles["inner-container"]}>
<InPlaceInput
placeholder={"Название колонки"}
onComplete={statusesCrud.onCreate}
onChange={statusesCrud.onCreate}
getChildren={startEditing => (
<Center
p={"sm"}

View File

@ -31,8 +31,8 @@ const StatusColumnHeader: FC<Props> = ({ status, isDragging }) => {
mb={"xs"}
className={styles.header}>
<InPlaceInput
defaultValue={status.name}
onComplete={value => handleSave(value)}
value={status.name}
onChange={value => handleSave(value)}
inputStyles={{
input: {
height: 25,

View File

@ -6,6 +6,7 @@ import { useStatusesContext } from "@/app/deals/contexts/StatusesContext";
import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters";
import { DealsCrud, useDealsCrud } from "@/hooks/cruds/useDealsCrud";
import useDealsList from "@/hooks/lists/useDealsList";
import { SortingForm } from "@/hooks/utils/useSorting";
import { DealSchema, PaginationInfoSchema } from "@/lib/client";
import makeContext from "@/lib/contextFactory/contextFactory";
@ -19,6 +20,7 @@ type DealsContextState = {
setPage: React.Dispatch<React.SetStateAction<number>>;
dealsFiltersForm: UseFormReturnType<DealsFiltersForm>;
isChangedFilters: boolean;
sortingForm: UseFormReturnType<SortingForm>;
};
type Props = {

View File

@ -13,7 +13,7 @@ const CreateStatusButton: FC = () => {
title: "Создание колонки",
withCloseButton: true,
innerProps: {
onComplete: statusesCrud.onCreate,
onChange: values => statusesCrud.onCreate(values.name),
},
});
};

View File

@ -19,8 +19,8 @@ const StatusMobile: FC<Props> = ({ status, board }) => {
title: "Редактирование статуса",
withCloseButton: true,
innerProps: {
onComplete: name => statusesCrud.onUpdate(status.id, { name }),
defaultValue: status.name,
onChange: values => statusesCrud.onUpdate(status.id, values),
value: status,
},
});
};

View File

@ -18,8 +18,8 @@ const BoardMobile: FC<Props> = ({ board }) => {
title: "Редактирование доски",
withCloseButton: true,
innerProps: {
onComplete: name => boardsCrud.onUpdate(board.id, { name }),
defaultValue: board.name,
onChange: values => boardsCrud.onUpdate(board.id, values),
value: board,
},
});
};

View File

@ -14,7 +14,7 @@ const CreateBoardButton: FC<Props> = ({ onCreateBoard }) => {
title: "Создание доски",
withCloseButton: true,
innerProps: {
onComplete: onCreateBoard,
onChange: values => onCreateBoard(values.name),
},
});
};

View File

@ -13,7 +13,7 @@ const CreateProjectButton: FC = () => {
title: "Создание проекта",
withCloseButton: true,
innerProps: {
onComplete: projectsCrud.onCreate,
onChange: values => projectsCrud.onCreate(values.name),
},
});
};

View File

@ -25,8 +25,8 @@ const ProjectMobile: FC<Props> = ({
title: "Редактирование проекта",
withCloseButton: true,
innerProps: {
onComplete: name => projectsCrud.onUpdate(project.id, { name }),
defaultValue: project.name,
onChange: values => projectsCrud.onUpdate(project.id, values),
value: project,
},
});
};

View File

@ -1,14 +1,12 @@
import { isEqual } from "lodash";
import { useForm, UseFormReturnType } from "@mantine/form";
import { BoardSchema, SortDir, StatusSchema } from "@/lib/client";
import { BoardSchema, StatusSchema } from "@/lib/client";
export type DealsFiltersForm = {
id: number | null;
name: string;
board: BoardSchema | null;
status: StatusSchema | null;
sortingField?: string;
sortingDirection: SortDir;
};
type ReturnType = {
@ -17,20 +15,18 @@ type ReturnType = {
};
const useDealsFilters = (): ReturnType => {
const initialValues = {
const initialFilters = {
id: null,
board: null,
status: null,
name: "",
sortingField: "createdAt",
sortingDirection: "asc" as SortDir,
};
const form = useForm<DealsFiltersForm>({
initialValues,
initialValues: initialFilters,
});
const isChangedFilters = !isEqual(form.values, initialValues);
const isChangedFilters = !isEqual(form.values, initialFilters);
return {
form,

View File

@ -0,0 +1,71 @@
"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 { ProjectSchema } from "@/lib/client";
type Props = {
value: DealsFiltersForm;
onChange: (values: DealsFiltersForm) => void;
project: ProjectSchema | null;
};
const DealsBoardFiltersModal = ({
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")}
/>
<Space />
<Button
variant={"default"}
type={"submit"}>
<Text>Сохранить</Text>
</Button>
</Flex>
</form>
);
};
export default DealsBoardFiltersModal;

View File

@ -20,10 +20,9 @@ type Props = {
value: DealsFiltersForm;
onChange: (values: DealsFiltersForm) => void;
project: ProjectSchema | null;
boardAndStatusEnabled: boolean;
};
const DealsFiltersModal = ({
const DealsScheduleFiltersModal = ({
id,
context,
innerProps,
@ -60,23 +59,19 @@ const DealsFiltersModal = ({
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
/>
</>
)}
<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"}
@ -88,4 +83,4 @@ const DealsFiltersModal = ({
);
};
export default DealsFiltersModal;
export default DealsScheduleFiltersModal;

View File

@ -0,0 +1,86 @@
"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;
};
const DealsTableFiltersModal = ({
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")}
/>
<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 DealsTableFiltersModal;