refactor: moved ProjectEditorDrawer into common drawers directory

This commit is contained in:
2025-10-18 13:06:37 +04:00
parent 159d6948c7
commit 9023b07c65
17 changed files with 786 additions and 12 deletions

View File

@ -1,4 +0,0 @@
.tab {
border-bottom-width: 3px;
}

View File

@ -1,53 +0,0 @@
"use client";
import React, { FC, useState } from "react";
import { Drawer } from "@mantine/core";
import ProjectEditorBody from "@/app/deals/drawers/ProjectEditorDrawer/components/ProjectEditorBody";
import { DrawerProps } from "@/drawers/types";
import useIsMobile from "@/hooks/utils/useIsMobile";
import { ProjectSchema } from "@/lib/client";
type Props = {
value: ProjectSchema;
onChange: (value: ProjectSchema) => void;
onDelete: (value: ProjectSchema, onSuccess: () => void) => void;
};
const ProjectEditorDrawer: FC<DrawerProps<Props>> = ({
opened,
onClose,
props,
}) => {
const isMobile = useIsMobile();
const [project, setProject] = useState(props.value);
return (
<Drawer
size={isMobile ? "100%" : "40%"}
position={"right"}
onClose={onClose}
removeScrollProps={{ allowPinchZoom: true }}
withCloseButton={false}
opened={opened}
trapFocus={false}
styles={{
body: {
height: "100%",
display: "flex",
flexDirection: "column",
padding: 0,
},
}}>
<ProjectEditorBody
value={project}
onChange={project => {
setProject(project);
props.onChange(project);
}}
onDelete={value => props.onDelete(value, onClose)}
/>
</Drawer>
);
};
export default ProjectEditorDrawer;

View File

@ -1,44 +0,0 @@
import { FC } from "react";
import { IconBlocks, IconEdit } from "@tabler/icons-react";
import { Tabs } from "@mantine/core";
import {
GeneralTab,
ModulesTab,
} from "@/app/deals/drawers/ProjectEditorDrawer/tabs";
import { ProjectSchema } from "@/lib/client";
import styles from "../ProjectEditorDrawer.module.css";
type Props = {
value: ProjectSchema;
onChange: (value: ProjectSchema) => void;
onDelete: (value: ProjectSchema) => void;
};
const ProjectEditorBody: FC<Props> = props => {
return (
<Tabs
defaultValue="general"
classNames={{ tab: styles.tab }}>
<Tabs.List>
<Tabs.Tab
value="general"
leftSection={<IconEdit />}>
Общая информация
</Tabs.Tab>
<Tabs.Tab
value="modules"
leftSection={<IconBlocks />}>
Модули
</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="general">
<GeneralTab {...props} />
</Tabs.Panel>
<Tabs.Panel value="modules">
<ModulesTab {...props} />
</Tabs.Panel>
</Tabs>
);
};
export default ProjectEditorBody;

View File

@ -1,3 +0,0 @@
import ProjectEditorDrawer from "@/app/deals/drawers/ProjectEditorDrawer/ProjectEditorDrawer";
export default ProjectEditorDrawer;

View File

