From 8c33003b17585c49c85a8a46734cbfc7ba90013b Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Mon, 25 May 2026 11:31:37 +0800 Subject: [PATCH 1/6] 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) --- src/app.ts | 20 ++- src/frontend/config/api.ts | 9 +- src/frontend/routes/bug-reports.tsx | 53 +++++- src/lib/seafile.ts | 252 ---------------------------- 4 files changed, 73 insertions(+), 261 deletions(-) delete mode 100644 src/lib/seafile.ts diff --git a/src/app.ts b/src/app.ts index 65b47ce..92ebb9e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -805,6 +805,9 @@ export function createApp() { const search = query.search || '' const app = query.app as any const status = query.status as any + const source = query.source as any + const dateFrom = query.dateFrom + const dateTo = query.dateTo const where: any = {} if (search) { @@ -821,6 +824,18 @@ export function createApp() { if (status && status !== 'all') { where.status = status } + if (source && source !== 'all') { + where.source = source + } + if (dateFrom || dateTo) { + where.createdAt = {} + if (dateFrom) where.createdAt.gte = new Date(dateFrom) + if (dateTo) { + const end = new Date(dateTo) + end.setHours(23, 59, 59, 999) + where.createdAt.lte = end + } + } const [bugs, total] = await Promise.all([ prisma.bug.findMany({ @@ -852,10 +867,13 @@ export function createApp() { search: t.Optional(t.String({ description: 'Cari berdasarkan deskripsi, device, OS, atau versi' })), app: t.Optional(t.String({ description: 'Filter berdasarkan ID aplikasi, atau "all"' })), status: t.Optional(t.String({ description: 'Filter status: OPEN | ON_HOLD | IN_PROGRESS | RESOLVED | RELEASED | CLOSED | all' })), + source: t.Optional(t.String({ description: 'Filter sumber: QC | SYSTEM | USER | all' })), + dateFrom: t.Optional(t.String({ description: 'Filter dari tanggal (YYYY-MM-DD)' })), + dateTo: t.Optional(t.String({ description: 'Filter sampai tanggal (YYYY-MM-DD)' })), }), detail: { summary: 'List Bug Reports', - description: 'Mengembalikan daftar bug report dengan pagination, beserta data pelapor, gambar, dan riwayat status (BugLog). Mendukung filter berdasarkan aplikasi dan status.', + description: 'Mengembalikan daftar bug report dengan pagination, beserta data pelapor, gambar, dan riwayat status (BugLog). Mendukung filter berdasarkan aplikasi, status, source, dan tanggal.', tags: ['Bugs'], }, }) diff --git a/src/frontend/config/api.ts b/src/frontend/config/api.ts index 2264dea..a9e6d4c 100644 --- a/src/frontend/config/api.ts +++ b/src/frontend/config/api.ts @@ -51,8 +51,13 @@ export const API_URLS = { createOperator: () => `/api/operators`, editOperator: (id: string) => `/api/operators/${id}`, deleteOperator: (id: string) => `/api/operators/${id}`, - getBugs: (page: number, search: string, app: string, status: string) => - `/api/bugs?page=${page}&search=${encodeURIComponent(search)}&app=${app}&status=${status}`, + getBugs: (page: number, search: string, app: string, status: string, source?: string, dateFrom?: string, dateTo?: string) => { + const params = new URLSearchParams({ page: String(page), search: encodeURIComponent(search), app, status }) + if (source && source !== 'all') params.set('source', source) + if (dateFrom) params.set('dateFrom', dateFrom) + if (dateTo) params.set('dateTo', dateTo) + return `/api/bugs?${params}` + }, createBug: () => `/api/bugs`, uploadImage: () => `/api/upload/image`, updateBugStatus: (id: string) => `/api/bugs/${id}/status`, diff --git a/src/frontend/routes/bug-reports.tsx b/src/frontend/routes/bug-reports.tsx index 7c0c10a..50c54d8 100644 --- a/src/frontend/routes/bug-reports.tsx +++ b/src/frontend/routes/bug-reports.tsx @@ -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 = { 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([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>({}) const [showStackTrace, setShowStackTrace] = useState>({}) + 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() { - + setStatus(val || 'all')} radius="md" /> +