aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-05-01 21:30:31 +0800
committercrupest <crupest@outlook.com>2022-05-01 21:30:31 +0800
commit3f07b047df4d66f83047a5bb747c0a1665bceb6c (patch)
tree95f2a8814806cdefd9b42b72aea39dd4b39db434
parentf15f883198226a146113f82b3d7ca4864f3aa58b (diff)
downloadtimeline-3f07b047df4d66f83047a5bb747c0a1665bceb6c.tar.gz
timeline-3f07b047df4d66f83047a5bb747c0a1665bceb6c.tar.bz2
timeline-3f07b047df4d66f83047a5bb747c0a1665bceb6c.zip
...
-rw-r--r--BackEnd/Timeline/Services/Timeline/TimelinePostService.cs2
-rw-r--r--FrontEnd/src/utilities/hooks.ts10
-rw-r--r--FrontEnd/src/utilities/hooks/useReverseScrollPositionRemember.ts2
-rw-r--r--FrontEnd/src/utilities/hooks/useScrollToBottom.ts (renamed from FrontEnd/src/utilities/hooks/useScrollToTop.ts)12
-rw-r--r--FrontEnd/src/views/timeline/Timeline.css (renamed from FrontEnd/src/views/timeline/index.css)0
-rw-r--r--FrontEnd/src/views/timeline/Timeline.tsx128
-rw-r--r--FrontEnd/src/views/timeline/TimelinePagedPostListView.tsx34
-rw-r--r--FrontEnd/src/views/timeline/TimelinePostEdit.css8
-rw-r--r--FrontEnd/src/views/timeline/TimelinePostEditCard.tsx2
-rw-r--r--FrontEnd/src/views/timeline/index.tsx4
10 files changed, 83 insertions, 119 deletions
diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs
index 8fee0467..8a1501c1 100644
--- a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs
+++ b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs
@@ -400,7 +400,7 @@ namespace Timeline.Services.Timeline
query = query.Where(p => p.LastUpdated >= modifiedSince || (p.Author != null && p.Author.UsernameChangeTime >= modifiedSince));
}
- query = query.OrderBy(p => p.Time).Skip(pageSize * (page - 1)).Take(pageSize);
+ query = query.OrderByDescending(p => p.Time).Skip(pageSize * (page - 1)).Take(pageSize);
var items = await query.ToListAsync();
diff --git a/FrontEnd/src/utilities/hooks.ts b/FrontEnd/src/utilities/hooks.ts
index c499b36b..a59f7167 100644
--- a/FrontEnd/src/utilities/hooks.ts
+++ b/FrontEnd/src/utilities/hooks.ts
@@ -1,11 +1,5 @@
import useClickOutside from "./hooks/useClickOutside";
-import useReverseScrollPositionRemember from "./hooks/useReverseScrollPositionRemember";
-import useScrollToTop from "./hooks/useScrollToTop";
+import useScrollToBottom from "./hooks/useScrollToBottom";
import { useIsSmallScreen } from "./hooks/mediaQuery";
-export {
- useClickOutside,
- useReverseScrollPositionRemember,
- useScrollToTop,
- useIsSmallScreen,
-};
+export { useClickOutside, useScrollToBottom, useIsSmallScreen };
diff --git a/FrontEnd/src/utilities/hooks/useReverseScrollPositionRemember.ts b/FrontEnd/src/utilities/hooks/useReverseScrollPositionRemember.ts
index 6fdd4b43..c0b6ce2c 100644
--- a/FrontEnd/src/utilities/hooks/useReverseScrollPositionRemember.ts
+++ b/FrontEnd/src/utilities/hooks/useReverseScrollPositionRemember.ts
@@ -1,3 +1,5 @@
+// Not used now!!! But preserved for future use.
+
import React from "react";
let on = false;
diff --git a/FrontEnd/src/utilities/hooks/useScrollToTop.ts b/FrontEnd/src/utilities/hooks/useScrollToBottom.ts
index 95c8b7b9..f6780d9f 100644
--- a/FrontEnd/src/utilities/hooks/useScrollToTop.ts
+++ b/FrontEnd/src/utilities/hooks/useScrollToBottom.ts
@@ -2,7 +2,7 @@ import React from "react";
import { fromEvent } from "rxjs";
import { filter, throttleTime } from "rxjs/operators";
-function useScrollToTop(
+function useScrollToBottom(
handler: () => void,
enable = true,
option = {
@@ -23,9 +23,11 @@ function useScrollToTop(
React.useEffect(() => {
const subscription = fromEvent(window, "scroll")
.pipe(
- filter(() => {
- return window.scrollY <= option.maxOffset;
- }),
+ filter(
+ () =>
+ window.scrollY >=
+ document.body.scrollHeight - window.innerHeight - option.maxOffset
+ ),
throttleTime(option.throttle)
)
.subscribe(() => {
@@ -40,4 +42,4 @@ function useScrollToTop(
}, [enable, option.maxOffset, option.throttle]);
}
-export default useScrollToTop;
+export default useScrollToBottom;
diff --git a/FrontEnd/src/views/timeline/index.css b/FrontEnd/src/views/timeline/Timeline.css
index fa3542dd..fa3542dd 100644
--- a/FrontEnd/src/views/timeline/index.css
+++ b/FrontEnd/src/views/timeline/Timeline.css
diff --git a/FrontEnd/src/views/timeline/Timeline.tsx b/FrontEnd/src/views/timeline/Timeline.tsx
index 6399b6bc..84624313 100644
--- a/FrontEnd/src/views/timeline/Timeline.tsx
+++ b/FrontEnd/src/views/timeline/Timeline.tsx
@@ -1,5 +1,6 @@
import React from "react";
import classnames from "classnames";
+import { useScrollToBottom } from "@/utilities/hooks";
import { HubConnectionState } from "@microsoft/signalr";
import {
@@ -16,14 +17,14 @@ import {
import { useUser } from "@/services/user";
import { getTimelinePostUpdate$ } from "@/services/timeline";
-import TimelinePagedPostListView from "./TimelinePagedPostListView";
+import TimelinePostListView from "./TimelinePostListView";
import TimelineEmptyItem from "./TimelineEmptyItem";
import TimelineLoading from "./TimelineLoading";
import TimelinePostEdit from "./TimelinePostEdit";
import TimelinePostEditNoLogin from "./TimelinePostEditNoLogin";
import TimelineCard from "./TimelineCard";
-import "./index.css";
+import "./Timeline.css";
export interface TimelineProps {
className?: string;
@@ -46,6 +47,9 @@ const Timeline: React.FC<TimelineProps> = (props) => {
"offline" | "forbid" | "notfound" | "error" | null
>(null);
+ const [currentPage, setCurrentPage] = React.useState(1);
+ const [totalPage, setTotalPage] = React.useState(0);
+
const [timelineReloadKey, setTimelineReloadKey] = React.useState(0);
const [postsReloadKey, setPostsReloadKey] = React.useState(0);
@@ -60,71 +64,50 @@ const Timeline: React.FC<TimelineProps> = (props) => {
}, [timelineOwner, timelineName]);
React.useEffect(() => {
- if (timelineName != null) {
- let subscribe = true;
-
- getHttpTimelineClient()
- .getTimeline(timelineOwner, timelineName)
- .then(
- (t) => {
- if (subscribe) {
- setTimeline(t);
- }
- },
- (error) => {
- if (subscribe) {
- if (error instanceof HttpNetworkError) {
- setError("offline");
- } else if (error instanceof HttpForbiddenError) {
- setError("forbid");
- } else if (error instanceof HttpNotFoundError) {
- setError("notfound");
- } else {
- console.error(error);
- setError("error");
- }
- }
+ getHttpTimelineClient()
+ .getTimeline(timelineOwner, timelineName)
+ .then(
+ (t) => {
+ setTimeline(t);
+ },
+ (error) => {
+ if (error instanceof HttpNetworkError) {
+ setError("offline");
+ } else if (error instanceof HttpForbiddenError) {
+ setError("forbid");
+ } else if (error instanceof HttpNotFoundError) {
+ setError("notfound");
+ } else {
+ console.error(error);
+ setError("error");
}
- );
-
- return () => {
- subscribe = false;
- };
- }
+ }
+ );
}, [timelineOwner, timelineName, timelineReloadKey]);
React.useEffect(() => {
- let subscribe = true;
- void getHttpTimelineClient()
- .listPost(timelineOwner, timelineName)
+ getHttpTimelineClient()
+ .listPost(timelineOwner, timelineName, 1)
.then(
- (ps) => {
- if (subscribe) {
- setPosts(
- ps.items.filter(
- (p): p is HttpTimelinePostInfo => p.deleted === false
- )
- );
- }
+ (page) => {
+ setPosts(
+ page.items.filter((p): p is HttpTimelinePostInfo => !p.deleted)
+ );
+ setTotalPage(page.totalPageCount);
},
(error) => {
- if (subscribe) {
- if (error instanceof HttpNetworkError) {
- setError("offline");
- } else if (error instanceof HttpForbiddenError) {
- setError("forbid");
- } else if (error instanceof HttpNotFoundError) {
- setError("notfound");
- } else {
- console.error(error);
- setError("error");
- }
+ if (error instanceof HttpNetworkError) {
+ setError("offline");
+ } else if (error instanceof HttpForbiddenError) {
+ setError("forbid");
+ } else if (error instanceof HttpNotFoundError) {
+ setError("notfound");
+ } else {
+ console.error(error);
+ setError("error");
}
}
);
- return () => {
- subscribe = false;
- };
}, [timelineOwner, timelineName, postsReloadKey]);
React.useEffect(() => {
@@ -143,6 +126,33 @@ const Timeline: React.FC<TimelineProps> = (props) => {
};
}, [timelineOwner, timelineName]);
+ useScrollToBottom(() => {
+ console.log(`Load page ${currentPage + 1}.`);
+ setCurrentPage(currentPage + 1);
+ void getHttpTimelineClient()
+ .listPost(timelineOwner, timelineName, currentPage + 1)
+ .then(
+ (page) => {
+ const ps = page.items.filter(
+ (p): p is HttpTimelinePostInfo => !p.deleted
+ );
+ setPosts((old) => [...(old ?? []), ...ps]);
+ },
+ (error) => {
+ if (error instanceof HttpNetworkError) {
+ setError("offline");
+ } else if (error instanceof HttpForbiddenError) {
+ setError("forbid");
+ } else if (error instanceof HttpNotFoundError) {
+ setError("notfound");
+ } else {
+ console.error(error);
+ setError("error");
+ }
+ }
+ );
+ }, currentPage < totalPage);
+
if (error === "offline") {
return (
<div className={className} style={style}>
@@ -181,8 +191,7 @@ const Timeline: React.FC<TimelineProps> = (props) => {
)}
{posts && (
<div style={style} className={classnames("timeline", className)}>
- <TimelineEmptyItem height={40} />
- <TimelinePagedPostListView posts={posts} onReload={updatePosts} />
+ <TimelineEmptyItem height={50} />
{timeline?.postable ? (
<TimelinePostEdit timeline={timeline} onPosted={updatePosts} />
) : user == null ? (
@@ -190,6 +199,7 @@ const Timeline: React.FC<TimelineProps> = (props) => {
) : (
<TimelineEmptyItem startSegmentLength={20} center="none" current />
)}
+ <TimelinePostListView posts={posts} onReload={updatePosts} />
</div>
)}
</>
diff --git a/FrontEnd/src/views/timeline/TimelinePagedPostListView.tsx b/FrontEnd/src/views/timeline/TimelinePagedPostListView.tsx
deleted file mode 100644
index 6a0ad0f5..00000000
--- a/FrontEnd/src/views/timeline/TimelinePagedPostListView.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from "react";
-
-import { HttpTimelinePostInfo } from "@/http/timeline";
-
-import { useScrollToTop } from "@/utilities/hooks";
-
-import TimelinePostListView from "./TimelinePostListView";
-
-export interface TimelinePagedPostListViewProps {
- posts: HttpTimelinePostInfo[];
- onReload: () => void;
-}
-
-const TimelinePagedPostListView: React.FC<TimelinePagedPostListViewProps> = (
- props
-) => {
- const { posts, onReload } = props;
-
- const [lastViewCount, setLastViewCount] = React.useState<number>(10);
-
- const viewingPosts = React.useMemo(() => {
- return lastViewCount >= posts.length
- ? posts.slice()
- : posts.slice(-lastViewCount);
- }, [posts, lastViewCount]);
-
- useScrollToTop(() => {
- setLastViewCount(lastViewCount + 10);
- }, lastViewCount < posts.length);
-
- return <TimelinePostListView posts={viewingPosts} onReload={onReload} />;
-};
-
-export default TimelinePagedPostListView;
diff --git a/FrontEnd/src/views/timeline/TimelinePostEdit.css b/FrontEnd/src/views/timeline/TimelinePostEdit.css
index 4ce98383..fb34e673 100644
--- a/FrontEnd/src/views/timeline/TimelinePostEdit.css
+++ b/FrontEnd/src/views/timeline/TimelinePostEdit.css
@@ -2,15 +2,9 @@
padding-bottom: 0;
}
-.timeline-post-edit .timeline-item-card {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- border-bottom: none;
-}
-
.timeline-post-edit {
position: sticky !important;
- bottom: 0;
+ top: 0;
z-index: 1;
}
diff --git a/FrontEnd/src/views/timeline/TimelinePostEditCard.tsx b/FrontEnd/src/views/timeline/TimelinePostEditCard.tsx
index a69d413a..de0e7e43 100644
--- a/FrontEnd/src/views/timeline/TimelinePostEditCard.tsx
+++ b/FrontEnd/src/views/timeline/TimelinePostEditCard.tsx
@@ -22,7 +22,7 @@ const TimelinePostEdit: React.FC<TimelinePostEditCardProps> = ({
className={classnames("timeline-item timeline-post-edit", className)}
style={style}
>
- <TimelineLine center="node" current />
+ <TimelineLine center="node" />
<Card className="timeline-item-card">{children}</Card>
</div>
);
diff --git a/FrontEnd/src/views/timeline/index.tsx b/FrontEnd/src/views/timeline/index.tsx
index 131c38c7..cb9fb46f 100644
--- a/FrontEnd/src/views/timeline/index.tsx
+++ b/FrontEnd/src/views/timeline/index.tsx
@@ -3,8 +3,6 @@ import { useParams } from "react-router-dom";
import { UiLogicError } from "@/common";
-import { useReverseScrollPositionRemember } from "@/utilities/hooks";
-
import Timeline from "./Timeline";
const TimelinePage: React.FC = () => {
@@ -15,8 +13,6 @@ const TimelinePage: React.FC = () => {
const timeline = timelineNameParam || "self";
- useReverseScrollPositionRemember();
-
return (
<div className="container">
<Timeline timelineOwner={owner} timelineName={timeline} />