Add shared empty states, customer product filters, and SSO handoff across dashboards.
Standardize list empty UI, searchable country fields, customer-products filter row, password/login polish, and one-time business dashboard handoff from the customer app. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
832ac32a09
commit
f8a9a28346
@@ -13,13 +13,9 @@ const PASSWORD_RULES = [
|
||||
id: 'number',
|
||||
test: (value: string) => /\d/.test(value),
|
||||
},
|
||||
{
|
||||
id: 'special',
|
||||
test: (value: string) => /[^A-Za-z0-9]/.test(value),
|
||||
},
|
||||
] as const
|
||||
|
||||
export type PasswordRuleId = (typeof PASSWORD_RULES)[number]['id']
|
||||
export type PasswordRuleId = (typeof PASSWORD_RULES)[number]['id'] | 'match'
|
||||
export type StrengthTone = 'empty' | 'weak' | 'fair' | 'good' | 'strong'
|
||||
|
||||
export type PasswordStrengthLabels = {
|
||||
@@ -43,16 +39,31 @@ const DEFAULT_LABELS: PasswordStrengthLabels = {
|
||||
length: 'At least 8 characters',
|
||||
upper: 'One uppercase letter',
|
||||
number: 'One number',
|
||||
special: 'One special character',
|
||||
match: 'Passwords match',
|
||||
},
|
||||
}
|
||||
|
||||
export function getPasswordChecks(password: string, labels: PasswordStrengthLabels = DEFAULT_LABELS) {
|
||||
return PASSWORD_RULES.map((rule) => ({
|
||||
id: rule.id,
|
||||
label: labels.rules[rule.id],
|
||||
met: rule.test(password),
|
||||
}))
|
||||
function passwordsMatch(password: string, confirmPassword: string) {
|
||||
return confirmPassword.length > 0 && password === confirmPassword
|
||||
}
|
||||
|
||||
export function getPasswordChecks(
|
||||
password: string,
|
||||
labels: PasswordStrengthLabels = DEFAULT_LABELS,
|
||||
confirmPassword = '',
|
||||
) {
|
||||
return [
|
||||
...PASSWORD_RULES.map((rule) => ({
|
||||
id: rule.id,
|
||||
label: labels.rules[rule.id],
|
||||
met: rule.test(password),
|
||||
})),
|
||||
{
|
||||
id: 'match' as const,
|
||||
label: labels.rules.match,
|
||||
met: passwordsMatch(password, confirmPassword),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export function getStrengthMeta(
|
||||
@@ -88,16 +99,18 @@ export function getPasswordValidationError(
|
||||
|
||||
export interface PasswordStrengthMeterProps {
|
||||
password: string
|
||||
confirmPassword?: string
|
||||
labels?: PasswordStrengthLabels
|
||||
id?: string
|
||||
}
|
||||
|
||||
export function PasswordStrengthMeter({
|
||||
password,
|
||||
confirmPassword = '',
|
||||
labels = DEFAULT_LABELS,
|
||||
id = 'password-strength',
|
||||
}: PasswordStrengthMeterProps) {
|
||||
const checks = getPasswordChecks(password, labels)
|
||||
const checks = getPasswordChecks(password, labels, confirmPassword)
|
||||
const metCount = checks.filter((check) => check.met).length
|
||||
const strength = getStrengthMeta(metCount, password.length > 0, labels)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user