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
339c3875
Commit
339c3875
authored
Sep 22, 2024
by
johnnyjoy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: paged memo list container
parent
41976cb8
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
196 additions
and
239 deletions
+196
-239
PagedMemoList.tsx
web/src/components/PagedMemoList/PagedMemoList.tsx
+81
-0
index.ts
web/src/components/PagedMemoList/index.ts
+3
-0
Archived.tsx
web/src/pages/Archived.tsx
+44
-74
Explore.tsx
web/src/pages/Explore.tsx
+21
-54
Home.tsx
web/src/pages/Home.tsx
+21
-57
UserProfile.tsx
web/src/pages/UserProfile.tsx
+26
-54
No files found.
web/src/components/PagedMemoList/PagedMemoList.tsx
0 → 100644
View file @
339c3875
import
{
Button
}
from
"@mui/joy"
;
import
{
ArrowDownIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts"
;
import
{
useMemoList
,
useMemoStore
}
from
"@/store/v1"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Empty
from
"../Empty"
;
interface
Props
{
renderer
:
(
memo
:
Memo
)
=>
JSX
.
Element
;
listSort
?:
(
list
:
Memo
[])
=>
Memo
[];
filter
?:
string
;
pageSize
?:
number
;
}
interface
State
{
isRequesting
:
boolean
;
nextPageToken
:
string
;
}
const
PagedMemoList
=
(
props
:
Props
)
=>
{
const
t
=
useTranslate
();
const
memoStore
=
useMemoStore
();
const
memoList
=
useMemoList
();
const
[
state
,
setState
]
=
useState
<
State
>
({
isRequesting
:
false
,
nextPageToken
:
""
,
});
const
sortedMemoList
=
props
.
listSort
?
props
.
listSort
(
memoList
.
value
)
:
memoList
.
value
;
const
setIsRequesting
=
(
isRequesting
:
boolean
)
=>
{
setState
((
state
)
=>
({
...
state
,
isRequesting
}));
};
const
fetchMoreMemos
=
async
()
=>
{
setIsRequesting
(
true
);
const
response
=
await
memoStore
.
fetchMemos
({
filter
:
props
.
filter
||
""
,
pageSize
:
props
.
pageSize
||
DEFAULT_LIST_MEMOS_PAGE_SIZE
,
pageToken
:
state
.
nextPageToken
,
});
setState
(()
=>
({
isRequesting
:
false
,
nextPageToken
:
response
.
nextPageToken
,
}));
};
useEffect
(()
=>
{
memoList
.
reset
();
setState
((
state
)
=>
({
...
state
,
nextPageToken
:
""
}));
fetchMoreMemos
();
},
[
props
.
filter
,
props
.
pageSize
]);
return
(
<>
{
sortedMemoList
.
map
((
memo
)
=>
props
.
renderer
(
memo
))
}
{
state
.
nextPageToken
&&
(
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
<
Button
variant=
"plain"
color=
"neutral"
loading=
{
state
.
isRequesting
}
endDecorator=
{
<
ArrowDownIcon
className=
"w-4 h-auto"
/>
}
onClick=
{
()
=>
fetchMoreMemos
()
}
>
{
t
(
"memo.load-more"
)
}
</
Button
>
</
div
>
)
}
{
!
state
.
nextPageToken
&&
sortedMemoList
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
)
}
</>
);
};
export
default
PagedMemoList
;
web/src/components/PagedMemoList/index.ts
0 → 100644
View file @
339c3875
import
PagedMemoList
from
"./PagedMemoList"
;
export
default
PagedMemoList
;
web/src/pages/Archived.tsx
View file @
339c3875
import
{
Button
,
Tooltip
}
from
"@mui/joy"
;
import
{
Tooltip
}
from
"@mui/joy"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArchiveIcon
,
ArchiveRestoreIcon
,
ArrowDownIcon
,
TrashIcon
}
from
"lucide-react"
;
import
{
ArchiveIcon
,
ArchiveRestoreIcon
,
TrashIcon
}
from
"lucide-react"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
use
Effect
,
useState
}
from
"react"
;
import
{
use
Memo
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
Empty
from
"@/components/Empty"
;
import
MemoContent
from
"@/components/MemoContent"
;
import
MemoContent
from
"@/components/MemoContent"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
SearchBar
from
"@/components/SearchBar"
;
import
SearchBar
from
"@/components/SearchBar"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoFilterStore
,
useMemo
List
,
useMemo
Store
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
,
useMemoStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -20,25 +19,9 @@ const Archived = () => {
...
@@ -20,25 +19,9 @@ const Archived = () => {
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
user
=
useCurrentUser
();
const
user
=
useCurrentUser
();
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
const
memoList
=
useMemoList
();
const
memoFilterStore
=
useMemoFilterStore
();
const
memoFilterStore
=
useMemoFilterStore
();
const
[
isRequesting
,
setIsRequesting
]
=
useState
(
true
);
const
[
nextPageToken
,
setNextPageToken
]
=
useState
<
string
>
(
""
);
const
sortedMemos
=
memoList
.
value
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
)
.
sort
((
a
,
b
)
=>
memoFilterStore
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
);
useEffect
(()
=>
{
const
memoListFilter
=
useMemo
(()
=>
{
memoList
.
reset
();
fetchMemos
(
""
);
},
[
memoFilterStore
.
filters
]);
const
fetchMemos
=
async
(
nextPageToken
:
string
)
=>
{
setIsRequesting
(
true
);
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`row_status == "ARCHIVED"`
];
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`row_status == "ARCHIVED"`
];
const
contentSearch
:
string
[]
=
[];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
...
@@ -58,14 +41,8 @@ const Archived = () => {
...
@@ -58,14 +41,8 @@ const Archived = () => {
if
(
tagSearch
.
length
>
0
)
{
if
(
tagSearch
.
length
>
0
)
{
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
}
}
const
response
=
await
memoStore
.
fetchMemos
({
return
filters
.
join
(
" && "
);
pageSize
:
DEFAULT_LIST_MEMOS_PAGE_SIZE
,
},
[
user
,
memoFilterStore
.
filters
]);
filter
:
filters
.
join
(
" && "
),
pageToken
:
nextPageToken
,
});
setIsRequesting
(
false
);
setNextPageToken
(
response
.
nextPageToken
);
};
const
handleDeleteMemoClick
=
async
(
memo
:
Memo
)
=>
{
const
handleDeleteMemoClick
=
async
(
memo
:
Memo
)
=>
{
const
confirmed
=
window
.
confirm
(
t
(
"memo.delete-confirm"
));
const
confirmed
=
window
.
confirm
(
t
(
"memo.delete-confirm"
));
...
@@ -105,52 +82,45 @@ const Archived = () => {
...
@@ -105,52 +82,45 @@ const Archived = () => {
</
div
>
</
div
>
</
div
>
</
div
>
<
MemoFilters
/>
<
MemoFilters
/>
{
sortedMemos
.
map
((
memo
)
=>
(
<
PagedMemoList
<
div
renderer=
{
(
memo
:
Memo
)
=>
(
key=
{
memo
.
name
}
<
div
className=
"relative flex flex-col justify-start items-start w-full p-4 pt-3 mb-2 bg-white dark:bg-zinc-800 rounded-lg"
key=
{
memo
.
name
}
>
className=
"relative flex flex-col justify-start items-start w-full p-4 pt-3 mb-2 bg-white dark:bg-zinc-800 rounded-lg"
<
div
className=
"w-full mb-1 flex flex-row justify-between items-center"
>
>
<
div
className=
"w-full max-w-[calc(100%-20px)] flex flex-row justify-start items-center mr-1"
>
<
div
className=
"w-full mb-1 flex flex-row justify-between items-center"
>
<
div
className=
"text-sm leading-6 text-gray-400 select-none"
>
<
div
className=
"w-full max-w-[calc(100%-20px)] flex flex-row justify-start items-center mr-1"
>
<
relative
-
time
datetime=
{
memo
.
displayTime
?.
toISOString
()
}
tense=
"past"
></
relative
-
time
>
<
div
className=
"text-sm leading-6 text-gray-400 select-none"
>
<
relative
-
time
datetime=
{
memo
.
displayTime
?.
toISOString
()
}
tense=
"past"
></
relative
-
time
>
</
div
>
</
div
>
<
div
className=
"flex flex-row justify-end items-center gap-x-2"
>
<
Tooltip
title=
{
t
(
"common.restore"
)
}
placement=
"top"
>
<
button
onClick=
{
()
=>
handleRestoreMemoClick
(
memo
)
}
>
<
ArchiveRestoreIcon
className=
"w-4 h-auto cursor-pointer text-gray-500 dark:text-gray-400"
/>
</
button
>
</
Tooltip
>
<
Tooltip
title=
{
t
(
"common.delete"
)
}
placement=
"top"
>
<
button
onClick=
{
()
=>
handleDeleteMemoClick
(
memo
)
}
className=
"text-gray-500 dark:text-gray-400"
>
<
TrashIcon
className=
"w-4 h-auto cursor-pointer"
/>
</
button
>
</
Tooltip
>
</
div
>
</
div
>
</
div
>
</
div
>
<
div
className=
"flex flex-row justify-end items-center gap-x-2"
>
<
MemoContent
key=
{
`${memo.name}-${memo.displayTime}`
}
memoName=
{
memo
.
name
}
nodes=
{
memo
.
nodes
}
readonly=
{
true
}
/>
<
Tooltip
title=
{
t
(
"common.restore"
)
}
placement=
"top"
>
<
button
onClick=
{
()
=>
handleRestoreMemoClick
(
memo
)
}
>
<
ArchiveRestoreIcon
className=
"w-4 h-auto cursor-pointer text-gray-500 dark:text-gray-400"
/>
</
button
>
</
Tooltip
>
<
Tooltip
title=
{
t
(
"common.delete"
)
}
placement=
"top"
>
<
button
onClick=
{
()
=>
handleDeleteMemoClick
(
memo
)
}
className=
"text-gray-500 dark:text-gray-400"
>
<
TrashIcon
className=
"w-4 h-auto cursor-pointer"
/>
</
button
>
</
Tooltip
>
</
div
>
</
div
>
</
div
>
<
MemoContent
key=
{
`${memo.name}-${memo.displayTime}`
}
memoName=
{
memo
.
name
}
nodes=
{
memo
.
nodes
}
readonly=
{
true
}
/>
)
}
</
div
>
listSort=
{
(
memos
:
Memo
[])
=>
))
}
memos
{
nextPageToken
&&
(
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
)
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
.
sort
((
a
,
b
)
=>
<
Button
memoFilterStore
.
orderByTimeAsc
variant=
"plain"
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
color=
"neutral"
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
loading=
{
isRequesting
}
)
endDecorator=
{
<
ArrowDownIcon
className=
"w-4 h-auto"
/>
}
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
filter=
{
memoListFilter
}
>
/>
{
t
(
"memo.load-more"
)
}
</
Button
>
</
div
>
)
}
{
!
nextPageToken
&&
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
)
}
</
div
>
</
div
>
</
div
>
</
div
>
</
section
>
</
section
>
...
...
web/src/pages/Explore.tsx
View file @
339c3875
import
{
Button
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArrowDownIcon
}
from
"lucide-react"
;
import
{
useMemo
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
Empty
from
"@/components/Empty"
;
import
{
ExploreSidebar
,
ExploreSidebarDrawer
}
from
"@/components/ExploreSidebar"
;
import
{
ExploreSidebar
,
ExploreSidebarDrawer
}
from
"@/components/ExploreSidebar"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoView
from
"@/components/MemoView"
;
import
MemoView
from
"@/components/MemoView"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts
"
;
import
PagedMemoList
from
"@/components/PagedMemoList
"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
{
useMemoFilterStore
,
useMemoList
,
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
const
Explore
=
()
=>
{
const
Explore
=
()
=>
{
const
t
=
useTranslate
();
const
{
md
}
=
useResponsiveWidth
();
const
{
md
}
=
useResponsiveWidth
();
const
user
=
useCurrentUser
();
const
user
=
useCurrentUser
();
const
memoStore
=
useMemoStore
();
const
memoList
=
useMemoList
();
const
memoFilterStore
=
useMemoFilterStore
();
const
memoFilterStore
=
useMemoFilterStore
();
const
[
isRequesting
,
setIsRequesting
]
=
useState
(
true
);
const
[
nextPageToken
,
setNextPageToken
]
=
useState
<
string
>
(
""
);
const
sortedMemos
=
memoList
.
value
.
sort
((
a
,
b
)
=>
memoFilterStore
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
);
useEffect
(()
=>
{
memoList
.
reset
();
fetchMemos
(
""
);
},
[
memoFilterStore
.
filters
]);
const
fetchMemos
=
async
(
nextPageToken
:
string
)
=>
{
const
memoListFilter
=
useMemo
(()
=>
{
setIsRequesting
(
true
);
const
filters
=
[
`row_status == "NORMAL"`
,
`visibilities == [
${
user
?
"'PUBLIC', 'PROTECTED'"
:
"'PUBLIC'"
}
]`
];
const
filters
=
[
`row_status == "NORMAL"`
,
`visibilities == [
${
user
?
"'PUBLIC', 'PROTECTED'"
:
"'PUBLIC'"
}
]`
];
const
contentSearch
:
string
[]
=
[];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
...
@@ -55,14 +37,8 @@ const Explore = () => {
...
@@ -55,14 +37,8 @@ const Explore = () => {
if
(
tagSearch
.
length
>
0
)
{
if
(
tagSearch
.
length
>
0
)
{
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
}
}
const
response
=
await
memoStore
.
fetchMemos
({
return
filters
.
join
(
" && "
);
pageSize
:
DEFAULT_LIST_MEMOS_PAGE_SIZE
,
},
[
user
,
memoFilterStore
.
filters
,
memoFilterStore
.
orderByTimeAsc
]);
filter
:
filters
.
join
(
" && "
),
pageToken
:
nextPageToken
,
});
setIsRequesting
(
false
);
setNextPageToken
(
response
.
nextPageToken
);
};
return
(
return
(
<
section
className=
"@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8"
>
<
section
className=
"@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8"
>
...
@@ -75,28 +51,19 @@ const Explore = () => {
...
@@ -75,28 +51,19 @@ const Explore = () => {
<
div
className=
{
clsx
(
md
?
"w-[calc(100%-15rem)]"
:
"w-full"
)
}
>
<
div
className=
{
clsx
(
md
?
"w-[calc(100%-15rem)]"
:
"w-full"
)
}
>
<
MemoFilters
/>
<
MemoFilters
/>
<
div
className=
"flex flex-col justify-start items-start w-full max-w-full"
>
<
div
className=
"flex flex-col justify-start items-start w-full max-w-full"
>
{
sortedMemos
.
map
((
memo
)
=>
(
<
PagedMemoList
<
MemoView
key=
{
`${memo.name}-${memo.updateTime}`
}
memo=
{
memo
}
showCreator
showVisibility
showPinned
compact
/>
renderer=
{
(
memo
:
Memo
)
=>
<
MemoView
key=
{
`${memo.name}-${memo.updateTime}`
}
memo=
{
memo
}
showCreator
showVisibility
compact
/>
}
))
}
listSort=
{
(
memos
:
Memo
[])
=>
{
nextPageToken
&&
(
memos
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
<
Button
.
sort
((
a
,
b
)
=>
variant=
"plain"
memoFilterStore
.
orderByTimeAsc
color=
"neutral"
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
loading=
{
isRequesting
}
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
endDecorator=
{
<
ArrowDownIcon
className=
"w-4 h-auto"
/>
}
)
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
}
>
filter=
{
memoListFilter
}
{
t
(
"memo.load-more"
)
}
/>
</
Button
>
</
div
>
)
}
{
!
nextPageToken
&&
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
)
}
</
div
>
</
div
>
</
div
>
</
div
>
{
md
&&
(
{
md
&&
(
...
...
web/src/pages/Home.tsx
View file @
339c3875
import
{
Button
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArrowDownIcon
}
from
"lucide-react"
;
import
{
useMemo
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
Empty
from
"@/components/Empty"
;
import
{
HomeSidebar
,
HomeSidebarDrawer
}
from
"@/components/HomeSidebar"
;
import
{
HomeSidebar
,
HomeSidebarDrawer
}
from
"@/components/HomeSidebar"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoView
from
"@/components/MemoView"
;
import
MemoView
from
"@/components/MemoView"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts
"
;
import
PagedMemoList
from
"@/components/PagedMemoList
"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
{
useMemoFilterStore
,
useMemoList
,
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
useTranslate
}
from
"@/utils/i18n
"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service
"
;
const
Home
=
()
=>
{
const
Home
=
()
=>
{
const
t
=
useTranslate
();
const
{
md
}
=
useResponsiveWidth
();
const
{
md
}
=
useResponsiveWidth
();
const
user
=
useCurrentUser
();
const
user
=
useCurrentUser
();
const
memoStore
=
useMemoStore
();
const
memoList
=
useMemoList
();
const
memoFilterStore
=
useMemoFilterStore
();
const
memoFilterStore
=
useMemoFilterStore
();
const
[
isRequesting
,
setIsRequesting
]
=
useState
(
true
);
const
[
nextPageToken
,
setNextPageToken
]
=
useState
<
string
>
(
""
);
const
sortedMemos
=
memoList
.
value
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
.
sort
((
a
,
b
)
=>
memoFilterStore
.
orderByTimeAsc
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
)
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
));
useEffect
(()
=>
{
const
memoListFilter
=
useMemo
(()
=>
{
memoList
.
reset
();
fetchMemos
(
""
);
},
[
memoFilterStore
.
filters
]);
const
fetchMemos
=
async
(
nextPageToken
:
string
)
=>
{
setIsRequesting
(
true
);
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`row_status == "NORMAL"`
,
`order_by_pinned == true`
];
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`row_status == "NORMAL"`
,
`order_by_pinned == true`
];
const
contentSearch
:
string
[]
=
[];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
...
@@ -70,14 +48,8 @@ const Home = () => {
...
@@ -70,14 +48,8 @@ const Home = () => {
if
(
tagSearch
.
length
>
0
)
{
if
(
tagSearch
.
length
>
0
)
{
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
}
}
const
response
=
await
memoStore
.
fetchMemos
({
return
filters
.
join
(
" && "
);
pageSize
:
DEFAULT_LIST_MEMOS_PAGE_SIZE
,
},
[
user
,
memoFilterStore
.
filters
,
memoFilterStore
.
orderByTimeAsc
]);
filter
:
filters
.
join
(
" && "
),
pageToken
:
nextPageToken
,
});
setIsRequesting
(
false
);
setNextPageToken
(
response
.
nextPageToken
);
};
return
(
return
(
<
section
className=
"@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8"
>
<
section
className=
"@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8"
>
...
@@ -91,28 +63,20 @@ const Home = () => {
...
@@ -91,28 +63,20 @@ const Home = () => {
<
MemoEditor
className=
"mb-2"
cacheKey=
"home-memo-editor"
/>
<
MemoEditor
className=
"mb-2"
cacheKey=
"home-memo-editor"
/>
<
MemoFilters
/>
<
MemoFilters
/>
<
div
className=
"flex flex-col justify-start items-start w-full max-w-full"
>
<
div
className=
"flex flex-col justify-start items-start w-full max-w-full"
>
{
sortedMemos
.
map
((
memo
)
=>
(
<
PagedMemoList
<
MemoView
key=
{
`${memo.name}-${memo.updateTime}`
}
memo=
{
memo
}
showVisibility
showPinned
compact
/>
renderer=
{
(
memo
:
Memo
)
=>
<
MemoView
key=
{
`${memo.name}-${memo.displayTime}`
}
memo=
{
memo
}
showVisibility
showPinned
compact
/>
}
))
}
listSort=
{
(
memos
:
Memo
[])
=>
{
nextPageToken
&&
(
memos
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
<
Button
.
sort
((
a
,
b
)
=>
variant=
"plain"
memoFilterStore
.
orderByTimeAsc
color=
"neutral"
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
loading=
{
isRequesting
}
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
endDecorator=
{
<
ArrowDownIcon
className=
"w-4 h-auto"
/>
}
)
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
))
>
}
{
t
(
"memo.load-more"
)
}
filter=
{
memoListFilter
}
</
Button
>
/>
</
div
>
)
}
{
!
nextPageToken
&&
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
)
}
</
div
>
</
div
>
</
div
>
</
div
>
{
md
&&
(
{
md
&&
(
...
...
web/src/pages/UserProfile.tsx
View file @
339c3875
import
{
Button
}
from
"@mui/joy"
;
import
{
Button
}
from
"@mui/joy"
;
import
copy
from
"copy-to-clipboard"
;
import
copy
from
"copy-to-clipboard"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArrowDownIcon
,
ExternalLinkIcon
}
from
"lucide-react"
;
import
{
ExternalLinkIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
use
Memo
,
use
State
}
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
Empty
from
"@/components/Empty"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoView
from
"@/components/MemoView"
;
import
MemoView
from
"@/components/MemoView"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
PagedMemoList
from
"@/components/PagedMemoList"
;
import
UserAvatar
from
"@/components/UserAvatar"
;
import
UserAvatar
from
"@/components/UserAvatar"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
useMemoFilterStore
,
useMemoList
,
useMemoStore
,
useUserStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
,
useUserStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -22,14 +23,7 @@ const UserProfile = () => {
...
@@ -22,14 +23,7 @@ const UserProfile = () => {
const
userStore
=
useUserStore
();
const
userStore
=
useUserStore
();
const
loadingState
=
useLoading
();
const
loadingState
=
useLoading
();
const
[
user
,
setUser
]
=
useState
<
User
>
();
const
[
user
,
setUser
]
=
useState
<
User
>
();
const
memoStore
=
useMemoStore
();
const
memoList
=
useMemoList
();
const
memoFilterStore
=
useMemoFilterStore
();
const
memoFilterStore
=
useMemoFilterStore
();
const
[
isRequesting
,
setIsRequesting
]
=
useState
(
true
);
const
[
nextPageToken
,
setNextPageToken
]
=
useState
<
string
>
(
""
);
const
sortedMemos
=
memoList
.
value
.
sort
((
a
,
b
)
=>
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
())
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
));
useEffect
(()
=>
{
useEffect
(()
=>
{
const
username
=
params
.
username
;
const
username
=
params
.
username
;
...
@@ -53,21 +47,11 @@ const UserProfile = () => {
...
@@ -53,21 +47,11 @@ const UserProfile = () => {
});
});
},
[
params
.
username
]);
},
[
params
.
username
]);
useEffect
(()
=>
{
const
memoListFilter
=
useMemo
(()
=>
{
if
(
!
user
)
{
return
;
}
memoList
.
reset
();
fetchMemos
(
""
);
},
[
user
,
memoFilterStore
.
filters
]);
const
fetchMemos
=
async
(
nextPageToken
:
string
)
=>
{
if
(
!
user
)
{
if
(
!
user
)
{
return
;
return
""
;
}
}
setIsRequesting
(
true
);
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`row_status == "NORMAL"`
,
`order_by_pinned == true`
];
const
filters
=
[
`creator == "
${
user
.
name
}
"`
,
`row_status == "NORMAL"`
,
`order_by_pinned == true`
];
const
contentSearch
:
string
[]
=
[];
const
contentSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
const
tagSearch
:
string
[]
=
[];
...
@@ -84,14 +68,8 @@ const UserProfile = () => {
...
@@ -84,14 +68,8 @@ const UserProfile = () => {
if
(
tagSearch
.
length
>
0
)
{
if
(
tagSearch
.
length
>
0
)
{
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
filters
.
push
(
`tag_search == [
${
tagSearch
.
join
(
", "
)}
]`
);
}
}
const
response
=
await
memoStore
.
fetchMemos
({
return
filters
.
join
(
" && "
);
pageSize
:
DEFAULT_LIST_MEMOS_PAGE_SIZE
,
},
[
user
,
memoFilterStore
.
filters
]);
filter
:
filters
.
join
(
" && "
),
pageToken
:
nextPageToken
,
});
setIsRequesting
(
false
);
setNextPageToken
(
response
.
nextPageToken
);
};
const
handleCopyProfileLink
=
()
=>
{
const
handleCopyProfileLink
=
()
=>
{
if
(
!
user
)
{
if
(
!
user
)
{
...
@@ -131,28 +109,22 @@ const UserProfile = () => {
...
@@ -131,28 +109,22 @@ const UserProfile = () => {
</
div
>
</
div
>
</
div
>
</
div
>
<
MemoFilters
/>
<
MemoFilters
/>
{
sortedMemos
.
map
((
memo
)
=>
(
<
PagedMemoList
<
MemoView
key=
{
`${memo.name}-${memo.displayTime}`
}
memo=
{
memo
}
showVisibility
showPinned
compact
/>
renderer=
{
(
memo
:
Memo
)
=>
(
))
}
<
MemoView
key=
{
`${memo.name}-${memo.displayTime}`
}
memo=
{
memo
}
showVisibility
showPinned
compact
/>
{
nextPageToken
&&
(
)
}
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
listSort=
{
(
memos
:
Memo
[])
=>
<
Button
memos
variant=
"plain"
.
filter
((
memo
)
=>
memo
.
rowStatus
===
RowStatus
.
ACTIVE
)
color=
"neutral"
.
sort
((
a
,
b
)
=>
loading=
{
isRequesting
}
memoFilterStore
.
orderByTimeAsc
endDecorator=
{
<
ArrowDownIcon
className=
"w-4 h-auto"
/>
}
?
dayjs
(
a
.
displayTime
).
unix
()
-
dayjs
(
b
.
displayTime
).
unix
()
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
:
dayjs
(
b
.
displayTime
).
unix
()
-
dayjs
(
a
.
displayTime
).
unix
(),
>
)
{
t
(
"memo.load-more"
)
}
.
sort
((
a
,
b
)
=>
Number
(
b
.
pinned
)
-
Number
(
a
.
pinned
))
</
Button
>
}
</
div
>
filter=
{
memoListFilter
}
)
}
/>
{
!
nextPageToken
&&
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
)
}
</>
</>
)
:
(
)
:
(
<
p
>
Not found
</
p
>
<
p
>
Not found
</
p
>
...
...
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