diff --git a/web/src/components/Memo.tsx b/web/src/components/Memo.tsx index 40579052..f5d1d602 100644 --- a/web/src/components/Memo.tsx +++ b/web/src/components/Memo.tsx @@ -1,6 +1,6 @@ import { memo, useEffect, useRef, useState } from "react"; import { escape, indexOf } from "lodash-es"; -import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG, UNKNOWN_ID } from "../helpers/consts"; +import { IMAGE_URL_REG, LINK_URL_REG, MEMO_LINK_REG, TAG_REG, UNKNOWN_ID } from "../helpers/consts"; import * as utils from "../helpers/utils"; import { DONE_BLOCK_REG, parseMarkedToHtml, TODO_BLOCK_REG } from "../helpers/marked"; import { editorStateService, locationService, memoService, userService } from "../services"; @@ -229,9 +229,9 @@ export function formatMemoContent(content: string) { return tempElement.innerHTML .replace(IMAGE_URL_REG, "") - .replace(TAG_REG, "#$1 ") - .replace(LINK_REG, "$1") - .replace(MEMO_LINK_REG, "$1"); + .replace(MEMO_LINK_REG, "$1") + .replace(LINK_URL_REG, "$1") + .replace(TAG_REG, "#$1 "); } export default memo(Memo); diff --git a/web/src/components/MemoEditor.tsx b/web/src/components/MemoEditor.tsx index 74413832..90787450 100644 --- a/web/src/components/MemoEditor.tsx +++ b/web/src/components/MemoEditor.tsx @@ -28,7 +28,7 @@ const MemoEditor: React.FC = () => { useEffect(() => { if (editorState.markMemoId && editorState.markMemoId !== UNKNOWN_ID) { const editorCurrentValue = editorRef.current?.getContent(); - const memoLinkText = `${editorCurrentValue ? "\n" : ""}Mark: [@MEMO](${editorState.markMemoId})`; + const memoLinkText = `${editorCurrentValue ? "\n" : ""}Mark: @[MEMO](${editorState.markMemoId})`; editorRef.current?.insertText(memoLinkText); editorStateService.clearMarkMemo(); } diff --git a/web/src/components/MemoList.tsx b/web/src/components/MemoList.tsx index 40ce0649..f184c173 100644 --- a/web/src/components/MemoList.tsx +++ b/web/src/components/MemoList.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from "react"; import { memoService, shortcutService } from "../services"; import { useAppSelector } from "../store"; -import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG } from "../helpers/consts"; +import { IMAGE_URL_REG, LINK_URL_REG, MEMO_LINK_REG, TAG_REG } from "../helpers/consts"; import * as utils from "../helpers/utils"; import { checkShouldShowMemoWithFilters } from "../helpers/filter"; import toastHelper from "./Toast"; @@ -58,7 +58,7 @@ const MemoList: React.FC = () => { if (memoType) { if (memoType === "NOT_TAGGED" && memo.content.match(TAG_REG) !== null) { shouldShow = false; - } else if (memoType === "LINKED" && memo.content.match(LINK_REG) === null) { + } else if (memoType === "LINKED" && memo.content.match(LINK_URL_REG) === null) { shouldShow = false; } else if (memoType === "IMAGED" && memo.content.match(IMAGE_URL_REG) === null) { shouldShow = false; diff --git a/web/src/components/UserBanner.tsx b/web/src/components/UserBanner.tsx index a7dca2b6..d8bec85a 100644 --- a/web/src/components/UserBanner.tsx +++ b/web/src/components/UserBanner.tsx @@ -3,14 +3,13 @@ import * as utils from "../helpers/utils"; import userService from "../services/userService"; import { locationService } from "../services"; import { useAppSelector } from "../store"; -import toastHelper from "./Toast"; import MenuBtnsPopup from "./MenuBtnsPopup"; import "../less/user-banner.less"; interface Props {} const UserBanner: React.FC = () => { - const user = useAppSelector((state) => state.user.user); + const { user, owner } = useAppSelector((state) => state.user); const { memos, tags } = useAppSelector((state) => state.memo); const [shouldShowPopupBtns, setShouldShowPopupBtns] = useState(false); const [username, setUsername] = useState("Memos"); @@ -18,24 +17,15 @@ const UserBanner: React.FC = () => { const isVisitorMode = userService.isVisitorMode(); useEffect(() => { - const currentUserId = userService.getUserIdFromPath(); - if (isVisitorMode && currentUserId) { - userService - .getUserById(currentUserId) - .then((user) => { - if (user) { - setUsername(user.name); - setCreatedDays(user ? Math.ceil((Date.now() - utils.getTimeStampByDate(user.createdTs)) / 1000 / 3600 / 24) : 0); - } else { - toastHelper.error("User not found"); - } - }) - .catch(() => { - // do nth - }); + if (isVisitorMode) { + if (!owner) { + return; + } + setUsername(owner.name); + setCreatedDays(Math.ceil((Date.now() - utils.getTimeStampByDate(owner.createdTs)) / 1000 / 3600 / 24)); } else if (user) { setUsername(user.name); - setCreatedDays(user ? Math.ceil((Date.now() - utils.getTimeStampByDate(user.createdTs)) / 1000 / 3600 / 24) : 0); + setCreatedDays(Math.ceil((Date.now() - utils.getTimeStampByDate(user.createdTs)) / 1000 / 3600 / 24)); } }, []); diff --git a/web/src/helpers/consts.ts b/web/src/helpers/consts.ts index 52e9d29d..01b4bcc0 100644 --- a/web/src/helpers/consts.ts +++ b/web/src/helpers/consts.ts @@ -13,11 +13,11 @@ export const DAILY_TIMESTAMP = 3600 * 24 * 1000; // tag regex export const TAG_REG = /#(.+?) /g; -// URL regex -export const LINK_REG = /(https?:\/\/[^\s<\\*>']+)/g; - -// image regex +// markdown image regex export const IMAGE_URL_REG = /!\[.*?\]\((.+?)\)/g; +// markdown link regex +export const LINK_URL_REG = /\[(.*?)\]\((.+?)\)/g; + // linked memo regex -export const MEMO_LINK_REG = /\[@(.+?)\]\((.+?)\)/g; +export const MEMO_LINK_REG = /@\[(.+?)\]\((.+?)\)/g; diff --git a/web/src/helpers/filter.ts b/web/src/helpers/filter.ts index b9290e5e..78f83e48 100644 --- a/web/src/helpers/filter.ts +++ b/web/src/helpers/filter.ts @@ -1,4 +1,4 @@ -import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG } from "./consts"; +import { IMAGE_URL_REG, LINK_URL_REG, MEMO_LINK_REG, TAG_REG } from "./consts"; export const relationConsts = [ { text: "And", value: "AND" }, @@ -142,7 +142,7 @@ export const checkShouldShowMemo = (memo: Memo, filter: Filter) => { let matched = false; if (value === "NOT_TAGGED" && memo.content.match(TAG_REG) === null) { matched = true; - } else if (value === "LINKED" && memo.content.match(LINK_REG) !== null) { + } else if (value === "LINKED" && memo.content.match(LINK_URL_REG) !== null) { matched = true; } else if (value === "IMAGED" && memo.content.match(IMAGE_URL_REG) !== null) { matched = true; diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index e7de74a4..e28e9eae 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -15,19 +15,22 @@ function Home() { useEffect(() => { userService - .doSignIn() + .initialState() .catch() .finally(async () => { - if (!userService.getState().user) { - if (userService.isVisitorMode()) { - const currentUserId = userService.getUserIdFromPath() as number; - const user = await userService.getUserById(currentUserId); - if (!user) { - toastHelper.error("User not found"); - } - } else { - locationService.replaceHistory("/signin"); - return; + const { host, owner, user } = userService.getState(); + if (!host) { + locationService.replaceHistory("/signin"); + return; + } + + if (userService.isVisitorMode()) { + if (!owner) { + toastHelper.error("User not found"); + } + } else { + if (!user) { + locationService.replaceHistory(`/u/${host.id}`); } } loadingState.setFinish(); diff --git a/web/src/services/memoService.ts b/web/src/services/memoService.ts index a1446fa7..7f93c21b 100644 --- a/web/src/services/memoService.ts +++ b/web/src/services/memoService.ts @@ -17,9 +17,10 @@ const memoService = { }, fetchAllMemos: async () => { - const memoFind: MemoFind = { - creatorId: userService.getUserIdFromPath(), - }; + const memoFind: MemoFind = {}; + if (userService.isVisitorMode()) { + memoFind.creatorId = userService.getUserIdFromPath(); + } const { data } = (await api.getMemoList(memoFind)).data; const memos = data.filter((m) => m.rowStatus !== "ARCHIVED").map((m) => convertResponseModelMemo(m)); store.dispatch(setMemos(memos)); @@ -29,9 +30,11 @@ const memoService = { fetchArchivedMemos: async () => { const memoFind: MemoFind = { - creatorId: userService.getUserIdFromPath(), rowStatus: "ARCHIVED", }; + if (userService.isVisitorMode()) { + memoFind.creatorId = userService.getUserIdFromPath(); + } const { data } = (await api.getMemoList(memoFind)).data; const archivedMemos = data.map((m) => { return convertResponseModelMemo(m); @@ -50,9 +53,10 @@ const memoService = { }, updateTagsState: async () => { - const tagFind: TagFind = { - creatorId: userService.getUserIdFromPath(), - }; + const tagFind: TagFind = {}; + if (userService.isVisitorMode()) { + tagFind.creatorId = userService.getUserIdFromPath(); + } const { data } = (await api.getTagList(tagFind)).data; store.dispatch(setTags(data)); }, diff --git a/web/src/services/userService.ts b/web/src/services/userService.ts index e176c040..fea35093 100644 --- a/web/src/services/userService.ts +++ b/web/src/services/userService.ts @@ -2,7 +2,7 @@ import { isUndefined } from "lodash-es"; import { locationService } from "."; import * as api from "../helpers/api"; import store from "../store"; -import { setUser, patchUser } from "../store/modules/user"; +import { setUser, patchUser, setHost, setOwner } from "../store/modules/user"; const convertResponseModelUser = (user: User): User => { return { @@ -17,12 +17,30 @@ const userService = { return store.getState().user; }, - isVisitorMode: () => { - return !isUndefined(userService.getUserIdFromPath()); + initialState: async () => { + const { + data: { host }, + } = (await api.getSystemStatus()).data; + if (host) { + store.dispatch(setHost(convertResponseModelUser(host))); + } + + const ownerUserId = userService.getUserIdFromPath(); + if (ownerUserId) { + const { data: owner } = (await api.getUserById(ownerUserId)).data; + if (owner) { + store.dispatch(setOwner(convertResponseModelUser(owner))); + } + } + + const { data: user } = (await api.getUser()).data; + if (user) { + store.dispatch(setUser(convertResponseModelUser(user))); + } }, - getCurrentUserId: () => { - return userService.getUserIdFromPath() ?? store.getState().user.user?.id; + isVisitorMode: () => { + return !isUndefined(userService.getUserIdFromPath()); }, getUserIdFromPath: () => { diff --git a/web/src/store/modules/user.ts b/web/src/store/modules/user.ts index a1e58fc3..a1d34e81 100644 --- a/web/src/store/modules/user.ts +++ b/web/src/store/modules/user.ts @@ -1,6 +1,11 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; interface State { + // host is the user who hist the system + host?: User; + // owner is the user who owns the page. If in `/u/101`, then owner's id is `101` + owner?: User; + // user is the user who is currently logged in user?: User; } @@ -8,6 +13,18 @@ const userSlice = createSlice({ name: "user", initialState: {} as State, reducers: { + setHost: (state, action: PayloadAction) => { + return { + ...state, + host: action.payload, + }; + }, + setOwner: (state, action: PayloadAction) => { + return { + ...state, + owner: action.payload, + }; + }, setUser: (state, action: PayloadAction) => { return { ...state, @@ -26,6 +43,6 @@ const userSlice = createSlice({ }, }); -export const { setUser, patchUser } = userSlice.actions; +export const { setHost, setOwner, setUser, patchUser } = userSlice.actions; export default userSlice.reducer;