feat: debounce search, tambah filter source & date range di bug-reports, hapus seafile.ts

- Debounce search input (400ms, min 3 karakter) sesuai konvensi
- Tambah filter source (QC/SYSTEM/USER) dan date range di bug-reports
- Backend /api/bugs support query param source, dateFrom, dateTo
- Update API_URLS.getBugs dengan param baru
- Hapus seafile.ts (dead code, tidak digunakan)
This commit is contained in:
2026-05-25 11:31:37 +08:00
parent cc81c8b91e
commit 8c33003b17
4 changed files with 73 additions and 261 deletions

View File

@@ -27,12 +27,13 @@ import {
Title,
Tooltip,
} from '@mantine/core'
import { useDisclosure } from '@mantine/hooks'
import { useDebouncedValue, useDisclosure } from '@mantine/hooks'
import { DatePickerInput, type DatesRangeValue } from '@mantine/dates'
import { notifications } from '@mantine/notifications'
import { useQuery } from '@tanstack/react-query'
import { createFileRoute } from '@tanstack/react-router'
import dayjs from 'dayjs'
import { useState } from 'react'
import { useEffect, useState } from 'react'
import {
TbAlertTriangle,
TbBug,
@@ -71,18 +72,35 @@ const STATUS_LABEL: Record<string, string> = {
function ListErrorsPage() {
const [page, setPage] = useState(1)
const [search, setSearch] = useState('')
const [searchQuery, setSearchQuery] = useState('')
const [app, setApp] = useState('all')
const [status, setStatus] = useState('all')
const [source, setSource] = useState('all')
const [dateRange, setDateRange] = useState<DatesRangeValue>([null, null])
const [debouncedSearch] = useDebouncedValue(search, 400)
useEffect(() => {
if (debouncedSearch.length >= 3 || debouncedSearch.length === 0) {
setSearchQuery(debouncedSearch)
setPage(1)
}
}, [debouncedSearch])
useEffect(() => { setPage(1) }, [app, status, source, dateRange])
const [showLogs, setShowLogs] = useState<Record<string, boolean>>({})
const [showStackTrace, setShowStackTrace] = useState<Record<string, boolean>>({})
const dateFrom = dateRange[0] ? dayjs(dateRange[0]).format('YYYY-MM-DD') : undefined
const dateTo = dateRange[1] ? dayjs(dateRange[1]).format('YYYY-MM-DD') : undefined
const toggleLogs = (bugId: string) => setShowLogs((prev) => ({ ...prev, [bugId]: !prev[bugId] }))
const toggleStackTrace = (bugId: string) => setShowStackTrace((prev) => ({ ...prev, [bugId]: !prev[bugId] }))
const { data, isLoading, refetch } = useQuery({
queryKey: ['bugs', { page, search, app, status }],
queryFn: () => fetch(API_URLS.getBugs(page, search, app, status)).then((r) => r.json()),
queryKey: ['bugs', { page, searchQuery, app, status, source, dateFrom, dateTo }],
queryFn: () => fetch(API_URLS.getBugs(page, searchQuery, app, status, source, dateFrom, dateTo)).then((r) => r.json()),
})
const { data: appsList } = useQuery({
@@ -411,7 +429,7 @@ function ListErrorsPage() {
</Modal>
<Paper withBorder radius="2xl" className="glass" p="md">
<SimpleGrid cols={{ base: 1, sm: 4 }} mb="lg">
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} mb="sm">
<TextInput
label="Search"
placeholder="Description, device, OS..."
@@ -444,12 +462,35 @@ function ListErrorsPage() {
onChange={(val) => setStatus(val || 'all')}
radius="md"
/>
<Select
label="Source"
size="sm"
data={[
{ value: 'all', label: 'All Sources' },
{ value: 'QC', label: 'QC' },
{ value: 'SYSTEM', label: 'System' },
{ value: 'USER', label: 'User' },
]}
value={source}
onChange={(val) => setSource(val || 'all')}
radius="md"
/>
<DatePickerInput
type="range"
label="Date Range"
placeholder="Pick date range"
size="sm"
radius="md"
value={dateRange}
onChange={setDateRange}
clearable
/>
<Stack justify="flex-end">
<Button
variant="filled"
color="violet"
size="sm"
onClick={() => { setSearch(''); setApp('all'); setStatus('all') }}
onClick={() => { setSearch(''); setApp('all'); setStatus('all'); setSource('all'); setDateRange([null, null]) }}
>
Reset Filters
</Button>