WS-3 session 1b-ii Task 4 (audit Buckets A, C, D — 26 items resolved
this commit; 24 indent items in useTimeSlotDropdown.ts remain — see
deviations).
Bucket A — Trivial fixes (12 items resolved):
- A.1: second-pass eslint --fix on App.vue resolved 4 multi-attribute
warnings. AppKpiCard / PortalLayout / PublicLayout
lines-around-comment items were attempted via blank-line addition,
but that introduced an equal number of vue/block-tag-newline
errors (the rules conflict at the SFC <script>-tag boundary). The
blank-line additions were reverted; net-zero, the 3 items remain
for a 1b-iii .eslintrc.cjs override decision.
- A.3: 6 unused-imports / unused-vars manual deletes:
* OrganisationSwitcher.vue: removed orphan toggleMenu() function
* CreateShiftDialog.vue: removed unused 'scenario' from destructure
* pages/events/[id]/time-slots/index.vue: removed unused 'event'
slot scope binding (template <#default="{ event }"> → <#default>)
* pages/organisation/companies.vue: removed unused authStore
declaration + import
* pages/platform/activity-log/index.vue: removed unused
search/searchDebounced pair
* PersonDetailPanel.vue:77: removed redundant single-statement
if-braces (curly autofix that the original pass didn't reach)
Bucket C — Style preference (8 items resolved):
- DismissFailureDialog.vue:43: collapsed two consecutive `if cond return false`
branches into `return !(cond)`
- FormFailureDetail.vue:44: replaced `void clipboard.writeText(...)` with
`clipboard.writeText(...).catch(() => {})` — fire-and-forget with
silent rejection (the no-void rule wants the void operator gone;
.catch() handles it semantically).
- AssignShiftDialog.vue:40-46: hasOverlapWarning collapsed from
always-false branching to `computed(() => false)` (the early-return
was dead code; backend enforces the constraint).
- SectionsShiftsPanel.vue:333 + registration-fields.vue:335: rewrote
`:delay-on-touch-only="true"` to attribute-shorthand `delay-on-touch-only`.
- AssignPersonDialog.vue:120-128: collapsed two `if outer { if inner ... }`
pairs into single `if (outer && inner)` form (sonarjs/no-collapsible-if).
- useImpersonationStore.ts:99-104: collapsed the same nested-if pattern
into `if (!data.data.active && state.value)`.
Bucket D — Vuetify utility class rename (5 items, 3 files):
- ml-1 → ms-1 (PersonDetailPanel:271, SectionsShiftsPanel:357,
AssignPersonDialog:496)
- pl-4 → ps-4 (AssignPersonDialog:457)
- ml-auto → ms-auto (AssignPersonDialog:471)
LTR/RTL-aware Vuetify utilities, matching the Vuexy reference idiom.
Tests + typecheck verified green.
Lint baseline: 62 → 36.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
73 lines
2.1 KiB
Vue
73 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import { useTheme } from 'vuetify'
|
|
import ScrollToTop from '@core/components/ScrollToTop.vue'
|
|
import initCore from '@core/initCore'
|
|
import { initConfigStore, useConfigStore } from '@core/stores/config'
|
|
import { hexToRgb } from '@core/utils/colorConverter'
|
|
import { useAuthStore } from '@/stores/useAuthStore'
|
|
import { useImpersonationStore } from '@/stores/useImpersonationStore'
|
|
import { useNotificationStore } from '@/stores/useNotificationStore'
|
|
|
|
const { global } = useTheme()
|
|
|
|
initCore()
|
|
initConfigStore()
|
|
|
|
const configStore = useConfigStore()
|
|
const authStore = useAuthStore()
|
|
const impersonationStore = useImpersonationStore()
|
|
const notificationStore = useNotificationStore()
|
|
|
|
// Restore impersonation state and listen for cross-tab sync
|
|
impersonationStore.restoreFromStorage()
|
|
impersonationStore.listenForBroadcasts()
|
|
|
|
// Validate stored token on app startup — must complete before rendering protected content
|
|
authStore.initialize()
|
|
</script>
|
|
|
|
<template>
|
|
<VLocaleProvider :rtl="configStore.isAppRTL">
|
|
<VApp :style="`--v-global-theme-primary: ${hexToRgb(global.current.value.colors.primary)}`">
|
|
<!-- Show loading state while validating auth token -->
|
|
<template v-if="!authStore.isInitialized">
|
|
<div
|
|
class="d-flex align-center justify-center"
|
|
style="min-height: 100vh;"
|
|
>
|
|
<VProgressCircular
|
|
indeterminate
|
|
color="primary"
|
|
size="48"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Only render app shell after auth is resolved -->
|
|
<template v-else>
|
|
<RouterView />
|
|
<ScrollToTop />
|
|
</template>
|
|
</VApp>
|
|
|
|
<!-- Global notification snackbar -->
|
|
<VSnackbar
|
|
v-model="notificationStore.visible"
|
|
:color="notificationStore.type"
|
|
:timeout="notificationStore.timeout"
|
|
location="top end"
|
|
>
|
|
{{ notificationStore.message }}
|
|
|
|
<template #actions>
|
|
<VBtn
|
|
variant="text"
|
|
@click="notificationStore.hide()"
|
|
>
|
|
Close
|
|
</VBtn>
|
|
</template>
|
|
</VSnackbar>
|
|
</VLocaleProvider>
|
|
</template>
|