brestok's picture
init
90723a6
import { useEffect, useMemo, useState } from 'react'
import { fetchJobs, filterJobs, fetchStatistics } from '../api/jobs.js'
import { formatDateTime } from '../utils/date.js'
export const INITIAL_FILTERS = {
titles: [],
companies: [],
locations: [],
salaryMin: '',
salaryMax: '',
top: false,
dateFrom: null,
dateTo: null,
}
export function useJobs() {
const [jobs, setJobs] = useState([])
const [isLoading, setIsLoading] = useState(false)
const [filters, setFilters] = useState(INITIAL_FILTERS)
const [lastUpdatedAt, setLastUpdatedAt] = useState(formatDateTime(new Date()))
const [nextPlannedAt, setNextPlannedAt] = useState(formatDateTime(new Date(Date.now() + 6 * 36e5)))
const [pageIndex, setPageIndex] = useState(0)
const [pageSize, setPageSize] = useState(25)
const [totalJobs, setTotalJobs] = useState(0)
const [serverFilter, setServerFilter] = useState(null)
async function load() {
setIsLoading(true)
try {
let api
if (serverFilter) {
api = await filterJobs({ filter: serverFilter, pageIndex, pageSize })
} else {
api = await fetchJobs({ pageIndex, pageSize })
}
const payload = api?.data
const items = payload?.data || []
const paging = payload?.paging || {}
setJobs(items)
setTotalJobs(Number(paging.totalCount) || 0)
try {
const stats = await fetchStatistics()
const last = stats?.data?.lastUpdate
const next = stats?.data?.nextUpdate
setLastUpdatedAt(last ? formatDateTime(last) : formatDateTime(new Date()))
setNextPlannedAt(next ? formatDateTime(next) : formatDateTime(new Date(Date.now() + 6 * 36e5)))
} catch (_) {
setLastUpdatedAt(formatDateTime(new Date()))
setNextPlannedAt(formatDateTime(new Date(Date.now() + 6 * 36e5)))
}
} catch (e) {
setJobs([])
setTotalJobs(0)
} finally {
setIsLoading(false)
}
}
useEffect(() => {
load()
}, [pageIndex, pageSize, serverFilter])
const pageCount = useMemo(() => Math.max(1, Math.ceil((totalJobs || 0) / pageSize)), [totalJobs, pageSize])
function setPage(newIndex) {
const clamped = Math.max(0, Math.min(newIndex, pageCount - 1))
setPageIndex(clamped)
}
function setSize(newSize) {
setPageSize(newSize)
setPageIndex(0)
}
function refresh() {
load()
}
function buildServerFilter() {
const filter = {}
if (filters.titles && filters.titles.length) filter.titles = filters.titles
if (filters.companies && filters.companies.length) filter.companies = filters.companies
if (filters.locations && filters.locations.length) filter.locations = filters.locations
if (filters.salaryMin !== '' && !Number.isNaN(Number(filters.salaryMin))) filter.minSalary = Number(filters.salaryMin)
if (filters.salaryMax !== '' && !Number.isNaN(Number(filters.salaryMax))) filter.maxSalary = Number(filters.salaryMax)
if (filters.top) filter.isTop5 = true
if (filters.dateFrom) filter.minDate = new Date(filters.dateFrom).toISOString().slice(0, 10)
if (filters.dateTo) filter.maxDate = new Date(filters.dateTo).toISOString().slice(0, 10)
return filter
}
function submitFilters() {
const f = buildServerFilter()
setServerFilter(Object.keys(f).length ? f : null)
setPageIndex(0)
}
const domain = useMemo(() => {
const unique = (arr) => Array.from(new Set(arr)).sort()
return {
titles: unique(jobs.map(j => j.title)),
companies: unique(jobs.map(j => j.company)),
locations: unique(jobs.map(j => j.location)),
}
}, [jobs])
function resetFilters() {
setFilters(INITIAL_FILTERS)
setServerFilter(null)
setPageIndex(0)
}
return { jobs, totalJobs, pageIndex, pageCount, pageSize, setPage, setSize, isLoading, lastUpdatedAt, nextPlannedAt, refresh, setFilters, filters, domain, resetFilters, submitFilters }
}