chore: update detail styles (#1964)

pull/1965/head
boojack 2 years ago committed by GitHub
parent 49dd90578b
commit 01f4780655
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,6 +14,7 @@
"@mui/joy": "^5.0.0-alpha.75", "@mui/joy": "^5.0.0-alpha.75",
"@reduxjs/toolkit": "^1.8.1", "@reduxjs/toolkit": "^1.8.1",
"axios": "^0.27.2", "axios": "^0.27.2",
"classnames": "^2.3.2",
"copy-to-clipboard": "^3.3.2", "copy-to-clipboard": "^3.3.2",
"highlight.js": "^11.6.0", "highlight.js": "^11.6.0",
"i18next": "^21.9.2", "i18next": "^21.9.2",

@ -1,4 +1,4 @@
lockfileVersion: '6.0' lockfileVersion: '6.1'
settings: settings:
autoInstallPeers: true autoInstallPeers: true
@ -23,6 +23,9 @@ dependencies:
axios: axios:
specifier: ^0.27.2 specifier: ^0.27.2
version: 0.27.2 version: 0.27.2
classnames:
specifier: ^2.3.2
version: 2.3.2
copy-to-clipboard: copy-to-clipboard:
specifier: ^3.3.2 specifier: ^3.3.2
version: 3.3.2 version: 3.3.2
@ -1346,6 +1349,10 @@ packages:
fsevents: 2.3.2 fsevents: 2.3.2
dev: false dev: false
/classnames@2.3.2:
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
dev: false
/clsx@1.2.1: /clsx@1.2.1:
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
engines: {node: '>=6'} engines: {node: '>=6'}

@ -1,7 +1,8 @@
import classNames from "classnames";
import { useEffect } from "react"; import { useEffect } from "react";
import { NavLink, useLocation } from "react-router-dom"; import { NavLink, useLocation } from "react-router-dom";
import { useTranslate } from "@/utils/i18n";
import { useLayoutStore, useUserStore } from "@/store/module"; import { useLayoutStore, useUserStore } from "@/store/module";
import { useTranslate } from "@/utils/i18n";
import { resolution } from "@/utils/layout"; import { resolution } from "@/utils/layout";
import Icon from "./Icon"; import Icon from "./Icon";
import UserBanner from "./UserBanner"; import UserBanner from "./UserBanner";
@ -53,9 +54,10 @@ const Header = () => {
to="/" to="/"
id="header-home" id="header-home"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>
@ -66,9 +68,10 @@ const Header = () => {
to="/review" to="/review"
id="header-review" id="header-review"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>
@ -79,9 +82,10 @@ const Header = () => {
to="/resources" to="/resources"
id="header-resources" id="header-resources"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>
@ -94,9 +98,10 @@ const Header = () => {
to="/explore" to="/explore"
id="header-explore" id="header-explore"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>
@ -110,9 +115,10 @@ const Header = () => {
to="/memo-chat" to="/memo-chat"
id="header-memo-chat" id="header-memo-chat"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 shadow" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:shadow dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>
@ -123,9 +129,10 @@ const Header = () => {
to="/archived" to="/archived"
id="header-archived" id="header-archived"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>
@ -136,9 +143,10 @@ const Header = () => {
to="/setting" to="/setting"
id="header-setting" id="header-setting"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>
@ -154,9 +162,10 @@ const Header = () => {
to="/auth" to="/auth"
id="header-auth" id="header-auth"
className={({ isActive }) => className={({ isActive }) =>
`${ classNames(
isActive && "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" "px-4 pr-5 py-2 rounded-full border flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700",
} px-4 pr-5 py-2 rounded-full border border-transparent flex flex-row items-center text-lg text-gray-800 dark:text-gray-300 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-600 dark:hover:bg-zinc-700` isActive ? "bg-white dark:bg-zinc-700 border-gray-200 dark:border-zinc-600" : "border-transparent"
)
} }
> >
<> <>

@ -2,20 +2,15 @@ import Icon from "@/components/Icon";
import Textarea from "@mui/joy/Textarea/Textarea"; import Textarea from "@mui/joy/Textarea/Textarea";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
interface MemosChatInputProps { interface Props {
question: string; question: string;
handleQuestionTextareaChange: any; handleQuestionTextareaChange: any;
setIsInIME: any; setIsInIME: any;
handleKeyDown: any; handleKeyDown: any;
handleSendQuestionButtonClick: any; handleSendQuestionButtonClick: any;
} }
const MemosChatInput = ({
question, const ChatInput = ({ question, handleQuestionTextareaChange, setIsInIME, handleKeyDown, handleSendQuestionButtonClick }: Props) => {
handleQuestionTextareaChange,
setIsInIME,
handleKeyDown,
handleSendQuestionButtonClick,
}: MemosChatInputProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@ -39,4 +34,4 @@ const MemosChatInput = ({
); );
}; };
export default MemosChatInput; export default ChatInput;

@ -7,7 +7,7 @@ interface MessageProps {
message: Message; message: Message;
} }
const MemosChatMessage = ({ index, message }: MessageProps) => { const ChatMessage = ({ index, message }: MessageProps) => {
return ( return (
<div key={index} className="w-full flex flex-col justify-start items-start space-y-2"> <div key={index} className="w-full flex flex-col justify-start items-start space-y-2">
{message.role === "user" ? ( {message.role === "user" ? (
@ -28,4 +28,4 @@ const MemosChatMessage = ({ index, message }: MessageProps) => {
); );
}; };
export default MemosChatMessage; export default ChatMessage;

@ -1,3 +1,4 @@
import { Button } from "@mui/joy";
import { isNumber, last, uniq } from "lodash-es"; import { isNumber, last, uniq } from "lodash-es";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
@ -421,9 +422,9 @@ const MemoEditor = (props: Props) => {
<div className="editor-footer-container"> <div className="editor-footer-container">
<MemoVisibilitySelector value={state.memoVisibility} onChange={handleMemoVisibilityChange} /> <MemoVisibilitySelector value={state.memoVisibility} onChange={handleMemoVisibilityChange} />
<div className="buttons-container"> <div className="buttons-container">
<button className="action-btn confirm-btn" disabled={!allowSave} onClick={handleSaveBtnClick}> <Button disabled={!allowSave} onClick={handleSaveBtnClick}>
{t("editor.save")} {t("editor.save")}
</button> </Button>
</div> </div>
</div> </div>
</div> </div>

@ -76,7 +76,7 @@ const MemoList = () => {
return shouldShow; return shouldShow;
}) })
: memos : memos
).filter((memo) => memo.creatorId === currentUserId); ).filter((memo) => memo.creatorId === currentUserId && memo.rowStatus === "NORMAL");
const pinnedMemos = shownMemos.filter((m) => m.pinned); const pinnedMemos = shownMemos.filter((m) => m.pinned);
const unpinnedMemos = shownMemos.filter((m) => !m.pinned); const unpinnedMemos = shownMemos.filter((m) => !m.pinned);

@ -326,6 +326,14 @@
"and": "And", "and": "And",
"or": "Or" "or": "Or"
}, },
"amount-text": {
"memo_one": "MEMO",
"memo_other": "MEMOS",
"tag_one": "TAG",
"tag_other": "TAGS",
"day_one": "TAG",
"day_other": "TAGE"
},
"message": { "message": {
"no-data": "Maybe no data was found, maybe it should be another option.", "no-data": "Maybe no data was found, maybe it should be another option.",
"memos-ready": "all memos are ready 🎉", "memos-ready": "all memos are ready 🎉",

@ -1,4 +1,4 @@
import { Button, Divider } from "@mui/joy"; import { Button, Divider, Input } from "@mui/joy";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
@ -131,71 +131,44 @@ const Auth = () => {
<div className="flex flex-row justify-center items-center w-full h-full dark:bg-zinc-800"> <div className="flex flex-row justify-center items-center w-full h-full dark:bg-zinc-800">
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center"> <div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
<div className="w-full py-4 grow flex flex-col justify-center items-center"> <div className="w-full py-4 grow flex flex-col justify-center items-center">
<div className="flex flex-col justify-start items-start w-full mb-4"> <div className="w-full flex flex-col justify-center items-center mb-2">
<div className="w-full flex flex-row justify-start items-center mb-2"> <img className="h-20 w-auto rounded-full shadow mr-1" src={systemStatus.customizedProfile.logoUrl} alt="" />
<img className="h-12 w-auto rounded-lg mr-1" src={systemStatus.customizedProfile.logoUrl} alt="" /> <p className="text-3xl text-black opacity-80 dark:text-gray-200">{systemStatus.customizedProfile.name}</p>
<p className="text-6xl tracking-wide text-black opacity-80 dark:text-gray-200">{systemStatus.customizedProfile.name}</p>
</div>
<p className="text-sm text-gray-700 dark:text-gray-300">
{systemStatus.customizedProfile.description || t("common.memos-slogan")}
</p>
</div> </div>
<form className="w-full" onSubmit={handleFormSubmit}> <form className="w-full mt-4" onSubmit={handleFormSubmit}>
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading && "opacity-80"}`}> <div className="flex flex-col justify-start items-start w-full gap-4">
<div className="flex flex-col justify-start items-start relative w-full text-base mt-2 py-2"> <Input
<span className="w-full"
className={`absolute top-3 left-3 px-1 leading-10 shrink-0 text-base cursor-text text-gray-400 transition-all select-none pointer-events-none ${ size="lg"
username ? "!text-sm !top-0 !z-10 !leading-4 bg-white dark:bg-zinc-800 rounded" : "" type="text"
}`} placeholder={t("common.username")}
> value={username}
{t("common.username")} onChange={handleUsernameInputChanged}
</span> required
<input />
className="input-text w-full py-3 px-3 text-base rounded-lg dark:bg-zinc-800" <Input
type="text" className="w-full"
value={username} size="lg"
onChange={handleUsernameInputChanged} type="password"
required placeholder={t("common.password")}
/> value={password}
</div> onChange={handlePasswordInputChanged}
<div className="flex flex-col justify-start items-start relative w-full text-base mt-2 py-2"> required
<span />
className={`absolute top-3 left-3 px-1 leading-10 shrink-0 text-base cursor-text text-gray-400 transition-all select-none pointer-events-none ${
password ? "!text-sm !top-0 !z-10 !leading-4 bg-white dark:bg-zinc-800 rounded" : ""
}`}
>
{t("common.password")}
</span>
<input
className="input-text w-full py-3 px-3 text-base rounded-lg dark:bg-zinc-800"
type="password"
value={password}
onChange={handlePasswordInputChanged}
required
/>
</div>
</div> </div>
<div className="flex flex-row justify-end items-center w-full mt-2"> <div className="flex flex-row justify-end items-center w-full mt-6">
{actionBtnLoadingState.isLoading && <Icon.Loader className="w-4 h-auto mr-2 animate-spin dark:text-gray-300" />} {actionBtnLoadingState.isLoading && <Icon.Loader className="w-4 h-auto mr-2 animate-spin dark:text-gray-300" />}
{systemStatus?.allowSignUp && ( {systemStatus?.allowSignUp && (
<> <>
<button <Button variant={"plain"} loading={actionBtnLoadingState.isLoading} onClick={handleSignUpButtonClick}>
type="button"
className={`btn-text ${actionBtnLoadingState.isLoading ? "cursor-wait opacity-80" : ""}`}
onClick={handleSignUpButtonClick}
>
{t("common.sign-up")} {t("common.sign-up")}
</button> </Button>
<span className="mr-2 font-mono text-gray-200">/</span> <span className="mr-2 font-mono text-gray-200">/</span>
</> </>
)} )}
<button <Button type="submit" loading={actionBtnLoadingState.isLoading} onClick={handleSignInButtonClick}>
type="submit"
className={`btn-primary ${actionBtnLoadingState.isLoading ? "cursor-wait opacity-80" : ""}`}
onClick={handleSignInButtonClick}
>
{t("common.sign-in")} {t("common.sign-in")}
</button> </Button>
</div> </div>
</form> </form>
{identityProviderList.length > 0 && ( {identityProviderList.length > 0 && (

@ -11,19 +11,13 @@ import Memo from "@/components/Memo";
import MobileHeader from "@/components/MobileHeader"; import MobileHeader from "@/components/MobileHeader";
import Empty from "@/components/Empty"; import Empty from "@/components/Empty";
interface State {
memos: Memo[];
}
const Explore = () => { const Explore = () => {
const t = useTranslate(); const t = useTranslate();
const location = useLocation(); const location = useLocation();
const filterStore = useFilterStore(); const filterStore = useFilterStore();
const memoStore = useMemoStore(); const memoStore = useMemoStore();
const filter = filterStore.state; const filter = filterStore.state;
const [state, setState] = useState<State>({ const memos = memoStore.state.memos;
memos: [],
});
const [isComplete, setIsComplete] = useState<boolean>(false); const [isComplete, setIsComplete] = useState<boolean>(false);
const loadingState = useLoading(); const loadingState = useLoading();
@ -32,9 +26,6 @@ const Explore = () => {
if (memos.length < DEFAULT_MEMO_LIMIT) { if (memos.length < DEFAULT_MEMO_LIMIT) {
setIsComplete(true); setIsComplete(true);
} }
setState({
memos,
});
loadingState.setFinish(); loadingState.setFinish();
}); });
}, [location]); }, [location]);
@ -43,7 +34,7 @@ const Explore = () => {
const showMemoFilter = Boolean(tagQuery || textQuery); const showMemoFilter = Boolean(tagQuery || textQuery);
const shownMemos = showMemoFilter const shownMemos = showMemoFilter
? state.memos.filter((memo) => { ? memos.filter((memo) => {
let shouldShow = true; let shouldShow = true;
if (tagQuery) { if (tagQuery) {
@ -64,21 +55,17 @@ const Explore = () => {
} }
return shouldShow; return shouldShow;
}) })
: state.memos; : memos;
const sortedMemos = shownMemos.filter((m) => m.rowStatus === "NORMAL");
const sortedMemos = shownMemos.filter((m) => m.rowStatus === "NORMAL" && m.visibility !== "PRIVATE");
const handleFetchMoreClick = async () => { const handleFetchMoreClick = async () => {
try { try {
const fetchedMemos = await memoStore.fetchAllMemos(DEFAULT_MEMO_LIMIT, state.memos.length); const fetchedMemos = await memoStore.fetchAllMemos(DEFAULT_MEMO_LIMIT, memos.length);
if (fetchedMemos.length < DEFAULT_MEMO_LIMIT) { if (fetchedMemos.length < DEFAULT_MEMO_LIMIT) {
setIsComplete(true); setIsComplete(true);
} else { } else {
setIsComplete(false); setIsComplete(false);
} }
setState({
memos: state.memos.concat(fetchedMemos),
});
} catch (error: any) { } catch (error: any) {
console.error(error); console.error(error);
toast.error(error.response.data.message); toast.error(error.response.data.message);
@ -95,7 +82,7 @@ const Explore = () => {
return <Memo key={`${memo.id}-${memo.displayTs}`} memo={memo} showCreator />; return <Memo key={`${memo.id}-${memo.displayTs}`} memo={memo} showCreator />;
})} })}
{isComplete ? ( {isComplete ? (
state.memos.length === 0 && ( memos.length === 0 && (
<div className="w-full mt-16 mb-8 flex flex-col justify-center items-center italic"> <div className="w-full mt-16 mb-8 flex flex-col justify-center items-center italic">
<Empty /> <Empty />
<p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p> <p className="mt-4 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>

@ -1,4 +1,5 @@
import { Button, Stack } from "@mui/joy"; import { Button, Stack } from "@mui/joy";
import { head } from "lodash-es";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -9,27 +10,23 @@ import { Conversation, useConversationStore } from "@/store/zustand/conversation
import Icon from "@/components/Icon"; import Icon from "@/components/Icon";
import { generateUUID } from "@/utils/uuid"; import { generateUUID } from "@/utils/uuid";
import MobileHeader from "@/components/MobileHeader"; import MobileHeader from "@/components/MobileHeader";
import MemosChatMessage from "@/components/MemosChat/MemosChatMessage"; import ChatMessage from "@/components/MemoChat/ChatMessage";
import MemosChatInput from "@/components/MemosChat/MemosChatInput"; import ChatInput from "@/components/MemoChat/ChatInput";
import head from "lodash-es/head"; import ConversationTab from "@/components/MemoChat/ConversationTab";
import ConversationTab from "@/components/MemosChat/ConversationTab";
import Empty from "@/components/Empty"; import Empty from "@/components/Empty";
const MemosChat = () => { const MemoChat = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const fetchingState = useLoading(false); const fetchingState = useLoading(false);
const [isEnabled, setIsEnabled] = useState<boolean>(true); const [isEnabled, setIsEnabled] = useState<boolean>(true);
const [isInIME, setIsInIME] = useState(false); const [isInIME, setIsInIME] = useState(false);
const [question, setQuestion] = useState<string>(""); const [question, setQuestion] = useState<string>("");
const conversationStore = useConversationStore(); const conversationStore = useConversationStore();
const conversationList = conversationStore.conversationList; const conversationList = conversationStore.conversationList;
const [selectedConversationId, setSelectedConversationId] = useState<string>(head(conversationList)?.messageStorageId || ""); const [selectedConversationId, setSelectedConversationId] = useState<string>(head(conversationList)?.messageStorageId || "");
const messageStore = useMessageStore(selectedConversationId)(); const messageStore = useMessageStore(selectedConversationId)();
const messageList = messageStore.messageList; const messageList = messageStore.messageList;
// The state didn't show in component, just for trigger re-render
// the state didn't show in component, just for trigger re-render
const [message, setMessage] = useState<string>(""); const [message, setMessage] = useState<string>("");
useEffect(() => { useEffect(() => {
@ -170,7 +167,7 @@ const MemosChat = () => {
</div> </div>
)} )}
{messageList.map((message, index) => ( {messageList.map((message, index) => (
<MemosChatMessage key={index} message={message} index={index} /> <ChatMessage key={index} message={message} index={index} />
))} ))}
</Stack> </Stack>
{fetchingState.isLoading && ( {fetchingState.isLoading && (
@ -185,7 +182,7 @@ const MemosChat = () => {
</div> </div>
)} )}
<MemosChatInput <ChatInput
question={question} question={question}
handleQuestionTextareaChange={handleQuestionTextareaChange} handleQuestionTextareaChange={handleQuestionTextareaChange}
setIsInIME={setIsInIME} setIsInIME={setIsInIME}
@ -198,4 +195,4 @@ const MemosChat = () => {
); );
}; };
export default MemosChat; export default MemoChat;

@ -1,40 +1,28 @@
import { useEffect, useState } from "react"; import { useEffect } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { Link, useLocation, useParams } from "react-router-dom"; import { Link, useLocation, useParams } from "react-router-dom";
import { UNKNOWN_ID } from "@/helpers/consts";
import { useGlobalStore, useMemoStore } from "@/store/module"; import { useGlobalStore, useMemoStore } from "@/store/module";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import Icon from "@/components/Icon"; import Icon from "@/components/Icon";
import Memo from "@/components/Memo"; import Memo from "@/components/Memo";
interface State {
memo: Memo;
}
const MemoDetail = () => { const MemoDetail = () => {
const t = useTranslate(); const t = useTranslate();
const params = useParams(); const params = useParams();
const location = useLocation(); const location = useLocation();
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const memoStore = useMemoStore(); const memoStore = useMemoStore();
const [state, setState] = useState<State>({
memo: {
id: UNKNOWN_ID,
} as Memo,
});
const loadingState = useLoading(); const loadingState = useLoading();
const customizedProfile = globalStore.state.systemStatus.customizedProfile; const customizedProfile = globalStore.state.systemStatus.customizedProfile;
const memoId = Number(params.memoId);
const memo = memoStore.state.memos.find((memo) => memo.id === memoId);
useEffect(() => { useEffect(() => {
const memoId = Number(params.memoId);
if (memoId && !isNaN(memoId)) { if (memoId && !isNaN(memoId)) {
memoStore memoStore
.fetchMemoById(memoId) .fetchMemoById(memoId)
.then((memo) => { .then(() => {
setState({
memo,
});
loadingState.setFinish(); loadingState.setFinish();
}) })
.catch((error) => { .catch((error) => {
@ -53,21 +41,26 @@ const MemoDetail = () => {
<p className="detail-name text-4xl tracking-wide text-black dark:text-white">{customizedProfile.name}</p> <p className="detail-name text-4xl tracking-wide text-black dark:text-white">{customizedProfile.name}</p>
</div> </div>
</div> </div>
{!loadingState.isLoading && ( {!loadingState.isLoading &&
<> (memo ? (
<main className="relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4"> <>
<Memo memo={state.memo} showCreator showRelatedMemos /> <main className="relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4">
</main> <Memo memo={memo} showCreator showRelatedMemos />
<div className="mt-4 w-full flex flex-row justify-center items-center gap-2"> </main>
<Link <div className="mt-4 w-full flex flex-row justify-center items-center gap-2">
to="/" <Link
className="flex flex-row justify-center items-center text-gray-600 dark:text-gray-300 text-sm px-3 hover:opacity-80 hover:underline" to="/"
> className="flex flex-row justify-center items-center text-gray-600 dark:text-gray-300 text-sm px-3 hover:opacity-80 hover:underline"
<Icon.Home className="w-4 h-auto mr-1 -mt-0.5" /> {t("router.back-to-home")} >
</Link> <Icon.Home className="w-4 h-auto mr-1 -mt-0.5" /> {t("router.back-to-home")}
</div> </Link>
</> </div>
)} </>
) : (
<>
<p>Not found</p>
</>
))}
</div> </div>
</section> </section>
); );

@ -16,7 +16,7 @@ const Home = lazy(() => import("@/pages/Home"));
const MemoDetail = lazy(() => import("@/pages/MemoDetail")); const MemoDetail = lazy(() => import("@/pages/MemoDetail"));
const EmbedMemo = lazy(() => import("@/pages/EmbedMemo")); const EmbedMemo = lazy(() => import("@/pages/EmbedMemo"));
const NotFound = lazy(() => import("@/pages/NotFound")); const NotFound = lazy(() => import("@/pages/NotFound"));
const MemosChat = lazy(() => import("@/pages/MemosChat")); const MemoChat = lazy(() => import("@/pages/MemoChat"));
const initialGlobalStateLoader = (() => { const initialGlobalStateLoader = (() => {
let done = false; let done = false;
@ -150,7 +150,7 @@ const router = createBrowserRouter([
}, },
{ {
path: "memo-chat", path: "memo-chat",
element: <MemosChat />, element: <MemoChat />,
loader: async () => { loader: async () => {
await initialGlobalStateLoader(); await initialGlobalStateLoader();

@ -23,6 +23,7 @@ export const useMemoStore = () => {
const fetchMemoById = async (memoId: MemoId) => { const fetchMemoById = async (memoId: MemoId) => {
const { data } = await api.getMemoById(memoId); const { data } = await api.getMemoById(memoId);
const memo = convertResponseModelMemo(data); const memo = convertResponseModelMemo(data);
store.dispatch(upsertMemos([memo]));
return memo; return memo;
}; };
@ -62,6 +63,7 @@ export const useMemoStore = () => {
const { data } = await api.getAllMemos(memoFind); const { data } = await api.getAllMemos(memoFind);
const fetchedMemos = data.map((m) => convertResponseModelMemo(m)); const fetchedMemos = data.map((m) => convertResponseModelMemo(m));
store.dispatch(upsertMemos(fetchedMemos));
for (const m of fetchedMemos) { for (const m of fetchedMemos) {
memoCacheStore.setMemoCache(m); memoCacheStore.setMemoCache(m);

Loading…
Cancel
Save