diff --git a/src/core/client/embed/PymControl.ts b/src/core/client/embed/PymControl.ts index 1255d0854..92a8dbefc 100644 --- a/src/core/client/embed/PymControl.ts +++ b/src/core/client/embed/PymControl.ts @@ -25,7 +25,6 @@ export default class PymControl { title: config.title, id: `${config.id}_iframe`, name: `${config.id}_iframe`, - optionalparams: "", }); this.cleanups = decorators diff --git a/src/core/client/framework/helpers/getURLWithCommentID.tsx b/src/core/client/framework/helpers/getURLWithCommentID.tsx new file mode 100644 index 000000000..421032782 --- /dev/null +++ b/src/core/client/framework/helpers/getURLWithCommentID.tsx @@ -0,0 +1,8 @@ +import { modifyQuery } from "talk-framework/utils"; + +export default function getURLWithCommentID( + assetURL: string, + commentID?: string +) { + return modifyQuery(assetURL, { commentID }); +} diff --git a/src/core/client/framework/helpers/index.ts b/src/core/client/framework/helpers/index.ts index 653f66d98..e4a5c898f 100644 --- a/src/core/client/framework/helpers/index.ts +++ b/src/core/client/framework/helpers/index.ts @@ -1 +1,2 @@ export { default as getMe } from "./getMe"; +export { default as getURLWithCommentID } from "./getURLWithCommentID"; diff --git a/src/core/client/stream/tabs/comments/components/Comment/ButtonsBar.tsx b/src/core/client/stream/tabs/comments/components/Comment/ButtonsBar.tsx new file mode 100644 index 000000000..f9e2e9f49 --- /dev/null +++ b/src/core/client/stream/tabs/comments/components/Comment/ButtonsBar.tsx @@ -0,0 +1,13 @@ +import React, { StatelessComponent } from "react"; + +import { Flex } from "talk-ui/components"; + +const ButtonsBar: StatelessComponent = props => { + return ( + + {props.children} + + ); +}; + +export default ButtonsBar; diff --git a/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx b/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx index b30621913..7ed3d93f9 100644 --- a/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx +++ b/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx @@ -2,7 +2,7 @@ import React, { StatelessComponent } from "react"; import HTMLContent from "talk-stream/components/HTMLContent"; import Timestamp from "talk-stream/components/Timestamp"; -import { Flex } from "talk-ui/components"; +import { Flex, HorizontalGutter } from "talk-ui/components"; import * as styles from "./Comment.css"; import EditedMarker from "./EditedMarker"; @@ -43,10 +43,10 @@ const Comment: StatelessComponent = props => { {props.topBarRight &&
{props.topBarRight}
} - {props.body || ""} - + + {props.body || ""} {props.footer} - + ); }; diff --git a/src/core/client/stream/tabs/comments/components/Comment/ShowConversationLink.tsx b/src/core/client/stream/tabs/comments/components/Comment/ShowConversationLink.tsx new file mode 100644 index 000000000..2025974c5 --- /dev/null +++ b/src/core/client/stream/tabs/comments/components/Comment/ShowConversationLink.tsx @@ -0,0 +1,31 @@ +import React, { EventHandler, MouseEvent } from "react"; +import { StatelessComponent } from "react"; + +import { Localized } from "fluent-react/compat"; +import { Button } from "talk-ui/components"; + +export interface ShowConversationLinkProps { + href?: string; + onClick?: EventHandler; +} + +const ShowConversationLink: StatelessComponent< + ShowConversationLinkProps +> = props => { + return ( + + + + ); +}; + +export default ShowConversationLink; diff --git a/src/core/client/stream/tabs/comments/components/Comment/index.ts b/src/core/client/stream/tabs/comments/components/Comment/index.ts index e89d4b958..d05ab70f8 100644 --- a/src/core/client/stream/tabs/comments/components/Comment/index.ts +++ b/src/core/client/stream/tabs/comments/components/Comment/index.ts @@ -1,3 +1,5 @@ export { default, default as IndentedComment } from "./IndentedComment"; export { default as TopBarLeft } from "./TopBarLeft"; export { default as Username } from "./Username"; +export { default as ButtonsBar } from "./ButtonsBar"; +export { default as ShowConversationLink } from "./ShowConversationLink"; diff --git a/src/core/client/stream/tabs/comments/components/ReplyList.tsx b/src/core/client/stream/tabs/comments/components/ReplyList.tsx index 896120b91..87f9eb610 100644 --- a/src/core/client/stream/tabs/comments/components/ReplyList.tsx +++ b/src/core/client/stream/tabs/comments/components/ReplyList.tsx @@ -15,7 +15,9 @@ export interface ReplyListProps { id: string; }; comments: ReadonlyArray< - { id: string } & PropTypesOf["comment"] + { id: string; showConversationLink?: boolean } & PropTypesOf< + typeof CommentContainer + >["comment"] >; onShowAll?: () => void; hasMore?: boolean; @@ -52,6 +54,7 @@ const ReplyList: StatelessComponent = props => { indentLevel={props.indentLevel} localReply={props.localReply} disableReplies={props.disableReplies} + showConversationLink={!!comment.showConversationLink} /> {getReplyListElement(props, comment)} diff --git a/src/core/client/stream/tabs/comments/containers/CommentContainer.tsx b/src/core/client/stream/tabs/comments/containers/CommentContainer.tsx index f9db4932c..cebc13c28 100644 --- a/src/core/client/stream/tabs/comments/containers/CommentContainer.tsx +++ b/src/core/client/stream/tabs/comments/containers/CommentContainer.tsx @@ -1,20 +1,26 @@ import { Localized } from "fluent-react/compat"; -import React, { Component } from "react"; +import React, { Component, MouseEvent } from "react"; import { graphql } from "react-relay"; import { isBeforeDate } from "talk-common/utils"; +import { getURLWithCommentID } from "talk-framework/helpers"; import withFragmentContainer from "talk-framework/lib/relay/withFragmentContainer"; import { PropTypesOf } from "talk-framework/types"; import { CommentContainer_asset as AssetData } from "talk-stream/__generated__/CommentContainer_asset.graphql"; import { CommentContainer_comment as CommentData } from "talk-stream/__generated__/CommentContainer_comment.graphql"; import { CommentContainer_me as MeData } from "talk-stream/__generated__/CommentContainer_me.graphql"; import { + SetCommentIDMutation, ShowAuthPopupMutation, + withSetCommentIDMutation, withShowAuthPopupMutation, } from "talk-stream/mutations"; import { Button } from "talk-ui/components"; -import Comment from "../components/Comment"; +import Comment, { + ButtonsBar, + ShowConversationLink, +} from "../components/Comment"; import ReplyButton from "../components/Comment/ReplyButton"; import EditCommentFormContainer from "./EditCommentFormContainer"; import PermalinkButtonContainer from "./PermalinkButtonContainer"; @@ -26,6 +32,7 @@ interface InnerProps { asset: AssetData; indentLevel?: number; showAuthPopup: ShowAuthPopupMutation; + setCommentID: SetCommentIDMutation; /** * localReply will integrate the mutation response into * localReplies @@ -33,6 +40,8 @@ interface InnerProps { localReply?: boolean; /** disableReplies will remove the ReplyButton */ disableReplies?: boolean; + /** showConversationLink will render a link to the conversation */ + showConversationLink?: boolean; } interface State { @@ -113,6 +122,12 @@ export class CommentContainer extends Component { return; } + private handleShowConversation = (e: MouseEvent) => { + e.preventDefault(); + this.props.setCommentID({ id: this.props.comment.id }); + return false; + }; + public render() { const { comment, @@ -120,6 +135,7 @@ export class CommentContainer extends Component { indentLevel, localReply, disableReplies, + showConversationLink, } = this.props; const { showReplyDialog, showEditDialog, editable } = this.state; if (showEditDialog) { @@ -157,14 +173,25 @@ export class CommentContainer extends Component { } footer={ <> - {!disableReplies && ( - + {!disableReplies && ( + + )} + + + {showConversationLink && ( + )} - } /> @@ -181,37 +208,40 @@ export class CommentContainer extends Component { } } -const enhanced = withShowAuthPopupMutation( - withFragmentContainer({ - me: graphql` - fragment CommentContainer_me on User { - id - } - `, - asset: graphql` - fragment CommentContainer_asset on Asset { - ...ReplyCommentFormContainer_asset - } - `, - comment: graphql` - fragment CommentContainer_comment on Comment { - id - author { +const enhanced = withSetCommentIDMutation( + withShowAuthPopupMutation( + withFragmentContainer({ + me: graphql` + fragment CommentContainer_me on User { id - username } - body - createdAt - editing { - edited - editableUntil + `, + asset: graphql` + fragment CommentContainer_asset on Asset { + url + ...ReplyCommentFormContainer_asset } - pending - ...ReplyCommentFormContainer_comment - ...EditCommentFormContainer_comment - } - `, - })(CommentContainer) + `, + comment: graphql` + fragment CommentContainer_comment on Comment { + id + author { + id + username + } + body + createdAt + editing { + edited + editableUntil + } + pending + ...ReplyCommentFormContainer_comment + ...EditCommentFormContainer_comment + } + `, + })(CommentContainer) + ) ); export type CommentContainerProps = PropTypesOf; diff --git a/src/core/client/stream/tabs/comments/containers/PermalinkButtonContainer.tsx b/src/core/client/stream/tabs/comments/containers/PermalinkButtonContainer.tsx index 12900c5f7..7c8aa17f5 100644 --- a/src/core/client/stream/tabs/comments/containers/PermalinkButtonContainer.tsx +++ b/src/core/client/stream/tabs/comments/containers/PermalinkButtonContainer.tsx @@ -1,7 +1,7 @@ import React, { StatelessComponent } from "react"; import { graphql } from "react-relay"; +import { getURLWithCommentID } from "talk-framework/helpers"; import { withLocalStateContainer } from "talk-framework/lib/relay"; -import { modifyQuery } from "talk-framework/utils"; import { PermalinkButtonContainerLocal as Local } from "talk-stream/__generated__/PermalinkButtonContainerLocal.graphql"; import PermalinkButton from "../components/PermalinkButton"; @@ -18,7 +18,7 @@ export const PermalinkContainer: StatelessComponent = ({ return local.assetURL ? ( ) : null; }; diff --git a/src/core/client/stream/tabs/comments/containers/PermalinkViewContainer.tsx b/src/core/client/stream/tabs/comments/containers/PermalinkViewContainer.tsx index a21057c04..cdc5c2f65 100644 --- a/src/core/client/stream/tabs/comments/containers/PermalinkViewContainer.tsx +++ b/src/core/client/stream/tabs/comments/containers/PermalinkViewContainer.tsx @@ -1,10 +1,10 @@ import { Child as PymChild } from "pym.js"; -import qs from "query-string"; import React, { MouseEvent } from "react"; import { graphql } from "react-relay"; + +import { getURLWithCommentID } from "talk-framework/helpers"; import { withContext } from "talk-framework/lib/bootstrap"; import { withFragmentContainer } from "talk-framework/lib/relay"; -import { buildURL, parseURL } from "talk-framework/utils"; import { PermalinkViewContainer_asset as AssetData } from "talk-stream/__generated__/PermalinkViewContainer_asset.graphql"; import { PermalinkViewContainer_comment as CommentData } from "talk-stream/__generated__/PermalinkViewContainer_comment.graphql"; import { PermalinkViewContainer_me as MeData } from "talk-stream/__generated__/PermalinkViewContainer_me.graphql"; @@ -32,13 +32,8 @@ class PermalinkViewContainer extends React.Component< }; private getShowAllCommentsHref() { const { pym } = this.props; - const urlParts = parseURL((pym && pym.parentUrl) || window.location.href); - const search = qs.stringify({ - ...qs.parse(urlParts.search), - commentID: undefined, - }); - // Remove the commentId url param. - return buildURL({ ...urlParts, search }); + const url = (pym && pym.parentUrl) || window.location.href; + return getURLWithCommentID(url, undefined); } public componentDidMount() { diff --git a/src/core/client/stream/tabs/comments/containers/ReplyListContainer.tsx b/src/core/client/stream/tabs/comments/containers/ReplyListContainer.tsx index 0dfe3a80f..cb64d4ade 100644 --- a/src/core/client/stream/tabs/comments/containers/ReplyListContainer.tsx +++ b/src/core/client/stream/tabs/comments/containers/ReplyListContainer.tsx @@ -11,11 +11,15 @@ import { COMMENT_SORT, ReplyListContainer1PaginationQueryVariables, } from "talk-stream/__generated__/ReplyListContainer1PaginationQuery.graphql"; +import { ReplyListContainer5_comment as Comment5Data } from "talk-stream/__generated__/ReplyListContainer5_comment.graphql"; import { StatelessComponent } from "enzyme"; import ReplyList from "../components/ReplyList"; import LocalReplyListContainer from "./LocalReplyListContainer"; +type UnpackArray = T extends ReadonlyArray ? U : any; +type ReplyNode5 = UnpackArray["node"]; + export interface InnerProps { me: MeData | null; asset: AssetData; @@ -44,7 +48,11 @@ export class ReplyListContainer extends React.Component { ) { return null; } - const comments = this.props.comment.replies.edges.map(edge => edge.node); + const comments = this.props.comment.replies.edges.map(edge => ({ + ...edge.node, + // ReplyListContainer5 contains replyCount. + showConversationLink: ((edge.node as any) as ReplyNode5).replyCount > 0, + })); return ( remaining comments-editCommentForm-editTimeExpired = Edit time has expired. You can no longer edit this comment. Why not post another one? comments-editedMarker-edited = Edited + +comments-showConversationLink-readMore = Read More of this Conversation >