chore: add user profile page (#2175)

chore: some enhancements
This commit is contained in:
boojack
2023-08-25 23:10:51 +08:00
committed by GitHub
parent 8c312e647d
commit 4af0d03e93
18 changed files with 173 additions and 132 deletions

View File

@ -1,5 +1,4 @@
import { Divider } from "@mui/joy";
import { isEqual, uniqWith } from "lodash-es";
import { memo, useEffect, useRef, useState } from "react";
import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
@ -7,7 +6,7 @@ import { Link } from "react-router-dom";
import { UNKNOWN_ID } from "@/helpers/consts";
import { getRelativeTimeString } from "@/helpers/datetime";
import { useFilterStore, useMemoStore, useUserStore } from "@/store/module";
import { useMemoCacheStore, useUserV1Store } from "@/store/v1";
import { useUserV1Store } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import showChangeMemoCreatedTsDialog from "./ChangeMemoCreatedTsDialog";
import { showCommonDialog } from "./Dialog/CommonDialog";
@ -23,24 +22,20 @@ import "@/less/memo.less";
interface Props {
memo: Memo;
showCreator?: boolean;
showVisibility?: boolean;
showRelatedMemos?: boolean;
lazyRendering?: boolean;
}
const Memo: React.FC<Props> = (props: Props) => {
const { memo, showCreator, showRelatedMemos, lazyRendering } = props;
const { memo, lazyRendering } = props;
const { i18n } = useTranslation();
const t = useTranslate();
const filterStore = useFilterStore();
const userStore = useUserStore();
const memoStore = useMemoStore();
const memoCacheStore = useMemoCacheStore();
const userV1Store = useUserV1Store();
const [shouldRender, setShouldRender] = useState<boolean>(lazyRendering ? false : true);
const [createdTimeStr, setCreatedTimeStr] = useState<string>(getRelativeTimeString(memo.displayTs));
const [relatedMemoList, setRelatedMemoList] = useState<Memo[]>([]);
const [displayTime, setDisplayTime] = useState<string>(getRelativeTimeString(memo.displayTs));
const memoContainerRef = useRef<HTMLDivElement>(null);
const readonly = userStore.isVisitorMode() || userStore.getCurrentUsername() !== memo.creatorUsername;
const creator = userV1Store.getUserByUsername(memo.creatorUsername);
@ -50,27 +45,12 @@ const Memo: React.FC<Props> = (props: Props) => {
userV1Store.getOrFetchUserByUsername(memo.creatorUsername);
}, [memo.creatorUsername]);
// Prepare related memos.
useEffect(() => {
Promise.allSettled(memo.relationList.map((memoRelation) => memoCacheStore.getOrFetchMemoById(memoRelation.relatedMemoId))).then(
(results) => {
const memoList = [];
for (const result of results) {
if (result.status === "fulfilled") {
memoList.push(result.value);
}
}
setRelatedMemoList(uniqWith(memoList, isEqual));
}
);
}, [memo.relationList]);
// Update display time string.
useEffect(() => {
let intervalFlag: any = -1;
if (Date.now() - memo.displayTs < 1000 * 60 * 60 * 24) {
intervalFlag = setInterval(() => {
setCreatedTimeStr(getRelativeTimeString(memo.displayTs));
setDisplayTime(getRelativeTimeString(memo.displayTs));
}, 1000 * 1);
}
@ -246,26 +226,25 @@ const Memo: React.FC<Props> = (props: Props) => {
<>
<div className={`memo-wrapper ${"memos-" + memo.id} ${memo.pinned && !readonly ? "pinned" : ""}`} ref={memoContainerRef}>
<div className="memo-top-wrapper">
<div className="status-text-container">
{showCreator && creator && (
<p className="w-full max-w-[calc(100%-20px)] flex flex-row justify-start items-center mr-1">
{creator && (
<>
<Link className="flex flex-row justify-start items-center" to={`/u/${memo.creatorUsername}`}>
<UserAvatar className="!w-5 !h-auto mr-1" avatarUrl={creator.avatarUrl} />
<span className="text-sm text-gray-600 dark:text-zinc-300">{creator.nickname}</span>
<span className="text-sm text-gray-600 max-w-[8em] truncate dark:text-zinc-300">{creator.nickname}</span>
</Link>
<Icon.Dot className="w-4 h-auto text-gray-400 dark:text-zinc-400" />
</>
)}
<Link className="time-text" to={`/m/${memo.id}`} onClick={handleMemoCreatedTimeClick}>
{createdTimeStr}
</Link>
</div>
<span className="text-sm text-gray-400" onClick={handleMemoCreatedTimeClick}>
{displayTime}
</span>
</p>
<div className="btns-container space-x-2">
{memo.pinned && <Icon.Bookmark className="w-4 h-auto rounded text-green-600" />}
{!readonly && (
<>
<span className="btn more-action-btn">
<Icon.MoreHorizontal className="icon-img" />
<Icon.MoreVertical className="icon-img" />
</span>
<div className="more-action-btns-wrapper">
<div className="more-action-btns-container min-w-[6em]">
@ -306,24 +285,8 @@ const Memo: React.FC<Props> = (props: Props) => {
onMemoContentDoubleClick={handleMemoContentDoubleClick}
/>
<MemoResourceListView resourceList={memo.resourceList} />
{!showRelatedMemos && <MemoRelationListView relationList={memo.relationList} />}
<MemoRelationListView relationList={memo.relationList} />
</div>
{showRelatedMemos && relatedMemoList.length > 0 && (
<>
<p className="text-sm dark:text-gray-300 my-2 pl-4 opacity-50 flex flex-row items-center">
<Icon.Link className="w-4 h-auto mr-1" />
<span>Related memos</span>
</p>
{relatedMemoList.map((relatedMemo) => {
return (
<div key={relatedMemo.id} className="w-full">
<Memo memo={relatedMemo} showCreator />
</div>
);
})}
</>
)}
</>
);
};