import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { useParams } from "react-router-dom"; import { Button, Col, Collapse, Input, ListGroup, Modal, ModalBody, Row, TabContent, TabPane, } from "reactstrap"; import { toast } from "react-toastify"; import { observer } from "mobx-react-lite"; import { useTranslation } from "react-i18next"; import { useTo, useWindowArea } from "taehui-ts/fe-utility"; import { useAvatarStore, useForumStore, useTaehuiStore } from "src/Stores"; import TextView from "src/forum/TextView"; import AutoEssayTitleView from "src/forum//AutoEssayTitleView"; import { AutoEssayViewLoading } from "src/Loading"; import useGetAutoEssay from "src/forum/useGetAutoEssay"; import usePostAutoEssay from "src/forum/usePostAutoEssay"; import usePutAutoEssay from "src/forum/usePutAutoEssay"; import withTotem from "src/withTotem"; import usePutEssay from "src/forum/usePutEssay"; import usePostFile from "src/forum/usePostFile"; import useGetEssay from "src/forum/useGetEssay"; import usePostEssay from "src/forum/usePostEssay"; export default withTotem( observer(() => { const { isTitleTextFilled, title, text, setTitle, setText, autoEssayID, setAutoEssayID, } = useForumStore(); const { titleViewHeight, avatarViewHeight } = useTaehuiStore(); const { taehuiAvatarID, taehuiAvatarName } = useAvatarStore(); const { t } = useTranslation(); const [isEdit, setEdit] = useState(true); const [testText, setTestText] = useState(""); const [textViewHeight, setTextViewHeight] = useState(100); const [isAutoEssayOpened, setAutoEssayOpened] = useState(false); type PostEssayViewParams = { forumID: string; essayID?: string; }; const { forumID, essayID } = useParams<PostEssayViewParams>() as PostEssayViewParams; const { isFetched: isAutoEssayLoaded, data: autoEssay } = useGetAutoEssay( forumID, isAutoEssayOpened, ); const editView = useRef<HTMLDivElement>(null); const textView = useRef<HTMLTextAreaElement>(null); const inputView = useRef<HTMLDivElement>(null); const { mutateAsync: postAutoEssay } = usePostAutoEssay(); const { mutateAsync: putAutoEssay } = usePutAutoEssay(); const { mutateAsync: putEssay } = usePutEssay(); const { isPending, mutateAsync: postFile } = usePostFile(); const { mutateAsync: postEssay } = usePostEssay(); const { data: essay, data: { forumTitle }, isFetched: isEssayLoaded, } = useGetEssay(essayID); useEffect(() => { if (isEssayLoaded) { setTitle(essay.title); setText(essay.text); } }, [essay, isEssayLoaded, setText, setTitle]); const { windowHeight } = useWindowArea(); const to = useTo(); const setTag = (tag: string) => { const { current } = textView; if (current) { const { selectionStart, selectionEnd } = current; const t = text.substring(selectionStart, selectionEnd); const tag0 = "<" + tag + ">"; const tag1 = "</" + tag + ">"; if (t.startsWith(tag0) || t.endsWith(tag1)) { setText( text.substring(0, selectionStart) + text.substring( selectionStart + tag0.length, selectionStart + t.length - tag1.length, ) + text.substring(selectionEnd), ); setTimeout(() => { current.selectionStart = selectionStart; current.selectionEnd = selectionEnd - tag0.length - tag1.length; current.focus(); }, 0); } else { setText( text.substring(0, selectionStart) + tag0 + text.substring(selectionStart, selectionEnd) + tag1 + text.substring(selectionEnd), ); setTimeout(() => { current.selectionStart = selectionStart; current.selectionEnd = selectionEnd + tag0.length + tag1.length; current.focus(); }, 0); } } }; useEffect(() => { setTextViewHeight( windowHeight - titleViewHeight - avatarViewHeight - (editView.current?.clientHeight ?? 0) - (inputView.current?.clientHeight ?? 0), ); }, [avatarViewHeight, titleViewHeight, windowHeight]); useEffect(() => { if (!essayID) { setTitle(""); setText(""); } }, [essayID, setText, setTitle]); useEffect(() => { const postAutoEssaysID = setInterval(async () => { if (isTitleTextFilled) { if (typeof autoEssayID === "number") { await putAutoEssay({ autoEssayID, title, text }); } else { const { autoEssayID } = await postAutoEssay({ forumID, title, text, }); setAutoEssayID(autoEssayID); } } }, 60000); return () => { clearInterval(postAutoEssaysID); }; }, [ autoEssayID, forumID, isTitleTextFilled, postAutoEssay, putAutoEssay, setAutoEssayID, t, text, title, ]); useLayoutEffect(() => { if (!isEdit) { setTestText(text); } }, [isEdit, text]); return ( <> {isEdit && ( <div ref={editView}> <Row className="g-0"> <Col className="m-1"> <Input invalid={!title} valid={!!title} placeholder={t("title")} value={title} onChange={({ target: { value } }) => { setTitle(value); }} /> </Col> </Row> <Row className="g-0"> <Col className="m-1" xs="auto"> <Button onClick={() => { const inputElement = document.createElement("input"); inputElement.type = "file"; inputElement.accept = "audio/*,image/*,video/*"; inputElement.addEventListener( "change", async ({ target }) => { const file = (target as HTMLInputElement).files?.[0]; const { current } = textView; if (file && current) { const text = await postFile({ file, textView: current, }); if (text) { setText(text); } } }, ); inputElement.click(); }} color="info" > {t("fileUpload")} </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setAutoEssayOpened((prevState) => !prevState); }} color={isAutoEssayOpened ? "secondary" : "primary"} > {t("autoEssays")} </Button> </Col> </Row> <Row className="g-0"> <Col className="m-1"> <Collapse isOpen={isAutoEssayOpened}> {isAutoEssayLoaded ? ( <ListGroup> {autoEssay.map((autoEssay) => ( <AutoEssayTitleView key={autoEssay.autoEssayID} autoEssay={autoEssay} /> ))} </ListGroup> ) : ( <AutoEssayViewLoading /> )} </Collapse> </Col> </Row> </div> )} <Row className="g-0"> <Col className="m-1"> <TabContent activeTab={isEdit ? 1 : 2}> <TabPane tabId={1}> <Input type="textarea" className="form-control" placeholder={t("text")} value={text} onChange={({ target: { value } }) => { setText(value); }} innerRef={textView} style={{ height: textViewHeight }} /> </TabPane> <TabPane tabId={2}> <TextView forumTitle={forumTitle} title={title} text={testText} avatarID={taehuiAvatarID} avatarName={taehuiAvatarName} /> </TabPane> </TabContent> </Col> </Row> <div ref={inputView}> <Row className="g-0"> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("strong"); }} color="info" > <strong>{t("textTag")}</strong> </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("i"); }} color="info" > <i>{t("textTag")}</i> </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("u"); }} color="info" > <u>{t("textTag")}</u> </Button> </Col> <Col className="m-1" xs="auto"> <Button onClick={() => { setTag("s"); }} color="info" > <s>{t("textTag")}</s> </Button> </Col> </Row> <Row className="g-0"> <Col className="m-1"> <Button color={isEdit ? "secondary" : "primary"} onClick={() => { setEdit((prevState) => !prevState); }} > {t("viewEditedEssay")} </Button> </Col> {essayID ? ( <Col className="m-1" xs="auto"> <Button color="warning" onClick={async () => { if (title && text) { await putEssay({ essayID, title, text }); to(`/forum/${forumID}/${essayID}`); } else { toast.error(t("failedValidation")); } }} > {t("doModifyEssay")} </Button> </Col> ) : ( <Col className="m-1" xs="auto"> <Button color="success" onClick={async () => { if (title && text) { await postEssay({ forumID, title, text, }); to(`/forum/${forumID}/${essayID}`); } else { toast.error(t("failedValidation")); } }} > {t("postEssay")} </Button> </Col> )} <Col className="m-1" xs="auto"> <Button color="danger" onClick={() => { to(`/forum/${forumID}`); }} > {t("quit")} </Button> </Col> </Row> </div> <Modal isOpen={isPending}> <ModalBody> <span>{t("fileUploading")}</span> </ModalBody> </Modal> </> ); }), );