From a314b5350e269676e8c39eda4cc7842751b1a7fc Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 1 Sep 2020 02:32:06 +0800 Subject: ... --- .../ClientApp/src/app/views/settings/index.tsx | 221 +++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 Timeline/ClientApp/src/app/views/settings/index.tsx (limited to 'Timeline/ClientApp/src/app/views/settings') diff --git a/Timeline/ClientApp/src/app/views/settings/index.tsx b/Timeline/ClientApp/src/app/views/settings/index.tsx new file mode 100644 index 00000000..04834d39 --- /dev/null +++ b/Timeline/ClientApp/src/app/views/settings/index.tsx @@ -0,0 +1,221 @@ +import React, { useState } from "react"; +import { useHistory } from "react-router"; +import { useTranslation } from "react-i18next"; +import { + Container, + Row, + Col, + Input, + Modal, + ModalHeader, + ModalBody, + ModalFooter, + Button, +} from "reactstrap"; + +import { useUser, userService } from "@/services/user"; +import AppBar from "../common/AppBar"; +import OperationDialog, { + OperationInputErrorInfo, +} from "../common/OperationDialog"; + +interface ChangePasswordDialogProps { + open: boolean; + close: () => void; +} + +const ChangePasswordDialog: React.FC = (props) => { + const history = useHistory(); + const { t } = useTranslation(); + + const [redirect, setRedirect] = useState(false); + + return ( + + v === "" + ? "settings.dialogChangePassword.errorEmptyOldPassword" + : null, + }, + { + type: "text", + label: t("settings.dialogChangePassword.inputNewPassword"), + password: true, + validator: (v, values) => { + const error: OperationInputErrorInfo = {}; + error[1] = + v === "" + ? "settings.dialogChangePassword.errorEmptyNewPassword" + : null; + if (v === values[2]) { + error[2] = null; + } else { + if (values[2] !== "") { + error[2] = "settings.dialogChangePassword.errorRetypeNotMatch"; + } + } + return error; + }, + }, + { + type: "text", + label: t("settings.dialogChangePassword.inputRetypeNewPassword"), + password: true, + validator: (v, values) => + v !== values[1] + ? "settings.dialogChangePassword.errorRetypeNotMatch" + : null, + }, + ]} + onProcess={async ([oldPassword, newPassword]) => { + await userService + .changePassword(oldPassword as string, newPassword as string) + .toPromise(); + await userService.logout(); + setRedirect(true); + }} + close={() => { + props.close(); + if (redirect) { + history.push("/login"); + } + }} + /> + ); +}; + +const ConfirmLogoutDialog: React.FC<{ + toggle: () => void; + onConfirm: () => void; +}> = ({ toggle, onConfirm }) => { + const { t } = useTranslation(); + + return ( + + + {t("settings.dialogConfirmLogout.title")} + + {t("settings.dialogConfirmLogout.prompt")} + + + + + + ); +}; + +const SettingsPage: React.FC = (_) => { + const { i18n, t } = useTranslation(); + const user = useUser(); + const history = useHistory(); + + const [dialog, setDialog] = useState( + null + ); + + const language = i18n.language.slice(0, 2); + + return ( + <> + + + {user ? ( + <> + + +
{ + history.push(`/users/${user.username}`); + }} + > + {t("settings.gotoSelf")} +
+ +
+ + +
setDialog("changepassword")} + > + {t("settings.changePassword")} +
+ +
+ + +
{ + setDialog("logout"); + }} + > + {t("settings.logout")} +
+ +
+ + ) : null} + + +
{t("settings.languagePrimary")}
+

{t("settings.languageSecondary")}

