partial update revision simplify feature

This commit is contained in:
2025-08-13 17:51:30 +07:00
parent 5d9195d903
commit 39af7d1692
12 changed files with 1209 additions and 1734 deletions

View File

@@ -2,7 +2,6 @@ import { useState } from "react";
import {
Shield,
Calendar,
Search,
Filter,
AlertCircle,
CheckCircle,
@@ -36,10 +35,15 @@ interface BPJSSyncStats {
}
export default function BPJSSync() {
const [searchTerm, setSearchTerm] = useState("");
const [statusFilter, setStatusFilter] = useState("all");
const [statusInput, setStatusInput] = useState("all");
const [appliedStatus, setAppliedStatus] = useState("all");
const [isImporting, setIsImporting] = useState(false);
const [isSyncing, setIsSyncing] = useState(false);
const [startDateInput, setStartDateInput] = useState("");
const [endDateInput, setEndDateInput] = useState("");
const [appliedStartDate, setAppliedStartDate] = useState<string | null>(null);
const [appliedEndDate, setAppliedEndDate] = useState<string | null>(null);
const [hasDateFiltered, setHasDateFiltered] = useState(false);
const formatDate = (dateString: string) => {
const date = new Date(dateString);
@@ -129,17 +133,23 @@ export default function BPJSSync() {
syncLogs.filter((log) => log.duration > 0).length || 0,
};
// Filter sync logs based on search and status
// Filter sync logs based on date and status (status applied via button)
const filteredLogs = syncLogs.filter((log) => {
const matchesSearch =
log.source.toLowerCase().includes(searchTerm.toLowerCase()) ||
log.type.toLowerCase().includes(searchTerm.toLowerCase()) ||
(log.errorMessage &&
log.errorMessage.toLowerCase().includes(searchTerm.toLowerCase()));
const matchesStatus =
appliedStatus === "all" || log.status === appliedStatus;
let matchesDate = true;
if (hasDateFiltered) {
const ts = new Date(log.timestamp).getTime();
const startOk =
!appliedStartDate ||
ts >= new Date(appliedStartDate + "T00:00:00").getTime();
const endOk =
!appliedEndDate ||
ts <= new Date(appliedEndDate + "T23:59:59").getTime();
matchesDate = startOk && endOk;
}
const matchesStatus = statusFilter === "all" || log.status === statusFilter;
return matchesSearch && matchesStatus;
return matchesStatus && matchesDate;
});
const handleImport = async () => {
@@ -267,25 +277,33 @@ export default function BPJSSync() {
</div>
</div>
{/* Filters and Search */}
{/* Filters */}
<div className="bg-white p-6 rounded-lg shadow-sm border mb-6">
<div className="flex flex-col md:flex-row md:items-center md:justify-between space-y-4 md:space-y-0">
<div className="flex items-center space-x-4">
<div className="relative">
<Search className="absolute left-3 top-3 h-4 w-4 text-gray-400" />
<div className="flex items-center space-x-3">
{/* Date range */}
<div className="flex items-center space-x-2">
<Calendar className="h-4 w-4 text-gray-400" />
<input
type="text"
placeholder="Cari source, type, atau error message..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-9 pr-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent w-80"
type="date"
value={startDateInput}
onChange={(e) => setStartDateInput(e.target.value)}
className="border border-gray-300 rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
<span className="text-gray-400 text-sm">s/d</span>
<input
type="date"
value={endDateInput}
onChange={(e) => setEndDateInput(e.target.value)}
className="border border-gray-300 rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Status */}
<div className="flex items-center space-x-2">
<Filter className="h-4 w-4 text-gray-400" />
<select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
value={statusInput}
onChange={(e) => setStatusInput(e.target.value)}
className="border border-gray-300 rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="all">Semua Status</option>
@@ -294,6 +312,34 @@ export default function BPJSSync() {
<option value="in_progress">Berlangsung</option>
</select>
</div>
{/* Buttons */}
<div className="flex items-center space-x-2">
<button
onClick={() => {
setAppliedStartDate(startDateInput || null);
setAppliedEndDate(endDateInput || null);
setHasDateFiltered(Boolean(startDateInput || endDateInput));
setAppliedStatus(statusInput);
}}
className="btn-primary px-3 py-2"
>
Filter
</button>
<button
onClick={() => {
setStartDateInput("");
setEndDateInput("");
setAppliedStartDate(null);
setAppliedEndDate(null);
setHasDateFiltered(false);
setStatusInput("all");
setAppliedStatus("all");
}}
className="btn-secondary px-3 py-2 border border-gray-300 rounded-md"
>
Reset
</button>
</div>
</div>
</div>
</div>