From 232a19d7dfe0e3847b3a9a9a9be83485ffb9031c Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 30 May 2020 16:23:25 +0800 Subject: Merge front end to this repo. But I need to wait for aspnet core support for custom port and package manager for dev server. --- Timeline/ClientApp/src/settings/Settings.tsx | 200 +++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 Timeline/ClientApp/src/settings/Settings.tsx (limited to 'Timeline/ClientApp/src/settings/Settings.tsx') diff --git a/Timeline/ClientApp/src/settings/Settings.tsx b/Timeline/ClientApp/src/settings/Settings.tsx new file mode 100644 index 00000000..b3996fdc --- /dev/null +++ b/Timeline/ClientApp/src/settings/Settings.tsx @@ -0,0 +1,200 @@ +import React, { useState } from 'react'; +import { useHistory } from 'react-router'; +import { useTranslation } from 'react-i18next'; +import axios, { AxiosError } from 'axios'; +import { Container, Row, Col, Input } from 'reactstrap'; + +import { apiBaseUrl } from '../config'; + +import { useUser, userLogout } from '../data/user'; + +import AppBar from '../common/AppBar'; +import OperationDialog, { + OperationInputErrorInfo, +} from '../common/OperationDialog'; + +interface ChangePasswordDialogProps { + open: boolean; + close: () => void; +} + +async function changePassword( + oldPassword: string, + newPassword: string, + token: string +): Promise { + const url = `${apiBaseUrl}/userop/changepassword?token=${token}`; + try { + await axios.post(url, { + oldPassword, + newPassword, + }); + } catch (e) { + const error = e as AxiosError; + if ( + error.response && + error.response.status === 400 && + error.response.data && + error.response.data.message + ) { + throw error.response.data.message; + } + throw e; + } +} + +const ChangePasswordDialog: React.FC = (props) => { + const user = useUser()!; + 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 changePassword( + oldPassword as string, + newPassword as string, + user.token + ); + userLogout(); + setRedirect(true); + }} + close={() => { + props.close(); + if (redirect) { + history.push('/login'); + } + }} + /> + ); +}; + +const Settings: 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')} +
+ +
+ + +
{ + userLogout(); + history.push('/'); + }} + > + {t('settings.logout')} +
+ +
+ + ) : null} + + +
{t('settings.languagePrimary')}
+

{t('settings.languageSecondary')}

+ + + { + i18n.changeLanguage(e.target.value); + }} + > + + + + +
+ {dialog === 'changepassword' ? ( + { + setDialog(null); + }} + /> + ) : null} +
+ + ); +}; + +export default Settings; -- cgit v1.2.3