Update comments component - reload, better reusability

This commit is contained in:
Brandon Thomas committed 2023-03-18 17:55:38 -04:00
1 parent 6721bc724d
commit c2f1dafe8b
4 files changed
+98 -47

No files matched your search

@@ -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<Array<Comment>>([]);
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 (
<div>
<CreateCommentForm
entityType={props.entityType}
entityToken={props.entityToken}
loadComments={loadComments}
sessionWrapper={props.sessionWrapper}
/>
<CommentList
entityType={props.entityType}
entityToken={props.entityToken}
comments={comments}
/>
</div>
);
}
export { CommentComponent };
@@ -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 <CommentComponent />
*/
function CommentList(props: Props) {
const [comments, setComments] = useState<Array<Comment>>([]);
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) {
<span className="px-2">·</span>
<span className="opacity-75">{relativeCreateTime}</span>
</div>
{/* 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.
*/}
<div
className="mt-1 text-center text-lg-start"
dangerouslySetInnerHTML={{
@@ -7,20 +7,21 @@ import { v4 as uuidv4 } from "uuid";
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
interface Props {
entity_type: string;
entity_token: string;
entityType: string;
entityToken: string;
loadComments: () => 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 <CommentComponent />
*/
function CreateCommentComponent(props: Props) {
function CreateCommentForm(props: Props) {
const {entityType, entityToken, loadComments} = props;
const [commentMarkdown, setCommentMarkdown] = useState<string>("");
const [uuidIdempotencyToken, setUuidIdempotencyToken] = useState<string>(
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 <div>{createCommentComponent}</div>;
}
export { CreateCommentComponent };
export { CreateCommentForm };
@@ -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"
>
<div className="d-flex flex-column gap-3">
<CreateCommentComponent
entity_type="user"
entity_token={userData?.user_token}
<CommentComponent
entityType="user"
entityToken={userData?.user_token}
sessionWrapper={props.sessionWrapper}
/>
<CommentList
entity_type="user"
entity_token={userData?.user_token}
/>
</div>
</div>
</div>