import { defineStore } from 'pinia' import { ref, computed } from 'vue' import { useLocations } from '@/composables/locations/useLocations' /** * Locations Store * Global state management for location data following CLAUDE.md guidelines * Orchestrates between composables and provides cross-component data sharing */ export const useLocationsStore = defineStore('locations', () => { // ==================== COMPOSABLE INTEGRATION ==================== const { locations, selectedLocation, loading, error, searchCriteria, miniLocations, searchLocations, loadMiniLocations, refreshLocations, updateSearchTerm, changePage, changePageSize, changeSorting, getLocationById, createLocation, updateLocation, deleteLocation, getChildLocations, selectLocation, clearSelectedLocation, validateLocation, formatLocationName, getLocationDisplayName, clearError } = useLocations() // ==================== ADDITIONAL GLOBAL STATE ==================== /** @type {import('vue').Ref} */ const recentLocations = ref([]) /** @type {import('vue').Ref} */ const locationFilters = ref({ type: '', status: 'all', // 'all', 'active', 'inactive' searchTerm: '' }) /** @type {import('vue').Ref} */ const showLocationModal = ref(false) /** @type {import('vue').Ref} */ const locationModalMode = ref('create') // 'create', 'edit', 'view' /** @type {import('vue').Ref} */ const locationHierarchy = ref({}) // ==================== COMPUTED PROPERTIES ==================== const activeLocations = computed(() => locations.value.content.filter(location => location.status !== 'inactive') ) const inactiveLocations = computed(() => locations.value.content.filter(location => location.status === 'inactive') ) const locationsByType = computed(() => { const grouped = {} locations.value.content.forEach(location => { const typeKey = location.type || 'General' if (!grouped[typeKey]) { grouped[typeKey] = [] } grouped[typeKey].push(location) }) return grouped }) const filteredLocations = computed(() => { let filtered = locations.value.content // Filter by type if (locationFilters.value.type) { filtered = filtered.filter(location => location.type === locationFilters.value.type ) } // Filter by status if (locationFilters.value.status === 'active') { filtered = filtered.filter(location => location.status !== 'inactive') } else if (locationFilters.value.status === 'inactive') { filtered = filtered.filter(location => location.status === 'inactive') } // Filter by search term if (locationFilters.value.searchTerm) { const searchTerm = locationFilters.value.searchTerm.toLowerCase() filtered = filtered.filter(location => location.name?.toLowerCase().includes(searchTerm) || location.description?.toLowerCase().includes(searchTerm) || location.address?.toLowerCase().includes(searchTerm) ) } return filtered }) const locationStats = computed(() => ({ total: locations.value.totalElements, active: activeLocations.value.length, inactive: inactiveLocations.value.length, byType: Object.keys(locationsByType.value).reduce((stats, type) => { stats[type] = locationsByType.value[type].length return stats }, {}) })) // ==================== ACTIONS ==================== /** * Initialize locations data * @returns {Promise} */ const initializeLocations = async () => { try { await Promise.all([ searchLocations(), loadMiniLocations() ]) } catch (err) { console.error('Failed to initialize locations:', err) } } /** * Search locations with filters * @param {Object} criteria - Search criteria * @returns {Promise} Search results */ const searchWithFilters = async (criteria = {}) => { const searchParams = { ...criteria, searchValue: locationFilters.value.searchTerm } return await searchLocations(searchParams) } /** * Update location filters and trigger search * @param {Object} filters - Filter updates * @returns {Promise} Search results */ const updateFilters = async (filters) => { locationFilters.value = { ...locationFilters.value, ...filters } return await searchWithFilters() } /** * Create new location and refresh data * @param {Object} locationData - Location data * @returns {Promise} Created location */ const createLocationAndRefresh = async (locationData) => { const response = await createLocation(locationData) // Refresh locations list after successful creation await refreshLocations() return response } /** * Update location and refresh data * @param {string|number} locationId - Location ID * @param {Object} locationData - Location data * @returns {Promise} Updated location */ const updateLocationAndRefresh = async (locationId, locationData) => { const updatedLocation = await updateLocation(locationId, locationData) await addToRecentLocations(updatedLocation) return updatedLocation } /** * Delete location and refresh data * @param {string|number} locationId - Location ID * @returns {Promise} Delete response */ const deleteLocationAndRefresh = async (locationId) => { const response = await deleteLocation(locationId) await refreshLocations() return response } /** * Select location and open in modal * @param {Object} location - Location to select * @param {string} mode - Modal mode ('view', 'edit') */ const openLocationModal = (location = null, mode = 'create') => { if (location) { selectLocation(location) locationModalMode.value = mode } else { clearSelectedLocation() locationModalMode.value = 'create' } showLocationModal.value = true } /** * Close location modal */ const closeLocationModal = () => { showLocationModal.value = false clearSelectedLocation() } /** * Add location to recent locations list * @param {Object} location - Location to add */ const addToRecentLocations = (location) => { if (!location) return // Remove if already exists const existingIndex = recentLocations.value.findIndex(l => l.id === location.id) if (existingIndex !== -1) { recentLocations.value.splice(existingIndex, 1) } // Add to beginning recentLocations.value.unshift(location) // Keep only last 10 if (recentLocations.value.length > 10) { recentLocations.value = recentLocations.value.slice(0, 10) } } /** * Get location by ID with caching * @param {string|number} locationId - Location ID * @returns {Promise} Location details */ const getLocation = async (locationId) => { // Check if location is already in current list const existingLocation = locations.value.content.find(l => l.id === locationId) if (existingLocation) { selectLocation(existingLocation) return existingLocation } // Fetch from API const location = await getLocationById(locationId) await addToRecentLocations(location) return location } /** * Build location hierarchy for a parent location * @param {string|number} parentLocationId - Parent location ID * @returns {Promise} Child locations hierarchy */ const buildLocationHierarchy = async (parentLocationId) => { const children = await getChildLocations(parentLocationId) locationHierarchy.value[parentLocationId] = children // Recursively build hierarchy for child locations for (const child of children) { if (child.hasChildren) { await buildLocationHierarchy(child.id) } } return children } /** * Clear all filters */ const clearFilters = () => { locationFilters.value = { type: '', status: 'all', searchTerm: '' } } /** * Reset store state */ const resetStore = () => { clearFilters() clearSelectedLocation() clearError() showLocationModal.value = false recentLocations.value = [] locationHierarchy.value = {} } // ==================== LEGACY SUPPORT ==================== /** * Legacy loadLocations method for backward compatibility * @deprecated Use initializeLocations instead */ const loadLocations = async () => { return await initializeLocations() } /** * Legacy locationCount for backward compatibility * @deprecated Use locationStats.total instead */ const locationCount = computed(() => locations.value.totalElements || 0) // ==================== RETURN STORE INTERFACE ==================== return { // State from composable locations, selectedLocation, loading, error, searchCriteria, miniLocations, // Additional global state recentLocations: computed(() => recentLocations.value), locationFilters: computed(() => locationFilters.value), showLocationModal: computed(() => showLocationModal.value), locationModalMode: computed(() => locationModalMode.value), locationHierarchy: computed(() => locationHierarchy.value), // Computed properties activeLocations, inactiveLocations, locationsByType, filteredLocations, locationStats, // Actions initializeLocations, searchWithFilters, updateFilters, createLocationAndRefresh, updateLocationAndRefresh, deleteLocationAndRefresh, openLocationModal, closeLocationModal, addToRecentLocations, getLocation, buildLocationHierarchy, clearFilters, resetStore, // Direct composable actions searchLocations, loadMiniLocations, refreshLocations, updateSearchTerm, changePage, changePageSize, changeSorting, getLocationById, createLocation, updateLocation, deleteLocation, getChildLocations, selectLocation, clearSelectedLocation, validateLocation, formatLocationName, getLocationDisplayName, clearError, // Legacy support loadLocations, locationCount } }) // Also export the legacy singular name for backward compatibility export const useLocationStore = useLocationsStore