Skip to content

Commit 976cd97

Browse files
committed
fix
1 parent 8fcb60d commit 976cd97

File tree

4 files changed

+207
-200
lines changed

4 files changed

+207
-200
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { DeleteThreadDialog } from "@/entities/thread/DeleteThreadDialog";
2+
import { IconButton } from "@/shared/components/IconButton";
3+
import { Tooltip } from "@/shared/components/Tooltip";
4+
import { urls } from "@/shared/consts/urls";
5+
import {
6+
DropdownMenu,
7+
DropdownMenuContent,
8+
DropdownMenuSeparator,
9+
DropdownMenuTrigger,
10+
} from "@/shared/ui/dropdown-menu";
11+
import { DropdownMenuItemWithIcon } from "@/shared/ui/dropdown-menu-item-with-icon";
12+
import { trpc } from "@/trpc/client";
13+
import { MoreHorizOutlined } from "@mui/icons-material";
14+
import { ThreadStatus } from "@prisma/client";
15+
import { Archive, ListCheck, Pencil, Trash2 } from "lucide-react";
16+
import { useRouter } from "next/navigation";
17+
import { useState } from "react";
18+
import { toast } from "sonner";
19+
20+
type Props = {
21+
threadId: string;
22+
threadTitle: string | null;
23+
includeIsArchived: boolean;
24+
onClickToggleDisplayArchiveButton: () => void;
25+
status: ThreadStatus;
26+
};
27+
28+
export function ManageThreadDropDown({
29+
threadId,
30+
threadTitle,
31+
includeIsArchived,
32+
onClickToggleDisplayArchiveButton,
33+
status,
34+
}: Props) {
35+
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
36+
const router = useRouter();
37+
const utils = trpc.useUtils();
38+
39+
const { mutate: updateStatus, isPending } =
40+
trpc.thread.updateThreadStatus.useMutation({
41+
onSuccess: () => {
42+
toast.success("ステータスを更新しました");
43+
utils.thread.getThreadInfo.invalidate({ id: threadId });
44+
utils.thread.listThreadsByCurrentUser.invalidate();
45+
},
46+
onError: (error) => {
47+
toast.error(`ステータスの更新に失敗しました: ${error.message}`);
48+
},
49+
});
50+
51+
const handleDeleteSuccess = () => {
52+
router.push(urls.dashboard);
53+
};
54+
55+
const handleStatusChange = (newStatus: ThreadStatus) => {
56+
if (newStatus !== status) {
57+
updateStatus({ id: threadId, status: newStatus });
58+
}
59+
};
60+
61+
return (
62+
<>
63+
<DropdownMenu>
64+
<DropdownMenuTrigger>
65+
<Tooltip content="スレッドを操作">
66+
<IconButton size="small">
67+
<MoreHorizOutlined />
68+
</IconButton>
69+
</Tooltip>
70+
</DropdownMenuTrigger>
71+
<DropdownMenuContent align="end">
72+
<DropdownMenuItemWithIcon
73+
icon={Archive}
74+
text={includeIsArchived ? "アーカイブの非表示" : "アーカイブの表示"}
75+
onClick={onClickToggleDisplayArchiveButton}
76+
/>
77+
<DropdownMenuSeparator />
78+
{status !== "WIP" && (
79+
<DropdownMenuItemWithIcon
80+
icon={Pencil}
81+
text="WIPに変更する"
82+
onClick={() => handleStatusChange("WIP")}
83+
disabled={isPending}
84+
/>
85+
)}
86+
{status !== "CLOSED" && (
87+
<DropdownMenuItemWithIcon
88+
icon={ListCheck}
89+
text="Closedに変更する"
90+
onClick={() => handleStatusChange("CLOSED")}
91+
disabled={isPending}
92+
/>
93+
)}
94+
<DropdownMenuSeparator />
95+
<DropdownMenuItemWithIcon
96+
icon={Trash2}
97+
text="スレッドの削除"
98+
variant="destructive"
99+
onClick={() => setIsDeleteDialogOpen(true)}
100+
/>
101+
</DropdownMenuContent>
102+
</DropdownMenu>
103+
104+
<DeleteThreadDialog
105+
threadId={threadId}
106+
threadTitle={threadTitle}
107+
isOpen={isDeleteDialogOpen}
108+
onOpenChange={setIsDeleteDialogOpen}
109+
onSuccess={handleDeleteSuccess}
110+
/>
111+
</>
112+
);
113+
}
Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1 @@
1-
import { DeleteThreadDialog } from "@/entities/thread/DeleteThreadDialog";
2-
import { IconButton } from "@/shared/components/IconButton";
3-
import { Tooltip } from "@/shared/components/Tooltip";
4-
import { urls } from "@/shared/consts/urls";
5-
import {
6-
DropdownMenu,
7-
DropdownMenuContent,
8-
DropdownMenuSeparator,
9-
DropdownMenuTrigger,
10-
} from "@/shared/ui/dropdown-menu";
11-
import { DropdownMenuItemWithIcon } from "@/shared/ui/dropdown-menu-item-with-icon";
12-
import { trpc } from "@/trpc/client";
13-
import { MoreHorizOutlined } from "@mui/icons-material";
14-
import { ThreadStatus } from "@prisma/client";
15-
import { Archive, ListCheck, Pencil, Trash2 } from "lucide-react";
16-
import { useRouter } from "next/navigation";
17-
import { useState } from "react";
18-
import { toast } from "sonner";
19-
20-
type Props = {
21-
threadId: string;
22-
threadTitle: string | null;
23-
includeIsArchived: boolean;
24-
onClickToggleDisplayArchiveButton: () => void;
25-
status: ThreadStatus;
26-
};
27-
28-
export function ManageThreadDropDown({
29-
threadId,
30-
threadTitle,
31-
includeIsArchived,
32-
onClickToggleDisplayArchiveButton,
33-
status,
34-
}: Props) {
35-
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
36-
const router = useRouter();
37-
const utils = trpc.useUtils();
38-
39-
const { mutate: updateStatus, isPending } =
40-
trpc.thread.updateThreadStatus.useMutation({
41-
onSuccess: () => {
42-
toast.success("ステータスを更新しました");
43-
utils.thread.getThreadInfo.invalidate({ id: threadId });
44-
utils.thread.listThreadsByCurrentUser.invalidate();
45-
},
46-
onError: (error) => {
47-
toast.error(`ステータスの更新に失敗しました: ${error.message}`);
48-
},
49-
});
50-
51-
const handleDeleteSuccess = () => {
52-
router.push(urls.dashboard);
53-
};
54-
55-
const handleStatusChange = (newStatus: ThreadStatus) => {
56-
if (newStatus !== status) {
57-
updateStatus({ id: threadId, status: newStatus });
58-
}
59-
};
60-
61-
return (
62-
<>
63-
<DropdownMenu>
64-
<DropdownMenuTrigger>
65-
<Tooltip content="スレッドを操作">
66-
<IconButton size="small">
67-
<MoreHorizOutlined />
68-
</IconButton>
69-
</Tooltip>
70-
</DropdownMenuTrigger>
71-
<DropdownMenuContent align="end">
72-
<DropdownMenuItemWithIcon
73-
icon={Archive}
74-
text={includeIsArchived ? "アーカイブの非表示" : "アーカイブの表示"}
75-
onClick={onClickToggleDisplayArchiveButton}
76-
/>
77-
<DropdownMenuSeparator />
78-
{status !== "WIP" && (
79-
<DropdownMenuItemWithIcon
80-
icon={Pencil}
81-
text="WIPに変更する"
82-
onClick={() => handleStatusChange("WIP")}
83-
disabled={isPending}
84-
/>
85-
)}
86-
{status !== "CLOSED" && (
87-
<DropdownMenuItemWithIcon
88-
icon={ListCheck}
89-
text="Closedに変更する"
90-
onClick={() => handleStatusChange("CLOSED")}
91-
disabled={isPending}
92-
/>
93-
)}
94-
<DropdownMenuSeparator />
95-
<DropdownMenuItemWithIcon
96-
icon={Trash2}
97-
text="スレッドの削除"
98-
variant="destructive"
99-
onClick={() => setIsDeleteDialogOpen(true)}
100-
/>
101-
</DropdownMenuContent>
102-
</DropdownMenu>
103-
104-
<DeleteThreadDialog
105-
threadId={threadId}
106-
threadTitle={threadTitle}
107-
isOpen={isDeleteDialogOpen}
108-
onOpenChange={setIsDeleteDialogOpen}
109-
onSuccess={handleDeleteSuccess}
110-
/>
111-
</>
112-
);
113-
}
1+
export { ManageThreadDropDown } from "./ManageThreadDropDown";
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"use client";
2+
3+
import { PublicStatusSheet } from "@/features/threadDetail/PublicStatusSheet";
4+
import { ThreadStatusBadge } from "@/features/threadDetail/ThreadStatusBadge";
5+
import { ThreadTitleEditModal } from "@/features/threadDetail/ThreadTitleEditModal";
6+
import { Box } from "@/shared/components/Box";
7+
import { Stack } from "@/shared/components/Stack";
8+
import { Tooltip } from "@/shared/components/Tooltip";
9+
import { Typography } from "@/shared/components/Typography";
10+
import { trpc } from "@/trpc/client";
11+
import { useState } from "react";
12+
import { ManageThreadDropDown } from "./ManageThreadDropDown";
13+
14+
export function ThreadInformation({
15+
threadId,
16+
includeIsArchived,
17+
toggleIncludeIsArchived,
18+
}: {
19+
threadId: string;
20+
includeIsArchived: boolean;
21+
toggleIncludeIsArchived: () => void;
22+
}) {
23+
const [threadInfo] = trpc.thread.getThreadInfo.useSuspenseQuery({
24+
id: threadId,
25+
});
26+
const [isModalOpen, setIsModalOpen] = useState(false);
27+
28+
if (!threadInfo) {
29+
return (
30+
<Stack rowGap="16px">
31+
<p>ポストが存在しません</p>
32+
</Stack>
33+
);
34+
}
35+
36+
return (
37+
<>
38+
<Stack rowGap="8px">
39+
<Box
40+
display="flex"
41+
alignItems="center"
42+
justifyContent="space-between"
43+
gap="8px"
44+
>
45+
<Tooltip content="タイトルを編集">
46+
<Box
47+
onClick={() => setIsModalOpen(true)}
48+
sx={{
49+
cursor: "pointer",
50+
p: "4px",
51+
"&:hover": {
52+
background: (theme) => theme.palette.action.hover,
53+
borderRadius: "4px",
54+
},
55+
}}
56+
>
57+
<Typography variant="body1" bold>
58+
{threadInfo.title || "タイトルなし"}
59+
</Typography>
60+
</Box>
61+
</Tooltip>
62+
63+
<Box display="flex" alignItems="center" gap="8px">
64+
<PublicStatusSheet
65+
threadTitle={threadInfo.title}
66+
threadId={threadId}
67+
isPublic={threadInfo.isPublic}
68+
ogpTitle={threadInfo.ogpTitle}
69+
ogpDescription={threadInfo.ogpDescription}
70+
ogpImagePath={threadInfo.ogpImagePath}
71+
/>
72+
<ThreadStatusBadge status={threadInfo.status || "WIP"} />
73+
<ManageThreadDropDown
74+
threadId={threadId}
75+
threadTitle={threadInfo.title}
76+
includeIsArchived={includeIsArchived}
77+
onClickToggleDisplayArchiveButton={toggleIncludeIsArchived}
78+
status={threadInfo.status || "WIP"}
79+
/>
80+
</Box>
81+
</Box>
82+
</Stack>
83+
84+
<ThreadTitleEditModal
85+
open={isModalOpen}
86+
onClose={() => setIsModalOpen(false)}
87+
threadId={threadId}
88+
currentTitle={threadInfo.title || ""}
89+
/>
90+
</>
91+
);
92+
}

0 commit comments

Comments
 (0)