Skip to content

Commit

Permalink
feat(next/web): load timeline dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
sdjdd committed Mar 13, 2024
1 parent 3e43ece commit 32385a4
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 133 deletions.
24 changes: 16 additions & 8 deletions next/web/src/App/Admin/Tickets/Ticket/TicketDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import { TicketCard } from './components/TicketCard';
import { useMixedTicket } from './mixed-ticket';
import { TicketField_v1, useTicketFields_v1 } from './api1';
import { CustomFields } from './components/CustomFields';
import { useTicketOpsLogs, useTicketReplies } from './timeline-data';
import { useTimeline } from './timeline-data';
import { RecentTickets } from './components/RecentTickets';
import { Evaluation } from './components/Evaluation';
import { TicketViewers } from './components/TicketViewers';
Expand All @@ -70,20 +70,26 @@ export function TicketDetail() {
restoreOnUnmount: true,
});

const { replies, fetchMoreReplies, refetchReples } = useTicketReplies(ticket?.id);
const { opsLogs, fetchMoreOpsLogs } = useTicketOpsLogs(ticket?.id);
const {
data: timeline,
isLoading: isLoadingTimeline,
isLoadingGap,
loadGap,
refetch: refetchTimeline,
loadMore: loadMoreTimeline,
} = useTimeline(ticket?.id);

const { mutateAsync: createReply } = useCreateReply({
onSuccess: () => {
refetch();
fetchMoreReplies();
loadMoreTimeline();
},
});

const { mutate: operate, isLoading: operating } = useOperateTicket({
onSuccess: () => {
refetch();
fetchMoreOpsLogs();
loadMoreTimeline();
},
});

Expand Down Expand Up @@ -142,9 +148,11 @@ export function TicketDetail() {
onUpdate={update}
/>
}
replies={replies}
opsLogs={opsLogs}
onRefetchReplies={refetchReples}
loading={isLoadingTimeline}
loadingMore={isLoadingGap}
timeline={timeline}
onRefetchReplies={refetchTimeline}
onLoadMore={loadGap}
/>

{ticket.author && (
Expand Down
88 changes: 48 additions & 40 deletions next/web/src/App/Admin/Tickets/Ticket/Timeline/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ReactNode, useMemo, useRef } from 'react';
import { Modal, Skeleton } from 'antd';
import { ReactNode, useRef } from 'react';
import { Button, Divider, Modal, Skeleton } from 'antd';
import cx from 'classnames';

import { ReplySchema, useDeleteReply, useUpdateReply } from '@/api/reply';
Expand All @@ -15,35 +15,32 @@ type TimelineData =
| {
type: 'reply';
data: ReplySchema;
createTime: number;
}
| {
type: 'opsLog';
data: OpsLogSchema;
createTime: number;
}
| {
type: 'gap';
};

interface TimelineProps {
header?: ReactNode;
replies?: ReplySchema[];
opsLogs?: OpsLogSchema[];
timeline?: TimelineData[];
loading?: boolean;
onRefetchReplies: () => void;
onLoadMore?: () => void;
loadingMore?: boolean;
}

export function Timeline({ header, replies, opsLogs, onRefetchReplies }: TimelineProps) {
const timeline = useMemo(() => {
const timeline: TimelineData[] = [];
replies?.forEach((data) =>
timeline.push({ type: 'reply', data, createTime: new Date(data.createdAt).getTime() })
);
opsLogs?.forEach((data) =>
timeline.push({ type: 'opsLog', data, createTime: new Date(data.createdAt).getTime() })
);
return timeline.sort((a, b) => a.createTime - b.createTime);
}, [replies, opsLogs]);

const loading = !replies && !opsLogs;

export function Timeline({
header,
timeline,
loading,
onRefetchReplies,
onLoadMore,
loadingMore,
}: TimelineProps) {
const editReplyModalRef = useRef<EditReplyModalRef>(null!);
const replyRevisionsModalRef = useRef<ReplyRevisionsModalRef>(null!);

Expand Down Expand Up @@ -102,26 +99,37 @@ export function Timeline({ header, replies, opsLogs, onRefetchReplies }: Timelin
>
{header}
{loading && <Skeleton active paragraph={{ rows: 4 }} />}
{timeline.map((timeline) => {
if (timeline.type === 'reply') {
return (
<ReplyCard
key={timeline.data.id}
id={timeline.data.id}
author={<UserLabel user={timeline.data.author} />}
createTime={timeline.data.createdAt}
content={timeline.data.contentSafeHTML}
files={timeline.data.files}
isAgent={timeline.data.isCustomerService}
isInternal={timeline.data.internal}
edited={timeline.data.edited}
deleted={!!timeline.data.deletedAt}
menuItems={createMenuItems(timeline.data)}
onClickMenu={(key) => handleClickMenu(timeline.data, key)}
/>
);
} else {
return <OpsLog key={timeline.data.id} data={timeline.data} />;
{timeline?.map((timeline) => {
switch (timeline.type) {
case 'reply':
return (
<ReplyCard
key={timeline.data.id}
id={timeline.data.id}
author={<UserLabel user={timeline.data.author} />}
createTime={timeline.data.createdAt}
content={timeline.data.contentSafeHTML}
files={timeline.data.files}
isAgent={timeline.data.isCustomerService}
isInternal={timeline.data.internal}
edited={timeline.data.edited}
deleted={!!timeline.data.deletedAt}
menuItems={createMenuItems(timeline.data)}
onClickMenu={(key) => handleClickMenu(timeline.data, key)}
/>
);
case 'opsLog':
return <OpsLog key={timeline.data.id} data={timeline.data} />;
case 'gap':
return (
<div key="gap" className="bg-white py-5">
<Divider>
<Button loading={loadingMore} onClick={() => onLoadMore?.()}>
加载更多...
</Button>
</Divider>
</div>
);
}
})}

Expand Down
Loading

0 comments on commit 32385a4

Please sign in to comment.