Merged in feat/new-passwordinput-component (pull request #3376)

feat(SW-3672): Update PasswordInput component

* Update PasswordInput component

* Removed some tests not working as expected

* Remove IconButton from PasswordInput

* Remove IconButton from Input

* Merge branch 'master' into feat/new-passwordinput-component


Approved-by: Linus Flood
This commit is contained in:
Rasmus Langvad
2026-01-07 09:10:22 +00:00
parent 8c03a8b560
commit ffef566316
13 changed files with 665 additions and 206 deletions

View File

@@ -0,0 +1,126 @@
import { useIntl } from 'react-intl'
import { passwordValidators } from '@scandic-hotels/common/utils/zod/passwordValidator'
import type { PasswordValidatorKey } from '@scandic-hotels/common/utils/zod/newPassword'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import styles from './passwordInput.module.css'
export function NewPasswordValidation({
value,
errors,
id,
}: {
value: string
errors: string[]
id: string
}) {
const intl = useIntl()
if (!value) return null
function getErrorMessage(key: PasswordValidatorKey) {
switch (key) {
case 'length':
return intl.formatMessage(
{
id: 'passwordInput.lengthRequirement',
defaultMessage: '{min} to {max} characters',
},
{
min: 10,
max: 40,
}
)
case 'hasUppercase':
return intl.formatMessage(
{
id: 'passwordInput.uppercaseRequirement',
defaultMessage: '{count} uppercase letter',
},
{ count: 1 }
)
case 'hasLowercase':
return intl.formatMessage(
{
id: 'passwordInput.lowercaseRequirement',
defaultMessage: '{count} lowercase letter',
},
{ count: 1 }
)
case 'hasNumber':
return intl.formatMessage(
{
id: 'passwordInput.numberRequirement',
defaultMessage: '{count} number',
},
{ count: 1 }
)
case 'hasSpecialChar':
return intl.formatMessage(
{
id: 'passwordInput.specialCharacterRequirement',
defaultMessage: '{count} special character',
},
{ count: 1 }
)
case 'allowedCharacters':
return intl.formatMessage({
id: 'passwordInput.allowedCharactersRequirement',
defaultMessage: 'Only allowed characters',
})
}
}
return (
<div
className={styles.errors}
role="status"
aria-live="polite"
aria-atomic="false"
id={id}
>
{Object.entries(passwordValidators).map(([key, { message }]) => (
<Typography variant="Label/xsRegular" key={key}>
<span className={styles.helpText}>
<Icon errorMessage={message} errors={errors} />
{getErrorMessage(key as PasswordValidatorKey)}
</span>
</Typography>
))}
</div>
)
}
interface IconProps {
errorMessage: string
errors: string[]
}
function Icon({ errorMessage, errors }: IconProps) {
const intl = useIntl()
return errors.includes(errorMessage) ? (
<MaterialIcon
icon="close"
color="Icon/Feedback/Error"
size={20}
role="img"
aria-label={intl.formatMessage({
id: 'common.error',
defaultMessage: 'Error',
})}
/>
) : (
<MaterialIcon
icon="check"
color="Icon/Feedback/Success"
size={20}
role="img"
aria-label={intl.formatMessage({
id: 'common.success',
defaultMessage: 'Success',
})}
/>
)
}