import { ref, computed, watch, readonly, type Ref } from 'vue' import { refDebounced } from '@vueuse/core' import type { PostalCode } from '~/models/postal-code' import type { SelectItem } from '~/components/pub/my-ui/form/select.vue' import * as postalCodeService from '../services/postal-code.service' // Global cache untuk postal codes berdasarkan village code const postalCodesCache = ref>(new Map()) const loadingStates = ref>(new Map()) const errorStates = ref>(new Map()) export function usePostalCodes(villageCode: Ref | string | undefined) { // Convert villageCode ke ref jika bukan ref const villageCodeRef = typeof villageCode === 'string' || villageCode === undefined ? ref(villageCode) : villageCode // Computed untuk mendapatkan postalCodes berdasarkan village code const postalCodes = computed(() => { const code = villageCodeRef.value if (!code) return [] return postalCodesCache.value.get(code) || [] }) // Computed untuk loading state const isLoading = computed(() => { const code = villageCodeRef.value if (!code) return false return loadingStates.value.get(code) || false }) // Computed untuk error state const error = computed(() => { const code = villageCodeRef.value if (!code) return null return errorStates.value.get(code) || null }) // Computed untuk format SelectItem const postalCodeOptions = computed(() => { return postalCodes.value.map((postalCode) => ({ label: postalCode.code, value: postalCode.code, searchValue: postalCode.code, })) }) // Function untuk fetch postalCodes berdasarkan village code async function fetchPostalCodes(villageCodeParam?: string, forceRefresh = false, isUserAction = false) { const code = villageCodeParam || villageCodeRef.value if (!code) return // Jika user action atau force refresh, selalu fetch // Jika bukan user action dan sudah ada cache, skip if (!isUserAction && !forceRefresh && postalCodesCache.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 postalCodeService.getList({ sort: 'code:asc', 'village-code': code, 'page-no-limit': true, }) if (response.success) { const postalCodesData = response.body.data || [] postalCodesCache.value.set(code, postalCodesData) } else { errorStates.value.set(code, 'Gagal memuat data kode pos') console.error('Failed to fetch postal codes:', response) } } catch (err) { errorStates.value.set(code, 'Terjadi kesalahan saat memuat data kode pos') console.error('Error fetching postal codes:', err) } finally { loadingStates.value.set(code, false) loadingStates.value.delete(pendingKey) } } // Function untuk mencari postalCode berdasarkan code function getPostalCodeByCode(code: string): PostalCode | undefined { const villageCode = villageCodeRef.value if (!villageCode) return undefined const postalCodesForVillage = postalCodesCache.value.get(villageCode) || [] return postalCodesForVillage.find((postalCode) => postalCode.code === code) } // Function untuk clear cache village tertentu function clearCache(villageCodeParam?: string) { const code = villageCodeParam || villageCodeRef.value if (code) { postalCodesCache.value.delete(code) loadingStates.value.delete(code) errorStates.value.delete(code) } } // Function untuk clear semua cache function clearAllCache() { postalCodesCache.value.clear() loadingStates.value.clear() errorStates.value.clear() } // Function untuk refresh data function refreshPostalCodes(villageCodeParam?: string) { const code = villageCodeParam || villageCodeRef.value if (code) { return fetchPostalCodes(code, true) } } // Debounced village code untuk mencegah multiple calls const debouncedVillageCode = refDebounced(villageCodeRef, 100) // Watch perubahan village code untuk auto fetch watch( debouncedVillageCode, (newCode, oldCode) => { if (newCode && newCode !== oldCode) { // Jika ada oldCode berarti user action (ganti pilihan) const isUserAction = !!oldCode fetchPostalCodes(newCode, false, isUserAction) } }, { immediate: true }, ) return { // Data postalCodes: readonly(postalCodes), postalCodeOptions, // State isLoading: readonly(isLoading), error: readonly(error), // Methods fetchPostalCodes, refreshPostalCodes, getPostalCodeByCode, clearCache, clearAllCache, } } // Export untuk direct access ke cached data (jika diperlukan) export const usePostalCodesCache = () => ({ postalCodesCache: readonly(postalCodesCache), loadingStates: readonly(loadingStates), errorStates: readonly(errorStates), })