Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: edit group reply #426

Merged
merged 15 commits into from
Mar 24, 2023
12 changes: 7 additions & 5 deletions packages/design/components/Topic/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,16 +184,18 @@ const Comment: FC<CommentProps> = ({
<Button type='secondary' size='small'>
+1
</Button>
{user.id === creator.id ? (
{user.id === creator.id && (
<>
<Button type='text' size='small'>
编辑
</Button>
{!replies?.length && (
<Button.Link type='text' size='small' to={`/group/reply/${props.id}/edit`}>
编辑
</Button.Link>
)}
<Button type='text' size='small' onClick={handleDeleteReply}>
删除
</Button>
</>
) : null}
)}
</>
)}
</div>
Expand Down
12 changes: 12 additions & 0 deletions packages/design/components/Topic/__test__/Comment.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ describe('Normal Comment', () => {
expect(getByText('删除')).toBeInTheDocument();
});

it('hide edit button if there are subreplies', () => {
const user = { ...mockedCurrentUser, id: 1 };
const props = buildProps(false, repliesComment, '233', 233, user);
const { container } = render(<Comment {...props} />);
// 选取主评论的操作区域
const actions = container.querySelector(
'.bgm-comment__box > .bgm-comment__opinions',
)?.textContent;
y-young marked this conversation as resolved.
Show resolved Hide resolved
expect(actions?.includes('编辑')).toBeFalsy();
expect(actions?.includes('删除')).toBeTruthy();
});

it('do not show opinions if not login', () => {
const props = buildProps(false, singleComment, '233', 233, null as any);
const { container } = render(<Comment {...props} />);
Expand Down
19 changes: 19 additions & 0 deletions packages/website/src/hooks/use-group-post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ok } from 'oazapfts';
import type { KeyedMutator } from 'swr';
import useSWR from 'swr';

import { ozaClient } from '@bangumi/client';

export interface UseGroupPostRet {
data: ozaClient.GroupReply;
mutate: KeyedMutator<ozaClient.GroupReply>;
}

function useGroupPost(id: number): UseGroupPostRet {
const { data, mutate } = useSWR(`/group/post/${id}`, async () => ok(ozaClient.getGroupPost(id)), {
suspense: true,
});
return { data, mutate };
}

export default useGroupPost;
12 changes: 12 additions & 0 deletions packages/website/src/pages/index/group/reply/[id].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { Outlet } from 'react-router-dom';

import ErrorBoundary from '@bangumi/website/components/ErrorBoundary';

const GroupReplyPage = () => (
<ErrorBoundary fallback={{ 404: <>数据库中没有查询到指定话题,话题可能正在审核或已被删除。</> }}>
<Outlet />
</ErrorBoundary>
);

export default GroupReplyPage;
14 changes: 14 additions & 0 deletions packages/website/src/pages/index/group/reply/[id]/edit.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.form {
display: flex;
flex-direction: column;
gap: 1rem;
}

.tipText {
display: block;
margin-bottom: 10px;
}

.topicLink {
padding: 0 10px;
}
96 changes: 96 additions & 0 deletions packages/website/src/pages/index/group/reply/[id]/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import type { TopicDetail } from 'packages/client/client';
import React, { useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useSWRConfig } from 'swr';

import { ozaClient } from '@bangumi/client';
import { EditorForm, toast, Typography } from '@bangumi/design';
import useGroupPost from '@bangumi/website/hooks/use-group-post';
import { useUser } from '@bangumi/website/hooks/use-user';

import styles from './edit.module.less';

const EditReplyPage = () => {
const { id } = useParams();
if (!id || Number.isNaN(Number(id))) {
y-young marked this conversation as resolved.
Show resolved Hide resolved
throw new Error('BUG: post id is required');
}
const postId = parseInt(id);

const { user } = useUser();
if (!user) {
throw new Error('抱歉,当前操作需要登录后才能继续进行');
}

const { data, mutate } = useGroupPost(postId);
if (data.creator.id !== user.id) {
throw new Error('抱歉,你只能修改自己发表的帖子。');
}

const { mutate: mutateTopic } = useSWRConfig();
const navigate = useNavigate();

const [sending, setSending] = useState(false);
const [content, setContent] = useState(data.text);

const handleSubmit = async (text: string) => {
if (!text) {
toast('请填写回复内容');
return;
}
setSending(true);
const response = await ozaClient.editGroupPost(postId, { text });
if (response.status === 200) {
const topicPath = `/group/topic/${data.topicID}`;
// 确保再次回到此页面时内容是最新的,不需要向后端请求数据,因此将 revalidate 设置为 false
mutate({ ...data, text }, { revalidate: false });
// 乐观更新回复内容
await mutateTopic(topicPath, (topic?: TopicDetail) => {
if (!topic) {
return topic;
}
const reply = topic.replies.find((reply) => reply.id === postId);
if (reply) {
reply.text = text;
}
return topic;
});
navigate(topicPath);
} else {
console.error(response);
toast(response.data.message);
}
setSending(false);
};

return (
<>
<Typography.Text type='secondary' className={styles.tipText}>
修改主题
<Typography.Link
to={`/group/topic/${data.topicID}`}
fontWeight='bold'
className={styles.topicLink}
>
{data.topicTitle}
</Typography.Link>
的回复
</Typography.Text>
<div className={styles.form}>
<EditorForm
placeholder='回复内容…'
hideCancel
value={content}
onChange={setContent}
onConfirm={handleSubmit}
// TODO: use loading state
confirmText={sending ? '...' : undefined}
rows={15}
/>
</div>
{/* TODO: add right column */}
</>
);
};

export default EditReplyPage;