Skip to content

Commit 7ff3344

Browse files
authored
fix: support publish pages sorted by publish time (#14)
* fix: support publish pages sorted by publish time * fix: add publish pages skeleton
1 parent 50d33e7 commit 7ff3344

File tree

5 files changed

+96
-65
lines changed

5 files changed

+96
-65
lines changed

src/application/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,9 @@ export interface View {
846846
last_viewed_at?: string;
847847
created_at?: string;
848848
database_relations?: DatabaseRelations;
849+
publisher_email?: string;
850+
publish_name?: string;
851+
publish_timestamp?: string;
849852
}
850853

851854
export interface Invitation {

src/components/app/publish-manage/PublishManage.tsx

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { flattenViews } from '@/components/_shared/outline/utils';
44
import { useAppHandlers, useUserWorkspaceInfo } from '@/components/app/app.hooks';
55
import HomePageSetting from '@/components/app/publish-manage/HomePageSetting';
66
import PublishedPages from '@/components/app/publish-manage/PublishedPages';
7+
import PublishPagesSkeleton from '@/components/app/publish-manage/PublishPagesSkeleton';
78
import UpdateNamespace from '@/components/app/publish-manage/UpdateNamespace';
89
import { useCurrentUser, useService } from '@/components/main/app.hooks';
910
import { openUrl } from '@/utils/url';
10-
import { Button, Divider, IconButton, Tooltip } from '@mui/material';
11+
import { Button, CircularProgress, Divider, IconButton, Tooltip } from '@mui/material';
1112
import React, { useCallback, useEffect, useMemo } from 'react';
1213
import { useTranslation } from 'react-i18next';
1314
import { ReactComponent as EditIcon } from '@/assets/edit.svg';
@@ -64,8 +65,14 @@ export function PublishManage ({
6465
setLoading(true);
6566
try {
6667
const outline = await service.getPublishOutline(namespace);
67-
68-
setPublishViews(flattenViews(outline).filter(item => item.is_published));
68+
69+
setPublishViews(flattenViews(outline).filter(item => item.is_published).sort((a, b) => {
70+
if (!a.publish_timestamp || !b.publish_timestamp) {
71+
return 0;
72+
}
73+
74+
return new Date(b.publish_timestamp).getTime() - new Date(a.publish_timestamp).getTime();
75+
}));
6976
// eslint-disable-next-line
7077
} catch (e: any) {
7178
console.error(e);
@@ -261,7 +268,10 @@ export function PublishManage ({
261268
</div>
262269
</div>
263270

264-
<div className={'text-base mt-4 px-1 font-medium'}>{t('settings.sites.publishedPage.title')}</div>
271+
<div className={'text-base flex items-center gap-2 mt-4 px-1 font-medium'}>
272+
{t('settings.sites.publishedPage.title')}
273+
{loading && <CircularProgress size={14} />}
274+
</div>
265275
<div className={'text-text-caption px-1 text-xs'}>{t('settings.sites.publishedPage.description')}</div>
266276
<Divider className={'mb-2'} />
267277
<div className={'w-full px-1 flex text-sm font-medium items-center gap-4'}>
@@ -273,13 +283,14 @@ export function PublishManage ({
273283
</div>
274284

275285
<Divider className={'mb-1'} />
276-
<PublishedPages
277-
loading={loading}
278-
publishViews={publishViews}
279-
onPublish={handlePublish}
280-
onClose={onClose}
281-
onUnPublish={handleUnpublish}
282-
/>
286+
{loading && !publishViews.length ? <PublishPagesSkeleton /> :
287+
<PublishedPages
288+
publishViews={publishViews}
289+
onPublish={handlePublish}
290+
onClose={onClose}
291+
onUnPublish={handleUnpublish}
292+
namespace={namespace}
293+
/>}
283294

284295
{updateOpen && <UpdateNamespace
285296
namespace={namespace}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Skeleton } from '@mui/material';
2+
import React from 'react';
3+
4+
function PublishPagesSkeleton () {
5+
return (
6+
<>
7+
{
8+
Array.from({ length: 5 }).map((_, index) => (
9+
<div
10+
key={index}
11+
className={'w-full px-1 flex text-sm font-medium items-center gap-4'}
12+
>
13+
{
14+
Array.from({ length: 3 }).map((_, i) => (
15+
<div
16+
key={i}
17+
className={'flex-1'}
18+
>
19+
<Skeleton
20+
height={24}
21+
variant={'text'}
22+
width={100}
23+
/>
24+
</div>
25+
))
26+
}
27+
</div>))
28+
}
29+
</>
30+
);
31+
}
32+
33+
export default PublishPagesSkeleton;

src/components/app/publish-manage/PublishedPageItem.tsx

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,44 @@ import { Popover } from '@/components/_shared/popover';
44
import PageIcon from '@/components/_shared/view-icon/PageIcon';
55
import { useAppHandlers, useUserWorkspaceInfo } from '@/components/app/app.hooks';
66
import { PublishNameSetting } from '@/components/app/publish-manage/PublishNameSetting';
7-
import { useCurrentUser, useService } from '@/components/main/app.hooks';
7+
import { useCurrentUser } from '@/components/main/app.hooks';
88
import { copyTextToClipboard } from '@/utils/copy';
99
import { openUrl } from '@/utils/url';
1010
import { Button, CircularProgress, IconButton, Tooltip } from '@mui/material';
1111
import dayjs from 'dayjs';
12-
import React, { useCallback, useEffect, useMemo } from 'react';
12+
import React, { useEffect, useMemo } from 'react';
1313
import { useTranslation } from 'react-i18next';
1414
import { ReactComponent as MoreIcon } from '@/assets/more.svg';
1515
import { ReactComponent as GlobalIcon } from '@/assets/publish.svg';
1616
import { ReactComponent as CopyIcon } from '@/assets/copy.svg';
1717
import { ReactComponent as TrashIcon } from '@/assets/trash.svg';
1818
import { ReactComponent as SettingIcon } from '@/assets/settings.svg';
1919

20-
function PublishedPageItem ({ onClose, view, onUnPublish, onPublish }: {
20+
function PublishedPageItem ({ namespace, onClose, view, onUnPublish, onPublish }: {
2121
view: View,
2222
onClose?: () => void;
2323
onUnPublish: (viewId: string) => Promise<void>;
2424
onPublish: (view: View, publishName: string) => Promise<void>
25+
namespace: string;
2526
}) {
2627
const { t } = useTranslation();
2728
const [openSetting, setOpenSetting] = React.useState<boolean>(false);
2829
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
29-
const [publishInfo, setPublishInfo] = React.useState<{
30-
namespace: string,
31-
publishName: string,
32-
publisherEmail: string
33-
publishedAt: string
34-
} | undefined>(undefined);
30+
const [publishName, setPublishName] = React.useState<string>(view.publish_name || '');
3531
const toView = useAppHandlers().toView;
36-
const service = useService();
3732
const [unPublishLoading, setUnPublishLoading] = React.useState<boolean>(false);
3833
const userWorkspaceInfo = useUserWorkspaceInfo();
3934
const currentUser = useCurrentUser();
4035
const isOwner = userWorkspaceInfo?.selectedWorkspace?.owner?.uid.toString() === currentUser?.uid.toString();
41-
const isPublisher = publishInfo?.publisherEmail === currentUser?.email;
36+
const isPublisher = view?.publisher_email === currentUser?.email;
4237

43-
const getPublishInfo = useCallback(async (viewId: string) => {
44-
if (!service) return;
45-
46-
try {
47-
const res = await service?.getPublishInfo(viewId);
48-
49-
setPublishInfo(res);
50-
return res;
51-
} catch (e) {
52-
console.error(e);
53-
}
54-
}, [service]);
38+
useEffect(() => {
39+
setPublishName(view.publish_name || '');
40+
}, [view.publish_name]);
5541

5642
const url = useMemo(() => {
57-
return `${window.origin}/${publishInfo?.namespace}/${publishInfo?.publishName}`;
58-
}, [publishInfo]);
59-
60-
useEffect(() => {
61-
void getPublishInfo(view.view_id);
62-
}, [getPublishInfo, view.view_id]);
43+
return `${window.origin}/${namespace}/${publishName}`;
44+
}, [namespace, publishName]);
6345

6446
const actions = useMemo(() => {
6547
return [
@@ -156,7 +138,7 @@ function PublishedPageItem ({ onClose, view, onUnPublish, onPublish }: {
156138
<Tooltip
157139
disableInteractive={true}
158140
title={<div className={'whitespace-pre-wrap break-words'}>
159-
{`Open Page in New Tab \n${publishInfo?.publishName || ''}`}
141+
{`Open Page in New Tab \n${publishName || ''}`}
160142
</div>}
161143
>
162144
<Button
@@ -169,13 +151,13 @@ function PublishedPageItem ({ onClose, view, onUnPublish, onPublish }: {
169151
className={'w-full p-1 px-2 justify-start overflow-hidden'}
170152
>
171153
<span className={'truncate'}>
172-
{publishInfo?.publishName}
154+
{publishName}
173155
</span>
174156
</Button>
175157
</Tooltip>
176158
</div>
177159
<div className={'flex-1 overflow-hidden flex gap-2 justify-between'}>
178-
{dayjs(publishInfo?.publishedAt).format('MMM D, YYYY')}
160+
{view?.publish_timestamp ? dayjs(view.publish_timestamp).format('MMM D, YYYY') : ''}
179161
<IconButton
180162
onClick={(e) => {
181163
setAnchorEl(e.currentTarget);
@@ -204,27 +186,30 @@ function PublishedPageItem ({ onClose, view, onUnPublish, onPublish }: {
204186
onClick={action.onClick}
205187
size={'small'}
206188
className={'justify-start'}
207-
startIcon={<action.IconComponent className={'w-4 h-4'} />}
189+
startIcon={<action.IconComponent
190+
size={14}
191+
className={'w-4 h-4'}
192+
/>}
208193
color={'inherit'}
209194
>{action.label}</Button>
210195
</Tooltip>;
211196
})}
212197
</div>
213198
</Popover>
214-
{openSetting && publishInfo && <PublishNameSetting
199+
{openSetting && <PublishNameSetting
215200
onUnPublish={() => {
216201
return onUnPublish(view.view_id);
217202
}}
218203
onPublish={async (publishName: string) => {
219204
await onPublish(view, publishName);
220-
void getPublishInfo(view.view_id);
205+
setPublishName(publishName);
221206
}}
222207
onClose={() => {
223208
setOpenSetting(false);
224209
}}
225210
url={url}
226211
open={openSetting}
227-
defaultName={publishInfo.publishName}
212+
defaultName={publishName}
228213
/>}
229214
</div>
230215
);

src/components/app/publish-manage/PublishedPages.tsx

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,40 @@
11
import { View } from '@/application/types';
22

33
import PublishedPageItem from '@/components/app/publish-manage/PublishedPageItem';
4-
import { CircularProgress, Divider } from '@mui/material';
4+
import { Divider } from '@mui/material';
55

66
import React from 'react';
77

88
function PublishedPages ({
99
publishViews,
1010
onUnPublish,
1111
onPublish,
12-
loading,
1312
onClose,
13+
namespace,
1414
}: {
1515
publishViews: View[];
16-
loading: boolean;
1716
onUnPublish: (viewId: string) => Promise<void>;
1817
onPublish: (view: View, publishName: string) => Promise<void>;
19-
onClose?: () => void
18+
onClose?: () => void;
19+
namespace: string;
2020
}) {
2121

2222
return (
2323
<div className={'flex flex-col gap-2'}>
2424

25-
{loading ? <div className={'flex justify-center w-full items-center'}>
26-
<CircularProgress size={20} /></div>
27-
: publishViews.map((view, index) => {
28-
return <React.StrictMode key={view.view_id}>
29-
<PublishedPageItem
30-
onClose={onClose}
31-
view={view}
32-
onUnPublish={onUnPublish}
33-
onPublish={onPublish}
34-
/>
35-
{index !== publishViews.length - 1 && <Divider />}
36-
37-
</React.StrictMode>;
38-
})}
25+
{publishViews.map((view, index) => {
26+
return <React.StrictMode key={view.view_id}>
27+
<PublishedPageItem
28+
namespace={namespace}
29+
onClose={onClose}
30+
view={view}
31+
onUnPublish={onUnPublish}
32+
onPublish={onPublish}
33+
/>
34+
{index !== publishViews.length - 1 && <Divider />}
35+
36+
</React.StrictMode>;
37+
})}
3938

4039
</div>
4140
);

0 commit comments

Comments
 (0)