DeleteCommentModal.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import React from 'react';
  2. import { isPopulated } from '@growi/core';
  3. import { UserPicture } from '@growi/ui/dist/components';
  4. import { format } from 'date-fns/format';
  5. import { useTranslation } from 'next-i18next';
  6. import {
  7. Button, Modal, ModalHeader, ModalBody, ModalFooter,
  8. } from 'reactstrap';
  9. import { Username } from '../../../components/User/Username';
  10. import type { ICommentHasId } from '../../../interfaces/comment';
  11. import styles from './DeleteCommentModal.module.scss';
  12. export type DeleteCommentModalProps = {
  13. isShown: boolean,
  14. comment: ICommentHasId | null,
  15. errorMessage: string,
  16. cancelToDelete: () => void,
  17. confirmToDelete: () => void,
  18. }
  19. export const DeleteCommentModal = (props: DeleteCommentModalProps): JSX.Element => {
  20. const {
  21. isShown, comment, errorMessage, cancelToDelete, confirmToDelete,
  22. } = props;
  23. const { t } = useTranslation();
  24. const headerContent = () => {
  25. if (comment == null || isShown === false) {
  26. return <></>;
  27. }
  28. return (
  29. <span>
  30. <span className="material-symbols-outlined">delete_forever</span>
  31. {t('page_comment.delete_comment')}
  32. </span>
  33. );
  34. };
  35. const bodyContent = () => {
  36. if (comment == null || isShown === false) {
  37. return <></>;
  38. }
  39. // the threshold for omitting body
  40. const OMIT_BODY_THRES = 400;
  41. const commentDate = format(new Date(comment.createdAt), 'yyyy/MM/dd HH:mm');
  42. const creator = isPopulated(comment.creator) ? comment.creator : undefined;
  43. let commentBody = comment.comment;
  44. if (commentBody.length > OMIT_BODY_THRES) { // omit
  45. commentBody = `${commentBody.substr(0, OMIT_BODY_THRES)}...`;
  46. }
  47. const commentBodyElement = <span style={{ whiteSpace: 'pre-wrap' }}>{commentBody}</span>;
  48. return (
  49. <>
  50. <UserPicture user={creator} size="xs" /> <strong className="me-2"><Username user={creator}></Username></strong>{commentDate}:
  51. <div className="card mt-2">
  52. <div className="card-body comment-body px-3 py-2">{commentBodyElement}</div>
  53. </div>
  54. </>
  55. );
  56. };
  57. const footerContent = () => {
  58. if (comment == null || isShown === false) {
  59. return <></>;
  60. }
  61. return (
  62. <>
  63. <span className="text-danger">{errorMessage}</span>&nbsp;
  64. <Button onClick={cancelToDelete}>{t('Cancel')}</Button>
  65. <Button data-testid="delete-comment-button" color="danger" onClick={confirmToDelete}>
  66. <span className="material-symbols-outlined">delete_forever</span>
  67. {t('Delete')}
  68. </Button>
  69. </>
  70. );
  71. };
  72. return (
  73. <Modal data-testid="page-comment-delete-modal" isOpen={isShown} toggle={cancelToDelete} className={`${styles['page-comment-delete-modal']}`}>
  74. <ModalHeader tag="h4" toggle={cancelToDelete} className="text-danger">
  75. {headerContent()}
  76. </ModalHeader>
  77. <ModalBody>
  78. {bodyContent()}
  79. </ModalBody>
  80. <ModalFooter>
  81. {footerContent()}
  82. </ModalFooter>
  83. </Modal>
  84. );
  85. };