Files
simrsx-fe/app/composables/useRegencies.ts
T
Khafid Prayoga 1f93fc2c81 refactor(composables): update API query params and improve code style
- Standardize parameter naming with hyphens instead of underscores
- Remove page size limit and enable no-limit flag for all region queries
- Improve arrow function syntax consistency and formatting
2025-10-09 10:13:00 +07:00

182 lines
5.7 KiB
TypeScript

import { ref, computed, watch } from 'vue'
import { refDebounced } from '@vueuse/core'
import type { Regency } from '~/models/regency'
import type { SelectItem } from '~/components/pub/my-ui/form/select.vue'
import { toTitleCase } from '~/lib/utils'
import * as regencyService from '~/services/regency.service'
// Global cache untuk regencies berdasarkan province code
const regenciesCache = ref<Map<string, Regency[]>>(new Map())
const loadingStates = ref<Map<string, boolean>>(new Map())
const errorStates = ref<Map<string, string | null>>(new Map())
export function useRegencies(provinceCode: Ref<string | undefined> | string | undefined) {
// Convert provinceCode ke ref jika bukan ref
const provinceCodeRef =
typeof provinceCode === 'string' || provinceCode === undefined ? ref(provinceCode) : provinceCode
// Computed untuk mendapatkan regencies berdasarkan province code
const regencies = computed(() => {
const code = provinceCodeRef.value
if (!code) return []
return regenciesCache.value.get(code) || []
})
// Computed untuk loading state
const isLoading = computed(() => {
const code = provinceCodeRef.value
if (!code) return false
return loadingStates.value.get(code) || false
})
// Computed untuk error state
const error = computed(() => {
const code = provinceCodeRef.value
if (!code) return null
return errorStates.value.get(code) || null
})
// Computed untuk format SelectItem
const regencyOptions = computed<SelectItem[]>(() => {
return regencies.value.map((regency) => ({
label: toTitleCase(regency.name),
value: regency.code,
searchValue: `${regency.code} ${regency.name}`.trim(),
}))
})
// Function untuk fetch regencies berdasarkan province code
async function fetchRegencies(provinceCodeParam?: string, forceRefresh = false, isUserAction = false) {
const code = provinceCodeParam || provinceCodeRef.value
if (!code) return
// Jika user action atau force refresh, selalu fetch
// Jika bukan user action dan sudah ada cache, skip
if (!isUserAction && !forceRefresh && regenciesCache.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 regencyService.getList({
sort: 'name:asc',
'page-no-limit': true,
'province-code': code,
})
if (response.success) {
const regenciesData = response.body.data || []
regenciesCache.value.set(code, regenciesData)
} else {
errorStates.value.set(code, 'Gagal memuat data kabupaten/kota')
console.error('Failed to fetch regencies:', response)
}
} catch (err) {
errorStates.value.set(code, 'Terjadi kesalahan saat memuat data kabupaten/kota')
console.error('Error fetching regencies:', err)
} finally {
loadingStates.value.set(code, false)
loadingStates.value.delete(pendingKey)
}
}
// Function untuk mencari regency berdasarkan code
function getRegencyByCode(code: string): Regency | undefined {
const provinceCode = provinceCodeRef.value
if (!provinceCode) return undefined
const regenciesForProvince = regenciesCache.value.get(provinceCode) || []
return regenciesForProvince.find((regency) => regency.code === code)
}
// Function untuk mencari regency berdasarkan name
function getRegencyByName(name: string): Regency | undefined {
const provinceCode = provinceCodeRef.value
if (!provinceCode) return undefined
const regenciesForProvince = regenciesCache.value.get(provinceCode) || []
return regenciesForProvince.find((regency) => regency.name.toLowerCase() === name.toLowerCase())
}
// Function untuk clear cache province tertentu
function clearCache(provinceCodeParam?: string) {
const code = provinceCodeParam || provinceCodeRef.value
if (code) {
regenciesCache.value.delete(code)
loadingStates.value.delete(code)
errorStates.value.delete(code)
}
}
// Function untuk clear semua cache
function clearAllCache() {
regenciesCache.value.clear()
loadingStates.value.clear()
errorStates.value.clear()
}
// Function untuk refresh data
function refreshRegencies(provinceCodeParam?: string) {
const code = provinceCodeParam || provinceCodeRef.value
if (code) {
return fetchRegencies(code, true)
}
}
// Debounced province code untuk mencegah multiple calls
const debouncedProvinceCode = refDebounced(provinceCodeRef, 100)
// Watch perubahan province code untuk auto fetch
watch(
debouncedProvinceCode,
(newCode, oldCode) => {
if (newCode && newCode !== oldCode) {
// Jika ada oldCode berarti user action (ganti pilihan)
const isUserAction = !!oldCode
fetchRegencies(newCode, false, isUserAction)
}
},
{ immediate: true },
)
return {
// Data
regencies: readonly(regencies),
regencyOptions,
// State
isLoading: readonly(isLoading),
error: readonly(error),
// Methods
fetchRegencies,
refreshRegencies,
getRegencyByCode,
getRegencyByName,
clearCache,
clearAllCache,
}
}
// Export untuk direct access ke cached data (jika diperlukan)
export const useRegenciesCache = () => ({
regenciesCache: readonly(regenciesCache),
loadingStates: readonly(loadingStates),
errorStates: readonly(errorStates),
})