edit logic
This commit is contained in:
parent
8f0b8c48a9
commit
aec66cdc2c
1
src/widgets/action-card/index.ts
Normal file
1
src/widgets/action-card/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as ActionCard } from "./ui/ActionCard";
|
||||||
138
src/widgets/action-card/ui/ActionCard.tsx
Normal file
138
src/widgets/action-card/ui/ActionCard.tsx
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
import type { Chain } from "@/entities/chain/schema";
|
||||||
|
import type { Action } from "@/entities/action/schema";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import humanizeDuration from "humanize-duration";
|
||||||
|
import { ChangeWaitForButton } from "@/features/change-wait-for";
|
||||||
|
import { getActionAttachmentType } from "@/entities/action/lib";
|
||||||
|
|
||||||
|
import { IconButton } from "@mui/material";
|
||||||
|
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
|
||||||
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
|
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
|
||||||
|
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
|
||||||
|
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
||||||
|
import { Menu, MenuItem, Divider } from "@mui/material";
|
||||||
|
|
||||||
|
interface ActionCardProps {
|
||||||
|
chain: Chain;
|
||||||
|
action: Action;
|
||||||
|
actionIndex: number;
|
||||||
|
onEdit?: (actionIndex: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ActionCard({
|
||||||
|
chain,
|
||||||
|
action,
|
||||||
|
actionIndex,
|
||||||
|
onEdit,
|
||||||
|
}: ActionCardProps) {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||||
|
|
||||||
|
if (action.actionType === "comment") {
|
||||||
|
const attachmentType = getActionAttachmentType(action);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative w-[450px] select-none whitespace-pre-line rounded-md bg-white text-[#4C4E64DE] opacity-[84%] shadow-lg after:absolute after:-bottom-12 after:left-1/2 after:h-8 after:w-1 after:-translate-x-1/2 after:rounded-md after:bg-[#666CFF] after:opacity-[12%]">
|
||||||
|
<div className="absolute -right-3 top-0 translate-x-full">
|
||||||
|
<IconButton
|
||||||
|
onClick={(event) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
setIsOpen(true);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
borderRadius: "4px",
|
||||||
|
border: "1px solid #4C4E641F",
|
||||||
|
width: "32px",
|
||||||
|
height: "32px",
|
||||||
|
}}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<MoreHorizIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
className="mt-2"
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={isOpen}
|
||||||
|
onClose={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
if (onEdit) onEdit(actionIndex);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EditIcon
|
||||||
|
sx={{ color: "#4C4E64DE", opacity: "87%" }}
|
||||||
|
className="mr-2"
|
||||||
|
/>
|
||||||
|
<span className="font-normal text-[#4C4E64DE] opacity-[87%]">
|
||||||
|
Редактировать
|
||||||
|
</span>
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
<Divider sx={{ my: 0.5 }} />
|
||||||
|
|
||||||
|
<MenuItem>
|
||||||
|
<ArrowUpwardIcon
|
||||||
|
sx={{ color: "#4C4E64DE", opacity: "87%" }}
|
||||||
|
className="mr-2"
|
||||||
|
/>
|
||||||
|
<span className="font-normal text-[#4C4E64DE] opacity-[87%]">
|
||||||
|
Переместить выше
|
||||||
|
</span>
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
<MenuItem>
|
||||||
|
<ArrowDownwardIcon
|
||||||
|
sx={{ color: "#4C4E64DE", opacity: "87%" }}
|
||||||
|
className="mr-2"
|
||||||
|
/>
|
||||||
|
<span className="font-normal text-[#4C4E64DE] opacity-[87%]">
|
||||||
|
Переместить ниже
|
||||||
|
</span>
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
<Divider sx={{ my: 0.5 }} />
|
||||||
|
|
||||||
|
<MenuItem>
|
||||||
|
<DeleteOutlineIcon
|
||||||
|
sx={{ color: "#4C4E64DE", opacity: "87%" }}
|
||||||
|
className="mr-2"
|
||||||
|
/>
|
||||||
|
<span className="font-normal text-[#4C4E64DE] opacity-[87%]">
|
||||||
|
Удалить
|
||||||
|
</span>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
{attachmentType === "image" && (
|
||||||
|
<img
|
||||||
|
src={action.fileUrls[0]}
|
||||||
|
alt="Image"
|
||||||
|
draggable={false}
|
||||||
|
className={`w-full select-none ${!action.text && "rounded-b-md"} rounded-t-md`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{action.text && <div className="p-4">{action.text}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative flex select-none items-center gap-x-2 text-[#4C4E64DE] opacity-[84%] before:absolute before:-top-6 before:left-1/2 before:h-4 before:w-4 before:-translate-x-1/2 before:rounded-full before:border-[2.5px] before:border-primary after:absolute after:left-1/2 after:top-11 after:h-16 after:w-1 after:-translate-x-1/2 after:rounded-md after:bg-[#666CFF] after:opacity-[12%]">
|
||||||
|
<span>
|
||||||
|
Задержка: {humanizeDuration(action.waitFor * 1000, { language: "ru" })}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<ChangeWaitForButton
|
||||||
|
chainId={chain._id!}
|
||||||
|
actionIndex={actionIndex}
|
||||||
|
action={action}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,19 +2,17 @@ import type { Chain } from "@/entities/chain/schema";
|
||||||
import { useChainState } from "@/entities/chain/model";
|
import { useChainState } from "@/entities/chain/model";
|
||||||
import { useNavigate } from "@tanstack/react-router";
|
import { useNavigate } from "@tanstack/react-router";
|
||||||
|
|
||||||
import { getActionAttachmentType } from "@/entities/action/lib";
|
|
||||||
|
|
||||||
import { useState, useRef } from "react";
|
import { useState, useRef } from "react";
|
||||||
import humanizeDuration from "humanize-duration";
|
|
||||||
import { upsertChain } from "@/entities/chain/api/upsert";
|
import { upsertChain } from "@/entities/chain/api/upsert";
|
||||||
import { ChangeWaitForButton } from "@/features/change-wait-for";
|
|
||||||
|
|
||||||
import { ActionEditor } from "@/widgets/action-editor";
|
import { ActionEditor } from "@/widgets/action-editor";
|
||||||
|
import { ActionCard } from "@/widgets/action-card";
|
||||||
import { RenameChainButton } from "@/features/rename-chain";
|
import { RenameChainButton } from "@/features/rename-chain";
|
||||||
import { DeleteChainButton } from "@/features/delete-chain";
|
import { DeleteChainButton } from "@/features/delete-chain";
|
||||||
|
|
||||||
import { Typography, Button } from "@mui/material";
|
import { Typography, Button } from "@mui/material";
|
||||||
import Breadcrumbs from "@mui/material/Breadcrumbs";
|
import Breadcrumbs from "@mui/material/Breadcrumbs";
|
||||||
|
import { CommentAction } from "@/entities/action/schema";
|
||||||
|
|
||||||
interface ChainEditorProps {
|
interface ChainEditorProps {
|
||||||
chain: Chain;
|
chain: Chain;
|
||||||
|
|
@ -22,11 +20,16 @@ interface ChainEditorProps {
|
||||||
|
|
||||||
export default function ChainEditor({ chain }: ChainEditorProps) {
|
export default function ChainEditor({ chain }: ChainEditorProps) {
|
||||||
const actionsListRef = useRef<HTMLDivElement>(null);
|
const actionsListRef = useRef<HTMLDivElement>(null);
|
||||||
const [addingNewAction, setAddingNewAction] = useState(false);
|
const [addingNewAction, setAddingNewAction] = useState(
|
||||||
|
!chain.actions || chain.actions.length === 0,
|
||||||
|
);
|
||||||
|
|
||||||
const navigate = useNavigate({ from: "/$namespace/$chainId" });
|
const navigate = useNavigate({ from: "/$namespace/$chainId" });
|
||||||
const addCommentAction = useChainState((state) => state.addCommentAction);
|
const addCommentAction = useChainState((state) => state.addCommentAction);
|
||||||
|
const updateAction = useChainState((state) => state.updateAction);
|
||||||
|
const [actionToEdit, setActionToEdit] = useState<number | null>(null);
|
||||||
|
|
||||||
if (!chain.actions || chain.actions.length === 0 || addingNewAction)
|
if (!chain.actions || addingNewAction || actionToEdit !== null)
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|
@ -55,11 +58,21 @@ export default function ChainEditor({ chain }: ChainEditorProps) {
|
||||||
|
|
||||||
<div className="flex grow flex-col items-center justify-center">
|
<div className="flex grow flex-col items-center justify-center">
|
||||||
<ActionEditor
|
<ActionEditor
|
||||||
onSave={async (_, action) => {
|
initialAction={
|
||||||
addCommentAction(chain._id!, action);
|
actionToEdit !== null
|
||||||
await upsertChain(chain);
|
? (chain.actions?.[actionToEdit] as CommentAction)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onSave={async (actionIndex, action) => {
|
||||||
|
if (addingNewAction) {
|
||||||
|
addCommentAction(chain._id!, action);
|
||||||
|
setAddingNewAction(false);
|
||||||
|
} else if (actionToEdit !== null) {
|
||||||
|
updateAction(chain._id!, actionIndex, action);
|
||||||
|
setActionToEdit(null);
|
||||||
|
}
|
||||||
|
|
||||||
if (addingNewAction) setAddingNewAction(false);
|
await upsertChain(chain);
|
||||||
navigate({ to: "/$namespace/$chainId" });
|
navigate({ to: "/$namespace/$chainId" });
|
||||||
|
|
||||||
setTimeout(
|
setTimeout(
|
||||||
|
|
@ -73,8 +86,9 @@ export default function ChainEditor({ chain }: ChainEditorProps) {
|
||||||
}}
|
}}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
if (addingNewAction) setAddingNewAction(false);
|
if (addingNewAction) setAddingNewAction(false);
|
||||||
|
if (actionToEdit !== null) setActionToEdit(null);
|
||||||
}}
|
}}
|
||||||
canExit={addingNewAction}
|
canExit={chain.actions?.length !== 0}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -100,46 +114,15 @@ export default function ChainEditor({ chain }: ChainEditorProps) {
|
||||||
ref={actionsListRef}
|
ref={actionsListRef}
|
||||||
className="no-scrollbar flex grow flex-col items-center gap-y-24 overflow-y-scroll pb-20 pt-8"
|
className="no-scrollbar flex grow flex-col items-center gap-y-24 overflow-y-scroll pb-20 pt-8"
|
||||||
>
|
>
|
||||||
{chain.actions.map((action, index) => {
|
{chain.actions.map((action, index) => (
|
||||||
if (action.actionType === "comment") {
|
<ActionCard
|
||||||
const attachmentType = getActionAttachmentType(action);
|
key={index}
|
||||||
|
chain={chain}
|
||||||
return (
|
action={action}
|
||||||
<div
|
actionIndex={index}
|
||||||
key={index}
|
onEdit={setActionToEdit}
|
||||||
className="relative w-[450px] select-none whitespace-pre-line rounded-md bg-white text-[#4C4E64DE] opacity-[84%] shadow-lg after:absolute after:-bottom-12 after:left-1/2 after:h-8 after:w-1 after:-translate-x-1/2 after:rounded-md after:bg-[#666CFF] after:opacity-[12%]"
|
/>
|
||||||
>
|
))}
|
||||||
{attachmentType === "image" && (
|
|
||||||
<img
|
|
||||||
src={action.fileUrls[0]}
|
|
||||||
alt="Image"
|
|
||||||
draggable={false}
|
|
||||||
className={`w-full select-none ${!action.text && "rounded-b-md"} rounded-t-md`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{action.text && <div className="p-4">{action.text}</div>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className="relative flex select-none items-center gap-x-2 text-[#4C4E64DE] opacity-[84%] before:absolute before:-top-6 before:left-1/2 before:h-4 before:w-4 before:-translate-x-1/2 before:rounded-full before:border-[2.5px] before:border-primary after:absolute after:left-1/2 after:top-11 after:h-16 after:w-1 after:-translate-x-1/2 after:rounded-md after:bg-[#666CFF] after:opacity-[12%]"
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
Задержка:{" "}
|
|
||||||
{humanizeDuration(action.waitFor * 1000, { language: "ru" })}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<ChangeWaitForButton
|
|
||||||
chainId={chain._id!}
|
|
||||||
actionIndex={index}
|
|
||||||
action={action}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
<div className="-mt-4">
|
<div className="-mt-4">
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user