No Description

CommentItem.tsx 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import React, { Component } from "react";
  2. import classnames from "classnames";
  3. import { Tooltip, Divider } from "antd";
  4. import { LOCALE_DAYJS } from "./config/constant";
  5. import { CommentContext } from "./context";
  6. import { CollapseBtn } from "./common/CollapseBtn";
  7. import { ReplyCard } from "./common/ReplyCard";
  8. import IconFont from "./common/ScheduleIconFont";
  9. import ItemToolBar, { TOOL_ACTION_TYPE } from "./common/ItemToolBar";
  10. import { getUserType, AuthType } from "./utils";
  11. import dayjs from "./utils/dayjsImport";
  12. import styles from "./CommentItem.less";
  13. import AudioPlayer from "./common/AudioPlayer";
  14. import { ContentRender } from "./common/ContentRender";
  15. import { toggleFavor } from "./utils/commentAjaxLogi";
  16. import OldCommontEditor from '../editor/OldCommentEditor';
  17. export interface CommentItemData {
  18. content: string;
  19. created: number;
  20. favor_count: number;
  21. favored: boolean;
  22. id: string;
  23. is_speak: boolean;
  24. medias: any;
  25. replies: Array<any>;
  26. reply_count: number;
  27. user_avatar: string;
  28. user_id: number;
  29. user_name: string;
  30. }
  31. interface IP {
  32. data: CommentItemData;
  33. onChangeListItem({
  34. commentId,
  35. changeProp,
  36. }: {
  37. commentId: string;
  38. changeProp: any;
  39. }): any;
  40. }
  41. interface IS {
  42. showReply: boolean;
  43. showReplyEditor: boolean;
  44. }
  45. export default class CommentItem extends Component<IP, IS> {
  46. static contextType = CommentContext;
  47. context!: React.ContextType<typeof CommentContext>;
  48. constructor(props: IP) {
  49. super(props);
  50. this.state = {
  51. showReply: false,
  52. showReplyEditor: false,
  53. };
  54. }
  55. get authType(): AuthType {
  56. const { currentUser } = this.context;
  57. const { user_id } = this.props.data;
  58. return getUserType(currentUser, user_id);
  59. }
  60. renderCommentTime = (created: number) => {
  61. const { locale } = this.context;
  62. return (
  63. <Tooltip
  64. placement="top"
  65. title={dayjs(created * 1000).format("YYYY-MM-DD HH:mm:ss")}
  66. >
  67. <span>
  68. {LOCALE_DAYJS[locale]
  69. ? dayjs(created * 1000)
  70. .locale(LOCALE_DAYJS[locale])
  71. .fromNow()
  72. : dayjs(created * 1000).fromNow()}
  73. </span>
  74. </Tooltip>
  75. );
  76. };
  77. renderContent = () => {
  78. const { is_speak, medias } = this.props.data;
  79. if (is_speak) {
  80. return (
  81. <>
  82. <div className={styles.speakContent}>[跟读语音]</div>
  83. <div className={styles.speakMediaWrapper}>
  84. <AudioPlayer src={medias && medias[0] && medias[0].url} />
  85. </div>
  86. </>
  87. );
  88. }
  89. return (
  90. <div className={styles.commentContent}>
  91. <ContentRender data={this.props.data} />
  92. </div>
  93. );
  94. };
  95. renderToolBar = () => {
  96. const { currentUser }: { currentUser: any } = this.context;
  97. const { showReply, showReplyEditor } = this.state;
  98. const { onChangeListItem } = this.props;
  99. const { id, reply_count, favor_count, favored, user_id } = this.props.data;
  100. // TODO: normal action and private action
  101. // console.log('this.props.data: ', this.props.data);
  102. return (
  103. <ItemToolBar
  104. authType={this.authType}
  105. handleReplyClick={() => {
  106. this.setState({ showReply: !showReply });
  107. return true;
  108. }}
  109. handleNormalClick={async (actionType: string) => {
  110. console.log("actionType: ", actionType);
  111. if (actionType === TOOL_ACTION_TYPE.REPLY) {
  112. this.setState({ showReplyEditor: !showReplyEditor });
  113. }
  114. if (actionType === TOOL_ACTION_TYPE.FAVOR) {
  115. if (currentUser) {
  116. const res = await toggleFavor({
  117. favored,
  118. id,
  119. commentId: id,
  120. userId: currentUser.id,
  121. });
  122. console.log("res: ", res);
  123. if (res) {
  124. onChangeListItem({
  125. commentId: res.id,
  126. changeProp: { favor_count: res.favor_count, favored: !favored },
  127. });
  128. }
  129. }
  130. }
  131. return true;
  132. }}
  133. handlePrivateClick={(actionType: string) => {
  134. return true;
  135. }}
  136. replyCount={reply_count}
  137. favorCount={favor_count}
  138. favored={favored}
  139. />
  140. );
  141. };
  142. renderCollapseReplyEditor = () => {
  143. const { showReplyEditor } = this.state;
  144. if (!showReplyEditor) return null;
  145. return <div className={styles.replyEditorWrapper}>
  146. <OldCommontEditor />
  147. </div>;
  148. };
  149. renderCollapseReplyContent = (replyList: Array<any>) => {
  150. const { locale } = this.context;
  151. const { showReply } = this.state;
  152. const { onChangeListItem } = this.props;
  153. const { id: commentId, replies } = this.props.data;
  154. if (!showReply) {
  155. return null;
  156. }
  157. return (
  158. <div className={styles.replyWrapper}>
  159. <Divider />
  160. {replyList.map((i, index) => {
  161. return (
  162. <div key={`reply_${i.id}`}>
  163. <ReplyCard
  164. commentId={commentId}
  165. replyContent={i}
  166. locale={locale}
  167. renderTime={this.renderCommentTime}
  168. onChangeListItem={async ({ replyId, changeProps }) => {
  169. const newReplies = replies.map(r => {
  170. if (r.id === replyId) {
  171. return {
  172. ...r,
  173. ...changeProps,
  174. }
  175. }
  176. return r;
  177. });
  178. return onChangeListItem({ commentId, changeProp: { replies: newReplies }, })
  179. }}
  180. />
  181. {index === replyList.length - 1 ? null : <Divider />}
  182. </div>
  183. );
  184. })}
  185. </div>
  186. );
  187. };
  188. render() {
  189. console.log(`data: `, this.props.data);
  190. const {
  191. id,
  192. user_avatar,
  193. content,
  194. user_name,
  195. created,
  196. replies,
  197. } = this.props.data;
  198. return (
  199. <article className={styles.wrapper}>
  200. <div className={styles.avatar}>
  201. {/* <img src={user_avatar} alt={`avatar_${id}`} /> */}
  202. <div
  203. className={styles.avatarImg}
  204. style={{
  205. backgroundImage: `url(${user_avatar})`,
  206. }}
  207. />
  208. </div>
  209. <section className={styles.content}>
  210. <header>
  211. <h4>{user_name}</h4>
  212. {this.renderCommentTime(created)}
  213. </header>
  214. {this.renderContent()}
  215. {this.renderToolBar()}
  216. {this.renderCollapseReplyEditor()}
  217. {this.renderCollapseReplyContent(replies)}
  218. </section>
  219. </article>
  220. );
  221. }
  222. }