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

@@ -87,7 +87,7 @@
{{ passkey.label }}
</div>
<div class="text-sm text-muted">
Added {{ formatDate(passkey.createdAt) }}
Added {{ formatDateTime(passkey.createdAt) }}
</div>
</div>
@@ -105,7 +105,10 @@
<script lang="ts" setup>
import type { FormError, FormSubmitEvent } from '@nuxt/ui'
import { MIN_PASSWORD_LENGTH, type PasskeySummary } from '~~/shared/auth'
import { getDefaultAuthenticatedPath, MIN_PASSWORD_LENGTH, type PasskeySummary } from '~~/shared/auth'
import { getErrorMessage } from '../../utils/errors'
import { formatDateTime } from '../../utils/formatters'
definePageMeta({
middleware: 'auth'
@@ -152,8 +155,8 @@ async function fetchPasskeys() {
}
function maybeRedirectAfterOnboarding(previouslyRequired: boolean) {
if (previouslyRequired && !auth.needsOnboarding.value) {
router.push(auth.isSuperAdmin.value ? '/management/users' : '/security')
if (previouslyRequired && auth.user.value && !auth.needsOnboarding.value) {
router.push(getDefaultAuthenticatedPath(auth.user.value))
}
}
@@ -192,7 +195,7 @@ async function changePassword(event: FormSubmitEvent<typeof passwordForm>) {
} catch (error: any) {
toast.add({
title: 'Password update failed',
description: error?.data?.statusMessage || 'Unable to update your password.',
description: getErrorMessage(error, 'Unable to update your password.'),
color: 'error',
icon: 'i-lucide-circle-alert'
})
@@ -246,7 +249,7 @@ async function registerPasskey() {
} catch (error: any) {
toast.add({
title: 'Passkey registration failed',
description: error?.data?.statusMessage || error?.message || 'Unable to register a passkey.',
description: getErrorMessage(error, 'Unable to register a passkey.'),
color: 'error',
icon: 'i-lucide-circle-alert'
})
@@ -254,15 +257,4 @@ async function registerPasskey() {
passkeyPending.value = false
}
}
function formatDate(value: string | null) {
if (!value) {
return 'Not available'
}
return new Intl.DateTimeFormat('en-MY', {
dateStyle: 'medium',
timeStyle: 'short'
}).format(new Date(value))
}
</script>