@ -1,40 +0,0 @@
import { FC } from "react";
import { Stack, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form";
import Footer from "@/app/deals/drawers/ProjectEditorDrawer/tabs/GeneralTab/components/Footer";
import { ProjectSchema } from "@/lib/client";
type Props = {
value: ProjectSchema;
onChange: (value: ProjectSchema) => void;
onDelete: (value: ProjectSchema) => void;
};
export const GeneralTab: FC<Props> = ({ value, onChange, onDelete }) => {
const form = useForm<ProjectSchema>({
initialValues: value,
validate: {
name: value => !value && "Введите название",
},
});
const onSubmit = (values: ProjectSchema) => {
form.resetDirty(values);
onChange(values);
};
return (
<form onSubmit={form.onSubmit(onSubmit)}>
<Stack p={"md"}>
<TextInput
label={"Название"}
{...form.getInputProps("name")}
/>
<Footer
form={form}
onDelete={() => onDelete(value)}
/>
</Stack>
</form>
);
};

View File

@ -1,41 +0,0 @@
import { FC } from "react";
import { Button, Group } from "@mantine/core";
import { UseFormReturnType } from "@mantine/form";
import { ProjectSchema } from "@/lib/client";
type Props = {
form: UseFormReturnType<ProjectSchema>;
onDelete: () => void;
};
const Footer: FC<Props> = ({ form, onDelete }) => {
return (
<Group
justify={"space-between"}
wrap={"nowrap"}>
<Group wrap={"nowrap"}>
<Button
type={"submit"}
disabled={!form.isDirty()}
variant={"filled"}>
Сохранить
</Button>
<Button
type={"reset"}
onClick={() => form.reset()}
disabled={!form.isDirty()}
variant={"default"}>
Отменить
</Button>
</Group>
<Button
onClick={onDelete}
color={"red"}
variant={"outline"}>
Удалить
</Button>
</Group>
);
};
export default Footer;

View File

@ -1,49 +0,0 @@
import { FC } from "react";
import { Button, Stack } from "@mantine/core";
import { useForm } from "@mantine/form";
import resolveDependencies from "@/app/deals/drawers/ProjectEditorDrawer/tabs/ModulesTab/utils/resolveDependencies";
import { ProjectSchema } from "@/lib/client";
import ModulesTable from "./components/ModulesTable";
type Props = {
value: ProjectSchema;
onChange: (value: ProjectSchema) => void;
};
export const ModulesTab: FC<Props> = ({ value, onChange }) => {
const form = useForm<ProjectSchema>({
initialValues: value,
});
const onSubmit = (values: ProjectSchema) => {
const modulesWithDependencies = resolveDependencies(
values.builtInModules
);
const updatedValues = {
...values,
builtInModules: modulesWithDependencies,
};
form.setValues(updatedValues);
form.resetDirty();
onChange(updatedValues);
};
return (
<form onSubmit={form.onSubmit(onSubmit)}>
<Stack p={"md"}>
<ModulesTable
selectedRecords={form.values.builtInModules}
onSelectedRecordsChange={modules =>
form.setFieldValue("builtInModules", modules)
}
/>
<Button
type={"submit"}
variant={"default"}
disabled={!form.isDirty()}>
Сохранить
</Button>
</Stack>
</form>
);
};

View File

@ -1,33 +0,0 @@
import { FC } from "react";
import { Divider, Stack } from "@mantine/core";
import useModulesTableColumns from "@/app/deals/drawers/ProjectEditorDrawer/tabs/ModulesTab/hooks/useModulesTableColumns";
import BaseTable from "@/components/ui/BaseTable/BaseTable";
import useBuiltInModulesList from "@/hooks/lists/useBuiltInModulesList";
import { BuiltInModuleSchemaOutput } from "@/lib/client";
type Props = {
selectedRecords: BuiltInModuleSchemaOutput[];
onSelectedRecordsChange: (records: BuiltInModuleSchemaOutput[]) => void;
};
const ModulesTable: FC<Props> = props => {
const columns = useModulesTableColumns();
const { builtInModules } = useBuiltInModulesList();
return (
<Stack gap={0}>
<Divider />
<BaseTable
records={builtInModules}
columns={columns}
verticalSpacing={"md"}
allRecordsSelectionCheckboxProps={{
hidden: true,
}}
{...props}
/>
</Stack>
);
};
export default ModulesTable;

View File

@ -1,46 +0,0 @@
import { useMemo } from "react";
import { IconInfoCircle } from "@tabler/icons-react";
import { DataTableColumn } from "mantine-datatable";
import { em, Group, Text, Tooltip } from "@mantine/core";
import { BuiltInModuleSchemaOutput } from "@/lib/client";
const useModulesTableColumns = () => {
return useMemo(
() =>
[
{
accessor: "label",
title: "Название",
width: "20%",
},
{
title: "Описание",
accessor: "description",
width: "50%",
},
{
title: (
<Group gap={"sm"}>
Зависит от модулей
<Tooltip
label={
"Зависимости автоматически подключатся при сохранении"
}>
<IconInfoCircle size={em(25)} />
</Tooltip>
</Group>
),
accessor: "dependsOn",
width: "30%",
render: module => (
<Text>
{module.dependsOn?.map(m => m.label).join(", ")}
</Text>
),
},
] as DataTableColumn<BuiltInModuleSchemaOutput>[],
[]
);
};
export default useModulesTableColumns;

View File

@ -1,22 +0,0 @@
import { uniqBy } from "lodash";
import { BuiltInModuleSchemaOutput } from "@/lib/client";
const resolveDependencies = (
modules: BuiltInModuleSchemaOutput[]
): BuiltInModuleSchemaOutput[] => {
const resolved = new Set<number>();
const result: BuiltInModuleSchemaOutput[] = [];
const addModule = (module: BuiltInModuleSchemaOutput) => {
if (resolved.has(module.id)) return;
resolved.add(module.id);
module.dependsOn.forEach(addModule);
result.push(module);
};
modules.forEach(addModule);
return uniqBy(result, "id");
};
export default resolveDependencies;

View File

@ -1,2 +0,0 @@
export { GeneralTab } from "./GeneralTab/GeneralTab";
export { ModulesTab } from "./ModulesTab/ModulesTab";