204 lines
5.2 KiB
TypeScript
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
|
|
}
|
|
}) |