Files
2026-03-23 21:43:40 +00:00

204 lines
5.2 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useAuthStore } from './auth'
import { useRBAC, type TilePermission } from '~/composables/useRBAC'
export interface UserTilePreference {
tileId: string
visible: boolean
position: number
size: 'small' | 'medium' | 'large'
}
export const useTileStore = defineStore('tiles', () => {
const authStore = useAuthStore()
const rbac = useRBAC()
// State
const userPreferences = ref<Record<string, UserTilePreference>>({})
const isLoading = ref(false)
// Initialize from localStorage
function loadPreferences() {
if (typeof window === 'undefined') return
const userId = authStore.user?.id
if (!userId) return
const stored = localStorage.getItem(`tile_preferences_${userId}`)
if (stored) {
try {
userPreferences.value = JSON.parse(stored)
} catch (err) {
console.error('Failed to parse tile preferences:', err)
userPreferences.value = {}
}
}
}
// Save to localStorage
function savePreferences() {
if (typeof window === 'undefined') return
const userId = authStore.user?.id
if (!userId) return
localStorage.setItem(`tile_preferences_${userId}`, JSON.stringify(userPreferences.value))
}
// Get default layout (sorted by tile ID for consistency)
const defaultLayout = computed(() => {
const filtered = rbac.getFilteredTiles()
return filtered.map((tile, index) => ({
tileId: tile.id,
visible: true,
position: index,
size: 'medium' as const
}))
})
// Check if layout has been modified from default
const isLayoutModified = computed(() => {
const currentPrefs = Object.values(userPreferences.value)
const defaultPrefs = defaultLayout.value
if (currentPrefs.length !== defaultPrefs.length) return true
// Check if any preference differs from default
for (const defaultPref of defaultPrefs) {
const currentPref = userPreferences.value[defaultPref.tileId]
if (!currentPref) return true
if (currentPref.visible !== defaultPref.visible ||
currentPref.position !== defaultPref.position ||
currentPref.size !== defaultPref.size) {
return true
}
}
return false
})
// Get user's accessible tiles with preferences
const accessibleTiles = computed(() => {
const filtered = rbac.getFilteredTiles()
return filtered.map(tile => {
const pref = userPreferences.value[tile.id] || {
tileId: tile.id,
visible: true,
position: 0,
size: 'medium' as const
}
return {
...tile,
preference: pref
}
}).sort((a, b) => a.preference.position - b.preference.position)
})
// Get visible tiles only
const visibleTiles = computed(() => {
return accessibleTiles.value.filter(tile => tile.preference.visible)
})
// Update tile preference
function updateTilePreference(tileId: string, updates: Partial<UserTilePreference>) {
const current = userPreferences.value[tileId] || {
tileId,
visible: true,
position: Object.keys(userPreferences.value).length,
size: 'medium'
}
userPreferences.value[tileId] = {
...current,
...updates
}
savePreferences()
}
// Toggle tile visibility
function toggleTileVisibility(tileId: string) {
const current = userPreferences.value[tileId]
updateTilePreference(tileId, {
visible: !(current?.visible ?? true)
})
}
// Update tile positions (for drag and drop)
function updateTilePositions(tileIds: string[]) {
tileIds.forEach((tileId, index) => {
updateTilePreference(tileId, { position: index })
})
}
// Reset to default preferences
function resetPreferences() {
const userId = authStore.user?.id
if (userId) {
localStorage.removeItem(`tile_preferences_${userId}`)
}
userPreferences.value = {}
// Reinitialize with default positions
const tiles = rbac.getFilteredTiles()
tiles.forEach((tile, index) => {
userPreferences.value[tile.id] = {
tileId: tile.id,
visible: true,
position: index,
size: 'medium'
}
})
savePreferences()
}
// Get tile size class for grid
function getTileSizeClass(size: 'small' | 'medium' | 'large'): string {
switch (size) {
case 'small': return 'cols-12 sm-6 md-4 lg-3'
case 'medium': return 'cols-12 sm-6 md-6 lg-4'
case 'large': return 'cols-12 md-12 lg-8'
default: return 'cols-12 sm-6 md-4 lg-3'
}
}
// Initialize when auth changes
authStore.$subscribe(() => {
if (authStore.isAuthenticated) {
loadPreferences()
} else {
userPreferences.value = {}
}
})
// Initial load
if (authStore.isAuthenticated) {
loadPreferences()
}
return {
// State
userPreferences,
isLoading,
// Getters
accessibleTiles,
visibleTiles,
defaultLayout,
isLayoutModified,
// Actions
updateTilePreference,
toggleTileVisibility,
updateTilePositions,
resetPreferences,
getTileSizeClass,
loadPreferences,
savePreferences
}
})