feat: boards and statuses editing and creating for mobiles
This commit is contained in:
@ -30,6 +30,7 @@
|
|||||||
"libphonenumber-js": "^1.12.10",
|
"libphonenumber-js": "^1.12.10",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
|
"react-device-detect": "^2.2.3",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-imask": "^7.6.1",
|
"react-imask": "^7.6.1",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
|
|||||||
@ -44,6 +44,7 @@ const Board: FC<Props> = ({ board }) => {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
modalTitle={"Редактирование доски"}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { IconDotsVertical, IconEdit, IconTrash } from "@tabler/icons-react";
|
import { IconDotsVertical, IconEdit, IconTrash } from "@tabler/icons-react";
|
||||||
|
import { isMobile } from "react-device-detect";
|
||||||
import { Box, Group, Menu, Text } from "@mantine/core";
|
import { Box, Group, Menu, Text } from "@mantine/core";
|
||||||
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
|
||||||
import { BoardSchema } from "@/lib/client";
|
import { BoardSchema } from "@/lib/client";
|
||||||
@ -19,7 +20,11 @@ const BoardMenu: FC<Props> = ({ isHovered, board, startEditing }) => {
|
|||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
opacity:
|
opacity:
|
||||||
isHovered || selectedBoard?.id === board.id ? 1 : 0,
|
isMobile ||
|
||||||
|
isHovered ||
|
||||||
|
selectedBoard?.id === board.id
|
||||||
|
? 1
|
||||||
|
: 0,
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ const CreateBoardButton = () => {
|
|||||||
<IconPlus />
|
<IconPlus />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
modalTitle={"Создание доски"}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ const CreateStatusButton = () => {
|
|||||||
<Text>Создать колонку</Text>
|
<Text>Создать колонку</Text>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
modalTitle={"Создание колонки"}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -28,7 +28,10 @@ const Funnel: FC = () => {
|
|||||||
<ScrollArea
|
<ScrollArea
|
||||||
offsetScrollbars={"x"}
|
offsetScrollbars={"x"}
|
||||||
scrollbarSize={"0.5rem"}>
|
scrollbarSize={"0.5rem"}>
|
||||||
<Group align={"start"}>
|
<Group
|
||||||
|
align={"start"}
|
||||||
|
wrap={"nowrap"}
|
||||||
|
gap={"sm"}>
|
||||||
<FunnelDnd
|
<FunnelDnd
|
||||||
containers={sortedStatuses}
|
containers={sortedStatuses}
|
||||||
items={deals}
|
items={deals}
|
||||||
|
|||||||
@ -64,6 +64,7 @@ const StatusColumnWrapper = ({
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
modalTitle={"Редактирование статуса"}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import React, { FC, ReactNode, useEffect, useRef, useState } from "react";
|
import React, { FC, ReactNode, useEffect, useRef, useState } from "react";
|
||||||
import { TextInput } from "@mantine/core";
|
import { TextInput } from "@mantine/core";
|
||||||
import { Styles } from "@mantine/core/lib/core/styles-api/styles-api.types";
|
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 = {
|
type Props = {
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
@ -8,6 +10,7 @@ type Props = {
|
|||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
getChildren: (startEditing: () => void) => ReactNode;
|
getChildren: (startEditing: () => void) => ReactNode;
|
||||||
inputStyles?: Styles<any>;
|
inputStyles?: Styles<any>;
|
||||||
|
modalTitle?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const InPlaceInput: FC<Props> = ({
|
const InPlaceInput: FC<Props> = ({
|
||||||
@ -15,11 +18,11 @@ const InPlaceInput: FC<Props> = ({
|
|||||||
placeholder,
|
placeholder,
|
||||||
inputStyles,
|
inputStyles,
|
||||||
getChildren,
|
getChildren,
|
||||||
|
modalTitle = "",
|
||||||
defaultValue = "",
|
defaultValue = "",
|
||||||
}) => {
|
}) => {
|
||||||
const [isWriting, setIsWriting] = useState<boolean>(false);
|
const [isWriting, setIsWriting] = useState<boolean>(false);
|
||||||
const [value, setValue] = useState<string>(defaultValue);
|
const [value, setValue] = useState<string>(defaultValue);
|
||||||
console.log(value);
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -45,8 +48,21 @@ const InPlaceInput: FC<Props> = ({
|
|||||||
}, [isWriting, value]);
|
}, [isWriting, value]);
|
||||||
|
|
||||||
const onStartCreating = () => {
|
const onStartCreating = () => {
|
||||||
setValue(defaultValue);
|
if (!isMobile) {
|
||||||
setIsWriting(true);
|
setValue(defaultValue);
|
||||||
|
setIsWriting(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modals.openContextModal({
|
||||||
|
modal: "enterNameModal",
|
||||||
|
title: modalTitle,
|
||||||
|
withCloseButton: true,
|
||||||
|
innerProps: {
|
||||||
|
onComplete,
|
||||||
|
defaultValue,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCancelCreating = () => {
|
const onCancelCreating = () => {
|
||||||
|
|||||||
51
src/modals/EnterNameModal/EnterNameModal.tsx
Normal file
51
src/modals/EnterNameModal/EnterNameModal.tsx
Normal 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;
|
||||||
@ -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;
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import TestModal from "@/modals/TestModal/TestModal";
|
import EnterNameModal from "@/modals/EnterNameModal/EnterNameModal";
|
||||||
|
|
||||||
export const modals = {
|
export const modals = {
|
||||||
testModal: TestModal,
|
enterNameModal: EnterNameModal,
|
||||||
};
|
};
|
||||||
|
|||||||
22
yarn.lock
22
yarn.lock
@ -6103,6 +6103,7 @@ __metadata:
|
|||||||
postcss-simple-vars: "npm:^7.0.1"
|
postcss-simple-vars: "npm:^7.0.1"
|
||||||
prettier: "npm:^3.5.3"
|
prettier: "npm:^3.5.3"
|
||||||
react: "npm:19.1.0"
|
react: "npm:19.1.0"
|
||||||
|
react-device-detect: "npm:^2.2.3"
|
||||||
react-dom: "npm:19.1.0"
|
react-dom: "npm:19.1.0"
|
||||||
react-imask: "npm:^7.6.1"
|
react-imask: "npm:^7.6.1"
|
||||||
react-redux: "npm:^9.2.0"
|
react-redux: "npm:^9.2.0"
|
||||||
@ -11543,6 +11544,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"react-docgen-typescript@npm:^2.2.2":
|
||||||
version: 2.4.0
|
version: 2.4.0
|
||||||
resolution: "react-docgen-typescript@npm:2.4.0"
|
resolution: "react-docgen-typescript@npm:2.4.0"
|
||||||
@ -13653,6 +13666,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"ufo@npm:^1.5.4":
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
resolution: "ufo@npm:1.6.1"
|
resolution: "ufo@npm:1.6.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user