+ + + { + void i18n.changeLanguage(e.target.value); + }} + > + + + + +
+ {(() => { + switch (dialog) { + case "changepassword": + return ( + { + setDialog(null); + }} + /> + ); + case "logout": + return ( + setDialog(null)} + onConfirm={() => { + void userService.logout().then(() => { + history.push("/"); + }); + }} + /> + ); + default: + return null; + } + })()} +
+ + ); +}; + +export default SettingsPage; -- cgit v1.2.3 From b06cd597488b2d1c12ef9e35b25bdba6a9d4b11e Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 2 Sep 2020 23:18:04 +0800 Subject: Migrate settings page. --- .../ClientApp/src/app/views/settings/index.tsx | 40 +++++++++------------- 1 file changed, 16 insertions(+), 24 deletions(-) (limited to 'Timeline/ClientApp/src/app/views/settings') diff --git a/Timeline/ClientApp/src/app/views/settings/index.tsx b/Timeline/ClientApp/src/app/views/settings/index.tsx index 04834d39..123e1353 100644 --- a/Timeline/ClientApp/src/app/views/settings/index.tsx +++ b/Timeline/ClientApp/src/app/views/settings/index.tsx @@ -1,17 +1,7 @@ import React, { useState } from "react"; import { useHistory } from "react-router"; import { useTranslation } from "react-i18next"; -import { - Container, - Row, - Col, - Input, - Modal, - ModalHeader, - ModalBody, - ModalFooter, - Button, -} from "reactstrap"; +import { Form, Container, Row, Col, Button, Modal } from "react-bootstrap"; import { useUser, userService } from "@/services/user"; import AppBar from "../common/AppBar"; @@ -100,19 +90,21 @@ const ConfirmLogoutDialog: React.FC<{ const { t } = useTranslation(); return ( - - - {t("settings.dialogConfirmLogout.title")} - - {t("settings.dialogConfirmLogout.prompt")} - - - - + ); }; @@ -131,7 +123,7 @@ const SettingsPage: React.FC = (_) => { return ( <> - + {user ? ( <> @@ -175,8 +167,8 @@ const SettingsPage: React.FC = (_) => {

{t("settings.languageSecondary")}

- { void i18n.changeLanguage(e.target.value); @@ -184,7 +176,7 @@ const SettingsPage: React.FC = (_) => { > - +
{(() => { -- cgit v1.2.3 From d9c2d4e6293599c5499d68679e4fe33b241379f1 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 3 Sep 2020 18:56:40 +0800 Subject: Move AppBar to App . --- Timeline/ClientApp/src/app/App.tsx | 75 +++++---- Timeline/ClientApp/src/app/views/about/index.tsx | 156 +++++++++---------- Timeline/ClientApp/src/app/views/admin/Admin.tsx | 2 - Timeline/ClientApp/src/app/views/home/index.tsx | 2 - Timeline/ClientApp/src/app/views/login/index.tsx | 151 +++++++++--------- .../ClientApp/src/app/views/settings/index.tsx | 170 ++++++++++----------- .../timeline-common/TimelinePageTemplateUI.tsx | 7 +- 7 files changed, 268 insertions(+), 295 deletions(-) (limited to 'Timeline/ClientApp/src/app/views/settings') diff --git a/Timeline/ClientApp/src/app/App.tsx b/Timeline/ClientApp/src/app/App.tsx index b64414b7..b68eddb6 100644 --- a/Timeline/ClientApp/src/app/App.tsx +++ b/Timeline/ClientApp/src/app/App.tsx @@ -11,6 +11,7 @@ import About from "./views/about"; import User from "./views/user"; import TimelinePage from "./views/timeline"; import AlertHost from "./views/common/alert/AlertHost"; + import { dataStorage } from "./services/common"; import { userService, useRawUser } from "./services/user"; @@ -38,50 +39,46 @@ const App: React.FC = () => { void dataStorage.ready().then(() => setLoading(false)); }, []); - let body; if (user === undefined || loading) { - body = ; + return ; } else { - body = ( - - - - - - - - - - - - - - - - - - - - - {user && user.administrator && ( - - + return ( + }> + + + + + + + + + + + + + + + + + - )} - - - - - + + + + {user && user.administrator && ( + + + + )} + + + + + + + ); } - - return ( - }> - {body} - - - ); }; export default hot(App); diff --git a/Timeline/ClientApp/src/app/views/about/index.tsx b/Timeline/ClientApp/src/app/views/about/index.tsx index 78cffb5f..e7771cec 100644 --- a/Timeline/ClientApp/src/app/views/about/index.tsx +++ b/Timeline/ClientApp/src/app/views/about/index.tsx @@ -1,8 +1,6 @@ import React from "react"; import { useTranslation, Trans } from "react-i18next"; -import AppBar from "../common/AppBar"; - import authorAvatarUrl from "./author-avatar.png"; import githubLogoUrl from "./github.png"; @@ -75,97 +73,91 @@ const AboutPage: React.FC = () => { const { t } = useTranslation(); return ( - <> - -
-
-

{t("about.author.title")}

-
-
- -
-

- {t("about.author.fullname")} - 杨宇千 -

-

- {t("about.author.nickname")} - crupest -

-

- {t("about.author.introduction")} - {t("about.author.introductionContent")} -

-
+
+
+

{t("about.author.title")}

+
+
+ +
+

+ {t("about.author.fullname")} + 杨宇千 +

+

+ {t("about.author.nickname")} + crupest +

+

+ {t("about.author.introduction")} + {t("about.author.introductionContent")} +

-

- {t("about.author.links")} - - - -

-
-
-

{t("about.site.title")}

-

- - 01234 - 56 - -

+ {t("about.author.links")} - {t("about.site.repo")} +

-
-

{t("about.credits.title")}

-

{t("about.credits.content")}

-

{t("about.credits.frontend")}

-
    - {frontendCredits.map((item, index) => { - return ( -
  • - - {item.name} - -
  • - ); - })} -
  • ...
  • -
-

{t("about.credits.backend")}

-
    - {backendCredits.map((item, index) => { - return ( -
  • - - {item.name} - -
  • - ); - })} -
  • ...
  • -
-
- +
+

{t("about.site.title")}

+

+ + 01234 + 56 + +

+

+ + {t("about.site.repo")} + +

+
+
+

{t("about.credits.title")}

+

{t("about.credits.content")}

+

{t("about.credits.frontend")}

+
    + {frontendCredits.map((item, index) => { + return ( +
  • + + {item.name} + +
  • + ); + })} +
  • ...
  • +
+

{t("about.credits.backend")}

+
    + {backendCredits.map((item, index) => { + return ( +
  • + + {item.name} + +
  • + ); + })} +
  • ...
  • +
+
+
); }; diff --git a/Timeline/ClientApp/src/app/views/admin/Admin.tsx b/Timeline/ClientApp/src/app/views/admin/Admin.tsx index e0f59b0f..9c0250e7 100644 --- a/Timeline/ClientApp/src/app/views/admin/Admin.tsx +++ b/Timeline/ClientApp/src/app/views/admin/Admin.tsx @@ -8,7 +8,6 @@ import { } from "react-router"; import { Nav } from "react-bootstrap"; -import AppBar from "../common/AppBar"; import { UserWithToken } from "@/services/user"; import UserAdmin from "./UserAdmin"; @@ -34,7 +33,6 @@ const Admin: React.FC = (props) => { ): React.ReactNode => { return ( -