feat: modules page and module editor page for mobiles

This commit is contained in:
2025-11-06 12:09:27 +04:00
parent d3270a3532
commit cc910c8495
14 changed files with 210 additions and 47 deletions

View File

@ -0,0 +1,40 @@
"use client";
import { FC, useMemo } from "react";
import useAttributesList from "@/app/module-editor/[moduleId]/hooks/useAttributesList";
import ObjectSelect, {
ObjectSelectProps,
} from "@/components/selects/ObjectSelect/ObjectSelect";
import { AttributeSchema } from "@/lib/client";
type Props = Omit<
ObjectSelectProps<AttributeSchema | null>,
"data" | "getLabelFn" | "getValueFn"
> & {
attributesToExclude?: AttributeSchema[];
};
const AttributeSelect: FC<Props> = ({ attributesToExclude, ...props }) => {
const { attributes } = useAttributesList();
const availableAttributes = useMemo(() => {
const attrIdsToExcludeSet = new Set(
attributesToExclude?.map(a => a.id)
);
return attributes.filter(a => !attrIdsToExcludeSet.has(a.id));
}, [attributes, attributesToExclude]);
return (
<ObjectSelect
searchable
placeholder={"Выберите статус"}
onClear={() => props.onChange(null)}
getLabelFn={(option: AttributeSchema) => option.label}
data={availableAttributes}
{...props}
/>
);
};
export default AttributeSelect;

View File

@ -24,7 +24,7 @@ const useAttributesTableColumns = () => {
accessor: "type.name",
render: attr =>
attr.type.type === "select"
? `Выбор "${attr.select?.label}"`
? `Выбор "${attr.select?.name}"`
: attr.type.name,
},
{

View File

@ -42,7 +42,7 @@ const ModuleAttribute: FC<Props> = ({ attribute }) => {
<>{getAttrLabelText()}</>
<Text>
Тип: {attribute.type.name}{" "}
{attribute.select && `"${attribute.select.label}"`}
{attribute.select && `"${attribute.select.name}"`}
</Text>
</Stack>
<Group

View File

@ -1,11 +1,18 @@
import React, { ReactNode } from "react";
import { Flex } from "@mantine/core";
import { modals } from "@mantine/modals";
import ModuleAttribute from "@/app/module-editor/[moduleId]/components/shared/ModuleAttribute/ModuleAttribute";
import { useModuleEditorContext } from "@/app/module-editor/[moduleId]/contexts/ModuleEditorContext";
import FormFlexRow from "@/components/ui/FormFlexRow/FormFlexRow";
import InlineButton from "@/components/ui/InlineButton/InlineButton";
import useIsMobile from "@/hooks/utils/useIsMobile";
const ModuleAttributesEditor = () => {
const { module } = useModuleEditorContext();
const {
module,
attributeActions: { addAttributeToModule },
} = useModuleEditorContext();
const isMobile = useIsMobile();
const getAttributesRows = () => {
if (!module?.attributes) return [];
@ -29,10 +36,27 @@ const ModuleAttributesEditor = () => {
return rows;
};
const onAddAttributeClick = () => {
modals.openContextModal({
modal: "addAttributeModal",
title: "Добавление атрибута",
withCloseButton: true,
innerProps: {
onSubmit: addAttributeToModule,
usedAttributes: module?.attributes ?? [],
},
});
};
return (
<Flex
gap={"xs"}
gap={isMobile ? "md" : "xs"}
direction={"column"}>
{isMobile && (
<InlineButton onClick={onAddAttributeClick}>
Добавить атрибут
</InlineButton>
)}
{getAttributesRows()}
</Flex>
);

View File

@ -1,6 +1,7 @@
import { Button, Flex, Group, Textarea, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form";
import { useModuleEditorContext } from "@/app/module-editor/[moduleId]/contexts/ModuleEditorContext";
import useIsMobile from "@/hooks/utils/useIsMobile";
import { ModuleInfo } from "../../../hooks/useModulesActions";
const ModuleCommonInfoEditor = () => {
@ -8,6 +9,7 @@ const ModuleCommonInfoEditor = () => {
module,
moduleActions: { updateCommonInfo },
} = useModuleEditorContext();
const isMobile = useIsMobile();
const form = useForm<ModuleInfo>({
initialValues: module ?? {
@ -39,6 +41,7 @@ const ModuleCommonInfoEditor = () => {
<Group>
<Button
variant={"default"}
w={isMobile ? "100%" : "auto"}
disabled={!form.isDirty()}
type={"submit"}>
Сохранить

View File

@ -7,52 +7,77 @@ import ModuleAttributesEditor from "@/app/module-editor/[moduleId]/components/sh
import ModuleCommonInfoEditor from "@/app/module-editor/[moduleId]/components/shared/ModuleCommonInfoEditor/ModuleCommonInfoEditor";
import { useModuleEditorContext } from "@/app/module-editor/[moduleId]/contexts/ModuleEditorContext";
import PageBlock from "@/components/layout/PageBlock/PageBlock";
import useIsMobile from "@/hooks/utils/useIsMobile";
const PageBody = () => {
const { module } = useModuleEditorContext();
const isMobile = useIsMobile();
if (!module) return;
const renderMobile = () => (
<Flex
m={"xs"}
gap={"xs"}
flex={2}
direction={"column"}>
<Fieldset
flex={1}
legend={"Общие данные модуля"}>
{module && <ModuleCommonInfoEditor />}
</Fieldset>
<Fieldset
flex={3}
legend={"Атрибуты модуля"}>
<ModuleAttributesEditor />
</Fieldset>
</Flex>
);
const renderDesktop = () => (
<Flex
w={"100%"}
h={"100%"}
flex={3}
style={{ overflow: "auto" }}
gap={"md"}>
<Fieldset
flex={1}
legend={"Атрибуты"}>
<Flex
direction={"column"}
h={"100%"}
gap={"xs"}>
<Box style={{ flex: 1, minHeight: 0 }}>
<AttributesTable />
</Box>
<CreateAttributeButton />
</Flex>
</Fieldset>
<Flex
gap={"xs"}
flex={2}
direction={"column"}>
<Fieldset
flex={1}
legend={"Общие данные модуля"}>
{module && <ModuleCommonInfoEditor />}
</Fieldset>
<Fieldset
flex={3}
legend={"Атрибуты модуля"}>
<ModuleAttributesEditor />
</Fieldset>
</Flex>
</Flex>
);
return (
<Stack h={"100%"}>
<PageBlock
style={{ flex: 1, minHeight: 0 }}
fullScreenMobile>
<Flex
w={"100%"}
h={"100%"}
flex={3}
style={{ overflow: "auto" }}
gap={"md"}>
<Fieldset
flex={1}
legend={"Атрибуты"}>
<Flex
direction={"column"}
h={"100%"}
gap={"xs"}>
<Box style={{ flex: 1, minHeight: 0 }}>
<AttributesTable />
</Box>
<CreateAttributeButton />
</Flex>
</Fieldset>
<Flex
gap={"xs"}
flex={2}
direction={"column"}>
<Fieldset
flex={1}
legend={"Общие данные модуля"}>
{module && <ModuleCommonInfoEditor />}
</Fieldset>
<Fieldset
flex={3}
legend={"Атрибуты модуля"}>
<ModuleAttributesEditor />
</Fieldset>
</Flex>
</Flex>
{isMobile ? renderMobile() : renderDesktop()}
</PageBlock>
</Stack>
);