mirror of https://github.com/fantasticit/think.git
client: add comment in share
This commit is contained in:
parent
778217022a
commit
a7fb655f4c
|
@ -3,11 +3,10 @@ import { DataRender } from 'components/data-render';
|
||||||
import { useComments } from 'data/comment';
|
import { useComments } from 'data/comment';
|
||||||
import { useUser } from 'data/user';
|
import { useUser } from 'data/user';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import { CommentKit, CommentMenuBar, EditorContent, useEditor } from 'tiptap/editor';
|
import { CommentKit, CommentMenuBar, EditorContent, useEditor } from 'tiptap/editor';
|
||||||
|
|
||||||
import { Comments } from './comments';
|
import { Comments } from './comments';
|
||||||
import { CommentItemPlaceholder } from './comments/Item';
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
@ -17,7 +16,7 @@ interface IProps {
|
||||||
const { Text, Paragraph } = Typography;
|
const { Text, Paragraph } = Typography;
|
||||||
|
|
||||||
export const CommentEditor: React.FC<IProps> = ({ documentId }) => {
|
export const CommentEditor: React.FC<IProps> = ({ documentId }) => {
|
||||||
const { user } = useUser();
|
const { user, logout } = useUser();
|
||||||
const {
|
const {
|
||||||
data: commentsData,
|
data: commentsData,
|
||||||
loading,
|
loading,
|
||||||
|
@ -37,18 +36,21 @@ export const CommentEditor: React.FC<IProps> = ({ documentId }) => {
|
||||||
extensions: CommentKit,
|
extensions: CommentKit,
|
||||||
});
|
});
|
||||||
|
|
||||||
const openEditor = () => {
|
const openEditor = useCallback(() => {
|
||||||
|
if (!user) {
|
||||||
|
return logout();
|
||||||
|
}
|
||||||
toggleIsEdit(true);
|
toggleIsEdit(true);
|
||||||
editor.chain().focus();
|
editor.chain().focus();
|
||||||
};
|
}, [editor, logout, toggleIsEdit, user]);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = useCallback(() => {
|
||||||
setReplyComment(null);
|
setReplyComment(null);
|
||||||
setEditComment(null);
|
setEditComment(null);
|
||||||
toggleIsEdit(false);
|
toggleIsEdit(false);
|
||||||
};
|
}, [toggleIsEdit]);
|
||||||
|
|
||||||
const save = () => {
|
const save = useCallback(() => {
|
||||||
const html = editor.getHTML();
|
const html = editor.getHTML();
|
||||||
|
|
||||||
if (editComment) {
|
if (editComment) {
|
||||||
|
@ -71,19 +73,25 @@ export const CommentEditor: React.FC<IProps> = ({ documentId }) => {
|
||||||
editor.commands.clearContent();
|
editor.commands.clearContent();
|
||||||
handleClose();
|
handleClose();
|
||||||
});
|
});
|
||||||
};
|
}, [addComment, editComment, editor, handleClose, replyComment, updateComment]);
|
||||||
|
|
||||||
const handleReplyComment = (comment) => {
|
const handleReplyComment = useCallback(
|
||||||
setReplyComment(comment);
|
(comment) => {
|
||||||
setEditComment(null);
|
setReplyComment(comment);
|
||||||
openEditor();
|
setEditComment(null);
|
||||||
};
|
openEditor();
|
||||||
|
},
|
||||||
|
[openEditor]
|
||||||
|
);
|
||||||
|
|
||||||
const handleEditComment = (comment) => {
|
const handleEditComment = useCallback(
|
||||||
setReplyComment(null);
|
(comment) => {
|
||||||
setEditComment(comment);
|
setReplyComment(null);
|
||||||
openEditor();
|
setEditComment(comment);
|
||||||
};
|
openEditor();
|
||||||
|
},
|
||||||
|
[openEditor]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={$container}>
|
<div ref={$container}>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
} from '@douyinfe/semi-ui';
|
} from '@douyinfe/semi-ui';
|
||||||
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
|
import { CommentEditor } from 'components/document/comments';
|
||||||
import { DocumentStyle } from 'components/document/style';
|
import { DocumentStyle } from 'components/document/style';
|
||||||
import { LogoImage, LogoText } from 'components/logo';
|
import { LogoImage, LogoText } from 'components/logo';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
|
@ -118,7 +119,6 @@ export const DocumentPublicReader: React.FC<IProps> = ({ documentId, hideLogo =
|
||||||
user={null}
|
user={null}
|
||||||
id={documentId}
|
id={documentId}
|
||||||
type="document"
|
type="document"
|
||||||
hideComment
|
|
||||||
renderInEditorPortal={renderAuthor}
|
renderInEditorPortal={renderAuthor}
|
||||||
/>}
|
/>}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -9,14 +9,14 @@ import { UserSetting } from './setting';
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
export const User: React.FC = () => {
|
export const User: React.FC = () => {
|
||||||
const { user, loading, error, gotoLogin, logout } = useUser();
|
const { user, loading, error, toLogin, logout } = useUser();
|
||||||
const [visible, toggleVisible] = useToggle(false);
|
const [visible, toggleVisible] = useToggle(false);
|
||||||
|
|
||||||
if (loading) return <Button icon={<IconSpin />} theme="borderless" type="tertiary" />;
|
if (loading) return <Button icon={<IconSpin />} theme="borderless" type="tertiary" />;
|
||||||
|
|
||||||
if (error || !user) {
|
if (error || !user) {
|
||||||
return (
|
return (
|
||||||
<Button theme="solid" type="primary" size="small" onClick={gotoLogin}>
|
<Button theme="solid" type="primary" size="small" onClick={toLogin}>
|
||||||
登录
|
登录
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,7 +34,7 @@ export const useComments = (documentId) => {
|
||||||
const { data, error, isLoading, refetch } = useQuery(
|
const { data, error, isLoading, refetch } = useQuery(
|
||||||
[CommentApiDefinition.documents.client(documentId), page],
|
[CommentApiDefinition.documents.client(documentId), page],
|
||||||
() => getComments(documentId, page),
|
() => getComments(documentId, page),
|
||||||
{ keepPreviousData: true }
|
{ keepPreviousData: true, refetchOnMount: true, refetchOnWindowFocus: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const addComment = useCallback(
|
const addComment = useCallback(
|
||||||
|
|
|
@ -5,12 +5,26 @@ import { useCallback, useEffect } from 'react';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { HttpClient } from 'services/http-client';
|
import { HttpClient } from 'services/http-client';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接去登录页
|
||||||
|
*/
|
||||||
|
export const toLogin = () => {
|
||||||
|
const currentPath = Router.asPath;
|
||||||
|
const isInLogin = currentPath.startsWith('login');
|
||||||
|
if (!isInLogin) {
|
||||||
|
Router.push(`/login?redirect=${currentPath}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const useUser = () => {
|
export const useUser = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data, error, refetch } = useQuery<ILoginUser>('user', () => {
|
const { data, error, refetch } = useQuery<ILoginUser>('user', () => {
|
||||||
return getStorage('user');
|
return getStorage('user');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除用户信息后跳到登录页
|
||||||
|
*/
|
||||||
const logout = useCallback(() => {
|
const logout = useCallback(() => {
|
||||||
window.localStorage.removeItem('user');
|
window.localStorage.removeItem('user');
|
||||||
window.localStorage.removeItem('token');
|
window.localStorage.removeItem('token');
|
||||||
|
@ -19,7 +33,9 @@ export const useUser = () => {
|
||||||
method: UserApiDefinition.logout.method,
|
method: UserApiDefinition.logout.method,
|
||||||
url: UserApiDefinition.logout.client(),
|
url: UserApiDefinition.logout.client(),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
Router.replace('/login');
|
const isInShare = Router.asPath.startsWith('/share');
|
||||||
|
if (isInShare) return;
|
||||||
|
toLogin();
|
||||||
});
|
});
|
||||||
}, [refetch]);
|
}, [refetch]);
|
||||||
|
|
||||||
|
@ -56,7 +72,7 @@ export const useUser = () => {
|
||||||
user: data,
|
user: data,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: data ? null : error,
|
error: data ? null : error,
|
||||||
gotoLogin: logout,
|
toLogin,
|
||||||
login,
|
login,
|
||||||
logout,
|
logout,
|
||||||
updateUser,
|
updateUser,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Toast } from '@douyinfe/semi-ui';
|
import { Toast } from '@douyinfe/semi-ui';
|
||||||
import axios, { Axios, AxiosRequestConfig, AxiosResponse } from 'axios';
|
import axios, { Axios, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import Router from 'next/router';
|
import { toLogin } from 'data/user';
|
||||||
|
|
||||||
type WithCookieAxiosRequestConfig = AxiosRequestConfig & { cookie?: string };
|
type WithCookieAxiosRequestConfig = AxiosRequestConfig & { cookie?: string };
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ HttpClient.interceptors.response.use(
|
||||||
break;
|
break;
|
||||||
case 401:
|
case 401:
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
Router.replace(`/login?redirect=${window.location.pathname}`);
|
toLogin();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 429:
|
case 429:
|
||||||
|
|
Loading…
Reference in New Issue