From 127e26a1433e2064126aebbd5a3a3d929946b14a Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 24 Apr 2024 11:03:38 +0800 Subject: [PATCH 1/3] chore: added custom error message to passwordInput component --- .../PasswordInput/PasswordConstants.ts | 2 +- src/components/PasswordInput/PasswordUtils.ts | 3 +- src/components/PasswordInput/index.tsx | 24 +++++++++++---- stories/PasswordInput.stories.tsx | 29 +++++++++++++++++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/components/PasswordInput/PasswordConstants.ts b/src/components/PasswordInput/PasswordConstants.ts index 90e55f7a..c880be0b 100644 --- a/src/components/PasswordInput/PasswordConstants.ts +++ b/src/components/PasswordInput/PasswordConstants.ts @@ -1,4 +1,4 @@ -export type TScore = 0 | 1 | 2 | 3 | 4; +export type TScore = 0 | 1 | 2 | 3 | 4 | 5; export type passwordKeys = | "common" diff --git a/src/components/PasswordInput/PasswordUtils.ts b/src/components/PasswordInput/PasswordUtils.ts index 309c4e27..5bcf6f45 100644 --- a/src/components/PasswordInput/PasswordUtils.ts +++ b/src/components/PasswordInput/PasswordUtils.ts @@ -31,8 +31,9 @@ export const isPasswordStrong = (password: string) => { ); }; -export const calculateScore = (password: string) => { +export const calculateScore = (password: string, customErrorMessage="") => { if (password?.length === 0) return 0; + if (customErrorMessage) return 5; if (!isPasswordValid(password)) return 1; if ( !isPasswordStrong(password) && diff --git a/src/components/PasswordInput/index.tsx b/src/components/PasswordInput/index.tsx index 64fc2ce9..57213c37 100644 --- a/src/components/PasswordInput/index.tsx +++ b/src/components/PasswordInput/index.tsx @@ -3,6 +3,7 @@ import React, { ComponentProps, FocusEvent, useCallback, + useEffect, useMemo, useState, } from "react"; @@ -22,8 +23,8 @@ import { EyeIcon, EyeIconSlash } from "./PasswordIcon"; import { PasswordMeter } from "./PasswordMeter"; import "./PasswordInput.scss"; -export const validatePassword = (password: string) => { - const score = calculateScore(password); +export const validatePassword = (password: string, customErrorMessage="") => { + const score = calculateScore(password, customErrorMessage); let errorMessage = ""; const options = { dictionary: { ...dictionary } }; @@ -36,9 +37,14 @@ export const validatePassword = (password: string) => { errorMessage = passwordErrorMessage.invalidLength; } else if (!isPasswordValid(password)) { errorMessage = passwordErrorMessage.missingCharacter; - } else { + } + else if( customErrorMessage){ + errorMessage = customErrorMessage; + } + else { errorMessage = warningMessages[feedback.warning as passwordKeys] ?? ""; } + return { errorMessage, score }; }; @@ -47,6 +53,7 @@ type InputProps = ComponentProps; interface PasswordInputProps extends Omit { hidePasswordMeter?: boolean; hint?: string; + customErrorMessage?: string; } const PasswordVariant: Record = { @@ -55,6 +62,7 @@ const PasswordVariant: Record = { 2: "warning", 3: "success", 4: "success", + 5: "error", }; /** @@ -86,19 +94,25 @@ export const PasswordInput = ({ onBlur, onChange, value, + customErrorMessage="", ...rest }: PasswordInputProps) => { + useEffect(() => { + setBackendErrorMessage(customErrorMessage); + }, [customErrorMessage]); const [isTouched, setIsTouched] = useState(false); const [showPassword, setShowPassword] = useState(false); + const [backendErrorMessage, setBackendErrorMessage] = useState(customErrorMessage); const { errorMessage, score } = useMemo( - () => validatePassword(value as string), - [value], + () => validatePassword(value as string, backendErrorMessage), + [value, backendErrorMessage], ); const handleChange = useCallback( (e: ChangeEvent) => { onChange?.(e); + setBackendErrorMessage(""); if (!isTouched) { setIsTouched(true); } diff --git a/stories/PasswordInput.stories.tsx b/stories/PasswordInput.stories.tsx index 8bb10453..287ac5be 100644 --- a/stories/PasswordInput.stories.tsx +++ b/stories/PasswordInput.stories.tsx @@ -1,6 +1,7 @@ import { StoryObj, Meta } from "@storybook/react"; import { PasswordInput } from "../src/main"; import { useState } from "react"; +import {Button} from "../src/main"; const meta = { title: "Components/PasswordInput", @@ -121,3 +122,31 @@ export const HidePasswordMeter: Story = { ); }, }; + +export const customErrorMessage: Story = { + name: "Password Input with custom error message", + args: { + label: "Enter Password", + value: "", + onChange: () => {}, + hidePasswordMeter: true, + hint: "This is a hint message", + }, + render: (args) => { + const [value, setValue] = useState(args.value); + const [errorMessage, setErrorMessage] = useState(""); + + + return ( +
+ setValue(e.target.value)} + /> + +
+ ); + }, +}; From 9d22be6a67dfcfac8a1139bb5f069684ba130a0f Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 24 Apr 2024 11:16:54 +0800 Subject: [PATCH 2/3] fix: fixed build issue --- src/components/PasswordInput/PasswordMeter.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/PasswordInput/PasswordMeter.tsx b/src/components/PasswordInput/PasswordMeter.tsx index f6d5df1f..51493dd6 100644 --- a/src/components/PasswordInput/PasswordMeter.tsx +++ b/src/components/PasswordInput/PasswordMeter.tsx @@ -13,6 +13,7 @@ const PasswordStrengthClass: Record = { 2: "deriv-password__meter__bar--moderate", 3: "deriv-password__meter__bar--strong", 4: "deriv-password__meter__bar--complete", + 5: "deriv-password__meter__bar--error", }; export const PasswordMeter = ({ score }: PasswordMeterProps) => ( From b6c4e525d311c1f39cc03112b5f902a6d9d0c202 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 24 Apr 2024 12:07:27 +0800 Subject: [PATCH 3/3] chore: formatting by prettier --- src/components/PasswordInput/PasswordUtils.ts | 2 +- src/components/PasswordInput/index.tsx | 8 ++++---- stories/PasswordInput.stories.tsx | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/PasswordInput/PasswordUtils.ts b/src/components/PasswordInput/PasswordUtils.ts index 5bcf6f45..14a5ccbe 100644 --- a/src/components/PasswordInput/PasswordUtils.ts +++ b/src/components/PasswordInput/PasswordUtils.ts @@ -31,7 +31,7 @@ export const isPasswordStrong = (password: string) => { ); }; -export const calculateScore = (password: string, customErrorMessage="") => { +export const calculateScore = (password: string, customErrorMessage = "") => { if (password?.length === 0) return 0; if (customErrorMessage) return 5; if (!isPasswordValid(password)) return 1; diff --git a/src/components/PasswordInput/index.tsx b/src/components/PasswordInput/index.tsx index 57213c37..d452a213 100644 --- a/src/components/PasswordInput/index.tsx +++ b/src/components/PasswordInput/index.tsx @@ -23,13 +23,13 @@ import { EyeIcon, EyeIconSlash } from "./PasswordIcon"; import { PasswordMeter } from "./PasswordMeter"; import "./PasswordInput.scss"; -export const validatePassword = (password: string, customErrorMessage="") => { +export const validatePassword = (password: string, customErrorMessage = "") => { const score = calculateScore(password, customErrorMessage); let errorMessage = ""; const options = { dictionary: { ...dictionary } }; zxcvbnOptions.setOptions(options); - if(!password){ + if (!password) { return { errorMessage, score }; } const { feedback } = zxcvbn(password); @@ -38,7 +38,7 @@ export const validatePassword = (password: string, customErrorMessage="") => { } else if (!isPasswordValid(password)) { errorMessage = passwordErrorMessage.missingCharacter; } - else if( customErrorMessage){ + else if (customErrorMessage) { errorMessage = customErrorMessage; } else { @@ -94,7 +94,7 @@ export const PasswordInput = ({ onBlur, onChange, value, - customErrorMessage="", + customErrorMessage = "", ...rest }: PasswordInputProps) => { useEffect(() => { diff --git a/stories/PasswordInput.stories.tsx b/stories/PasswordInput.stories.tsx index 287ac5be..b7d0f094 100644 --- a/stories/PasswordInput.stories.tsx +++ b/stories/PasswordInput.stories.tsx @@ -1,7 +1,7 @@ import { StoryObj, Meta } from "@storybook/react"; import { PasswordInput } from "../src/main"; import { useState } from "react"; -import {Button} from "../src/main"; +import { Button } from "../src/main"; const meta = { title: "Components/PasswordInput", @@ -13,7 +13,7 @@ const meta = { hideMessage: false, label: "Enter Password", value: "", - onChange: () => {}, + onChange: () => { }, hidePasswordMeter: false, hint: "This is a hint message", }, @@ -55,7 +55,7 @@ export const Default: Story = { args: { label: "Enter Password", value: "", - onChange: () => {}, + onChange: () => { }, hidePasswordMeter: false, hint: "This is a hint message", }, @@ -80,7 +80,7 @@ export const HideMessage: Story = { hideMessage: true, label: "Enter Password", value: "", - onChange: () => {}, + onChange: () => { }, hidePasswordMeter: false, hint: "This is a hint message", }, @@ -104,7 +104,7 @@ export const HidePasswordMeter: Story = { args: { label: "Enter Password", value: "", - onChange: () => {}, + onChange: () => { }, hidePasswordMeter: true, hint: "This is a hint message", }, @@ -128,7 +128,7 @@ export const customErrorMessage: Story = { args: { label: "Enter Password", value: "", - onChange: () => {}, + onChange: () => { }, hidePasswordMeter: true, hint: "This is a hint message", }, @@ -138,7 +138,7 @@ export const customErrorMessage: Story = { return ( -
+