aboutsummaryrefslogtreecommitdiff
path: root/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-10-27 19:21:35 +0800
committercrupest <crupest@outlook.com>2020-10-27 19:21:35 +0800
commitac769e656b122ff569c3f1534701b71e00fed586 (patch)
tree72966645ff1e25139d3995262e1c4349f2c14733 /Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
parent14e5848c23c643cea9b5d709770747d98c3d75e2 (diff)
downloadtimeline-ac769e656b122ff569c3f1534701b71e00fed586.tar.gz
timeline-ac769e656b122ff569c3f1534701b71e00fed586.tar.bz2
timeline-ac769e656b122ff569c3f1534701b71e00fed586.zip
Split front and back end.
Diffstat (limited to 'Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx')
-rw-r--r--Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx243
1 files changed, 0 insertions, 243 deletions
diff --git a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx b/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
deleted file mode 100644
index 6c2c43c1..00000000
--- a/Timeline/ClientApp/src/app/views/timeline-common/TimelinePageTemplateUI.tsx
+++ /dev/null
@@ -1,243 +0,0 @@
-import React from "react";
-import { useTranslation } from "react-i18next";
-import { fromEvent } from "rxjs";
-import { Spinner } from "react-bootstrap";
-
-import { getAlertHost } from "@/services/alert";
-import { useEventEmiiter, UiLogicError } from "@/common";
-import {
- TimelineInfo,
- TimelinePostsWithSyncState,
- timelineService,
-} from "@/services/timeline";
-import { userService } from "@/services/user";
-
-import Timeline, {
- TimelinePostInfoEx,
- TimelineDeleteCallback,
-} from "./Timeline";
-import TimelineTop from "./TimelineTop";
-import TimelinePostEdit, { TimelinePostSendCallback } from "./TimelinePostEdit";
-import { TimelineSyncStatus } from "./SyncStatusBadge";
-
-export interface TimelineCardComponentProps<TManageItems> {
- timeline: TimelineInfo;
- onManage?: (item: TManageItems | "property") => void;
- onMember: () => void;
- className?: string;
- collapse: boolean;
- syncStatus: TimelineSyncStatus;
- toggleCollapse: () => void;
-}
-
-export interface TimelinePageTemplateUIProps<TManageItems> {
- timeline?: TimelineInfo;
- postListState?: TimelinePostsWithSyncState;
- CardComponent: React.ComponentType<TimelineCardComponentProps<TManageItems>>;
- onMember: () => void;
- onManage?: (item: TManageItems | "property") => void;
- onPost?: TimelinePostSendCallback;
- onDelete: TimelineDeleteCallback;
- error?: string;
-}
-
-export default function TimelinePageTemplateUI<TManageItems>(
- props: TimelinePageTemplateUIProps<TManageItems>
-): React.ReactElement | null {
- const { timeline, postListState } = props;
-
- const { t } = useTranslation();
-
- const bottomSpaceRef = React.useRef<HTMLDivElement | null>(null);
-
- const onPostEditHeightChange = React.useCallback((height: number): void => {
- const { current: bottomSpaceDiv } = bottomSpaceRef;
- if (bottomSpaceDiv != null) {
- bottomSpaceDiv.style.height = `${height}px`;
- }
- if (height === 0) {
- const alertHost = getAlertHost();
- if (alertHost != null) {
- alertHost.style.removeProperty("margin-bottom");
- }
- } else {
- const alertHost = getAlertHost();
- if (alertHost != null) {
- alertHost.style.marginBottom = `${height}px`;
- }
- }
- }, []);
-
- const timelineRef = React.useRef<HTMLDivElement | null>(null);
-
- const [getResizeEvent, triggerResizeEvent] = useEventEmiiter();
-
- React.useEffect(() => {
- const { current: timelineElement } = timelineRef;
- if (timelineElement != null) {
- let loadingScrollToBottom = true;
- let pinBottom = false;
-
- const isAtBottom = (): boolean =>
- window.innerHeight + window.scrollY + 10 >= document.body.scrollHeight;
-
- const disableLoadingScrollToBottom = (): void => {
- loadingScrollToBottom = false;
- if (isAtBottom()) pinBottom = true;
- };
-
- const checkAndScrollToBottom = (): void => {
- if (loadingScrollToBottom || pinBottom) {
- window.scrollTo(0, document.body.scrollHeight);
- }
- };
-
- const subscriptions = [
- fromEvent(timelineElement, "wheel").subscribe(
- disableLoadingScrollToBottom
- ),
- fromEvent(timelineElement, "pointerdown").subscribe(
- disableLoadingScrollToBottom
- ),
- fromEvent(timelineElement, "keydown").subscribe(
- disableLoadingScrollToBottom
- ),
- fromEvent(window, "scroll").subscribe(() => {
- if (loadingScrollToBottom) return;
-
- if (isAtBottom()) {
- pinBottom = true;
- } else {
- pinBottom = false;
- }
- }),
- fromEvent(window, "resize").subscribe(checkAndScrollToBottom),
- getResizeEvent().subscribe(checkAndScrollToBottom),
- ];
-
- return () => {
- subscriptions.forEach((s) => s.unsubscribe());
- };
- }
- }, [getResizeEvent, triggerResizeEvent, timeline, postListState]);
-
- const genCardCollapseLocalStorageKey = (uniqueId: string): string =>
- `timeline.${uniqueId}.cardCollapse`;
-
- const cardCollapseLocalStorageKey =
- timeline != null ? genCardCollapseLocalStorageKey(timeline.uniqueId) : null;
-
- const [cardCollapse, setCardCollapse] = React.useState<boolean>(true);
- React.useEffect(() => {
- if (cardCollapseLocalStorageKey != null) {
- const savedCollapse =
- window.localStorage.getItem(cardCollapseLocalStorageKey) === "true";
- setCardCollapse(savedCollapse);
- }
- }, [cardCollapseLocalStorageKey]);
-
- const toggleCardCollapse = (): void => {
- const newState = !cardCollapse;
- setCardCollapse(newState);
- if (timeline != null) {
- window.localStorage.setItem(
- genCardCollapseLocalStorageKey(timeline.uniqueId),
- newState.toString()
- );
- }
- };
-
- let body: React.ReactElement;
-
- if (props.error != null) {
- body = <p className="text-danger">{t(props.error)}</p>;
- } else {
- if (timeline != null) {
- let timelineBody: React.ReactElement;
- if (postListState != null) {
- if (postListState.type === "notexist") {
- throw new UiLogicError(
- "Timeline is not null but post list state is notexist."
- );
- }
- if (postListState.type === "forbid") {
- timelineBody = (
- <p className="text-danger">{t("timeline.messageCantSee")}</p>
- );
- } else {
- const posts: TimelinePostInfoEx[] = postListState.posts.map(
- (post) => ({
- ...post,
- deletable: timelineService.hasModifyPostPermission(
- userService.currentUser,
- timeline,
- post
- ),
- })
- );
-
- timelineBody = (
- <Timeline
- containerRef={timelineRef}
- posts={posts}
- onDelete={props.onDelete}
- onResize={triggerResizeEvent}
- />
- );
- if (props.onPost != null) {
- timelineBody = (
- <>
- {timelineBody}
- <div ref={bottomSpaceRef} className="flex-fix-length" />
- <TimelinePostEdit
- className="fixed-bottom"
- onPost={props.onPost}
- onHeightChange={onPostEditHeightChange}
- timelineUniqueId={timeline.uniqueId}
- />
- </>
- );
- }
- }
- } else {
- timelineBody = (
- <div className="full-viewport-center-child">
- <Spinner variant="primary" animation="grow" />
- </div>
- );
- }
-
- const { CardComponent } = props;
- const syncStatus: TimelineSyncStatus =
- postListState == null || postListState.syncing
- ? "syncing"
- : postListState.type === "synced"
- ? "synced"
- : "offline";
-
- body = (
- <>
- <CardComponent
- className="timeline-template-card"
- timeline={timeline}
- onManage={props.onManage}
- onMember={props.onMember}
- syncStatus={syncStatus}
- collapse={cardCollapse}
- toggleCollapse={toggleCardCollapse}
- />
- <TimelineTop height="56px" />
- {timelineBody}
- </>
- );
- } else {
- body = (
- <div className="full-viewport-center-child">
- <Spinner variant="primary" animation="grow" />
- </div>
- );
- }
- }
-
- return body;
-}