Newer
Older
taehui / taehui-fe / src / forum / TextView.tsx
@Taehui Taehui on 14 Mar 2 KB v1.0.0
import { useEffect, useMemo, useState } from "react";
import { Badge, Col, Row } from "reactstrap";
import { sanitize } from "dompurify";
import { useTranslation } from "react-i18next";
import { sprintf } from "sprintf-js";
import { getDatetime } from "taehui-ts/date";

import { getHitTexts, tag } from "src/Utility";
import AvatarTitle from "src/AvatarTitle";

import scss from "src/forum/TextView.module.scss";
import useGetHit from "src/forum/useGetHit";

const TextView = ({
  forumTitle,
  title,
  text,
  avatarID,
  avatarName,
  date,
  hitCount,
}: {
  forumTitle: string;
  title: string;
  text: string;
  avatarID: string;
  avatarName: string;
  date?: string;
  hitCount?: number;
}) => {
  const hitTexts = useMemo(() => getHitTexts(text), [text]);
  const [textHTMLContents, setTextHTMLContents] = useState("");

  const { t } = useTranslation();

  const { data: hit, isFetched: isHitLoaded } = useGetHit(hitTexts);

  useEffect(() => {
    setTextHTMLContents(
      sanitize(tag(t, text, {}, scss.essay), {
        ADD_ATTR: ["target"],
      }),
    );
  }, [t, text]);

  useEffect(() => {
    if (isHitLoaded) {
      setTextHTMLContents(
        sanitize(
          tag(
            t,
            text,
            Object.fromEntries(hitTexts.map((hitText, i) => [hitText, hit[i]])),
            scss.essay,
          ),
          {
            ADD_ATTR: ["target"],
          },
        ),
      );
    }
  }, [hit, hitTexts, isHitLoaded, t, text]);

  return (
    <>
      <Row className="g-0">
        <Col className="m-1">
          <Badge>{forumTitle}</Badge>
        </Col>
      </Row>
      <Row className="g-0">
        <AvatarTitle avatarID={avatarID} avatarName={avatarName}>
          <span>{title}</span>
        </AvatarTitle>
        <Col className="m-1" xs="auto">
          {typeof hitCount === "number" && (
            <>
              <span>{getDatetime(date)}</span>
              <br />
              <span>{sprintf(t("hitCount"), hitCount)}</span>
            </>
          )}
        </Col>
      </Row>
      <Row className="g-0">
        <Col className="m-1">
          <span
            className="ln"
            dangerouslySetInnerHTML={{
              __html: textHTMLContents,
            }}
          />
        </Col>
      </Row>
    </>
  );
};

export default TextView;