mirror of
https://github.com/wassname/talk.git
synced 2026-07-11 06:23:32 +08:00
feat: added useLive hook
This commit is contained in:
@@ -7,3 +7,4 @@ export { default as useUUID } from "./useUUID";
|
||||
export { default as useToken } from "./useToken";
|
||||
export { default as useResizeObserver } from "./useResizeObserver";
|
||||
export { default as useToggleState } from "./useToggleState";
|
||||
export { default as useLive } from "./useLive";
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
interface Props {
|
||||
story: {
|
||||
isClosed: boolean;
|
||||
settings: {
|
||||
live: {
|
||||
enabled: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
settings: {
|
||||
disableCommenting: {
|
||||
enabled: boolean;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const useLive = ({ story, settings }: Props) =>
|
||||
useMemo(() => {
|
||||
if (
|
||||
// If live updates are disable for this story...
|
||||
!story.settings.live.enabled ||
|
||||
// Or the story is closed...
|
||||
story.isClosed ||
|
||||
// Or commenting is disabled...
|
||||
settings.disableCommenting.enabled
|
||||
) {
|
||||
// Then we aren't live!
|
||||
return false;
|
||||
}
|
||||
|
||||
// The story is open! Mark the story as open.
|
||||
return true;
|
||||
}, [
|
||||
// When used in conjunction with the StoryClosedTimeoutContainer, we don't
|
||||
// have to inspect the `story.closedAt` because it'll update the store for
|
||||
// us!
|
||||
story.isClosed,
|
||||
settings.disableCommenting.enabled,
|
||||
story.settings.live.enabled,
|
||||
]);
|
||||
|
||||
export default useLive;
|
||||
@@ -1,9 +1,8 @@
|
||||
import { clearLongTimeout } from "long-settimeout";
|
||||
import React, { FunctionComponent, useCallback, useEffect } from "react";
|
||||
import { graphql, GraphQLTaggedNode, RelayPaginationProp } from "react-relay";
|
||||
import { withProps } from "recompose";
|
||||
|
||||
import { createTimeoutAt } from "coral-common/utils";
|
||||
import { useLive } from "coral-framework/hooks";
|
||||
import { useViewerNetworkEvent } from "coral-framework/lib/events";
|
||||
import {
|
||||
useLoadMore,
|
||||
@@ -80,17 +79,16 @@ export const ReplyListContainer: React.FunctionComponent<Props> = (props) => {
|
||||
const subcribeToCommentReplyCreated = useSubscription(
|
||||
CommentReplyCreatedSubscription
|
||||
);
|
||||
|
||||
const live = useLive(props);
|
||||
useEffect(() => {
|
||||
// If the comment is pending, no need to subscribe the comment!
|
||||
if (props.comment.pending) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!props.story.settings.live.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.story.isClosed || props.settings.disableCommenting.enabled) {
|
||||
// If live updates aren't enabled, don't subscribe!
|
||||
if (!live) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,37 +101,16 @@ export const ReplyListContainer: React.FunctionComponent<Props> = (props) => {
|
||||
liveDirectRepliesInsertion: props.liveDirectRepliesInsertion,
|
||||
});
|
||||
|
||||
// If the story is scheduled to be closed, cancel the subscriptions because
|
||||
// we can't add any more comments!
|
||||
if (props.story.closedAt) {
|
||||
const timer = createTimeoutAt(() => {
|
||||
disposable.dispose();
|
||||
}, props.story.closedAt);
|
||||
|
||||
return () => {
|
||||
// Cancel the timer if there was one enabled.
|
||||
if (timer) {
|
||||
clearLongTimeout(timer);
|
||||
}
|
||||
|
||||
// Dispose the subscriptions.
|
||||
disposable.dispose();
|
||||
};
|
||||
}
|
||||
|
||||
return () => {
|
||||
disposable.dispose();
|
||||
};
|
||||
}, [
|
||||
live,
|
||||
subcribeToCommentReplyCreated,
|
||||
props.comment.id,
|
||||
props.indentLevel,
|
||||
props.comment.pending,
|
||||
props.settings.disableCommenting.enabled,
|
||||
props.liveDirectRepliesInsertion,
|
||||
props.story.isClosed,
|
||||
props.story.closedAt,
|
||||
props.story.settings.live.enabled,
|
||||
]);
|
||||
|
||||
const viewNew = useMutation(ReplyListViewNewMutation);
|
||||
|
||||
+10
-35
@@ -1,11 +1,10 @@
|
||||
import { Localized } from "@fluent/react/compat";
|
||||
import cn from "classnames";
|
||||
import { clearLongTimeout } from "long-settimeout";
|
||||
import React, { FunctionComponent, useCallback, useEffect } from "react";
|
||||
import { graphql, RelayPaginationProp } from "react-relay";
|
||||
|
||||
import { createTimeoutAt } from "coral-common/utils";
|
||||
import FadeInTransition from "coral-framework/components/FadeInTransition";
|
||||
import { useLive } from "coral-framework/hooks";
|
||||
import { useViewerNetworkEvent } from "coral-framework/lib/events";
|
||||
import {
|
||||
combineDisposables,
|
||||
@@ -73,22 +72,19 @@ export const AllCommentsTabContainer: FunctionComponent<Props> = ({
|
||||
const subscribeToCommentReleased = useSubscription(
|
||||
CommentReleasedSubscription
|
||||
);
|
||||
|
||||
const live = useLive({ story, settings });
|
||||
const hasMore = relay.hasMore();
|
||||
useEffect(() => {
|
||||
// If live updates are disabled, don't subscribe to new comments!!
|
||||
if (!story.settings.live.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the story is closed or commenting is disabled, then don't subscribe
|
||||
// to new comments because there isn't any!
|
||||
if (story.isClosed || settings.disableCommenting.enabled) {
|
||||
if (!live) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the sort ordering to apply extra logic.
|
||||
switch (commentsOrderBy) {
|
||||
case GQLCOMMENT_SORT.CREATED_AT_ASC:
|
||||
if (relay.hasMore()) {
|
||||
if (hasMore) {
|
||||
// Oldest first when there is more than one page of content can't
|
||||
// possibly have new comments to show in view!
|
||||
return;
|
||||
@@ -116,37 +112,16 @@ export const AllCommentsTabContainer: FunctionComponent<Props> = ({
|
||||
})
|
||||
);
|
||||
|
||||
// If the story is scheduled to be closed, cancel the subscriptions because
|
||||
// we can't add any more comments!
|
||||
if (story.closedAt) {
|
||||
const timer = createTimeoutAt(() => {
|
||||
disposable.dispose();
|
||||
}, story.closedAt);
|
||||
|
||||
return () => {
|
||||
// Cancel the timer if there was one enabled.
|
||||
if (timer) {
|
||||
clearLongTimeout(timer);
|
||||
}
|
||||
|
||||
// Dispose the subscriptions.
|
||||
disposable.dispose();
|
||||
};
|
||||
}
|
||||
|
||||
return () => {
|
||||
disposable.dispose();
|
||||
};
|
||||
}, [
|
||||
commentsOrderBy,
|
||||
hasMore,
|
||||
live,
|
||||
story.id,
|
||||
subscribeToCommentCreated,
|
||||
subscribeToCommentReleased,
|
||||
story.id,
|
||||
story.isClosed,
|
||||
story.closedAt,
|
||||
story.settings.live.enabled,
|
||||
settings.disableCommenting.enabled,
|
||||
relay.hasMore(),
|
||||
]);
|
||||
|
||||
const [loadMore, isLoadingMore] = useLoadMore(relay, 20);
|
||||
@@ -245,7 +220,7 @@ export const AllCommentsTabContainer: FunctionComponent<Props> = ({
|
||||
</FadeInTransition>
|
||||
</IgnoredTombstoneOrHideContainer>
|
||||
))}
|
||||
{relay.hasMore() && (
|
||||
{hasMore && (
|
||||
<Localized id="comments-loadMore">
|
||||
<Button
|
||||
onClick={loadMoreAndEmit}
|
||||
|
||||
+50
-38
@@ -3,8 +3,10 @@ import React, { FunctionComponent, useCallback, useEffect } from "react";
|
||||
import { graphql, RelayPaginationProp } from "react-relay";
|
||||
|
||||
import FadeInTransition from "coral-framework/components/FadeInTransition";
|
||||
import { useLive } from "coral-framework/hooks";
|
||||
import { useViewerNetworkEvent } from "coral-framework/lib/events";
|
||||
import {
|
||||
combineDisposables,
|
||||
useLoadMore,
|
||||
useLocal,
|
||||
useMutation,
|
||||
@@ -27,8 +29,8 @@ import { UnansweredCommentsTabContainerPaginationQueryVariables } from "coral-st
|
||||
import { CommentContainer } from "../../Comment";
|
||||
import IgnoredTombstoneOrHideContainer from "../../IgnoredTombstoneOrHideContainer";
|
||||
import { ReplyListContainer } from "../../ReplyList";
|
||||
import CommentCreatedSubscription from "./UnansweredCommentCreatedSubscription";
|
||||
import CommentReleasedSubscription from "./UnansweredCommentReleasedSubscription";
|
||||
import UnansweredCommentCreatedSubscription from "./UnansweredCommentCreatedSubscription";
|
||||
import UnansweredCommentReleasedSubscription from "./UnansweredCommentReleasedSubscription";
|
||||
import UnansweredCommentsTabViewNewMutation from "./UnansweredCommentsTabViewNewMutation";
|
||||
|
||||
import styles from "./UnansweredCommentsTabContainer.css";
|
||||
@@ -60,55 +62,65 @@ export const UnansweredCommentsTabContainer: FunctionComponent<Props> = (
|
||||
}
|
||||
`
|
||||
);
|
||||
const subscribeToCommentCreated = useSubscription(CommentCreatedSubscription);
|
||||
const subscribeToCommentReleased = useSubscription(
|
||||
CommentReleasedSubscription
|
||||
|
||||
const subscribeToCommentCreated = useSubscription(
|
||||
UnansweredCommentCreatedSubscription
|
||||
);
|
||||
const subscribeToCommentReleased = useSubscription(
|
||||
UnansweredCommentReleasedSubscription
|
||||
);
|
||||
|
||||
const live = useLive(props);
|
||||
const hasMore = props.relay.hasMore();
|
||||
useEffect(() => {
|
||||
if (!props.story.settings.live.enabled) {
|
||||
// If live updates are disabled, don't subscribe to new comments!!
|
||||
if (!live) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.story.isClosed || props.settings.disableCommenting.enabled) {
|
||||
return;
|
||||
// Check the sort ordering to apply extra logic.
|
||||
switch (commentsOrderBy) {
|
||||
case GQLCOMMENT_SORT.CREATED_AT_ASC:
|
||||
if (hasMore) {
|
||||
// Oldest first when there is more than one page of content can't
|
||||
// possibly have new comments to show in view!
|
||||
return;
|
||||
}
|
||||
|
||||
// We have all the comments for this story in view! Comments could load!
|
||||
break;
|
||||
case GQLCOMMENT_SORT.CREATED_AT_DESC:
|
||||
// Newest first can always get more comments in view.
|
||||
break;
|
||||
default:
|
||||
// Only chronological sort supports top level live updates of incoming
|
||||
// comments.
|
||||
return;
|
||||
}
|
||||
if (
|
||||
commentsOrderBy === GQLCOMMENT_SORT.CREATED_AT_ASC &&
|
||||
props.relay.hasMore()
|
||||
) {
|
||||
// If sort by oldest we only need to know if there is more to load.
|
||||
return;
|
||||
}
|
||||
if (
|
||||
![
|
||||
GQLCOMMENT_SORT.CREATED_AT_ASC,
|
||||
GQLCOMMENT_SORT.CREATED_AT_DESC,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
].includes(commentsOrderBy as GQLCOMMENT_SORT)
|
||||
) {
|
||||
// Only chronological sort supports top level live updates of incoming comments.
|
||||
return;
|
||||
}
|
||||
const newCommentDisposable = subscribeToCommentCreated({
|
||||
storyID: props.story.id,
|
||||
orderBy: commentsOrderBy,
|
||||
});
|
||||
const releasedCommentDisposable = subscribeToCommentReleased({
|
||||
storyID: props.story.id,
|
||||
orderBy: commentsOrderBy,
|
||||
});
|
||||
|
||||
const disposable = combineDisposables(
|
||||
subscribeToCommentCreated({
|
||||
storyID: props.story.id,
|
||||
orderBy: commentsOrderBy,
|
||||
}),
|
||||
subscribeToCommentReleased({
|
||||
storyID: props.story.id,
|
||||
orderBy: commentsOrderBy,
|
||||
})
|
||||
);
|
||||
|
||||
return () => {
|
||||
newCommentDisposable.dispose();
|
||||
releasedCommentDisposable.dispose();
|
||||
disposable.dispose();
|
||||
};
|
||||
}, [
|
||||
commentsOrderBy,
|
||||
hasMore,
|
||||
live,
|
||||
props.story.id,
|
||||
subscribeToCommentCreated,
|
||||
subscribeToCommentReleased,
|
||||
props.story.id,
|
||||
props.relay.hasMore(),
|
||||
props.story.settings.live.enabled,
|
||||
]);
|
||||
|
||||
const [loadMore, isLoadingMore] = useLoadMore(props.relay, 20);
|
||||
const beginLoadMoreEvent = useViewerNetworkEvent(LoadMoreAllCommentsEvent);
|
||||
const loadMoreAndEmit = useCallback(async () => {
|
||||
|
||||
Reference in New Issue
Block a user