Refactor frontend components for improved functionality and accessibility
- Consolidated global error handling in app.vue to redirect users to the login page on API authentication failure. - Enhanced MapView component by reintroducing event listeners for selected map and marker updates, improving interactivity. - Updated PasswordInput and various modal components to ensure proper input handling and accessibility compliance. - Refactored MapControls and MapControlsContent to streamline prop management and enhance user experience. - Improved error handling in local storage operations within useMapBookmarks and useRecentLocations composables. - Standardized input elements across forms for consistency in user interaction.
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import { useAppPaths } from '../useAppPaths'
|
||||
|
||||
const useRuntimeConfigMock = vi.fn()
|
||||
vi.stubGlobal('useRuntimeConfig', useRuntimeConfigMock)
|
||||
|
||||
import { useAppPaths } from '../useAppPaths'
|
||||
|
||||
describe('useAppPaths with default base /', () => {
|
||||
beforeEach(() => {
|
||||
useRuntimeConfigMock.mockReturnValue({ app: { baseURL: '/' } })
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
import { useMapApi } from '../useMapApi'
|
||||
|
||||
vi.stubGlobal('useRuntimeConfig', () => ({
|
||||
app: { baseURL: '/' },
|
||||
public: { apiBase: '/map/api' },
|
||||
}))
|
||||
|
||||
import { useMapApi } from '../useMapApi'
|
||||
|
||||
function mockFetch(status: number, body: unknown, contentType = 'application/json') {
|
||||
return vi.fn().mockResolvedValue({
|
||||
ok: status >= 200 && status < 300,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { useMapBookmarks } from '../useMapBookmarks'
|
||||
|
||||
const stateByKey: Record<string, ReturnType<typeof ref>> = {}
|
||||
const useStateMock = vi.fn((key: string, init: () => unknown) => {
|
||||
if (!stateByKey[key]) {
|
||||
@@ -18,15 +20,13 @@ const localStorageMock = {
|
||||
storage[key] = value
|
||||
}),
|
||||
clear: vi.fn(() => {
|
||||
for (const k of Object.keys(storage)) delete storage[k]
|
||||
delete storage['hnh-map-bookmarks']
|
||||
}),
|
||||
}
|
||||
vi.stubGlobal('localStorage', localStorageMock)
|
||||
vi.stubGlobal('import.meta.server', false)
|
||||
vi.stubGlobal('import.meta.client', true)
|
||||
|
||||
import { useMapBookmarks } from '../useMapBookmarks'
|
||||
|
||||
describe('useMapBookmarks', () => {
|
||||
beforeEach(() => {
|
||||
storage['hnh-map-bookmarks'] = '[]'
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { ref, reactive } from 'vue'
|
||||
import type { Map } from 'leaflet'
|
||||
|
||||
import { useMapLogic } from '../useMapLogic'
|
||||
|
||||
vi.stubGlobal('ref', ref)
|
||||
vi.stubGlobal('reactive', reactive)
|
||||
|
||||
import { useMapLogic } from '../useMapLogic'
|
||||
|
||||
describe('useMapLogic', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
@@ -27,7 +28,7 @@ describe('useMapLogic', () => {
|
||||
it('zoomIn calls map.zoomIn', () => {
|
||||
const { zoomIn } = useMapLogic()
|
||||
const mockMap = { zoomIn: vi.fn() }
|
||||
zoomIn(mockMap as unknown as import('leaflet').Map)
|
||||
zoomIn(mockMap as unknown as Map)
|
||||
expect(mockMap.zoomIn).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
@@ -39,7 +40,7 @@ describe('useMapLogic', () => {
|
||||
it('zoomOutControl calls map.zoomOut', () => {
|
||||
const { zoomOutControl } = useMapLogic()
|
||||
const mockMap = { zoomOut: vi.fn() }
|
||||
zoomOutControl(mockMap as unknown as import('leaflet').Map)
|
||||
zoomOutControl(mockMap as unknown as Map)
|
||||
expect(mockMap.zoomOut).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
@@ -47,7 +48,7 @@ describe('useMapLogic', () => {
|
||||
const { state, resetView } = useMapLogic()
|
||||
state.trackingCharacterId.value = 42
|
||||
const mockMap = { setView: vi.fn() }
|
||||
resetView(mockMap as unknown as import('leaflet').Map)
|
||||
resetView(mockMap as unknown as Map)
|
||||
expect(state.trackingCharacterId.value).toBe(-1)
|
||||
expect(mockMap.setView).toHaveBeenCalledWith([0, 0], 1, { animate: false })
|
||||
})
|
||||
@@ -59,7 +60,7 @@ describe('useMapLogic', () => {
|
||||
getCenter: vi.fn(() => ({ lat: 0, lng: 0 })),
|
||||
getZoom: vi.fn(() => 3),
|
||||
}
|
||||
updateDisplayCoords(mockMap as unknown as import('leaflet').Map)
|
||||
updateDisplayCoords(mockMap as unknown as Map)
|
||||
expect(state.displayCoords.value).toEqual({ x: 5, y: 3, z: 3 })
|
||||
})
|
||||
|
||||
@@ -72,7 +73,7 @@ describe('useMapLogic', () => {
|
||||
it('toLatLng calls map.unproject', () => {
|
||||
const { toLatLng } = useMapLogic()
|
||||
const mockMap = { unproject: vi.fn(() => ({ lat: 1, lng: 2 })) }
|
||||
const result = toLatLng(mockMap as unknown as import('leaflet').Map, 100, 200)
|
||||
const result = toLatLng(mockMap as unknown as Map, 100, 200)
|
||||
expect(mockMap.unproject).toHaveBeenCalledWith([100, 200], 6)
|
||||
expect(result).toEqual({ lat: 1, lng: 2 })
|
||||
})
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { useToast } from '../useToast'
|
||||
|
||||
const stateByKey: Record<string, ReturnType<typeof ref>> = {}
|
||||
const useStateMock = vi.fn((key: string, init: () => unknown) => {
|
||||
if (!stateByKey[key]) {
|
||||
@@ -10,8 +12,6 @@ const useStateMock = vi.fn((key: string, init: () => unknown) => {
|
||||
})
|
||||
vi.stubGlobal('useState', useStateMock)
|
||||
|
||||
import { useToast } from '../useToast'
|
||||
|
||||
describe('useToast', () => {
|
||||
beforeEach(() => {
|
||||
stateByKey['hnh-map-toasts'] = ref([])
|
||||
|
||||
@@ -29,7 +29,7 @@ function saveBookmarks(bookmarks: MapBookmark[]) {
|
||||
if (import.meta.server) return
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(bookmarks.slice(0, MAX_BOOKMARKS)))
|
||||
} catch (_) {}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
export function useMapBookmarks() {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import type { SmartTileLayer } from '~/lib/SmartTileLayer'
|
||||
import type { Marker as ApiMarker, Character as ApiCharacter } from '~/types/api'
|
||||
|
||||
type LeafletModule = L
|
||||
type SmartTileLayerInstance = InstanceType<typeof SmartTileLayer>
|
||||
|
||||
function escapeHtml(s: string): string {
|
||||
@@ -25,7 +26,7 @@ function escapeHtml(s: string): string {
|
||||
|
||||
export interface MapLayersOptions {
|
||||
/** Leaflet API (from dynamic import). Required for creating markers and characters without static leaflet import. */
|
||||
L: typeof import('leaflet')
|
||||
L: LeafletModule
|
||||
map: L.Map
|
||||
markerLayer: L.LayerGroup
|
||||
layer: SmartTileLayerInstance
|
||||
@@ -33,7 +34,7 @@ export interface MapLayersOptions {
|
||||
getCurrentMapId: () => number
|
||||
setCurrentMapId: (id: number) => void
|
||||
setSelectedMapId: (id: number) => void
|
||||
getAuths: () => string[]
|
||||
getAuths?: () => string[]
|
||||
getTrackingCharacterId: () => number
|
||||
setTrackingCharacterId: (id: number) => void
|
||||
onMarkerContextMenu: (clientX: number, clientY: number, id: number, name: string) => void
|
||||
@@ -69,7 +70,7 @@ export function createMapLayers(options: MapLayersOptions): MapLayersManager {
|
||||
getCurrentMapId,
|
||||
setCurrentMapId,
|
||||
setSelectedMapId,
|
||||
getAuths,
|
||||
getAuths: _getAuths,
|
||||
getTrackingCharacterId,
|
||||
setTrackingCharacterId,
|
||||
onMarkerContextMenu,
|
||||
|
||||
@@ -26,7 +26,7 @@ function saveRecent(list: RecentLocation[]) {
|
||||
if (import.meta.server) return
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(list.slice(0, MAX_RECENT)))
|
||||
} catch (_) {}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
export function useRecentLocations() {
|
||||
|
||||
Reference in New Issue
Block a user