import { ref, computed, watch } from 'vue' import { refDebounced } from '@vueuse/core' import type { Village } from '~/models/village' import type { SelectItem } from '~/components/pub/my-ui/form/select.vue' import { toTitleCase } from '~/lib/utils' import * as villageService from '~/services/village.service' // Global cache untuk villages berdasarkan district code const villagesCache = ref>(new Map()) const loadingStates = ref>(new Map()) const errorStates = ref>(new Map()) export function useVillages(districtCode: Ref | string | undefined) { // Convert districtCode ke ref jika bukan ref const districtCodeRef = typeof districtCode === 'string' || districtCode === undefined ? ref(districtCode) : districtCode // Computed untuk mendapatkan villages berdasarkan district code const villages = computed(() => { const code = districtCodeRef.value if (!code) return [] return villagesCache.value.get(code) || [] }) // Computed untuk loading state const isLoading = computed(() => { const code = districtCodeRef.value if (!code) return false return loadingStates.value.get(code) || false }) // Computed untuk error state const error = computed(() => { const code = districtCodeRef.value if (!code) return null return errorStates.value.get(code) || null }) // Computed untuk format SelectItem const villageOptions = computed(() => { return villages.value.map((village) => ({ label: toTitleCase(village.name), value: village.code, searchValue: `${village.code} ${village.name}`.trim(), })) }) // Function untuk fetch villages berdasarkan district code async function fetchVillages(districtCodeParam?: string, forceRefresh = false, isUserAction = false) { const code = districtCodeParam || districtCodeRef.value if (!code) return // Jika user action atau force refresh, selalu fetch // Jika bukan user action dan sudah ada cache, skip if (!isUserAction && !forceRefresh && villagesCache.value.has(code)) { return } // Jika sedang loading, skip untuk mencegah duplicate calls if (loadingStates.value.get(code)) { return } // Tambahan: Cek apakah ada pending request untuk code yang sama const pendingKey = `pending_${code}` if (loadingStates.value.get(pendingKey)) { return } loadingStates.value.set(pendingKey, true) loadingStates.value.set(code, true) errorStates.value.set(code, null) try { const response = await villageService.getList({ sort: 'name:asc', 'district-code': code, 'page-no-limit': true, }) if (response.success) { const villagesData = response.body.data || [] villagesCache.value.set(code, villagesData) } else { errorStates.value.set(code, 'Gagal memuat data kelurahan') console.error('Failed to fetch villages:', response) } } catch (err) { errorStates.value.set(code, 'Terjadi kesalahan saat memuat data kelurahan') console.error('Error fetching villages:', err) } finally { loadingStates.value.set(code, false) loadingStates.value.delete(pendingKey) } } // Function untuk mencari village berdasarkan code function getVillageByCode(code: string): Village | undefined { const districtCode = districtCodeRef.value if (!districtCode) return undefined const villagesForDistrict = villagesCache.value.get(districtCode) || [] return villagesForDistrict.find((village) => village.code === code) } // Function untuk mencari village berdasarkan name function getVillageByName(name: string): Village | undefined { const districtCode = districtCodeRef.value if (!districtCode) return undefined const villagesForDistrict = villagesCache.value.get(districtCode) || [] return villagesForDistrict.find((village) => village.name.toLowerCase() === name.toLowerCase()) } // Function untuk clear cache district tertentu function clearCache(districtCodeParam?: string) { const code = districtCodeParam || districtCodeRef.value if (code) { villagesCache.value.delete(code) loadingStates.value.delete(code) errorStates.value.delete(code) } } // Function untuk clear semua cache function clearAllCache() { villagesCache.value.clear() loadingStates.value.clear() errorStates.value.clear() } // Function untuk refresh data function refreshVillages(districtCodeParam?: string) { const code = districtCodeParam || districtCodeRef.value if (code) { return fetchVillages(code, true) } } // Debounced district code untuk mencegah multiple calls const debouncedDistrictCode = refDebounced(districtCodeRef, 100) // Watch perubahan district code untuk auto fetch watch( debouncedDistrictCode, (newCode, oldCode) => { if (newCode && newCode !== oldCode) { // Jika ada oldCode berarti user action (ganti pilihan) const isUserAction = !!oldCode fetchVillages(newCode, false, isUserAction) } }, { immediate: true }, ) return { // Data villages: readonly(villages), villageOptions, // State isLoading: readonly(isLoading), error: readonly(error), // Methods fetchVillages, refreshVillages, getVillageByCode, getVillageByName, clearCache, clearAllCache, } } // Export untuk direct access ke cached data (jika diperlukan) export const useVillagesCache = () => ({ villagesCache: readonly(villagesCache), loadingStates: readonly(loadingStates), errorStates: readonly(errorStates), })