feat: added useLive hook

This commit is contained in:
Wyatt Johnson
2020-08-07 12:42:24 -06:00
parent abfcdcc933
commit f41623bbd4
5 changed files with 111 additions and 102 deletions
+1
View File
@@ -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);
@@ -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}
@@ -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 () => {