From a027917a6be844cf13e9980a4d209f1b6d56e112 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 12 Jan 2021 18:10:58 +0800 Subject: ... --- .../views/timeline-common/TimelinePageTemplate.tsx | 42 +++++++++------------- 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx') diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx index f8b2b38b..e4d414b9 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx @@ -10,8 +10,10 @@ import { getHttpHighlightClient } from "@/http/highlight"; import { TimelineMemberDialog } from "./TimelineMember"; import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog"; -import { TimelinePageTemplateUIProps } from "./TimelinePageTemplateUI"; -import { TimelinePostSendCallback } from "./TimelinePostEdit"; +import { + TimelinePageTemplateData, + TimelinePageTemplateUIProps, +} from "./TimelinePageTemplateUI"; import { TimelinePostInfoEx } from "./Timeline"; import { mergeDataStatus } from "@/services/DataHub2"; @@ -42,26 +44,6 @@ export default function TimelinePageTemplate( const timelineAndStatus = useTimeline(name); const postsAndState = usePosts(name); - const onPost: TimelinePostSendCallback = React.useCallback( - (req) => { - return service.createPost(name, req).toPromise().then(); - }, - [service, name] - ); - - const onManageProp = props.onManage; - - const onManage = React.useCallback( - (item: "property" | TManageItem) => { - if (item === "property") { - setDialog(item); - } else { - onManageProp(item); - } - }, - [onManageProp] - ); - const data = ((): TimelinePageTemplateUIProps["data"] => { const { status, data: timeline } = timelineAndStatus; if (timeline == null) { @@ -98,10 +80,20 @@ export default function TimelinePageTemplate( } })(); - const operations = { - onPost: service.hasPostPermission(user, timeline) ? onPost : undefined, + const operations: TimelinePageTemplateData["operations"] = { + onPost: service.hasPostPermission(user, timeline) + ? (req) => { + return service.createPost(name, req).toPromise().then(); + } + : undefined, onManage: service.hasManagePermission(user, timeline) - ? onManage + ? (item) => { + if (item === "property") { + setDialog(item); + } else { + props.onManage(item); + } + } : undefined, onMember: () => setDialog("member"), onBookmark: -- cgit v1.2.3 From 07eb0d4d777c36da7ea62ea55a2ac3f68e899694 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 12 Jan 2021 22:01:51 +0800 Subject: ... --- FrontEnd/src/app/services/timeline.ts | 15 ++++++-------- .../views/timeline-common/TimelinePageTemplate.tsx | 10 ++-------- .../TimelinePropertyChangeDialog.tsx | 23 ++++++++++------------ 3 files changed, 18 insertions(+), 30 deletions(-) (limited to 'FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx') diff --git a/FrontEnd/src/app/services/timeline.ts b/FrontEnd/src/app/services/timeline.ts index 7d239fbf..4e2530cc 100644 --- a/FrontEnd/src/app/services/timeline.ts +++ b/FrontEnd/src/app/services/timeline.ts @@ -175,15 +175,12 @@ export class TimelineService { changeTimelineProperty( timelineName: string, req: TimelineChangePropertyRequest - ): Observable { - return from( - getHttpTimelineClient() - .patchTimeline(timelineName, req) - .then((timeline) => { - void this.syncTimeline(timelineName); - return timeline; - }) - ); + ): Promise { + return getHttpTimelineClient() + .patchTimeline(timelineName, req) + .then(() => { + void this.syncTimeline(timelineName); + }); } deleteTimeline(timelineName: string): Observable { diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx index e4d414b9..8422077a 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx @@ -173,14 +173,8 @@ export default function TimelinePageTemplate( { - return service.changeTimelineProperty(name, req).toPromise().then(); - }} + timeline={timeline} + onProcess={(req) => service.changeTimelineProperty(name, req)} /> ); } else if (dialog === "member") { diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx index aae227e6..ab3285f5 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx @@ -4,20 +4,15 @@ import { TimelineVisibility, kTimelineVisibilities, TimelineChangePropertyRequest, + TimelineInfo, } from "@/services/timeline"; import OperationDialog from "../common/OperationDialog"; -export interface TimelinePropertyInfo { - title: string; - visibility: TimelineVisibility; - description: string; -} - export interface TimelinePropertyChangeDialogProps { open: boolean; close: () => void; - oldInfo: TimelinePropertyInfo; + timeline: TimelineInfo; onProcess: (request: TimelineChangePropertyRequest) => Promise; } @@ -30,6 +25,8 @@ const labelMap: { [key in TimelineVisibility]: string } = { const TimelinePropertyChangeDialog: React.FC = ( props ) => { + const { timeline } = props; + return ( { type: "text", label: "timeline.dialogChangeProperty.titleField", - initValue: props.oldInfo.title, + initValue: timeline.title, }, { type: "select", @@ -46,25 +43,25 @@ const TimelinePropertyChangeDialog: React.FC label: labelMap[v], value: v, })), - initValue: props.oldInfo.visibility, + initValue: timeline.visibility, }, { type: "text", label: "timeline.dialogChangeProperty.description", - initValue: props.oldInfo.description, + initValue: timeline.description, }, ]} open={props.open} close={props.close} onProcess={([newTitle, newVisibility, newDescription]) => { const req: TimelineChangePropertyRequest = {}; - if (newTitle !== props.oldInfo.title) { + if (newTitle !== timeline.title) { req.title = newTitle; } - if (newVisibility !== props.oldInfo.visibility) { + if (newVisibility !== timeline.visibility) { req.visibility = newVisibility as TimelineVisibility; } - if (newDescription !== props.oldInfo.description) { + if (newDescription !== timeline.description) { req.description = newDescription; } return props.onProcess(req); -- cgit v1.2.3 From 2dbddec6a0419def50efd8136f1cab5dc35fcff3 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 12 Jan 2021 22:09:34 +0800 Subject: ... --- FrontEnd/src/app/services/timeline.ts | 50 +++++++++++++------- .../views/timeline-common/TimelinePageTemplate.tsx | 54 +++++++--------------- 2 files changed, 50 insertions(+), 54 deletions(-) (limited to 'FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx') diff --git a/FrontEnd/src/app/services/timeline.ts b/FrontEnd/src/app/services/timeline.ts index 4e2530cc..46671ea1 100644 --- a/FrontEnd/src/app/services/timeline.ts +++ b/FrontEnd/src/app/services/timeline.ts @@ -26,6 +26,8 @@ export type { TimelineVisibility } from "@/http/timeline"; import { dataStorage } from "./common"; import { userInfoService, AuthUser } from "./user"; import { DataAndStatus, DataHub2 } from "./DataHub2"; +import { getHttpBookmarkClient } from "@/http/bookmark"; +import { getHttpHighlightClient } from "@/http/highlight"; export type TimelineInfo = HttpTimelineInfo; export type TimelineChangePropertyRequest = HttpTimelinePatchRequest; @@ -347,24 +349,20 @@ export class TimelineService { createPost( timelineName: string, request: TimelineCreatePostRequest - ): Observable { - return from( - getHttpTimelineClient() - .postPost(timelineName, request) - .then(() => { - void this.syncPosts(timelineName); - }) - ); + ): Promise { + return getHttpTimelineClient() + .postPost(timelineName, request) + .then(() => { + void this.syncPosts(timelineName); + }); } - deletePost(timelineName: string, postId: number): Observable { - return from( - getHttpTimelineClient() - .deletePost(timelineName, postId) - .then(() => { - void this.syncPosts(timelineName); - }) - ); + deletePost(timelineName: string, postId: number): Promise { + return getHttpTimelineClient() + .deletePost(timelineName, postId) + .then(() => { + void this.syncPosts(timelineName); + }); } isMemberOf(username: string, timeline: TimelineInfo): boolean { @@ -433,6 +431,26 @@ export class TimelineService { user.username === post.author.username) ); } + + setHighlight(timelineName: string, highlight: boolean): Promise { + const client = getHttpHighlightClient(); + const promise = highlight + ? client.put(timelineName) + : client.delete(timelineName); + return promise.then(() => { + void timelineService.syncTimeline(timelineName); + }); + } + + setBookmark(timelineName: string, bookmark: boolean): Promise { + const client = getHttpBookmarkClient(); + const promise = bookmark + ? client.put(timelineName) + : client.delete(timelineName); + return promise.then(() => { + void timelineService.syncTimeline(timelineName); + }); + } } export const timelineService = new TimelineService(); diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx index 8422077a..5c87756c 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx @@ -5,8 +5,6 @@ import { UiLogicError } from "@/common"; import { pushAlert } from "@/services/alert"; import { useUser } from "@/services/user"; import { timelineService, usePosts, useTimeline } from "@/services/timeline"; -import { getHttpBookmarkClient } from "@/http/bookmark"; -import { getHttpHighlightClient } from "@/http/highlight"; import { TimelineMemberDialog } from "./TimelineMember"; import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog"; @@ -66,13 +64,11 @@ export default function TimelinePageTemplate( ...post, onDelete: service.hasModifyPostPermission(user, timeline, post) ? () => { - service.deletePost(name, post.id).subscribe({ - error: () => { - pushAlert({ - type: "danger", - message: t("timeline.deletePostFailed"), - }); - }, + service.deletePost(name, post.id).catch(() => { + pushAlert({ + type: "danger", + message: t("timeline.deletePostFailed"), + }); }); } : undefined, @@ -82,9 +78,7 @@ export default function TimelinePageTemplate( const operations: TimelinePageTemplateData["operations"] = { onPost: service.hasPostPermission(user, timeline) - ? (req) => { - return service.createPost(name, req).toPromise().then(); - } + ? (req) => service.createPost(name, req) : undefined, onManage: service.hasManagePermission(user, timeline) ? (item) => { @@ -99,53 +93,37 @@ export default function TimelinePageTemplate( onBookmark: user != null ? () => { - const { isBookmark } = timeline; - const client = getHttpBookmarkClient(); - const promise = isBookmark - ? client.delete(name) - : client.put(name); - promise.then( - () => { - void timelineService.syncTimeline(name); - }, - () => { + service + .setBookmark(timeline.name, !timeline.isBookmark) + .catch(() => { pushAlert({ message: { type: "i18n", - key: isBookmark + key: timeline.isBookmark ? "timeline.removeBookmarkFail" : "timeline.addBookmarkFail", }, type: "danger", }); - } - ); + }); } : undefined, onHighlight: user != null && user.hasHighlightTimelineAdministrationPermission ? () => { - const { isHighlight } = timeline; - const client = getHttpHighlightClient(); - const promise = isHighlight - ? client.delete(name) - : client.put(name); - promise.then( - () => { - void timelineService.syncTimeline(name); - }, - () => { + service + .setHighlight(timeline.name, !timeline.isHighlight) + .catch(() => { pushAlert({ message: { type: "i18n", - key: isHighlight + key: timeline.isHighlight ? "timeline.removeHighlightFail" : "timeline.addHighlightFail", }, type: "danger", }); - } - ); + }); } : undefined, }; -- cgit v1.2.3 From 9686bab8ec3008623c1f8827df8d831a70ce5e6b Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 12 Jan 2021 22:10:47 +0800 Subject: ... --- FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx') diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx index 5c87756c..5833c541 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx @@ -132,13 +132,9 @@ export default function TimelinePageTemplate( } })(); - const closeDialog = React.useCallback((): void => { - setDialog(null); - }, []); - - let dialogElement: React.ReactElement | undefined; - const timeline = timelineAndStatus?.data; + let dialogElement: React.ReactElement | undefined; + const closeDialog = (): void => setDialog(null); if (dialog === "property") { if (timeline == null || timeline === "notexist") { -- cgit v1.2.3 From 3030f0a84fbba9bd289d49609f700c4bb9a8fbf7 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 12 Jan 2021 23:47:08 +0800 Subject: fix: Fix #205. --- .../views/timeline-common/TimelinePageTemplate.tsx | 34 ++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx') diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx index 5833c541..fc4c52ec 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx @@ -5,6 +5,7 @@ import { UiLogicError } from "@/common"; import { pushAlert } from "@/services/alert"; import { useUser } from "@/services/user"; import { timelineService, usePosts, useTimeline } from "@/services/timeline"; +import { mergeDataStatus } from "@/services/DataHub2"; import { TimelineMemberDialog } from "./TimelineMember"; import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog"; @@ -13,7 +14,6 @@ import { TimelinePageTemplateUIProps, } from "./TimelinePageTemplateUI"; import { TimelinePostInfoEx } from "./Timeline"; -import { mergeDataStatus } from "@/services/DataHub2"; export interface TimelinePageTemplateProps { name: string; @@ -39,9 +39,38 @@ export default function TimelinePageTemplate( null ); + const [scrollBottomKey, setScrollBottomKey] = React.useState(0); + + React.useEffect(() => { + if (scrollBottomKey > 0) { + window.scrollTo(0, document.body.scrollHeight); + } + }, [scrollBottomKey]); + const timelineAndStatus = useTimeline(name); const postsAndState = usePosts(name); + const [ + scrollToBottomNextSyncKey, + setScrollToBottomNextSyncKey, + ] = React.useState(0); + + const scrollToBottomNextSync = (): void => { + setScrollToBottomNextSyncKey((old) => old + 1); + }; + + React.useEffect(() => { + let subscribe = true; + void timelineService.syncPosts(name).then(() => { + if (subscribe) { + setScrollBottomKey((old) => old + 1); + } + }); + return () => { + subscribe = false; + }; + }, [name, scrollToBottomNextSyncKey]); + const data = ((): TimelinePageTemplateUIProps["data"] => { const { status, data: timeline } = timelineAndStatus; if (timeline == null) { @@ -78,7 +107,8 @@ export default function TimelinePageTemplate( const operations: TimelinePageTemplateData["operations"] = { onPost: service.hasPostPermission(user, timeline) - ? (req) => service.createPost(name, req) + ? (req) => + service.createPost(name, req).then(() => scrollToBottomNextSync()) : undefined, onManage: service.hasManagePermission(user, timeline) ? (item) => { -- cgit v1.2.3