160 lines
4.2 KiB
TypeScript
160 lines
4.2 KiB
TypeScript
import { computed, onMounted, ref, watch } from 'vue'
|
|
import debounce from 'lodash/debounce'
|
|
import type { SortConfig } from '@/components/ui/usage/DataTable.vue'
|
|
import { useApiPagination } from '@/composables/useApiPagination'
|
|
import { getApiErrorMessage } from '@/core/utils/getApiErrorMessage'
|
|
import { getUserStats, listUsers } from '../services/user.service'
|
|
import type { UserListItem } from '../types/user.types'
|
|
|
|
export function useUserList() {
|
|
const users = ref<UserListItem[]>([])
|
|
const loading = ref(false)
|
|
const statsLoading = ref(false)
|
|
const error = ref<string | null>(null)
|
|
const statsError = ref<string | null>(null)
|
|
const search = ref('')
|
|
const statusFilter = ref('')
|
|
const joinDateFrom = ref('')
|
|
const joinDateTo = ref('')
|
|
const leaveDateFrom = ref('')
|
|
const leaveDateTo = ref('')
|
|
const sortBy = ref<SortConfig[]>([{ key: 'name', order: 'asc' }])
|
|
const page = ref(1)
|
|
const itemsPerPage = ref(10)
|
|
const stats = ref<{ total: number; joined_this_month: number }>({ total: 0, joined_this_month: 0 })
|
|
|
|
const { pagination, applyPagination } = useApiPagination({ per_page: 10 })
|
|
|
|
const hasJoinDateFilters = computed(() => Boolean(joinDateFrom.value || joinDateTo.value))
|
|
const hasLeaveDateFilters = computed(() => Boolean(leaveDateFrom.value || leaveDateTo.value))
|
|
|
|
function clearJoinDateFilters() {
|
|
joinDateFrom.value = ''
|
|
joinDateTo.value = ''
|
|
}
|
|
|
|
function clearLeaveDateFilters() {
|
|
leaveDateFrom.value = ''
|
|
leaveDateTo.value = ''
|
|
}
|
|
|
|
async function fetchUsers(requestPage = page.value) {
|
|
loading.value = true
|
|
error.value = null
|
|
|
|
try {
|
|
const activeSort = sortBy.value[0]
|
|
const data = await listUsers({
|
|
page: requestPage,
|
|
per_page: itemsPerPage.value,
|
|
sort_by: activeSort?.key ?? 'name',
|
|
sort_order: activeSort?.order ?? 'asc',
|
|
search: search.value.trim() || undefined,
|
|
status: statusFilter.value.trim() || undefined,
|
|
join_date_from: joinDateFrom.value || undefined,
|
|
join_date_to: joinDateTo.value || undefined,
|
|
leave_date_from: leaveDateFrom.value || undefined,
|
|
leave_date_to: leaveDateTo.value || undefined,
|
|
})
|
|
|
|
users.value = data.data
|
|
applyPagination(data.pagination)
|
|
page.value = data.pagination.current_page
|
|
} catch (err) {
|
|
error.value = getApiErrorMessage(err, 'Gagal memuatkan senarai pengguna.')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function fetchStats() {
|
|
statsLoading.value = true
|
|
statsError.value = null
|
|
|
|
try {
|
|
const res = await getUserStats({
|
|
search: search.value.trim() || undefined,
|
|
status: statusFilter.value.trim() || undefined,
|
|
join_date_from: joinDateFrom.value || undefined,
|
|
join_date_to: joinDateTo.value || undefined,
|
|
leave_date_from: leaveDateFrom.value || undefined,
|
|
leave_date_to: leaveDateTo.value || undefined,
|
|
})
|
|
|
|
stats.value = res.data
|
|
} catch (err) {
|
|
statsError.value = getApiErrorMessage(err, 'Gagal memuatkan statistik pengguna.')
|
|
stats.value = { total: 0, joined_this_month: 0 }
|
|
} finally {
|
|
statsLoading.value = false
|
|
}
|
|
}
|
|
|
|
function handleSortUpdate(value: SortConfig[]) {
|
|
sortBy.value = value
|
|
fetchUsers(1)
|
|
}
|
|
|
|
const debouncedSearch = debounce(() => {
|
|
fetchUsers(1)
|
|
fetchStats()
|
|
}, 400)
|
|
|
|
watch(search, () => {
|
|
debouncedSearch()
|
|
})
|
|
|
|
watch(statusFilter, () => {
|
|
fetchUsers(1)
|
|
fetchStats()
|
|
})
|
|
|
|
watch([joinDateFrom, joinDateTo, leaveDateFrom, leaveDateTo], () => {
|
|
fetchUsers(1)
|
|
fetchStats()
|
|
})
|
|
|
|
watch(page, (nextPage, previousPage) => {
|
|
if (nextPage !== previousPage) {
|
|
fetchUsers(nextPage)
|
|
}
|
|
})
|
|
|
|
watch(itemsPerPage, (nextValue, previousValue) => {
|
|
if (nextValue !== previousValue) {
|
|
fetchUsers(1)
|
|
}
|
|
})
|
|
|
|
onMounted(() => {
|
|
fetchUsers(1)
|
|
fetchStats()
|
|
})
|
|
|
|
return {
|
|
users,
|
|
loading,
|
|
stats,
|
|
statsLoading,
|
|
statsError,
|
|
error,
|
|
search,
|
|
statusFilter,
|
|
joinDateFrom,
|
|
joinDateTo,
|
|
leaveDateFrom,
|
|
leaveDateTo,
|
|
hasJoinDateFilters,
|
|
hasLeaveDateFilters,
|
|
clearJoinDateFilters,
|
|
clearLeaveDateFilters,
|
|
sortBy,
|
|
page,
|
|
itemsPerPage,
|
|
pagination,
|
|
handleSortUpdate,
|
|
fetchUsers,
|
|
fetchStats,
|
|
}
|
|
}
|