mirror of
https://github.com/haveno-dex/haveno-ui.git
synced 2024-10-01 07:35:39 -04:00
chore: Account Security page ui
--- Reviewed-by: schowdhuri
This commit is contained in:
parent
b0d51c5efa
commit
d8dd987ccf
@ -21,7 +21,7 @@ import { AccountPaymentAccounts } from "@pages/Account/AccountPaymentAccounts";
|
||||
import { AccountNodeSettings } from "@pages/Account/AccountNodeSettings";
|
||||
import { AccountBackup } from "@pages/Account/AccountBackup";
|
||||
import { AccountWallet } from "@pages/Account/AccountWallet";
|
||||
import { AccountSecurity } from "@pages/Account/AccountSecurity";
|
||||
import { AccountSecurity } from "@pages/Account/Security";
|
||||
import { ROUTES } from "@constants/routes";
|
||||
import { PaymentMethods } from "@pages/Account";
|
||||
import { AddPaymentMethod } from "@organisms/AddPaymentMethod";
|
||||
|
@ -20,10 +20,18 @@ export enum LangKeys {
|
||||
Header = "app.header",
|
||||
ConnectingToNetwork = "app.connectingToNetwork",
|
||||
WelcomeToHaveno = "app.welcomeToHaveno",
|
||||
Save = "app.save",
|
||||
AccountTitle = "account.title",
|
||||
AccountSidebarPaymentAccounts = "account.sidebar.paymentAccounts",
|
||||
AccountSidebarSecurity = "account.sidebar.security",
|
||||
AccountSidebarWallet = "account.sidebar.wallet",
|
||||
AccountSidebarBackup = "account.sidebar.backup",
|
||||
AccountSidebarNodeSettings = "account.sidebar.nodeSettings",
|
||||
AccountSecurityTitle = "account.security.title",
|
||||
AccountSecurityDesc = "account.security.desc",
|
||||
AccountSecurityFieldPassword = "account.security.field.password",
|
||||
AccountSecurityFieldRepeatPassword = "account.security.field.repeatPassword",
|
||||
AccountSecurityFieldCurrentPassword = "account.security.field.currentPassword",
|
||||
AccountSecurityFieldPasswordFormatMsg = "account.security.field.password.format.message",
|
||||
AccountSecurityFieldRepeatPasswordMatchMsg = "account.security.field.repeatPassword.match.message",
|
||||
}
|
||||
|
@ -23,12 +23,23 @@ const LangPackEN: { [key in LangKeys]: string } = {
|
||||
[LangKeys.Header]: "Haveno",
|
||||
[LangKeys.WelcomeToHaveno]:
|
||||
"Welcome to Haveno. The world’s first Monero based decentralised exchange.",
|
||||
[LangKeys.Save]: "Save",
|
||||
[LangKeys.AccountTitle]: "Account",
|
||||
[LangKeys.AccountSidebarPaymentAccounts]: "Payment Accounts",
|
||||
[LangKeys.AccountSidebarSecurity]: "Security",
|
||||
[LangKeys.AccountSidebarWallet]: "Wallet",
|
||||
[LangKeys.AccountSidebarBackup]: "Backup",
|
||||
[LangKeys.AccountSidebarNodeSettings]: "Settings",
|
||||
[LangKeys.AccountSecurityTitle]: "Account Security",
|
||||
[LangKeys.AccountSecurityDesc]:
|
||||
"Haveno does not store any of your data, this happens solely locally on your device. It’s not possible to restore your password when lost. Please make sure you store a copy of it on a safe place.",
|
||||
[LangKeys.AccountSecurityFieldPassword]: "Password",
|
||||
[LangKeys.AccountSecurityFieldRepeatPassword]: "Repeat new password",
|
||||
[LangKeys.AccountSecurityFieldCurrentPassword]: "Current password",
|
||||
[LangKeys.AccountSecurityFieldPasswordFormatMsg]:
|
||||
"contain atleast {minChars} characters, one uppercase, one lowercase and one number.",
|
||||
[LangKeys.AccountSecurityFieldRepeatPasswordMatchMsg]:
|
||||
"Password confirmation doesn't match Password.",
|
||||
};
|
||||
|
||||
export default LangPackEN;
|
||||
|
@ -23,12 +23,23 @@ const LangPackES: { [key in LangKeys]: string } = {
|
||||
[LangKeys.Header]: "Haveno",
|
||||
[LangKeys.WelcomeToHaveno]:
|
||||
"Bienvenido a Haveno. El primer intercambio descentralizado basado en Monero del mundo.",
|
||||
[LangKeys.Save]: "Guardar",
|
||||
[LangKeys.AccountTitle]: "Cuenta",
|
||||
[LangKeys.AccountSidebarPaymentAccounts]: "Cuentas de pago",
|
||||
[LangKeys.AccountSidebarSecurity]: "Seguridad",
|
||||
[LangKeys.AccountSidebarWallet]: "Cartera",
|
||||
[LangKeys.AccountSidebarBackup]: "Respaldo",
|
||||
[LangKeys.AccountSidebarNodeSettings]: "Ajustes",
|
||||
[LangKeys.AccountSecurityTitle]: "Seguridad de la cuenta",
|
||||
[LangKeys.AccountSecurityDesc]:
|
||||
"Haveno no almacena ninguno de sus datos, esto ocurre únicamente localmente en su dispositivo. No es posible restaurar su contraseña cuando se pierde. Asegúrese de guardar una copia en un lugar seguro.",
|
||||
[LangKeys.AccountSecurityFieldPassword]: "Clave",
|
||||
[LangKeys.AccountSecurityFieldRepeatPassword]: "Repita la nueva contraseña",
|
||||
[LangKeys.AccountSecurityFieldCurrentPassword]: "Contraseña actual",
|
||||
[LangKeys.AccountSecurityFieldPasswordFormatMsg]:
|
||||
"contener al menos {minChars} caracteres, una mayúscula, una minúscula y un número.",
|
||||
[LangKeys.AccountSecurityFieldRepeatPasswordMatchMsg]:
|
||||
"La confirmación de la contraseña no coincide con la contraseña.",
|
||||
};
|
||||
|
||||
export default LangPackES;
|
||||
|
@ -0,0 +1,58 @@
|
||||
// =============================================================================
|
||||
// Copyright 2022 Haveno
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
import { LangKeys } from "@constants/lang";
|
||||
import { Stack, Box, createStyles, Group } from "@mantine/core";
|
||||
import { AccountLayout } from "@templates/AccountLayout";
|
||||
import { AccountSecurityForm } from "./AccountSecurityForm";
|
||||
import { Heading, BodyText } from "@atoms/Typography";
|
||||
import { WIDTH } from "./_constants";
|
||||
|
||||
function AccountSecurityHeader() {
|
||||
return (
|
||||
<Group spacing="sm">
|
||||
<Heading stringId={LangKeys.AccountSecurityTitle} order={3}>
|
||||
Account Security
|
||||
</Heading>
|
||||
<BodyText stringId={LangKeys.AccountSecurityDesc} size="md">
|
||||
Haveno does not store any of your data, this happens solely locally on
|
||||
your device. It’s not possible to restore your password when lost.
|
||||
Please make sure you store a copy of it on a safe place.
|
||||
</BodyText>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
export function AccountSecurity() {
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<AccountLayout>
|
||||
<Box className={classes.content}>
|
||||
<Stack spacing="lg">
|
||||
<AccountSecurityHeader />
|
||||
<AccountSecurityForm />
|
||||
</Stack>
|
||||
</Box>
|
||||
</AccountLayout>
|
||||
);
|
||||
}
|
||||
|
||||
const useStyles = createStyles(() => ({
|
||||
content: {
|
||||
maxWidth: WIDTH,
|
||||
},
|
||||
}));
|
@ -0,0 +1,86 @@
|
||||
// =============================================================================
|
||||
// Copyright 2022 Haveno
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Stack, Box, Group } from "@mantine/core";
|
||||
import { useForm, joiResolver } from "@mantine/form";
|
||||
import { TextInput } from "@atoms/TextInput";
|
||||
import { LangKeys } from "@constants/lang";
|
||||
import { useAccountSecurityFormSchema } from "./_hooks";
|
||||
import { Button } from "@atoms/Buttons";
|
||||
|
||||
export function AccountSecurityForm() {
|
||||
const accountSecurityFormSchema = useAccountSecurityFormSchema();
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
currentPassword: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
schema: joiResolver(accountSecurityFormSchema),
|
||||
});
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<form onSubmit={form.onSubmit((values) => console.log(values))}>
|
||||
<Stack spacing="lg">
|
||||
<TextInput
|
||||
id={"password"}
|
||||
type={"password"}
|
||||
required
|
||||
label={
|
||||
<FormattedMessage
|
||||
id={LangKeys.AccountSecurityFieldPassword}
|
||||
defaultMessage={"Password"}
|
||||
/>
|
||||
}
|
||||
{...form.getInputProps("password")}
|
||||
/>
|
||||
<TextInput
|
||||
id={"confirmPassword"}
|
||||
required
|
||||
type={"password"}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id={LangKeys.AccountSecurityFieldRepeatPassword}
|
||||
defaultMessage={"Repeat new password"}
|
||||
/>
|
||||
}
|
||||
{...form.getInputProps("confirmPassword")}
|
||||
/>
|
||||
<TextInput
|
||||
id={"currentPassword"}
|
||||
type={"password"}
|
||||
required
|
||||
label={
|
||||
<FormattedMessage
|
||||
id={LangKeys.AccountSecurityFieldCurrentPassword}
|
||||
defaultMessage={"Current password"}
|
||||
/>
|
||||
}
|
||||
{...form.getInputProps("currentPassword")}
|
||||
/>
|
||||
<Group position="right" mt="md">
|
||||
<Button size="md" type={"submit"}>
|
||||
<FormattedMessage id={LangKeys.Save} defaultMessage={"Save"} />
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</form>
|
||||
</Box>
|
||||
);
|
||||
}
|
@ -14,12 +14,7 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
import { AccountLayout } from "@templates/AccountLayout";
|
||||
export const WIDTH = 475;
|
||||
|
||||
export function AccountSecurity() {
|
||||
return (
|
||||
<AccountLayout>
|
||||
<h1>Account Security</h1>
|
||||
</AccountLayout>
|
||||
);
|
||||
}
|
||||
// The minimum characters that should password field contain.
|
||||
export const MIN_PASSWORD_CHARS = 8;
|
57
packages/renderer/src/pages/Account/Security/_hooks.ts
Normal file
57
packages/renderer/src/pages/Account/Security/_hooks.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { LangKeys } from "@constants/lang";
|
||||
import Joi from "joi";
|
||||
import { useIntl } from "react-intl";
|
||||
import { MIN_PASSWORD_CHARS } from "./_constants";
|
||||
|
||||
const getPasswordRegex = () => {
|
||||
return RegExp(
|
||||
`^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{${MIN_PASSWORD_CHARS},})`,
|
||||
"i"
|
||||
);
|
||||
};
|
||||
|
||||
export const useAccountSecurityFormSchema = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return Joi.object({
|
||||
password: Joi.string()
|
||||
.required()
|
||||
.regex(
|
||||
getPasswordRegex(),
|
||||
formatMessage(
|
||||
{
|
||||
id: LangKeys.AccountSecurityFieldPasswordFormatMsg,
|
||||
defaultMessage: `contain atleast ${MIN_PASSWORD_CHARS} characters, one uppercase, one lowercase and one number`,
|
||||
},
|
||||
{
|
||||
minChars: MIN_PASSWORD_CHARS,
|
||||
}
|
||||
)
|
||||
)
|
||||
.label(
|
||||
formatMessage({
|
||||
id: LangKeys.AccountSecurityFieldPassword,
|
||||
defaultMessage: "Password",
|
||||
})
|
||||
),
|
||||
confirmPassword: Joi.string()
|
||||
.valid(Joi.ref("password"))
|
||||
.required()
|
||||
.options({
|
||||
messages: {
|
||||
"any.only": formatMessage({
|
||||
id: LangKeys.AccountSecurityFieldRepeatPasswordMatchMsg,
|
||||
defaultMessage: "Password confirmation doesn't match Password.",
|
||||
}),
|
||||
},
|
||||
}),
|
||||
currentPassword: Joi.string()
|
||||
.required()
|
||||
.label(
|
||||
formatMessage({
|
||||
id: LangKeys.AccountSecurityFieldCurrentPassword,
|
||||
defaultMessage: "Current password",
|
||||
})
|
||||
),
|
||||
});
|
||||
};
|
17
packages/renderer/src/pages/Account/Security/index.ts
Normal file
17
packages/renderer/src/pages/Account/Security/index.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// =============================================================================
|
||||
// Copyright 2022 Haveno
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
export * from "./AccountSecurity";
|
39
yarn.lock
39
yarn.lock
@ -1074,7 +1074,7 @@
|
||||
pirates "^4.0.5"
|
||||
source-map-support "^0.5.16"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.17.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
|
||||
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
|
||||
@ -3178,9 +3178,9 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
|
||||
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
|
||||
|
||||
"@types/lodash@^4.14.182":
|
||||
"@types/lodash@^4.14.175", "@types/lodash@^4.14.182":
|
||||
version "4.14.182"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
|
||||
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
|
||||
integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==
|
||||
|
||||
"@types/mdast@^3.0.0":
|
||||
@ -9198,6 +9198,11 @@ locate-path@^6.0.0:
|
||||
dependencies:
|
||||
p-locate "^5.0.0"
|
||||
|
||||
lodash-es@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
@ -9778,6 +9783,11 @@ nano-time@1.0.0:
|
||||
dependencies:
|
||||
big-integer "^1.6.16"
|
||||
|
||||
nanoclone@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4"
|
||||
integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==
|
||||
|
||||
nanoid@^3.1.23:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
|
||||
@ -10785,6 +10795,11 @@ proper-lockfile@4.1.2:
|
||||
retry "^0.12.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
property-expr@^2.0.4:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4"
|
||||
integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==
|
||||
|
||||
property-information@^5.0.0, property-information@^5.3.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69"
|
||||
@ -12677,6 +12692,11 @@ toidentifier@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
toposort@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
|
||||
integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
@ -13746,6 +13766,19 @@ yocto-queue@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
||||
yup@^0.32.11:
|
||||
version "0.32.11"
|
||||
resolved "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5"
|
||||
integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.15.4"
|
||||
"@types/lodash" "^4.14.175"
|
||||
lodash "^4.17.21"
|
||||
lodash-es "^4.17.21"
|
||||
nanoclone "^0.2.1"
|
||||
property-expr "^2.0.4"
|
||||
toposort "^2.0.2"
|
||||
|
||||
zwitch@^1.0.0:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
|
||||
|
Loading…
Reference in New Issue
Block a user