diff options
Diffstat (limited to 'FrontEnd/src/app/views')
-rw-r--r-- | FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx | 281 | ||||
-rw-r--r-- | FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx | 26 |
2 files changed, 142 insertions, 165 deletions
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx index f66d14e0..b4058fbe 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx @@ -1,25 +1,20 @@ import React from "react"; import { useTranslation } from "react-i18next"; -import { of } from "rxjs"; -import { catchError } from "rxjs/operators"; import { UiLogicError } from "@/common"; import { pushAlert } from "@/services/alert"; -import { useUser, userInfoService, UserNotExistError } from "@/services/user"; -import { - timelineService, - usePostList, - useTimelineInfo, -} from "@/services/timeline"; +import { useUser } from "@/services/user"; +import { timelineService, usePosts, useTimeline } from "@/services/timeline"; import { getHttpBookmarkClient } from "@/http/bookmark"; import { getHttpHighlightClient } from "@/http/highlight"; +import { getHttpUserClient, HttpUserNotExistError } from "@/http/user"; import { TimelineMemberDialog } from "./TimelineMember"; import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog"; import { TimelinePageTemplateUIProps } from "./TimelinePageTemplateUI"; import { TimelinePostSendCallback } from "./TimelinePostEdit"; -import { TimelineSyncStatus } from "./SyncStatusBadge"; import { TimelinePostInfoEx } from "./Timeline"; +import { mergeDataStatus } from "@/services/DataHub2"; export interface TimelinePageTemplateProps<TManageItem> { name: string; @@ -45,8 +40,8 @@ export default function TimelinePageTemplate<TManageItem>( null ); - const [timelineState, setTimelineState] = useTimelineInfo(name); - const postListState = usePostList(name); + const [timelineAndStatus, setTimelineAndStatus] = useTimeline(name); + const postsAndState = usePosts(name); const onPost: TimelinePostSendCallback = React.useCallback( (req) => { @@ -68,147 +63,122 @@ export default function TimelinePageTemplate<TManageItem>( [onManageProp] ); - const childProps = ((): [ - data: TimelinePageTemplateUIProps<TManageItem>["data"], - syncStatus: TimelineSyncStatus - ] => { - if (timelineState == null) { - return [undefined, "syncing"]; + const data = ((): TimelinePageTemplateUIProps<TManageItem>["data"] => { + const { status, data: timeline } = timelineAndStatus; + if (timeline == null) { + if (status === "offline") { + return { type: "custom", value: "Network Error" }; + } else { + return undefined; + } + } else if (timeline === "notexist") { + return props.notFoundI18nKey; } else { - const { type, timeline } = timelineState; - if (timeline == null) { - if (type === "offline") { - return [{ type: "custom", value: "Network Error" }, "offline"]; - } else if (type === "synced") { - return [props.notFoundI18nKey, "synced"]; + const posts = ((): TimelinePostInfoEx[] | "forbid" | undefined => { + const { data: postsInfo } = postsAndState; + if (postsInfo === "forbid") { + return "forbid"; + } else if (postsInfo === "notexist") { + return undefined; + } else if (postsInfo == null) { + return undefined; } else { - return [undefined, "syncing"]; - } - } else { - if (postListState != null && postListState.type === "notexist") { - return [props.notFoundI18nKey, "synced"]; - } - if (postListState != null && postListState.type === "forbid") { - return ["timeline.messageCantSee", "synced"]; + return postsInfo.posts.map((post) => ({ + ...post, + onDelete: service.hasModifyPostPermission(user, timeline, post) + ? () => { + service.deletePost(name, post.id).subscribe({ + error: () => { + pushAlert({ + type: "danger", + message: t("timeline.deletePostFailed"), + }); + }, + }); + } + : undefined, + })); } + })(); - const posts: - | TimelinePostInfoEx[] - | undefined = postListState?.posts?.map((post) => ({ - ...post, - onDelete: service.hasModifyPostPermission(user, timeline, post) + const operations = { + onPost: service.hasPostPermission(user, timeline) ? onPost : undefined, + onManage: service.hasManagePermission(user, timeline) + ? onManage + : undefined, + onMember: () => setDialog("member"), + onBookmark: + user != null ? () => { - service.deletePost(name, post.id).subscribe({ - error: () => { + const { isBookmark } = timeline; + setTimelineAndStatus({ + ...timelineAndStatus, + data: { + ...timeline, + isBookmark: !isBookmark, + }, + }); + const client = getHttpBookmarkClient(); + const promise = isBookmark + ? client.delete(name) + : client.put(name); + promise.then( + () => { + void timelineService.syncTimeline(name); + }, + () => { pushAlert({ + message: { + type: "i18n", + key: isBookmark + ? "timeline.removeBookmarkFail" + : "timeline.addBookmarkFail", + }, type: "danger", - message: t("timeline.deletePostFailed"), }); + setTimelineAndStatus(timelineAndStatus); + } + ); + } + : undefined, + onHighlight: + user != null && user.hasHighlightTimelineAdministrationPermission + ? () => { + const { isHighlight } = timeline; + setTimelineAndStatus({ + ...timelineAndStatus, + data: { + ...timeline, + isHighlight: !isHighlight, }, }); + const client = getHttpHighlightClient(); + const promise = isHighlight + ? client.delete(name) + : client.put(name); + promise.then( + () => { + void timelineService.syncTimeline(name); + }, + () => { + pushAlert({ + message: { + type: "i18n", + key: isHighlight + ? "timeline.removeHighlightFail" + : "timeline.addHighlightFail", + }, + type: "danger", + }); + setTimelineAndStatus(timelineAndStatus); + } + ); } : undefined, - })); - - const operations = { - onPost: service.hasPostPermission(user, timeline) - ? onPost - : undefined, - onManage: service.hasManagePermission(user, timeline) - ? onManage - : undefined, - onMember: () => setDialog("member"), - onBookmark: - user != null - ? () => { - const { isBookmark } = timeline; - setTimelineState({ - ...timelineState, - timeline: { - ...timeline, - isBookmark: !isBookmark, - }, - }); - const client = getHttpBookmarkClient(); - const promise = isBookmark - ? client.delete(name) - : client.put(name); - promise.then( - () => { - void timelineService.syncTimeline(name); - }, - () => { - pushAlert({ - message: { - type: "i18n", - key: isBookmark - ? "timeline.removeBookmarkFail" - : "timeline.addBookmarkFail", - }, - type: "danger", - }); - setTimelineState(timelineState); - } - ); - } - : undefined, - onHighlight: - user != null && user.hasHighlightTimelineAdministrationPermission - ? () => { - const { isHighlight } = timeline; - setTimelineState({ - ...timelineState, - timeline: { - ...timeline, - isHighlight: !isHighlight, - }, - }); - const client = getHttpHighlightClient(); - const promise = isHighlight - ? client.delete(name) - : client.put(name); - promise.then( - () => { - void timelineService.syncTimeline(name); - }, - () => { - pushAlert({ - message: { - type: "i18n", - key: isHighlight - ? "timeline.removeHighlightFail" - : "timeline.addHighlightFail", - }, - type: "danger", - }); - setTimelineState(timelineState); - } - ); - } - : undefined, - }; + }; - if (type === "cache") { - return [{ timeline, posts, operations }, "syncing"]; - } else if (type === "offline") { - return [{ timeline, posts, operations }, "offline"]; - } else { - if (postListState == null) { - return [{ timeline, posts, operations }, "syncing"]; - } else { - const { type: postListType } = postListState; - if (postListType === "synced") { - return [{ timeline, posts, operations }, "synced"]; - } else if (postListType === "cache") { - return [{ timeline, posts, operations }, "syncing"]; - } else if (postListType === "offline") { - return [{ timeline, posts, operations }, "offline"]; - } - } - } - } + return { timeline, posts, operations }; } - throw new UiLogicError("Failed to calculate TimelinePageUITemplate props."); })(); const closeDialog = React.useCallback((): void => { @@ -217,10 +187,10 @@ export default function TimelinePageTemplate<TManageItem>( let dialogElement: React.ReactElement | undefined; - const timeline = timelineState?.timeline; + const timeline = timelineAndStatus?.data; if (dialog === "property") { - if (timeline == null) { + if (timeline == null || timeline === "notexist") { throw new UiLogicError( "Timeline is null but attempt to open change property dialog." ); @@ -241,7 +211,7 @@ export default function TimelinePageTemplate<TManageItem>( /> ); } else if (dialog === "member") { - if (timeline == null) { + if (timeline == null || timeline === "notexist") { throw new UiLogicError( "Timeline is null but attempt to open change property dialog." ); @@ -256,18 +226,15 @@ export default function TimelinePageTemplate<TManageItem>( service.hasManagePermission(user, timeline) ? { onCheckUser: (u) => { - return userInfoService - .getUserInfo(u) - .pipe( - catchError((e) => { - if (e instanceof UserNotExistError) { - return of(null); - } else { - throw e; - } - }) - ) - .toPromise(); + return getHttpUserClient() + .get(u) + .catch((e) => { + if (e instanceof HttpUserNotExistError) { + return null; + } else { + throw e; + } + }); }, onAddUser: (u) => { return service.addMember(name, u.username).toPromise().then(); @@ -286,7 +253,13 @@ export default function TimelinePageTemplate<TManageItem>( return ( <> - <UiComponent data={childProps[0]} syncStatus={childProps[1]} /> + <UiComponent + data={data} + syncStatus={mergeDataStatus([ + timelineAndStatus.status, + postsAndState.status, + ])} + /> {dialogElement} </> ); diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx index b2824c84..41246175 100644 --- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx +++ b/FrontEnd/src/app/views/timeline-common/TimelinePageTemplateUI.tsx @@ -29,7 +29,7 @@ export interface TimelinePageTemplateUIProps<TManageItems> { data?: | { timeline: TimelineInfo; - posts?: TimelinePostInfoEx[]; + posts?: TimelinePostInfoEx[] | "forbid"; operations: { onManage?: (item: TManageItems | "property") => void; onMember: () => void; @@ -166,16 +166,20 @@ export default function TimelinePageTemplateUI<TManageItems>( /> ) : null} {posts != null ? ( - <div - className="timeline-container" - style={{ minHeight: `calc(100vh - ${56 + bottomSpaceHeight}px)` }} - > - <Timeline - containerRef={timelineRef} - posts={posts} - onResize={triggerResizeEvent} - /> - </div> + posts === "forbid" ? ( + <div>{t("timeline.messageCantSee")}</div> + ) : ( + <div + className="timeline-container" + style={{ minHeight: `calc(100vh - ${56 + bottomSpaceHeight}px)` }} + > + <Timeline + containerRef={timelineRef} + posts={posts} + onResize={triggerResizeEvent} + /> + </div> + ) ) : ( <div className="full-viewport-center-child"> <Spinner variant="primary" animation="grow" /> |