1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-05-04 17:16:40 +07:00

99 use swr ()

* 99: made node use SWR

* 99: fixed comments for SWR node

* 99: added error toast to useNodeFormFormik.ts
This commit is contained in:
muerwre 2022-01-02 17:10:21 +07:00 committed by GitHub
parent 832386d39a
commit c2d1c2bfc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 366 additions and 413 deletions

View file

@ -47,16 +47,7 @@ export const nodePostLocalComment = (
nodeId,
comment,
callback,
type: NODE_ACTIONS.POST_COMMENT,
});
export const nodeSubmitLocal = (
node: INode,
callback: (e?: string, errors?: Record<string, string>) => void
) => ({
node,
callback,
type: NODE_ACTIONS.SUBMIT_LOCAL,
type: NODE_ACTIONS.POST_LOCAL_COMMENT,
});
export const nodeSetSendingComment = (is_sending_comment: boolean) => ({
@ -69,34 +60,6 @@ export const nodeSetComments = (comments: IComment[]) => ({
type: NODE_ACTIONS.SET_COMMENTS,
});
export const nodeUpdateTags = (id: INode['id'], tags: string[]) => ({
type: NODE_ACTIONS.UPDATE_TAGS,
id,
tags,
});
export const nodeDeleteTag = (id: INode['id'], tagId: ITag['ID']) => ({
type: NODE_ACTIONS.DELETE_TAG,
id: id!,
tagId,
});
export const nodeSetTags = (tags: ITag[]) => ({
type: NODE_ACTIONS.SET_TAGS,
tags,
});
export const nodeCreate = (node_type: INode['type'], isLab?: boolean) => ({
type: NODE_ACTIONS.CREATE,
node_type,
isLab,
});
export const nodeEdit = (id: INode['id']) => ({
type: NODE_ACTIONS.EDIT,
id,
});
export const nodeLike = (id: INode['id']) => ({
type: NODE_ACTIONS.LIKE,
id,
@ -113,17 +76,13 @@ export const nodeLock = (id: INode['id'], is_locked: boolean) => ({
is_locked,
});
export const nodeLockComment = (id: IComment['id'], is_locked: boolean) => ({
export const nodeLockComment = (id: number, is_locked: boolean, nodeId: number) => ({
type: NODE_ACTIONS.LOCK_COMMENT,
nodeId,
id,
is_locked,
});
export const nodeEditComment = (id: IComment['id']) => ({
type: NODE_ACTIONS.EDIT_COMMENT,
id,
});
export const nodeSetEditor = (editor: INode) => ({
type: NODE_ACTIONS.SET_EDITOR,
editor,

View file

@ -42,9 +42,6 @@ export type ApiGetNodeCommentsResponse = { comments: IComment[]; comment_count:
export const apiPostNode = ({ node }: ApiPostNodeRequest) =>
api.post<ApiPostNodeResult>(API.NODE.SAVE, node).then(cleanResult);
export const apiPostNodeLocal = ({ node }: ApiPostNodeRequest) =>
api.post<ApiPostNodeResult>(API.NODE.SAVE, node).then(cleanResult);
export const getNodeDiff = ({
start,
end,
@ -69,7 +66,10 @@ export const getNodeDiff = ({
.then(cleanResult);
export const apiGetNode = ({ id }: ApiGetNodeRequest, config?: AxiosRequestConfig) =>
api.get<ApiGetNodeResponse>(API.NODE.GET_NODE(id), config).then(cleanResult);
api
.get<ApiGetNodeResponse>(API.NODE.GET_NODE(id), config)
.then(cleanResult)
.then(data => ({ node: data.node, last_seen: data.last_seen }));
export const apiGetNodeWithCancel = ({ id }: ApiGetNodeRequest) => {
const cancelToken = axios.CancelToken.source();

View file

@ -22,22 +22,18 @@ import { LabPad } from '~/components/lab/LabPad';
import { LabDescription } from '~/components/lab/LabDescription';
import { LabVideo } from '~/components/lab/LabVideo';
import { LabAudio } from '~/components/lab/LabAudioBlock';
import { LabLine } from '~/components/lab/LabLine';
const prefix = 'NODE.';
export const NODE_ACTIONS = {
SUBMIT_LOCAL: `${prefix}SUBMIT_LOCAL`,
LOAD_NODE: `${prefix}LOAD_NODE`,
GOTO_NODE: `${prefix}GOTO_NODE`,
SET: `${prefix}SET`,
EDIT: `${prefix}EDIT`,
LIKE: `${prefix}LIKE`,
STAR: `${prefix}STAR`,
LOCK: `${prefix}LOCK`,
LOCK_COMMENT: `${prefix}LOCK_COMMENT`,
EDIT_COMMENT: `${prefix}EDIT_COMMENT`,
CREATE: `${prefix}CREATE`,
LOAD_MORE_COMMENTS: `${prefix}LOAD_MORE_COMMENTS`,
SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`,
@ -47,13 +43,10 @@ export const NODE_ACTIONS = {
SET_CURRENT: `${prefix}SET_CURRENT`,
SET_EDITOR: `${prefix}SET_EDITOR`,
POST_COMMENT: `${prefix}POST_LOCAL_COMMENT`,
POST_LOCAL_COMMENT: `${prefix}POST_LOCAL_COMMENT`,
SET_COMMENTS: `${prefix}SET_COMMENTS`,
SET_RELATED: `${prefix}SET_RELATED`,
UPDATE_TAGS: `${prefix}UPDATE_TAGS`,
DELETE_TAG: `${prefix}DELETE_TAG`,
SET_TAGS: `${prefix}SET_TAGS`,
SET_COVER_IMAGE: `${prefix}SET_COVER_IMAGE`,
};

View file

@ -10,7 +10,6 @@ import {
nodeSetLoadingComments,
nodeSetSaveErrors,
nodeSetSendingComment,
nodeSetTags,
} from './actions';
import { INodeState } from './reducer';
@ -41,9 +40,6 @@ const setSendingComment = (
const setComments = (state: INodeState, { comments }: ReturnType<typeof nodeSetComments>) =>
assocPath(['comments'], comments, state);
const setTags = (state: INodeState, { tags }: ReturnType<typeof nodeSetTags>) =>
assocPath(['current', 'tags'], tags, state);
const setEditor = (state: INodeState, { editor }: ReturnType<typeof nodeSetEditor>) =>
assocPath(['editor'], editor, state);
@ -60,7 +56,6 @@ export const NODE_HANDLERS = {
[NODE_ACTIONS.SET_CURRENT]: setCurrent,
[NODE_ACTIONS.SET_SENDING_COMMENT]: setSendingComment,
[NODE_ACTIONS.SET_COMMENTS]: setComments,
[NODE_ACTIONS.SET_TAGS]: setTags,
[NODE_ACTIONS.SET_EDITOR]: setEditor,
[NODE_ACTIONS.SET_COVER_IMAGE]: setCoverImage,
};

View file

@ -1,11 +1,7 @@
import { call, put, select, takeLatest, takeLeading } from 'redux-saga/effects';
import { push } from 'connected-react-router';
import { COMMENTS_DISPLAY, EMPTY_NODE, NODE_ACTIONS, NODE_EDITOR_DATA } from './constants';
import {
nodeCreate,
nodeDeleteTag,
nodeEdit,
nodeGotoNode,
nodeLike,
nodeLoadNode,
@ -15,21 +11,13 @@ import {
nodeSet,
nodeSetComments,
nodeSetCurrent,
nodeSetEditor,
nodeSetLoading,
nodeSetLoadingComments,
nodeSetTags,
nodeSubmitLocal,
nodeUpdateTags,
} from './actions';
import {
apiDeleteNodeTag,
apiGetNode,
apiGetNodeComments,
apiLockComment,
apiLockNode,
apiPostComment,
apiPostNode,
apiPostNodeHeroic,
apiPostNodeLike,
apiPostNodeTags,
@ -45,6 +33,8 @@ import { DIALOGS } from '~/redux/modal/constants';
import { has } from 'ramda';
import { selectLabListNodes } from '~/redux/lab/selectors';
import { labSetList } from '~/redux/lab/actions';
import { apiPostNode } from '~/redux/node/api';
import { showErrorToast } from '~/utils/errors/showToast';
export function* updateNodeEverywhere(node) {
const {
@ -66,42 +56,6 @@ export function* updateNodeEverywhere(node) {
);
}
function* onNodeSubmitLocal({ node, callback }: ReturnType<typeof nodeSubmitLocal>) {
try {
const { errors, node: result }: Unwrap<typeof apiPostNode> = yield call(apiPostNode, { node });
if (errors && Object.values(errors).length > 0) {
callback('', errors);
return;
}
if (node.is_promoted) {
const nodes: ReturnType<typeof selectFlowNodes> = yield select(selectFlowNodes);
const updated_flow_nodes = node.id
? nodes.map(item => (item.id === result.id ? result : item))
: [result, ...nodes];
yield put(flowSetNodes(updated_flow_nodes));
} else {
const nodes: ReturnType<typeof selectLabListNodes> = yield select(selectLabListNodes);
const updated_lab_nodes = node.id
? nodes.map(item => (item.node.id === result.id ? { ...item, node: result } : item))
: [{ node: result, comment_count: 0, last_seen: node.created_at }, ...nodes];
yield put(labSetList({ nodes: updated_lab_nodes }));
}
const { current } = yield select(selectNode);
if (node.id && current.id === result.id) {
yield put(nodeSetCurrent(result));
}
callback();
return;
} catch (error) {
callback(error.message);
}
}
function* onNodeGoto({ id, node_type }: ReturnType<typeof nodeGotoNode>) {
if (!id) {
return;
@ -164,22 +118,9 @@ function* nodeGetComments(id: INode['id']) {
}
function* onNodeLoad({ id }: ReturnType<typeof nodeLoadNode>) {
// Get node body
try {
yield put(nodeSetLoading(true));
yield put(nodeSetLoadingComments(true));
const { node, last_seen }: Unwrap<typeof apiGetNode> = yield call(apiGetNode, { id });
yield put(nodeSet({ current: node, lastSeenCurrent: last_seen }));
yield put(nodeSetLoading(false));
} catch (error) {
yield put(push(URLS.ERRORS.NOT_FOUND));
yield put(nodeSetLoading(false));
}
// Comments
try {
yield put(nodeSetLoadingComments(true));
yield call(nodeGetComments, id);
yield put(
@ -197,82 +138,24 @@ function* onPostComment({ nodeId, comment, callback }: ReturnType<typeof nodePos
id: nodeId,
});
const { current }: ReturnType<typeof selectNode> = yield select(selectNode);
const { comments }: ReturnType<typeof selectNode> = yield select(selectNode);
if (current?.id === nodeId) {
const { comments }: ReturnType<typeof selectNode> = yield select(selectNode);
if (!comment.id) {
yield put(nodeSetComments([data.comment, ...comments]));
} else {
yield put(
nodeSet({
comments: comments.map(item => (item.id === comment.id ? data.comment : item)),
})
);
}
callback();
if (!comment.id) {
yield put(nodeSetComments([data.comment, ...comments]));
} else {
yield put(
nodeSet({
comments: comments.map(item => (item.id === comment.id ? data.comment : item)),
})
);
}
callback();
} catch (error) {
return callback(error.message);
}
}
function* onUpdateTags({ id, tags }: ReturnType<typeof nodeUpdateTags>) {
try {
const { node }: Unwrap<typeof apiPostNodeTags> = yield call(apiPostNodeTags, { id, tags });
const { current }: ReturnType<typeof selectNode> = yield select(selectNode);
if (!node || !node.id || node.id !== current.id) return;
yield put(nodeSetTags(node.tags));
} catch {}
}
function* onDeleteTag({ id, tagId }: ReturnType<typeof nodeDeleteTag>) {
try {
const { tags }: Unwrap<typeof apiDeleteNodeTag> = yield call(apiDeleteNodeTag, { id, tagId });
yield put(nodeSetTags(tags));
} catch {}
}
function* onCreateSaga({ node_type: type, isLab }: ReturnType<typeof nodeCreate>) {
if (!type || !has(type, NODE_EDITOR_DIALOGS)) return;
yield put(
nodeSetEditor({
...EMPTY_NODE,
...(NODE_EDITOR_DATA[type] || {}),
type,
is_promoted: !isLab,
})
);
yield put(modalShowDialog(NODE_EDITOR_DIALOGS[type]));
}
function* onEditSaga({ id }: ReturnType<typeof nodeEdit>) {
try {
if (!id) {
return;
}
yield put(modalShowDialog(DIALOGS.LOADING));
const { node }: Unwrap<typeof apiGetNode> = yield call(apiGetNode, { id });
if (!node.type || !has(node.type, NODE_EDITOR_DIALOGS)) return;
if (!NODE_EDITOR_DIALOGS[node?.type]) {
throw new Error('Unknown node type');
}
yield put(nodeSetEditor(node));
yield put(modalShowDialog(NODE_EDITOR_DIALOGS[node.type]));
} catch (error) {
yield put(modalSetShown(false));
}
}
function* onLikeSaga({ id }: ReturnType<typeof nodeLike>) {
const { current }: ReturnType<typeof selectNode> = yield select(selectNode);
@ -330,22 +213,12 @@ function* onLockSaga({ id, is_locked }: ReturnType<typeof nodeLock>) {
}
}
function* onLockCommentSaga({ id, is_locked }: ReturnType<typeof nodeLockComment>) {
const { current, comments }: ReturnType<typeof selectNode> = yield select(selectNode);
function* onLockCommentSaga({ nodeId, id, is_locked }: ReturnType<typeof nodeLockComment>) {
const { comments }: ReturnType<typeof selectNode> = yield select(selectNode);
try {
yield put(
nodeSetComments(
comments.map(comment =>
comment.id === id
? { ...comment, deleted_at: is_locked ? new Date().toISOString() : undefined }
: comment
)
)
);
const data: Unwrap<typeof apiLockComment> = yield call(apiLockComment, {
current: current.id,
current: nodeId,
id,
is_locked,
});
@ -357,26 +230,15 @@ function* onLockCommentSaga({ id, is_locked }: ReturnType<typeof nodeLockComment
)
)
);
} catch {
yield put(
nodeSetComments(
comments.map(comment =>
comment.id === id ? { ...comment, deleted_at: current.deleted_at } : comment
)
)
);
} catch (e) {
showErrorToast(e);
}
}
export default function* nodeSaga() {
yield takeLatest(NODE_ACTIONS.SUBMIT_LOCAL, onNodeSubmitLocal);
yield takeLatest(NODE_ACTIONS.GOTO_NODE, onNodeGoto);
yield takeLatest(NODE_ACTIONS.LOAD_NODE, onNodeLoad);
yield takeLatest(NODE_ACTIONS.POST_COMMENT, onPostComment);
yield takeLatest(NODE_ACTIONS.UPDATE_TAGS, onUpdateTags);
yield takeLatest(NODE_ACTIONS.DELETE_TAG, onDeleteTag);
yield takeLatest(NODE_ACTIONS.CREATE, onCreateSaga);
yield takeLatest(NODE_ACTIONS.EDIT, onEditSaga);
yield takeLatest(NODE_ACTIONS.POST_LOCAL_COMMENT, onPostComment);
yield takeLatest(NODE_ACTIONS.LIKE, onLikeSaga);
yield takeLatest(NODE_ACTIONS.STAR, onStarSaga);
yield takeLatest(NODE_ACTIONS.LOCK, onLockSaga);