refactor: centralize validation, error handling, and formatting logic

Extract shared auth logic and validation rules to shared/auth.ts
Introduce utility functions for HTTP errors and user input parsing
Standardize error messages and date formatting across the app
This commit is contained in:
2026-04-12 20:29:39 +08:00
parent 377a9617be
commit 07e5d42005
23 changed files with 294 additions and 267 deletions

View File

@@ -1,10 +1,19 @@
export const DEFAULT_USER_PASSWORD = '123456'
export const MIN_PASSWORD_LENGTH = 8
export const MIN_FULL_NAME_LENGTH = 2
export const USERNAME_PATTERN = /^[a-z0-9._-]{3,32}$/
export const PHONE_NUMBER_PATTERN = /^\+?\d{8,15}$/
export type UserRole = 'super_admin' | 'staff'
export function normalizeUsername(value: string) {
return value.trim().toLowerCase()
}
export function normalizeFullName(value: string) {
return value.trim()
}
export function normalizePhoneNumber(value: string) {
const trimmed = value.trim()
@@ -22,6 +31,18 @@ export function isValidPhoneNumber(value: string) {
return PHONE_NUMBER_PATTERN.test(normalizePhoneNumber(value))
}
export function isValidUsername(value: string) {
return USERNAME_PATTERN.test(normalizeUsername(value))
}
export function hasValidFullName(value: string) {
return normalizeFullName(value).length >= MIN_FULL_NAME_LENGTH
}
export function isUserRole(value: string | null | undefined): value is UserRole {
return value === 'super_admin' || value === 'staff'
}
export interface AuthUser {
id: string
username: string
@@ -55,3 +76,19 @@ export interface PasskeySummary {
deviceType: 'singleDevice' | 'multiDevice'
backedUp: boolean
}
export function needsUserOnboarding(
user: Pick<AuthUser, 'mustChangePassword' | 'needsPasskeySetup'> | null | undefined
) {
return Boolean(user && (user.mustChangePassword || user.needsPasskeySetup))
}
export function getDefaultAuthenticatedPath(
user: Pick<AuthUser, 'role' | 'mustChangePassword' | 'needsPasskeySetup'>
) {
if (needsUserOnboarding(user)) {
return '/security'
}
return user.role === 'super_admin' ? '/management/users' : '/security'
}