From a314b5350e269676e8c39eda4cc7842751b1a7fc Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 1 Sep 2020 02:32:06 +0800 Subject: ... --- .../ClientApp/src/app/user/ChangeAvatarDialog.tsx | 306 --------------------- .../src/app/user/ChangeNicknameDialog.tsx | 28 -- Timeline/ClientApp/src/app/user/Login.tsx | 147 ---------- Timeline/ClientApp/src/app/user/User.tsx | 71 ----- Timeline/ClientApp/src/app/user/UserInfoCard.tsx | 104 ------- Timeline/ClientApp/src/app/user/UserPage.tsx | 19 -- Timeline/ClientApp/src/app/user/user-page.sass | 10 - 7 files changed, 685 deletions(-) delete mode 100644 Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx delete mode 100644 Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx delete mode 100644 Timeline/ClientApp/src/app/user/Login.tsx delete mode 100644 Timeline/ClientApp/src/app/user/User.tsx delete mode 100644 Timeline/ClientApp/src/app/user/UserInfoCard.tsx delete mode 100644 Timeline/ClientApp/src/app/user/UserPage.tsx delete mode 100644 Timeline/ClientApp/src/app/user/user-page.sass (limited to 'Timeline/ClientApp/src/app/user') diff --git a/Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx b/Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx deleted file mode 100644 index 7d9f9514..00000000 --- a/Timeline/ClientApp/src/app/user/ChangeAvatarDialog.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { - Modal, - ModalHeader, - Row, - Button, - ModalBody, - ModalFooter, -} from "reactstrap"; -import { AxiosError } from "axios"; - -import ImageCropper, { Clip, applyClipToImage } from "../common/ImageCropper"; -import { UiLogicError } from "../common"; - -export interface ChangeAvatarDialogProps { - open: boolean; - close: () => void; - process: (blob: Blob) => Promise; -} - -const ChangeAvatarDialog: React.FC = (props) => { - const { t } = useTranslation(); - - const [file, setFile] = React.useState(null); - const [fileUrl, setFileUrl] = React.useState(null); - const [clip, setClip] = React.useState(null); - const [ - cropImgElement, - setCropImgElement, - ] = React.useState(null); - const [resultBlob, setResultBlob] = React.useState(null); - const [resultUrl, setResultUrl] = React.useState(null); - - const [state, setState] = React.useState< - | "select" - | "crop" - | "processcrop" - | "preview" - | "uploading" - | "success" - | "error" - >("select"); - - const [message, setMessage] = useState< - string | { type: "custom"; text: string } | null - >("userPage.dialogChangeAvatar.prompt.select"); - - const trueMessage = - message == null - ? null - : typeof message === "string" - ? t(message) - : message.text; - - const closeDialog = props.close; - - const toggle = React.useCallback((): void => { - if (!(state === "uploading")) { - closeDialog(); - } - }, [state, closeDialog]); - - useEffect(() => { - if (file != null) { - const url = URL.createObjectURL(file); - setClip(null); - setFileUrl(url); - setState("crop"); - return () => { - URL.revokeObjectURL(url); - }; - } else { - setFileUrl(null); - setState("select"); - } - }, [file]); - - React.useEffect(() => { - if (resultBlob != null) { - const url = URL.createObjectURL(resultBlob); - setResultUrl(url); - setState("preview"); - return () => { - URL.revokeObjectURL(url); - }; - } else { - setResultUrl(null); - } - }, [resultBlob]); - - const onSelectFile = React.useCallback( - (e: React.ChangeEvent): void => { - const files = e.target.files; - if (files == null || files.length === 0) { - setFile(null); - } else { - setFile(files[0]); - } - }, - [] - ); - - const onCropNext = React.useCallback(() => { - if ( - cropImgElement == null || - clip == null || - clip.width === 0 || - file == null - ) { - throw new UiLogicError(); - } - - setState("processcrop"); - void applyClipToImage(cropImgElement, clip, file.type).then((b) => { - setResultBlob(b); - }); - }, [cropImgElement, clip, file]); - - const onCropPrevious = React.useCallback(() => { - setFile(null); - setState("select"); - }, []); - - const onPreviewPrevious = React.useCallback(() => { - setResultBlob(null); - setState("crop"); - }, []); - - const process = props.process; - - const upload = React.useCallback(() => { - if (resultBlob == null) { - throw new UiLogicError(); - } - - setState("uploading"); - process(resultBlob).then( - () => { - setState("success"); - }, - (e: unknown) => { - setState("error"); - setMessage({ type: "custom", text: (e as AxiosError).message }); - } - ); - }, [resultBlob, process]); - - const createPreviewRow = (): React.ReactElement => { - if (resultUrl == null) { - throw new UiLogicError(); - } - return ( - - {t("userPage.dialogChangeAvatar.previewImgAlt")} - - ); - }; - - return ( - - {t("userPage.dialogChangeAvatar.title")} - {(() => { - if (state === "select") { - return ( - <> - - {t("userPage.dialogChangeAvatar.prompt.select")} - - - - - - - - - ); - } else if (state === "crop") { - if (fileUrl == null) { - throw new UiLogicError(); - } - return ( - <> - - - - - {t("userPage.dialogChangeAvatar.prompt.crop")} - - - - - - - - ); - } else if (state === "processcrop") { - return ( - <> - - - {t("userPage.dialogChangeAvatar.prompt.processingCrop")} - - - - - - - - ); - } else if (state === "preview") { - return ( - <> - - {createPreviewRow()} - {t("userPage.dialogChangeAvatar.prompt.preview")} - - - - - - - - ); - } else if (state === "uploading") { - return ( - <> - - {createPreviewRow()} - {t("userPage.dialogChangeAvatar.prompt.uploading")} - - - - ); - } else if (state === "success") { - return ( - <> - - - {t("operationDialog.success")} - - - - - - - ); - } else { - return ( - <> - - {createPreviewRow()} - {trueMessage} - - - - - - - ); - } - })()} - - ); -}; - -export default ChangeAvatarDialog; diff --git a/Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx b/Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx deleted file mode 100644 index 251b18c5..00000000 --- a/Timeline/ClientApp/src/app/user/ChangeNicknameDialog.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; - -import OperationDialog from "../common/OperationDialog"; - -export interface ChangeNicknameDialogProps { - open: boolean; - close: () => void; - onProcess: (newNickname: string) => Promise; -} - -const ChangeNicknameDialog: React.FC = (props) => { - return ( - { - return props.onProcess(newNickname as string); - }} - close={props.close} - /> - ); -}; - -export default ChangeNicknameDialog; diff --git a/Timeline/ClientApp/src/app/user/Login.tsx b/Timeline/ClientApp/src/app/user/Login.tsx deleted file mode 100644 index db6c43c4..00000000 --- a/Timeline/ClientApp/src/app/user/Login.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import React, { Fragment, useState, useEffect } from "react"; -import { useHistory } from "react-router"; -import { useTranslation } from "react-i18next"; -import { - Label, - FormGroup, - Input, - Form, - FormFeedback, - Spinner, - Button, -} from "reactstrap"; - -import AppBar from "../common/AppBar"; -import { useUser, userService } from "../data/user"; - -const Login: React.FC = (_) => { - const { t } = useTranslation(); - const history = useHistory(); - const [username, setUsername] = useState(""); - const [usernameDirty, setUsernameDirty] = useState(false); - const [password, setPassword] = useState(""); - const [passwordDirty, setPasswordDirty] = useState(false); - const [rememberMe, setRememberMe] = useState(true); - const [process, setProcess] = useState(false); - const [error, setError] = useState(null); - - const user = useUser(); - - useEffect(() => { - if (user != null) { - const id = setTimeout(() => history.push("/"), 3000); - return () => { - clearTimeout(id); - }; - } - }, [history, user]); - - if (user != null) { - return ( - <> - -

{t("login.alreadyLogin")}

- - ); - } - - function onSubmit(event: React.SyntheticEvent): void { - if (username === "" || password === "") { - setUsernameDirty(true); - setPasswordDirty(true); - return; - } - - setProcess(true); - userService - .login( - { - username: username, - password: password, - }, - rememberMe - ) - .then( - () => { - if (history.length === 0) { - history.push("/"); - } else { - history.goBack(); - } - }, - (e: Error) => { - setProcess(false); - setError(e.message); - } - ); - event.preventDefault(); - } - - return ( - - -
-

{t("welcome")}

-
- - - { - setUsername(e.target.value); - setUsernameDirty(true); - }} - value={username} - invalid={usernameDirty && username === ""} - /> - {usernameDirty && username === "" && ( - {t("login.emptyUsername")} - )} - - - - { - setPassword(e.target.value); - setPasswordDirty(true); - }} - value={password} - invalid={passwordDirty && password === ""} - /> - {passwordDirty && password === "" && ( - {t("login.emptyPassword")} - )} - - - { - const v = (e.target as HTMLInputElement).checked; - setRememberMe(v); - }} - /> - - - {error ?

{t(error)}

: null} -
- {process ? ( - - ) : ( - - )} -
-
-
-
- ); -}; - -export default Login; diff --git a/Timeline/ClientApp/src/app/user/User.tsx b/Timeline/ClientApp/src/app/user/User.tsx deleted file mode 100644 index db0a6f76..00000000 --- a/Timeline/ClientApp/src/app/user/User.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { useState } from "react"; -import { useParams } from "react-router"; - -import { UiLogicError } from "../common"; -import { useUser, userInfoService } from "../data/user"; -import TimelinePageTemplate from "../timeline/TimelinePageTemplate"; - -import UserPage from "./UserPage"; -import ChangeNicknameDialog from "./ChangeNicknameDialog"; -import ChangeAvatarDialog from "./ChangeAvatarDialog"; -import { PersonalTimelineManageItem } from "./UserInfoCard"; - -const User: React.FC = (_) => { - const { username } = useParams<{ username: string }>(); - - const user = useUser(); - - const [dialog, setDialog] = useState(null); - - let dialogElement: React.ReactElement | undefined; - - const closeDialogHandler = (): void => { - setDialog(null); - }; - - if (dialog === "nickname") { - if (user == null) { - throw new UiLogicError("Change nickname without login."); - } - - dialogElement = ( - - userInfoService.setNickname(username, newNickname) - } - /> - ); - } else if (dialog === "avatar") { - if (user == null) { - throw new UiLogicError("Change avatar without login."); - } - - dialogElement = ( - userInfoService.setAvatar(username, file)} - /> - ); - } - - const onManage = React.useCallback((item: PersonalTimelineManageItem) => { - setDialog(item); - }, []); - - return ( - <> - - {dialogElement} - - ); -}; - -export default User; diff --git a/Timeline/ClientApp/src/app/user/UserInfoCard.tsx b/Timeline/ClientApp/src/app/user/UserInfoCard.tsx deleted file mode 100644 index d6e648cc..00000000 --- a/Timeline/ClientApp/src/app/user/UserInfoCard.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import { - Dropdown, - DropdownToggle, - DropdownMenu, - DropdownItem, - Button, -} from "reactstrap"; -import { useTranslation } from "react-i18next"; -import { fromEvent } from "rxjs"; - -import { timelineVisibilityTooltipTranslationMap } from "../data/timeline"; -import { useAvatar } from "../data/user"; -import { TimelineCardComponentProps } from "../timeline/TimelinePageTemplateUI"; -import BlobImage from "../common/BlobImage"; - -export type PersonalTimelineManageItem = "avatar" | "nickname"; - -export type UserInfoCardProps = TimelineCardComponentProps< - PersonalTimelineManageItem ->; - -const UserInfoCard: React.FC = (props) => { - const { onHeight, onManage } = props; - const { t } = useTranslation(); - - const avatar = useAvatar(props.timeline.owner.username); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const containerRef = React.useRef(null!); - - const notifyHeight = React.useCallback((): void => { - if (onHeight) { - onHeight(containerRef.current.getBoundingClientRect().height); - } - }, [onHeight]); - - React.useEffect(() => { - const subscription = fromEvent(window, "resize").subscribe(notifyHeight); - return () => subscription.unsubscribe(); - }); - - const [manageDropdownOpen, setManageDropdownOpen] = React.useState( - false - ); - const toggleManageDropdown = React.useCallback( - (): void => setManageDropdownOpen((old) => !old), - [] - ); - - return ( -
- -
- {props.timeline.owner.nickname} - - @{props.timeline.owner.username} - -
-

{props.timeline.description}

- - {t(timelineVisibilityTooltipTranslationMap[props.timeline.visibility])} - -
- {onManage != null ? ( - - - {t("timeline.manage")} - - - onManage("nickname")}> - {t("timeline.manageItem.nickname")} - - onManage("avatar")}> - {t("timeline.manageItem.avatar")} - - onManage("property")}> - {t("timeline.manageItem.property")} - - - {t("timeline.manageItem.member")} - - - - ) : ( - - )} -
-
- ); -}; - -export default UserInfoCard; diff --git a/Timeline/ClientApp/src/app/user/UserPage.tsx b/Timeline/ClientApp/src/app/user/UserPage.tsx deleted file mode 100644 index ab498f30..00000000 --- a/Timeline/ClientApp/src/app/user/UserPage.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; - -import { ExcludeKey } from "../utilities/type"; -import TimelinePageTemplateUI, { - TimelinePageTemplateUIProps, -} from "../timeline/TimelinePageTemplateUI"; - -import UserInfoCard, { PersonalTimelineManageItem } from "./UserInfoCard"; - -export type UserPageProps = ExcludeKey< - TimelinePageTemplateUIProps, - "CardComponent" ->; - -const UserPage: React.FC = (props) => { - return ; -}; - -export default UserPage; diff --git a/Timeline/ClientApp/src/app/user/user-page.sass b/Timeline/ClientApp/src/app/user/user-page.sass deleted file mode 100644 index ca2d10f5..00000000 --- a/Timeline/ClientApp/src/app/user/user-page.sass +++ /dev/null @@ -1,10 +0,0 @@ -.login-container - max-width: 600px - -.change-avatar-cropper-row - max-height: 400px - -.change-avatar-img - min-width: 50% - max-width: 100% - max-height: 400px -- cgit v1.2.3