aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/pages/timeline/TimelinePostCreateView.tsx
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2023-09-14 23:47:16 +0800
committercrupest <crupest@outlook.com>2023-09-14 23:47:16 +0800
commit40b4871c3f7bfe04f332ae7fb687fd7d9ae34734 (patch)
treecba45fa30627a704c2fb5132eff3f936ba1dd54e /FrontEnd/src/pages/timeline/TimelinePostCreateView.tsx
parentc1f79460d57a4daba75bdc34b7b7a3ea2d7254b3 (diff)
downloadtimeline-40b4871c3f7bfe04f332ae7fb687fd7d9ae34734.tar.gz
timeline-40b4871c3f7bfe04f332ae7fb687fd7d9ae34734.tar.bz2
timeline-40b4871c3f7bfe04f332ae7fb687fd7d9ae34734.zip
...
Diffstat (limited to 'FrontEnd/src/pages/timeline/TimelinePostCreateView.tsx')
-rw-r--r--FrontEnd/src/pages/timeline/TimelinePostCreateView.tsx272
1 files changed, 0 insertions, 272 deletions
diff --git a/FrontEnd/src/pages/timeline/TimelinePostCreateView.tsx b/FrontEnd/src/pages/timeline/TimelinePostCreateView.tsx
deleted file mode 100644
index 70925cd9..00000000
--- a/FrontEnd/src/pages/timeline/TimelinePostCreateView.tsx
+++ /dev/null
@@ -1,272 +0,0 @@
-import { useState, useEffect, ChangeEventHandler } from "react";
-import { useTranslation } from "react-i18next";
-
-import { UiLogicError } from "~src/common";
-
-import {
- getHttpTimelineClient,
- HttpTimelineInfo,
- HttpTimelinePostInfo,
- HttpTimelinePostPostRequestData,
-} from "~src/http/timeline";
-
-import base64 from "~src/utilities/base64";
-
-import { pushAlert } from "~src/components/alert";
-import BlobImage from "~src/components/BlobImage";
-import LoadingButton from "~src/components/button/LoadingButton";
-import PopupMenu from "~src/components/menu/PopupMenu";
-import MarkdownPostEdit from "./MarkdownPostEdit";
-import TimelinePostCard from "./TimelinePostCard";
-import TimelinePostContainer from "./TimelinePostContainer";
-import IconButton from "~src/components/button/IconButton";
-
-import "./TimelinePostCreateView.css";
-import classNames from "classnames";
-
-interface TimelinePostEditTextProps {
- text: string;
- disabled: boolean;
- onChange: (text: string) => void;
- className?: string;
-}
-
-function TimelinePostEditText(props: TimelinePostEditTextProps) {
- const { text, disabled, onChange, className } = props;
-
- return (
- <textarea
- value={text}
- disabled={disabled}
- onChange={(event) => {
- onChange(event.target.value);
- }}
- className={classNames("timeline-post-create-edit-text", className)}
- />
- );
-}
-
-interface TimelinePostEditImageProps {
- onSelect: (file: File | null) => void;
- disabled: boolean;
-}
-
-function TimelinePostEditImage(props: TimelinePostEditImageProps) {
- const { onSelect, disabled } = props;
-
- const { t } = useTranslation();
-
- const [file, setFile] = useState<File | null>(null);
- const [error, setError] = useState<boolean>(false);
-
- const onInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
- setError(false);
- const files = e.target.files;
- if (files == null || files.length === 0) {
- setFile(null);
- onSelect(null);
- } else {
- setFile(files[0]);
- }
- };
-
- useEffect(() => {
- return () => {
- onSelect(null);
- };
- }, [onSelect]);
-
- return (
- <>
- <input
- type="file"
- onChange={onInputChange}
- accept="image/*"
- disabled={disabled}
- className="mx-3 my-1"
- />
- {file != null && !error && (
- <BlobImage
- src={file}
- className="timeline-post-create-image"
- onLoad={() => onSelect(file)}
- onError={() => {
- onSelect(null);
- setError(true);
- }}
- />
- )}
- {error ? <div className="text-danger">{t("loadImageError")}</div> : null}
- </>
- );
-}
-
-type PostKind = "text" | "markdown" | "image";
-
-const postKindIconMap: Record<PostKind, string> = {
- text: "fonts",
- markdown: "markdown",
- image: "image",
-};
-
-export interface TimelinePostEditProps {
- className?: string;
- timeline: HttpTimelineInfo;
- onPosted: (newPost: HttpTimelinePostInfo) => void;
-}
-
-function TimelinePostEdit(props: TimelinePostEditProps) {
- const { timeline, className, onPosted } = props;
-
- const { t } = useTranslation();
-
- const [process, setProcess] = useState<boolean>(false);
-
- const [kind, setKind] = useState<Exclude<PostKind, "markdown">>("text");
- const [showMarkdown, setShowMarkdown] = useState<boolean>(false);
-
- const [text, setText] = useState<string>("");
- const [image, setImage] = useState<File | null>(null);
-
- const draftTextLocalStorageKey = `timeline.${timeline.owner.username}.${timeline.nameV2}.postDraft.text`;
-
- useEffect(() => {
- setText(window.localStorage.getItem(draftTextLocalStorageKey) ?? "");
- }, [draftTextLocalStorageKey]);
-
- const canSend =
- (kind === "text" && text.length !== 0) ||
- (kind === "image" && image != null);
-
- const onPostError = (): void => {
- pushAlert({
- color: "danger",
- message: "timeline.sendPostFailed",
- });
- };
-
- const onSend = async (): Promise<void> => {
- setProcess(true);
-
- let requestData: HttpTimelinePostPostRequestData;
- switch (kind) {
- case "text":
- requestData = {
- contentType: "text/plain",
- data: await base64(text),
- };
- break;
- case "image":
- if (image == null) {
- throw new UiLogicError(
- "Content type is image but image blob is null.",
- );
- }
- requestData = {
- contentType: image.type,
- data: await base64(image),
- };
- break;
- default:
- throw new UiLogicError("Unknown content type.");
- }
-
- getHttpTimelineClient()
- .postPost(timeline.owner.username, timeline.nameV2, {
- dataList: [requestData],
- })
- .then(
- (data) => {
- if (kind === "text") {
- setText("");
- window.localStorage.removeItem(draftTextLocalStorageKey);
- }
- setProcess(false);
- setKind("text");
- onPosted(data);
- },
- () => {
- setProcess(false);
- onPostError();
- },
- );
- };
-
- return (
- <TimelinePostContainer
- className={classNames(className, "timeline-post-create-container")}
- >
- <TimelinePostCard className="timeline-post-create-card">
- {showMarkdown ? (
- <MarkdownPostEdit
- className="cru-fill-parent"
- onClose={() => setShowMarkdown(false)}
- owner={timeline.owner.username}
- timeline={timeline.nameV2}
- onPosted={onPosted}
- onPostError={onPostError}
- />
- ) : (
- <div className="timeline-post-create">
- <div className="timeline-post-create-edit-area">
- {(() => {
- if (kind === "text") {
- return (
- <TimelinePostEditText
- className="timeline-post-create-edit-text"
- text={text}
- disabled={process}
- onChange={(text) => {
- setText(text);
- window.localStorage.setItem(
- draftTextLocalStorageKey,
- text,
- );
- }}
- />
- );
- } else if (kind === "image") {
- return (
- <TimelinePostEditImage
- onSelect={setImage}
- disabled={process}
- />
- );
- }
- })()}
- </div>
- <div className="timeline-post-create-right-area">
- <PopupMenu
- containerClassName="timeline-post-create-kind-select"
- items={(["text", "image", "markdown"] as const).map((kind) => ({
- type: "button",
- text: `timeline.post.type.${kind}`,
- iconClassName: postKindIconMap[kind],
- onClick: () => {
- if (kind === "markdown") {
- setShowMarkdown(true);
- } else {
- setKind(kind);
- }
- },
- }))}
- >
- <IconButton color="primary" icon={postKindIconMap[kind]} />
- </PopupMenu>
- <LoadingButton
- onClick={() => void onSend()}
- color="primary"
- disabled={!canSend}
- loading={process}
- >
- {t("timeline.send")}
- </LoadingButton>
- </div>
- </div>
- )}
- </TimelinePostCard>
- </TimelinePostContainer>
- );
-}
-
-export default TimelinePostEdit;