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"> {hitCount !== undefined && ( <> <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;