import copy from "copy-to-clipboard"; import { useState, useEffect, useCallback } from "react"; import { useTranslation } from "react-i18next"; import { editorStateService, memoService, userService } from "../services"; import { useAppSelector } from "../store"; import { UNKNOWN_ID, VISIBILITY_SELECTOR_ITEMS } from "../helpers/consts"; import * as utils from "../helpers/utils"; import { formatMemoContent, MEMO_LINK_REG, parseHtmlToRawText } from "../helpers/marked"; import Only from "./common/OnlyWhen"; import toastHelper from "./Toast"; import { generateDialog } from "./Dialog"; import Icon from "./Icon"; import Selector from "./common/Selector"; import MemoContent from "./MemoContent"; import MemoResources from "./MemoResources"; import showChangeMemoCreatedTsDialog from "./ChangeMemoCreatedTsDialog"; import "../less/memo-card-dialog.less"; interface LinkedMemo extends Memo { createdAtStr: string; dateStr: string; } interface Props extends DialogProps { memo: Memo; } const MemoCardDialog: React.FC = (props: Props) => { const { t } = useTranslation(); const memos = useAppSelector((state) => state.memo.memos); const [memo, setMemo] = useState({ ...props.memo, }); const [linkMemos, setLinkMemos] = useState([]); const [linkedMemos, setLinkedMemos] = useState([]); const visibilitySelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => { return { value: item.value, text: t(`memo.visibility.${item.text.toLowerCase()}`), }; }); useEffect(() => { const fetchLinkedMemos = async () => { try { const linkMemos: LinkedMemo[] = []; const matchedArr = [...memo.content.matchAll(MEMO_LINK_REG)]; for (const matchRes of matchedArr) { if (matchRes && matchRes.length === 3) { const id = Number(matchRes[2]); if (id === memo.id) { continue; } const memoTemp = memoService.getMemoById(id); if (memoTemp) { linkMemos.push({ ...memoTemp, createdAtStr: utils.getDateTimeString(memoTemp.createdTs), dateStr: utils.getDateString(memoTemp.createdTs), }); } } } setLinkMemos([...linkMemos]); const linkedMemos = await memoService.getLinkedMemos(memo.id); setLinkedMemos( linkedMemos .filter((m) => m.rowStatus === "NORMAL" && m.id !== memo.id) .sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs)) .map((m) => ({ ...m, createdAtStr: utils.getDateTimeString(m.createdTs), dateStr: utils.getDateString(m.createdTs), })) ); } catch (error) { // do nth } }; fetchLinkedMemos(); setMemo(memoService.getMemoById(memo.id) as Memo); }, [memos, memo.id]); const handleMemoCreatedAtClick = () => { showChangeMemoCreatedTsDialog(memo.id); }; const handleMemoContentClick = useCallback(async (e: React.MouseEvent) => { const targetEl = e.target as HTMLElement; if (targetEl.className === "memo-link-text") { const nextMemoId = targetEl.dataset?.value; const memoTemp = memoService.getMemoById(Number(nextMemoId) ?? UNKNOWN_ID); if (memoTemp) { const nextMemo = { ...memoTemp, createdAtStr: utils.getDateTimeString(memoTemp.createdTs), }; setLinkMemos([]); setLinkedMemos([]); setMemo(nextMemo); } else { toastHelper.error(t("message.memo-not-found")); targetEl.classList.remove("memo-link-text"); } } }, []); const handleLinkedMemoClick = useCallback((memo: Memo) => { setLinkMemos([]); setLinkedMemos([]); setMemo(memo); }, []); const handleCopyMemoLinkBtnClick = () => { if (memo.visibility === "PRIVATE") { toastHelper.error(t("message.private-only")); return; } copy(`${window.location.origin}/explore?memoId=${memo.id}`); toastHelper.success(t("message.copied")); }; const handleEditMemoBtnClick = () => { props.destroy(); editorStateService.setEditMemoWithId(memo.id); }; const handleVisibilitySelectorChange = async (visibility: Visibility) => { if (memo.visibility === visibility) { return; } await memoService.patchMemo({ id: memo.id, visibility: visibility, }); setMemo({ ...memo, visibility: visibility, }); }; return ( <>
handleVisibilitySelectorChange(value as Visibility)} />

{utils.getDateTimeString(memo.createdTs)}

<> /
{linkMemos.map((_, idx) => { if (idx < 4) { return (
); } else { return null; } })}
{linkMemos.length > 0 ? (

{linkMemos.length} related MEMO

{linkMemos.map((memo, index) => { const rawtext = parseHtmlToRawText(formatMemoContent(memo.content)).replaceAll("\n", " "); return (
handleLinkedMemoClick(memo)}> {memo.dateStr} {rawtext}
); })}
) : null} {linkedMemos.length > 0 ? (

{linkedMemos.length} linked MEMO

{linkedMemos.map((memo, index) => { const rawtext = parseHtmlToRawText(formatMemoContent(memo.content)).replaceAll("\n", " "); return (
handleLinkedMemoClick(memo)}> {memo.dateStr} {rawtext}
); })}
) : null} ); }; export default function showMemoCardDialog(memo: Memo): void { generateDialog( { className: "memo-card-dialog", }, MemoCardDialog, { memo } ); }