diff --git a/packages/fakeyou.com/src/v2/view/_common/comments/CommentComponent.tsx b/packages/fakeyou.com/src/v2/view/_common/comments/CommentComponent.tsx new file mode 100644 index 0000000000..11ea6c14ba --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/_common/comments/CommentComponent.tsx @@ -0,0 +1,60 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { + Comment, + ListComments, + ListCommentsIsError, + ListCommentsIsOk, +} from "@storyteller/components/src/api/comments/ListComments"; +import { CreateCommentForm } from "./CreateCommentForm"; +import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper"; +import { CommentList } from "./CommentList"; + +interface Props { + entityType: string; + entityToken: string; + sessionWrapper: SessionWrapper; +} + +/** + * This is a reusable component that can be put on several different pages. + * + * It requires the entity type ("tts_model", "tts_result", "w2l_template", "w2l_result", etc.) + * and the entity token, and it will be able to fetch a user's previous vote and change it. + * + * This button component manages all of its own state and API calls. + */ +function CommentComponent(props: Props) { + const [comments, setComments] = useState>([]); + + const loadComments = useCallback(async () => { + const response = await ListComments(props.entityType, props.entityToken); + + if (ListCommentsIsOk(response)) { + setComments(response.comments); + } else if (ListCommentsIsError(response)) { + // TODO + } + }, [props.entityType, props.entityToken]); + + useEffect(() => { + loadComments(); + }, [loadComments]); + + return ( +
+ + +
+ ); +} + +export { CommentComponent }; diff --git a/packages/fakeyou.com/src/v2/view/_common/comments/CommentList.tsx b/packages/fakeyou.com/src/v2/view/_common/comments/CommentList.tsx index 4835507c51..cec2f266a7 100644 --- a/packages/fakeyou.com/src/v2/view/_common/comments/CommentList.tsx +++ b/packages/fakeyou.com/src/v2/view/_common/comments/CommentList.tsx @@ -1,38 +1,27 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React from "react"; import { formatDistance } from "date-fns"; import { Comment, - ListComments, - ListCommentsIsError, - ListCommentsIsOk, } from "@storyteller/components/src/api/comments/ListComments"; const Fade = require("react-reveal/Fade"); interface Props { - entity_type: string; - entity_token: string; + entityType: string; + entityToken: string; + comments: Comment[]; } +/** + * This is part of a reusable component for putting comments on several + * different page types. + * + * See the documentation on the parent + */ function CommentList(props: Props) { - const [comments, setComments] = useState>([]); - - const getComments = useCallback(async () => { - const response = await ListComments(props.entity_type, props.entity_token); - - if (ListCommentsIsOk(response)) { - setComments(response.comments); - } else if (ListCommentsIsError(response)) { - // TODO - } - }, [props.entity_token, props.entity_type]); - - useEffect(() => { - getComments(); - }, [getComments]); // NB: It's more convenient to show recent data first {.reverse()} - var reversedComments = comments.slice(); + var reversedComments = props.comments.slice(); const now = new Date(); @@ -55,7 +44,12 @@ function CommentList(props: Props) { ยท {relativeCreateTime} - {/* It's okay to set "dangerous" html here as the server safely created it. */} + {/* + It's okay to set "dangerous" html here as the server safely created + it from markdown and shields against user injection attempts. Don't + do this with other server data, though, unless you know that field + is safe from the backend engineers. + */}
void; sessionWrapper: SessionWrapper; } /** - * This is a reusable component that can be put on several different pages. + * This is part of a reusable component for putting comments on several + * different page types. * - * It requires the entity type ("tts_model", "tts_result", "w2l_template", "w2l_result", etc.) - * and the entity token, and it will be able to fetch a user's previous vote and change it. - * - * This button component manages all of its own state and API calls. + * See the documentation on the parent */ -function CreateCommentComponent(props: Props) { +function CreateCommentForm(props: Props) { + const {entityType, entityToken, loadComments} = props; + const [commentMarkdown, setCommentMarkdown] = useState(""); const [uuidIdempotencyToken, setUuidIdempotencyToken] = useState( uuidv4() @@ -29,19 +30,20 @@ function CreateCommentComponent(props: Props) { const postComment = useCallback(async () => { const request = { + // Idempotency token prevents the user from clicking submit twice. uuid_idempotency_token: uuidIdempotencyToken, - entity_type: props.entity_type, - entity_token: props.entity_token, + entity_type: entityType, + entity_token: entityToken, comment_markdown: commentMarkdown, }; const rating = await CreateComment(request); if (CreateCommentIsOk(rating)) { - //let ratingValue = rating.maybe_rating_value || undefined; - //setUserRatingValue(ratingValue); + loadComments(); // Trigger reload. } }, [ - props.entity_type, - props.entity_token, + entityType, + entityToken, + loadComments, uuidIdempotencyToken, commentMarkdown, ]); @@ -117,4 +119,4 @@ function CreateCommentComponent(props: Props) { return
{createCommentComponent}
; } -export { CreateCommentComponent }; +export { CreateCommentForm }; diff --git a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/ProfilePage.tsx b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/ProfilePage.tsx index 467069d144..dbc9211a30 100644 --- a/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/ProfilePage.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/profile/profile_view/ProfilePage.tsx @@ -39,8 +39,7 @@ import "tippy.js/dist/tippy.css"; import { motion } from "framer-motion"; import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle"; import { faCalendarAlt } from "@fortawesome/pro-solid-svg-icons"; -import { CreateCommentComponent } from "../../../_common/comments/CreateCommentComponent"; -import { CommentList } from "../../../_common/comments/CommentList"; +import { CommentComponent } from "../../../_common/comments/CommentComponent"; interface Props { sessionWrapper: SessionWrapper; @@ -537,15 +536,11 @@ function ProfilePage(this: any, props: Props) { aria-labelledby="comments-tab" >
- -