feat: boards and statuses editing and creating for mobiles

This commit is contained in:
2025-08-08 15:01:10 +04:00
parent f52fde0097
commit afad1b4605
12 changed files with 109 additions and 23 deletions

View File

@ -30,6 +30,7 @@
"libphonenumber-js": "^1.12.10",
"next": "15.3.3",
"react": "19.1.0",
"react-device-detect": "^2.2.3",
"react-dom": "19.1.0",
"react-imask": "^7.6.1",
"react-redux": "^9.2.0",

View File

@ -44,6 +44,7 @@ const Board: FC<Props> = ({ board }) => {
/>
</>
)}
modalTitle={"Редактирование доски"}
/>
</Group>
);

View File

@ -1,5 +1,6 @@
import React, { FC } from "react";
import { IconDotsVertical, IconEdit, IconTrash } from "@tabler/icons-react";
import { isMobile } from "react-device-detect";
import { Box, Group, Menu, Text } from "@mantine/core";
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
import { BoardSchema } from "@/lib/client";
@ -19,7 +20,11 @@ const BoardMenu: FC<Props> = ({ isHovered, board, startEditing }) => {
<Box
style={{
opacity:
isHovered || selectedBoard?.id === board.id ? 1 : 0,
isMobile ||
isHovered ||
selectedBoard?.id === board.id
? 1
: 0,
cursor: "pointer",
}}
onClick={e => {

View File

@ -16,6 +16,7 @@ const CreateBoardButton = () => {
<IconPlus />
</Box>
)}
modalTitle={"Создание доски"}
/>
</Box>
);

View File

@ -26,6 +26,7 @@ const CreateStatusButton = () => {
<Text>Создать колонку</Text>
</Box>
)}
modalTitle={"Создание колонки"}
/>
</Box>
);

View File

@ -28,7 +28,10 @@ const Funnel: FC = () => {
<ScrollArea
offsetScrollbars={"x"}
scrollbarSize={"0.5rem"}>
<Group align={"start"}>
<Group
align={"start"}
wrap={"nowrap"}
gap={"sm"}>
<FunnelDnd
containers={sortedStatuses}
items={deals}

View File

@ -64,6 +64,7 @@ const StatusColumnWrapper = ({
/>
</>
)}
modalTitle={"Редактирование статуса"}
/>
</Group>
{children}

View File

@ -1,6 +1,8 @@
import React, { FC, ReactNode, useEffect, useRef, useState } from "react";
import { TextInput } from "@mantine/core";
import { Styles } from "@mantine/core/lib/core/styles-api/styles-api.types";
import { isMobile } from "react-device-detect";
import { modals } from "@mantine/modals";
type Props = {
defaultValue?: string;
@ -8,6 +10,7 @@ type Props = {
placeholder?: string;
getChildren: (startEditing: () => void) => ReactNode;
inputStyles?: Styles<any>;
modalTitle?: string;
};
const InPlaceInput: FC<Props> = ({
@ -15,11 +18,11 @@ const InPlaceInput: FC<Props> = ({
placeholder,
inputStyles,
getChildren,
modalTitle = "",
defaultValue = "",
}) => {
const [isWriting, setIsWriting] = useState<boolean>(false);
const [value, setValue] = useState<string>(defaultValue);
console.log(value);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
@ -45,8 +48,21 @@ const InPlaceInput: FC<Props> = ({
}, [isWriting, value]);
const onStartCreating = () => {
setValue(defaultValue);
setIsWriting(true);
if (!isMobile) {
setValue(defaultValue);
setIsWriting(true);
return;
}
modals.openContextModal({
modal: "enterNameModal",
title: modalTitle,
withCloseButton: true,
innerProps: {
onComplete,
defaultValue,
},
});
};
const onCancelCreating = () => {

View File

@ -0,0 +1,51 @@
"use client";
import { Button, Flex, rem, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form";
import { ContextModalProps } from "@mantine/modals";
type Props = {
onComplete: (value: string) => void;
defaultValue?: string;
};
type FormType = {
name?: string;
};
const EnterNameModal = ({
id,
context,
innerProps,
}: ContextModalProps<Props>) => {
const form = useForm<FormType>({
initialValues: {
name: innerProps.defaultValue,
},
validate: {
name: name => !name && "Введите название",
},
});
const onSubmit = (values: FormType) => {
innerProps.onComplete(values.name!);
context.closeModal(id);
};
return (
<form onSubmit={form.onSubmit(values => onSubmit(values))}>
<Flex
gap={rem(10)}
direction={"column"}>
<TextInput {...form.getInputProps("name")} />
<Button
variant={"default"}
type={"submit"}>
Сохранить
</Button>
</Flex>
</form>
);
};
export default EnterNameModal;

View File

@ -1,16 +0,0 @@
"use client"
import { Flex, rem, Text } from "@mantine/core";
import { ContextModalProps } from "@mantine/modals";
const TestModal = ({ id, context, innerProps }: ContextModalProps) => {
return (
<Flex
gap={rem(10)}
direction={"column"}>
<Text>Hi</Text>
</Flex>
);
};
export default TestModal;

View File

@ -1,5 +1,5 @@
import TestModal from "@/modals/TestModal/TestModal";
import EnterNameModal from "@/modals/EnterNameModal/EnterNameModal";
export const modals = {
testModal: TestModal,
enterNameModal: EnterNameModal,
};

View File

@ -6103,6 +6103,7 @@ __metadata:
postcss-simple-vars: "npm:^7.0.1"
prettier: "npm:^3.5.3"
react: "npm:19.1.0"
react-device-detect: "npm:^2.2.3"
react-dom: "npm:19.1.0"
react-imask: "npm:^7.6.1"
react-redux: "npm:^9.2.0"
@ -11543,6 +11544,18 @@ __metadata:
languageName: node
linkType: hard
"react-device-detect@npm:^2.2.3":
version: 2.2.3
resolution: "react-device-detect@npm:2.2.3"
dependencies:
ua-parser-js: "npm:^1.0.33"
peerDependencies:
react: ">= 0.14.0"
react-dom: ">= 0.14.0"
checksum: 10c0/396bbeeab0cb21da084c67434d204c9cf502fad6c683903313084d3f6487950a36a34f9bf67ccf5c1772a1bb5b79a2a4403fcfe6b51d93877db4c2d9f3a3a925
languageName: node
linkType: hard
"react-docgen-typescript@npm:^2.2.2":
version: 2.4.0
resolution: "react-docgen-typescript@npm:2.4.0"
@ -13653,6 +13666,15 @@ __metadata:
languageName: node
linkType: hard
"ua-parser-js@npm:^1.0.33":
version: 1.0.40
resolution: "ua-parser-js@npm:1.0.40"
bin:
ua-parser-js: script/cli.js
checksum: 10c0/2b6ac642c74323957dae142c31f72287f2420c12dced9603d989b96c132b80232779c429b296d7de4012ef8b64e0d8fadc53c639ef06633ce13d785a78b5be6c
languageName: node
linkType: hard
"ufo@npm:^1.5.4":
version: 1.6.1
resolution: "ufo@npm:1.6.1"