Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
8b0083ff
Unverified
Commit
8b0083ff
authored
Nov 02, 2023
by
Zexi
Committed by
GitHub
Nov 02, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: auto fetch more (#2472)
* fix: auto fetch more * feat: use union type
parent
5d69d896
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
114 additions
and
129 deletions
+114
-129
Memo.tsx
web/src/components/Memo.tsx
+23
-21
MemoList.tsx
web/src/components/MemoList.tsx
+26
-53
Explore.tsx
web/src/pages/Explore.tsx
+44
-48
Home.tsx
web/src/pages/Home.tsx
+1
-5
memo.ts
web/src/store/module/memo.ts
+9
-1
memo.ts
web/src/store/reducer/memo.ts
+11
-1
No files found.
web/src/components/Memo.tsx
View file @
8b0083ff
...
@@ -43,13 +43,20 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -43,13 +43,20 @@ const Memo: React.FC<Props> = (props: Props) => {
const
[
displayTime
,
setDisplayTime
]
=
useState
<
string
>
(
getRelativeTimeString
(
memo
.
displayTs
));
const
[
displayTime
,
setDisplayTime
]
=
useState
<
string
>
(
getRelativeTimeString
(
memo
.
displayTs
));
const
memoContainerRef
=
useRef
<
HTMLDivElement
>
(
null
);
const
memoContainerRef
=
useRef
<
HTMLDivElement
>
(
null
);
const
readonly
=
memo
.
creatorUsername
!==
user
?.
username
;
const
readonly
=
memo
.
creatorUsername
!==
user
?.
username
;
const
creator
=
userV1Store
.
getUserByUsername
(
memo
.
creatorUsername
);
const
[
creator
,
setCreator
]
=
useState
(
userV1Store
.
getUserByUsername
(
memo
.
creatorUsername
)
);
const
referenceRelations
=
memo
.
relationList
.
filter
((
relation
)
=>
relation
.
type
===
"REFERENCE"
);
const
referenceRelations
=
memo
.
relationList
.
filter
((
relation
)
=>
relation
.
type
===
"REFERENCE"
);
const
commentRelations
=
memo
.
relationList
.
filter
((
relation
)
=>
relation
.
relatedMemoId
===
memo
.
id
&&
relation
.
type
===
"COMMENT"
);
const
commentRelations
=
memo
.
relationList
.
filter
((
relation
)
=>
relation
.
relatedMemoId
===
memo
.
id
&&
relation
.
type
===
"COMMENT"
);
// Prepare memo creator.
// Prepare memo creator.
useEffect
(()
=>
{
useEffect
(()
=>
{
userV1Store
.
getOrFetchUserByUsername
(
memo
.
creatorUsername
);
if
(
creator
)
return
;
const
fn
=
async
()
=>
{
const
user
=
await
userV1Store
.
getOrFetchUserByUsername
(
memo
.
creatorUsername
);
setCreator
(
user
);
};
fn
();
},
[
memo
.
creatorUsername
]);
},
[
memo
.
creatorUsername
]);
// Update display time string.
// Update display time string.
...
@@ -68,30 +75,23 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -68,30 +75,23 @@ const Memo: React.FC<Props> = (props: Props) => {
// Lazy rendering.
// Lazy rendering.
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
shouldRender
)
{
if
(
shouldRender
)
return
;
return
;
if
(
!
memoContainerRef
.
current
)
return
;
}
const
observer
=
new
IntersectionObserver
(([
entry
])
=>
{
if
(
!
entry
.
isIntersecting
)
return
;
observer
.
disconnect
();
const
root
=
document
.
body
.
querySelector
(
"#root"
);
if
(
root
)
{
const
checkShouldRender
=
()
=>
{
if
(
root
.
scrollTop
+
window
.
innerHeight
>
(
memoContainerRef
.
current
?.
offsetTop
||
0
))
{
setShouldRender
(
true
);
setShouldRender
(
true
);
root
.
removeEventListener
(
"scroll"
,
checkShouldRender
);
});
return
true
;
observer
.
observe
(
memoContainerRef
.
current
);
}
};
if
(
checkShouldRender
())
{
return
()
=>
observer
.
disconnect
();
return
;
}
root
.
addEventListener
(
"scroll"
,
checkShouldRender
);
}
},
[
lazyRendering
,
filterStore
.
state
]);
},
[
lazyRendering
,
filterStore
.
state
]);
if
(
!
shouldRender
)
{
if
(
!
shouldRender
)
{
// Render a placeholder to occupy the space.
// Render a placeholder to occupy the space.
return
<
div
className=
{
`w-full h-32 !bg-transparent ${"memos-" + memo.id}`
}
ref=
{
memoContainerRef
}
></
div
>;
return
<
div
className=
{
`w-full h-32 !bg-transparent ${"memos-" + memo.id}`
}
ref=
{
memoContainerRef
}
/
>;
}
}
const
handleGotoMemoDetailPage
=
(
event
:
React
.
MouseEvent
<
HTMLDivElement
>
)
=>
{
const
handleGotoMemoDetailPage
=
(
event
:
React
.
MouseEvent
<
HTMLDivElement
>
)
=>
{
...
@@ -299,7 +299,9 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -299,7 +299,9 @@ const Memo: React.FC<Props> = (props: Props) => {
<
Tooltip
title=
{
"Creator"
}
placement=
"top"
>
<
Tooltip
title=
{
"Creator"
}
placement=
"top"
>
<
span
className=
"flex flex-row justify-start items-center"
>
<
span
className=
"flex flex-row justify-start items-center"
>
<
UserAvatar
className=
"!w-5 !h-auto mr-1"
avatarUrl=
{
creator
.
avatarUrl
}
/>
<
UserAvatar
className=
"!w-5 !h-auto mr-1"
avatarUrl=
{
creator
.
avatarUrl
}
/>
<
span
className=
"text-sm text-gray-600 max-w-[8em] truncate dark:text-gray-400"
>
{
creator
.
nickname
}
</
span
>
<
span
className=
"text-sm text-gray-600 max-w-[8em] truncate dark:text-gray-400"
>
{
creator
.
nickname
||
creator
.
username
}
</
span
>
</
span
>
</
span
>
</
Tooltip
>
</
Tooltip
>
</
Link
>
</
Link
>
...
...
web/src/components/MemoList.tsx
View file @
8b0083ff
import
{
useEffect
,
use
State
}
from
"react"
;
import
{
useEffect
,
use
Ref
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useParams
}
from
"react-router-dom"
;
import
{
useParams
}
from
"react-router-dom"
;
import
MemoFilter
from
"@/components/MemoFilter"
;
import
{
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
{
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
{
getTimeStampByDate
}
from
"@/helpers/datetime"
;
import
{
getTimeStampByDate
}
from
"@/helpers/datetime"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
...
@@ -16,14 +17,14 @@ const MemoList: React.FC = () => {
...
@@ -16,14 +17,14 @@ const MemoList: React.FC = () => {
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
const
filterStore
=
useFilterStore
();
const
filterStore
=
useFilterStore
();
const
filter
=
filterStore
.
state
;
const
filter
=
filterStore
.
state
;
const
{
memos
}
=
memoStore
.
state
;
const
{
loadingStatus
,
memos
}
=
memoStore
.
state
;
const
[
isFetching
,
setIsFetching
]
=
useState
<
boolean
>
(
true
);
const
[
isComplete
,
setIsComplete
]
=
useState
<
boolean
>
(
false
);
const
user
=
useCurrentUser
();
const
user
=
useCurrentUser
();
const
{
tag
:
tagQuery
,
duration
,
text
:
textQuery
,
visibility
}
=
filter
;
const
{
tag
:
tagQuery
,
duration
,
text
:
textQuery
,
visibility
}
=
filter
;
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
textQuery
||
visibility
);
const
showMemoFilter
=
Boolean
(
tagQuery
||
(
duration
&&
duration
.
from
<
duration
.
to
)
||
textQuery
||
visibility
);
const
username
=
params
.
username
||
user
?
.
username
||
"";
const
username
=
params
.
username
||
user
?
.
username
||
"";
const
fetchMoreRef
=
useRef
<
HTMLSpanElement
>
(null);
const shownMemos = (
const shownMemos = (
showMemoFilter
showMemoFilter
? memos.filter((memo) =
>
{
? memos.filter((memo) =
>
{
...
@@ -74,74 +75,48 @@ const MemoList: React.FC = () => {
...
@@ -74,74 +75,48 @@ const MemoList: React.FC = () => {
const sortedMemos = pinnedMemos.concat(unpinnedMemos).filter((m) =
>
m.rowStatus === "NORMAL");
const sortedMemos = pinnedMemos.concat(unpinnedMemos).filter((m) =
>
m.rowStatus === "NORMAL");
useEffect(() =
>
{
useEffect(() =
>
{
memoStore
const
root
=
document
.
body
.
querySelector
(
"#root"
);
.
fetchMemos
(
username
)
if
(
root
)
{
.
then
((
fetchedMemos
)
=>
{
root
.
scrollTo
(
0
,
0
);
if
(
fetchedMemos
.
length
<
DEFAULT_MEMO_LIMIT
)
{
setIsComplete
(
true
);
}
else
{
setIsComplete
(
false
);
}
setIsFetching
(
false
);
})
.
catch
((
error
)
=>
{
console
.
error
(
error
);
toast
.
error
(
error
.
response
.
data
.
message
);
});
}
, [user?.username]);
useEffect(() =
>
{
const
pageWrapper
=
document
.
body
.
querySelector
(
".page-wrapper"
);
if
(
pageWrapper
)
{
pageWrapper
.
scrollTo
(
0
,
0
);
}
}
}
, [filter]);
}
, [filter]);
useEffect(() =
>
{
useEffect(() =
>
{
if
(
isFetching
||
isComplete
)
{
if
(
!
fetchMoreRef
.
current
)
return
;
return
;
}
if
(
sortedMemos
.
length
<
DEFAULT_MEMO_LIMIT
)
{
handleFetchMoreClick
();
return
;
}
const
observer
=
new
IntersectionObserver
(([
entry
])
=>
{
const
observer
=
new
IntersectionObserver
(([
entry
])
=>
{
if
(
entry
.
isIntersecting
)
{
if
(
!
entry
.
isIntersecting
)
return
;
observer
.
disconnect
();
handleFetchMoreClick
();
handleFetchMoreClick
();
observer
.
unobserve
(
entry
.
target
);
}
});
});
}
, [isFetching, isComplete, filter, sortedMemos.length]);
observer
.
observe
(
fetchMoreRef
.
current
);
return
()
=>
observer
.
disconnect
();
}
, [loadingStatus]);
const handleFetchMoreClick = async () =
>
{
const handleFetchMoreClick = async () =
>
{
try
{
try
{
setIsFetching
(
true
);
await
memoStore
.
fetchMemos
(
username
,
DEFAULT_MEMO_LIMIT
,
memos
.
length
);
const
fetchedMemos
=
await
memoStore
.
fetchMemos
(
username
,
DEFAULT_MEMO_LIMIT
,
memos
.
length
);
if
(
fetchedMemos
.
length
<
DEFAULT_MEMO_LIMIT
)
{
setIsComplete
(
true
);
}
else
{
setIsComplete
(
false
);
}
setIsFetching
(
false
);
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
toast
.
error
(
error
.
response
.
data
.
message
);
toast
.
error
(
error
.
response
.
data
.
message
);
}
}
}
;
}
;
return (
return (
<
div
className=
"flex flex-col justify-start items-start w-full max-w-full overflow-y-scroll pb-28 hide-scrollbar"
>
<
div
className=
"flex flex-col justify-start items-start w-full max-w-full overflow-y-scroll pb-28 hide-scrollbar"
>
<
MemoFilter
/>
{
sortedMemos
.
map
((
memo
)
=>
(
{
sortedMemos
.
map
((
memo
)
=>
(
<
Memo
key=
{
`${memo.id}-${memo.displayTs}`
}
memo=
{
memo
}
lazyRendering
showVisibility
showPinnedStyle
/>
<
Memo
key=
{
memo
.
id
}
memo=
{
memo
}
lazyRendering
showVisibility
showPinnedStyle
/>
))
}
))
}
{
isFetching
?
(
{
loadingStatus
===
"fetching"
?
(
<
div
className=
"flex flex-col justify-start items-center w-full mt-2 mb-1"
>
<
div
className=
"flex flex-col justify-start items-center w-full mt-2 mb-1"
>
<
p
className=
"text-sm text-gray-400 italic"
>
{
t
(
"memo.fetching-data"
)
}
</
p
>
<
p
className=
"text-sm text-gray-400 italic"
>
{
t
(
"memo.fetching-data"
)
}
</
p
>
</
div
>
</
div
>
)
:
(
)
:
(
<
div
className=
"flex flex-col justify-start items-center w-full my-6"
>
<
div
className=
"flex flex-col justify-start items-center w-full my-6"
>
<
div
className=
"text-sm text-gray-400 italic"
>
<
div
className=
"text-sm text-gray-400 italic"
>
{
isComplete
?
(
{
loadingStatus
===
"complete"
?
(
sortedMemos
.
length
===
0
&&
(
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
Empty
/>
...
@@ -149,11 +124,9 @@ const MemoList: React.FC = () => {
...
@@ -149,11 +124,9 @@ const MemoList: React.FC = () => {
</
div
>
</
div
>
)
)
)
:
(
)
:
(
<>
<
span
ref=
{
fetchMoreRef
}
className=
"cursor-pointer hover:text-green-600"
onClick=
{
handleFetchMoreClick
}
>
<
span
className=
"cursor-pointer hover:text-green-600"
onClick=
{
handleFetchMoreClick
}
>
{
t
(
"memo.fetch-more"
)
}
{
t
(
"memo.fetch-more"
)
}
</
span
>
</
span
>
</>
)
}
)
}
</
div
>
</
div
>
</
div
>
</
div
>
...
...
web/src/pages/Explore.tsx
View file @
8b0083ff
import
{
useEffect
,
use
State
}
from
"react"
;
import
{
useEffect
,
use
Ref
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
Empty
from
"@/components/Empty"
;
import
Empty
from
"@/components/Empty"
;
import
Memo
from
"@/components/Memo"
;
import
Memo
from
"@/components/Memo"
;
import
MemoFilter
from
"@/components/MemoFilter"
;
import
MemoFilter
from
"@/components/MemoFilter"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
{
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
{
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
TAG_REG
}
from
"@/labs/marked/parser"
;
import
{
TAG_REG
}
from
"@/labs/marked/parser"
;
import
{
useFilterStore
,
useMemoStore
}
from
"@/store/module"
;
import
{
useFilterStore
,
useMemoStore
}
from
"@/store/module"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
const
Explore
=
()
=>
{
const
Explore
=
()
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
location
=
useLocation
();
const
filterStore
=
useFilterStore
();
const
filterStore
=
useFilterStore
();
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
const
filter
=
filterStore
.
state
;
const
filter
=
filterStore
.
state
;
const
{
memos
}
=
memoStore
.
state
;
const
{
loadingStatus
,
memos
}
=
memoStore
.
state
;
const
[
isComplete
,
setIsComplete
]
=
useState
<
boolean
>
(
false
);
const
loadingState
=
useLoading
();
const
{
tag
:
tagQuery
,
text
:
textQuery
}
=
filter
;
const
{
tag
:
tagQuery
,
text
:
textQuery
}
=
filter
;
const
showMemoFilter
=
Boolean
(
tagQuery
||
textQuery
);
const
showMemoFilter
=
Boolean
(
tagQuery
||
textQuery
);
const
fetchMoreRef
=
useRef
<
HTMLSpanElement
>
(
null
);
const
fetchedMemos
=
showMemoFilter
const
fetchedMemos
=
showMemoFilter
?
memos
.
filter
((
memo
)
=>
{
?
memos
.
filter
((
memo
)
=>
{
...
@@ -58,30 +53,22 @@ const Explore = () => {
...
@@ -58,30 +53,22 @@ const Explore = () => {
.
sort
((
mi
,
mj
)
=>
mj
.
displayTs
-
mi
.
displayTs
);
.
sort
((
mi
,
mj
)
=>
mj
.
displayTs
-
mi
.
displayTs
);
useEffect
(()
=>
{
useEffect
(()
=>
{
memoStore
if
(
!
fetchMoreRef
.
current
)
return
;
.
fetchAllMemos
(
DEFAULT_MEMO_LIMIT
,
0
)
.
then
((
fetchedMemos
)
=>
{
const
observer
=
new
IntersectionObserver
(([
entry
])
=>
{
if
(
fetchedMemos
.
length
<
DEFAULT_MEMO_LIMIT
)
{
if
(
!
entry
.
isIntersecting
)
return
;
setIsComplete
(
true
);
observer
.
disconnect
();
}
handleFetchMoreClick
();
loadingState
.
setFinish
();
})
.
catch
((
error
)
=>
{
console
.
error
(
error
);
toast
.
error
(
error
.
response
.
data
.
message
);
});
});
},
[
location
]);
observer
.
observe
(
fetchMoreRef
.
current
);
return
()
=>
observer
.
disconnect
();
},
[
loadingStatus
]);
const
handleFetchMoreClick
=
async
()
=>
{
const
handleFetchMoreClick
=
async
()
=>
{
try
{
try
{
const
fetchedMemos
=
await
memoStore
.
fetchAllMemos
(
DEFAULT_MEMO_LIMIT
,
memos
.
length
);
await
memoStore
.
fetchAllMemos
(
DEFAULT_MEMO_LIMIT
,
memos
.
length
);
if
(
fetchedMemos
.
length
<
DEFAULT_MEMO_LIMIT
)
{
setIsComplete
(
true
);
}
else
{
setIsComplete
(
false
);
}
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
toast
.
error
(
error
.
response
.
data
.
message
);
toast
.
error
(
error
.
response
.
data
.
message
);
}
}
};
};
...
@@ -89,26 +76,35 @@ const Explore = () => {
...
@@ -89,26 +76,35 @@ const Explore = () => {
return
(
return
(
<
section
className=
"@container w-full max-w-3xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8 bg-zinc-100 dark:bg-zinc-800"
>
<
section
className=
"@container w-full max-w-3xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8 bg-zinc-100 dark:bg-zinc-800"
>
<
MobileHeader
showSearch=
{
false
}
/>
<
MobileHeader
showSearch=
{
false
}
/>
{
!
loadingState
.
isLoading
&&
(
<
div
className=
"relative w-full h-auto flex flex-col justify-start items-start"
>
<
div
className=
"relative w-full h-auto flex flex-col justify-start items-start"
>
<
MemoFilter
/>
<
MemoFilter
/>
{
sortedMemos
.
map
((
memo
)
=>
{
{
sortedMemos
.
map
((
memo
)
=>
(
return
<
Memo
key=
{
`${memo.id}-${memo.displayTs}`
}
memo=
{
memo
}
/>;
<
Memo
key=
{
memo
.
id
}
memo=
{
memo
}
lazyRendering
/>
})
}
))
}
{
isComplete
?
(
{
loadingStatus
===
"fetching"
?
(
<
div
className=
"flex flex-col justify-start items-center w-full mt-2 mb-1"
>
<
p
className=
"text-sm text-gray-400 italic"
>
{
t
(
"memo.fetching-data"
)
}
</
p
>
</
div
>
)
:
(
<
div
className=
"flex flex-col justify-start items-center w-full my-6"
>
<
div
className=
"text-sm text-gray-400 italic"
>
{
loadingStatus
===
"complete"
?
(
sortedMemos
.
length
===
0
&&
(
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-16
mb-8 flex flex-col justify-center items-center italic"
>
<
div
className=
"w-full mt-12
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
>
</
div
>
</
div
>
)
)
)
:
(
)
:
(
<
p
className=
"m-auto text-center mt-4 italic cursor-pointer text-gray-500
hover:text-green-600"
onClick=
{
handleFetchMoreClick
}
>
<
span
ref=
{
fetchMoreRef
}
className=
"cursor-pointer
hover:text-green-600"
onClick=
{
handleFetchMoreClick
}
>
{
t
(
"memo.fetch-more"
)
}
{
t
(
"memo.fetch-more"
)
}
</
p
>
</
span
>
)
}
)
}
</
div
>
</
div
>
</
div
>
)
}
)
}
</
div
>
</
section
>
</
section
>
);
);
};
};
...
...
web/src/pages/Home.tsx
View file @
8b0083ff
import
HomeSidebar
from
"@/components/HomeSidebar"
;
import
HomeSidebar
from
"@/components/HomeSidebar"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoFilter
from
"@/components/MemoFilter"
;
import
MemoList
from
"@/components/MemoList"
;
import
MemoList
from
"@/components/MemoList"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
...
@@ -9,10 +8,7 @@ const Home = () => {
...
@@ -9,10 +8,7 @@ const Home = () => {
<
div
className=
"@container w-full flex flex-row justify-start items-start"
>
<
div
className=
"@container w-full flex flex-row justify-start items-start"
>
<
div
className=
"w-full px-4 @lg:max-w-[calc(100%-14rem)] sm:px-2 sm:pt-4"
>
<
div
className=
"w-full px-4 @lg:max-w-[calc(100%-14rem)] sm:px-2 sm:pt-4"
>
<
MobileHeader
/>
<
MobileHeader
/>
<
div
className=
"w-full h-auto flex flex-col justify-start items-start bg-zinc-100 dark:bg-zinc-800 rounded-lg"
>
<
MemoEditor
className=
"mb-2"
cacheKey=
"home-memo-editor"
/>
<
MemoEditor
className=
"mb-2"
cacheKey=
"home-memo-editor"
/>
<
MemoFilter
/>
</
div
>
<
MemoList
/>
<
MemoList
/>
</
div
>
</
div
>
<
HomeSidebar
/>
<
HomeSidebar
/>
...
...
web/src/store/module/memo.ts
View file @
8b0083ff
...
@@ -2,7 +2,7 @@ import { omit } from "lodash-es";
...
@@ -2,7 +2,7 @@ import { omit } from "lodash-es";
import
*
as
api
from
"@/helpers/api"
;
import
*
as
api
from
"@/helpers/api"
;
import
{
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
{
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
store
,
{
useAppSelector
}
from
"../"
;
import
store
,
{
useAppSelector
}
from
"../"
;
import
{
createMemo
,
deleteMemo
,
patchMemo
,
upsertMemos
}
from
"../reducer/memo"
;
import
{
updateLoadingStatus
,
createMemo
,
deleteMemo
,
patchMemo
,
upsertMemos
}
from
"../reducer/memo"
;
import
{
useMemoCacheStore
}
from
"../v1"
;
import
{
useMemoCacheStore
}
from
"../v1"
;
export
const
convertResponseModelMemo
=
(
memo
:
Memo
):
Memo
=>
{
export
const
convertResponseModelMemo
=
(
memo
:
Memo
):
Memo
=>
{
...
@@ -40,12 +40,17 @@ export const useMemoStore = () => {
...
@@ -40,12 +40,17 @@ export const useMemoStore = () => {
if
(
username
)
{
if
(
username
)
{
memoFind
.
creatorUsername
=
username
;
memoFind
.
creatorUsername
=
username
;
}
}
store
.
dispatch
(
updateLoadingStatus
(
"fetching"
));
const
{
data
}
=
await
api
.
getMemoList
(
memoFind
);
const
{
data
}
=
await
api
.
getMemoList
(
memoFind
);
const
fetchedMemos
=
data
.
map
((
m
)
=>
convertResponseModelMemo
(
m
));
const
fetchedMemos
=
data
.
map
((
m
)
=>
convertResponseModelMemo
(
m
));
store
.
dispatch
(
upsertMemos
(
fetchedMemos
));
store
.
dispatch
(
upsertMemos
(
fetchedMemos
));
store
.
dispatch
(
updateLoadingStatus
(
fetchedMemos
.
length
===
limit
?
"incomplete"
:
"complete"
));
for
(
const
m
of
fetchedMemos
)
{
for
(
const
m
of
fetchedMemos
)
{
memoCacheStore
.
setMemoCache
(
m
);
memoCacheStore
.
setMemoCache
(
m
);
}
}
return
fetchedMemos
;
return
fetchedMemos
;
},
},
fetchAllMemos
:
async
(
limit
=
DEFAULT_MEMO_LIMIT
,
offset
?:
number
)
=>
{
fetchAllMemos
:
async
(
limit
=
DEFAULT_MEMO_LIMIT
,
offset
?:
number
)
=>
{
...
@@ -54,9 +59,12 @@ export const useMemoStore = () => {
...
@@ -54,9 +59,12 @@ export const useMemoStore = () => {
limit
,
limit
,
offset
,
offset
,
};
};
store
.
dispatch
(
updateLoadingStatus
(
"fetching"
));
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
));
store
.
dispatch
(
upsertMemos
(
fetchedMemos
));
store
.
dispatch
(
updateLoadingStatus
(
fetchedMemos
.
length
===
limit
?
"incomplete"
:
"complete"
));
for
(
const
m
of
fetchedMemos
)
{
for
(
const
m
of
fetchedMemos
)
{
memoCacheStore
.
setMemoCache
(
m
);
memoCacheStore
.
setMemoCache
(
m
);
...
...
web/src/store/reducer/memo.ts
View file @
8b0083ff
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
import
{
uniqBy
}
from
"lodash-es"
;
import
{
uniqBy
}
from
"lodash-es"
;
type
LoadingStatus
=
"incomplete"
|
"fetching"
|
"complete"
;
interface
State
{
interface
State
{
loadingStatus
:
LoadingStatus
;
memos
:
Memo
[];
memos
:
Memo
[];
}
}
const
memoSlice
=
createSlice
({
const
memoSlice
=
createSlice
({
name
:
"memo"
,
name
:
"memo"
,
initialState
:
{
initialState
:
{
loadingStatus
:
"incomplete"
,
memos
:
[],
memos
:
[],
}
as
State
,
}
as
State
,
reducers
:
{
reducers
:
{
updateLoadingStatus
:
(
state
,
action
:
PayloadAction
<
LoadingStatus
>
)
=>
{
return
{
...
state
,
loadingStatus
:
action
.
payload
,
};
},
upsertMemos
:
(
state
,
action
:
PayloadAction
<
Memo
[]
>
)
=>
{
upsertMemos
:
(
state
,
action
:
PayloadAction
<
Memo
[]
>
)
=>
{
return
{
return
{
...
state
,
...
state
,
...
@@ -51,6 +61,6 @@ const memoSlice = createSlice({
...
@@ -51,6 +61,6 @@ const memoSlice = createSlice({
},
},
});
});
export
const
{
upsertMemos
,
createMemo
,
patchMemo
,
deleteMemo
}
=
memoSlice
.
actions
;
export
const
{
up
dateLoadingStatus
,
up
sertMemos
,
createMemo
,
patchMemo
,
deleteMemo
}
=
memoSlice
.
actions
;
export
default
memoSlice
.
reducer
;
export
default
memoSlice
.
reducer
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment