style(app): apply eslint --fix to Tier 1 (Vue templates)

WS-3 session 1b-i Tier 1.

Scope: src/components/**, src/pages/**, src/layouts/**, src/views/**
restricted to *.vue files. Mechanical formatting only — predominantly
vue/html-indent (506 fixes in CrowdListDetailPanel.vue alone),
padding-line-between-statements, antfu/if-newline.

Excludes (per session prompt):
- apps/app/vite.config.ts (Tier 3)
- apps/app/themeConfig.ts (Tier 3)
- apps/app/vitest.config.ts (Tier 3)
- All TypeScript-only files in src/composables, src/lib, src/stores,
  src/plugins, src/types (Tier 2 — separate commit)

Includes session 1a layouts (PortalLayout.vue, PublicLayout.vue) where
2 'lines-around-comment' errors were flagged in the previous 1b-i
pre-flight inspection.

Tests + typecheck verified green post-fix:
- apps/app vitest: 49 passed (unchanged)
- apps/app vue-tsc: clean (unchanged)
- apps/portal vitest: 113 passed (unchanged — not touched)
- backend pest: 1486 passed (unchanged — not touched)

Lint baseline progression:
- Pre-Tier-1: 1451 problems
- Post-Tier-1: 422 problems

Visual smoke status:
- NOT YET SMOKED — Bert to verify before merge. This Claude Code
  session has no UI access; cannot run pnpm dev and click through
  affected routes. The high-traffic candidates are
  CrowdListDetailPanel (506 fixes), AssignPersonDialog (44),
  ShiftDetailPanel (36), and the events / form-failures pages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-29 11:04:46 +02:00
parent dd8430f600
commit 47bd533179
77 changed files with 1277 additions and 993 deletions

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useAuthStore } from '@/stores/useAuthStore'
import { useUpdateProfile, useChangeEmail } from '@/composables/api/useAccount'
import { useChangeEmail, useUpdateProfile } from '@/composables/api/useAccount'
import type { UpdateProfilePayload } from '@/composables/api/useAccount'
import { avatarText } from '@core/utils/formatters'
@@ -15,6 +15,7 @@ const profileForm = ref<UpdateProfilePayload>({
timezone: 'Europe/Amsterdam',
locale: 'nl',
})
const profileFieldErrors = ref<Record<string, string>>({})
const profileSuccess = ref('')
@@ -23,7 +24,7 @@ const updateProfileMutation = useUpdateProfile()
// Populate form from auth store
watch(
() => authStore.user,
(user) => {
user => {
if (user) {
profileForm.value = {
first_name: user.first_name,
@@ -49,20 +50,20 @@ async function handleProfileSave() {
date_of_birth: profileForm.value.date_of_birth || null,
},
{
onSuccess: async (data) => {
onSuccess: async data => {
profileSuccess.value = data.message
// Re-fetch user data to update the store
const { apiClient } = await import('@/lib/axios')
const { data: meData } = await apiClient.get<{ success: boolean; data: import('@/types/auth').MeResponse }>('/auth/me')
authStore.setUser(meData.data)
},
onError: (err: unknown) => {
const ax = err as { response?: { data?: { message?: string; errors?: Record<string, string[]> } } }
if (ax.response?.data?.errors) {
for (const [key, messages] of Object.entries(ax.response.data.errors)) {
for (const [key, messages] of Object.entries(ax.response.data.errors))
profileFieldErrors.value[key] = messages[0]
}
}
},
},
@@ -74,6 +75,7 @@ const emailForm = ref({
new_email: '',
password: '',
})
const emailFieldErrors = ref<Record<string, string>>({})
const emailSuccess = ref('')
const showEmailPw = ref(false)
@@ -87,16 +89,15 @@ async function handleEmailChange() {
changeEmailMutation.mutate(
{ ...emailForm.value, app: 'app' },
{
onSuccess: (data) => {
onSuccess: data => {
emailSuccess.value = data.message
emailForm.value = { new_email: '', password: '' }
},
onError: (err: unknown) => {
const ax = err as { response?: { data?: { message?: string; errors?: Record<string, string[]> } } }
if (ax.response?.data?.errors) {
for (const [key, messages] of Object.entries(ax.response.data.errors)) {
for (const [key, messages] of Object.entries(ax.response.data.errors))
emailFieldErrors.value[key] = messages[0]
}
}
},
},
@@ -111,6 +112,7 @@ const avatarSrc = computed((): string | null => {
if (raw.startsWith('http://') || raw.startsWith('https://'))
return raw
const base = (import.meta.env.VITE_API_URL as string | undefined)?.replace(/\/api\/v1\/?$/, '') ?? ''
return raw.startsWith('/') ? `${base}${raw}` : `${base}/${raw}`
})

View File

@@ -3,11 +3,11 @@ import { useAuthStore } from '@/stores/useAuthStore'
import { useChangePassword } from '@/composables/api/useAccount'
import {
useMfaStatus,
useTrustedDevices,
useRevokeDevice,
useRevokeAllDevices,
useRegenerateBackupCodes,
useRevokeAllDevices,
useRevokeDevice,
useSetPreferredMethod,
useTrustedDevices,
} from '@/composables/api/useMfa'
import MfaTotpSetupDialog from '@/components/settings/MfaTotpSetupDialog.vue'
import MfaEmailSetupDialog from '@/components/settings/MfaEmailSetupDialog.vue'
@@ -22,6 +22,7 @@ const passwordForm = ref({
password: '',
password_confirmation: '',
})
const passwordFieldErrors = ref<Record<string, string>>({})
const passwordSuccess = ref('')
const showCurrentPw = ref(false)
@@ -30,8 +31,11 @@ const showConfirmPw = ref(false)
const passwordReqsRef = ref<InstanceType<typeof PasswordRequirements>>()
const confirmationError = computed(() => {
if (!passwordForm.value.password_confirmation) return ''
if (passwordForm.value.password !== passwordForm.value.password_confirmation) return 'Wachtwoorden komen niet overeen'
if (!passwordForm.value.password_confirmation)
return ''
if (passwordForm.value.password !== passwordForm.value.password_confirmation)
return 'Wachtwoorden komen niet overeen'
return ''
})
@@ -46,12 +50,13 @@ const canSubmitPassword = computed(() =>
const changePasswordMutation = useChangePassword()
async function handlePasswordChange() {
if (!canSubmitPassword.value) return
if (!canSubmitPassword.value)
return
passwordFieldErrors.value = {}
passwordSuccess.value = ''
changePasswordMutation.mutate(passwordForm.value, {
onSuccess: (data) => {
onSuccess: data => {
passwordSuccess.value = data.message
passwordForm.value = {
current_password: '',
@@ -62,9 +67,8 @@ async function handlePasswordChange() {
onError: (err: unknown) => {
const ax = err as { response?: { data?: { message?: string; errors?: Record<string, string[]> } } }
if (ax.response?.data?.errors) {
for (const [key, messages] of Object.entries(ax.response.data.errors)) {
for (const [key, messages] of Object.entries(ax.response.data.errors))
passwordFieldErrors.value[key] = messages[0]
}
}
},
})
@@ -98,17 +102,23 @@ function handleSetPreferred(method: 'totp' | 'email') {
}
const backupCodesRemaining = computed(() => mfaStatus.value?.backup_codes_remaining ?? 0)
const backupCodesColor = computed(() => {
if (backupCodesRemaining.value > 5) return 'success'
if (backupCodesRemaining.value >= 3) return 'warning'
if (backupCodesRemaining.value > 5)
return 'success'
if (backupCodesRemaining.value >= 3)
return 'warning'
return 'error'
})
function onSetupCompleted() {
// Refetch MFA status so the method cards update (enabled, method, backup codes)
refetchMfaStatus()
// Immediately clear the enforcement flag so the router guard unblocks navigation
authStore.mfaSetupRequired = false
// Refresh the full /auth/me response into the store so the flag stays
// correct on subsequent navigations (without needing a full page reload)
authStore.refreshUser()
@@ -252,7 +262,8 @@ function copyRegeneratedCodes() {
>
<VCard
variant="outlined"
:class="['mfa-method-card h-100', { 'mfa-method-card--primary': totpConfigured && preferredMethod === 'totp' }]"
class="mfa-method-card h-100"
:class="[{ 'mfa-method-card--primary': totpConfigured && preferredMethod === 'totp' }]"
>
<VCardText>
<VAvatar
@@ -336,7 +347,8 @@ function copyRegeneratedCodes() {
>
<VCard
variant="outlined"
:class="['mfa-method-card h-100', { 'mfa-method-card--primary': emailConfigured && preferredMethod === 'email' }]"
class="mfa-method-card h-100"
:class="[{ 'mfa-method-card--primary': emailConfigured && preferredMethod === 'email' }]"
>
<VCardText>
<VAvatar