Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
136 lines
5.1 KiB
TypeScript
136 lines
5.1 KiB
TypeScript
// src/pages/admin/CorrectionsPage.tsx
|
|
import React from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { LoadingSpinner } from '../../components/LoadingSpinner';
|
|
import { ArrowPathIcon } from '../../components/icons/ArrowPathIcon';
|
|
import { CorrectionRow } from './components/CorrectionRow';
|
|
import { useSuggestedCorrectionsQuery } from '../../hooks/queries/useSuggestedCorrectionsQuery';
|
|
import { useMasterItemsQuery } from '../../hooks/queries/useMasterItemsQuery';
|
|
import { useCategoriesQuery } from '../../hooks/queries/useCategoriesQuery';
|
|
|
|
export const CorrectionsPage: React.FC = () => {
|
|
// Use TanStack Query for data fetching (ADR-0005 Phase 5)
|
|
const {
|
|
data: corrections = [],
|
|
isLoading: isLoadingCorrections,
|
|
error: correctionsError,
|
|
refetch: refetchCorrections,
|
|
} = useSuggestedCorrectionsQuery();
|
|
|
|
const { data: masterItems = [], isLoading: isLoadingMasterItems } = useMasterItemsQuery();
|
|
|
|
const { data: categories = [], isLoading: isLoadingCategories } = useCategoriesQuery();
|
|
|
|
const isLoading = isLoadingCorrections || isLoadingMasterItems || isLoadingCategories;
|
|
const error = correctionsError?.message || null;
|
|
|
|
const handleCorrectionProcessed = () => {
|
|
// Refetch corrections after processing
|
|
refetchCorrections();
|
|
};
|
|
|
|
return (
|
|
<div className="max-w-7xl mx-auto py-8 px-4">
|
|
<div className="mb-8">
|
|
<Link to="/admin" className="text-brand-primary hover:underline">
|
|
← Back to Admin Dashboard
|
|
</Link>
|
|
<div className="flex justify-between items-center mt-2">
|
|
<div>
|
|
<h1 className="text-3xl font-bold text-gray-800 dark:text-white">
|
|
User-Submitted Corrections
|
|
</h1>
|
|
<p className="text-gray-500 dark:text-gray-400">
|
|
Review and approve or reject pending data corrections.
|
|
</p>
|
|
</div>
|
|
<button
|
|
onClick={() => refetchCorrections()}
|
|
disabled={isLoading}
|
|
className="p-2 rounded-md bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 disabled:opacity-50"
|
|
title="Refresh Corrections"
|
|
>
|
|
<ArrowPathIcon className={`w-5 h-5 ${isLoading ? 'animate-spin' : ''}`} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{isLoading && (
|
|
<div
|
|
role="status"
|
|
aria-label="Loading corrections"
|
|
className="flex justify-center items-center h-64"
|
|
>
|
|
<LoadingSpinner />
|
|
</div>
|
|
)}
|
|
{error && (
|
|
<div className="text-red-500 bg-red-100 dark:bg-red-900/20 p-4 rounded-lg">{error}</div>
|
|
)}
|
|
|
|
{!isLoading && !error && (
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-x-auto">
|
|
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
<thead className="bg-gray-50 dark:bg-gray-700/50">
|
|
<tr>
|
|
<th
|
|
scope="col"
|
|
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider"
|
|
>
|
|
Item
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider"
|
|
>
|
|
Correction Type
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider"
|
|
>
|
|
Suggested Value
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider"
|
|
>
|
|
Submitted By
|
|
</th>
|
|
<th
|
|
scope="col"
|
|
className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider"
|
|
>
|
|
Date
|
|
</th>
|
|
<th scope="col" className="relative px-6 py-3">
|
|
<span className="sr-only">Actions</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
|
{corrections.length === 0 ? (
|
|
<tr>
|
|
<td colSpan={6} className="text-center py-8 text-gray-500">
|
|
No pending corrections. Great job!
|
|
</td>
|
|
</tr>
|
|
) : (
|
|
corrections.map((correction) => (
|
|
<CorrectionRow
|
|
key={correction.suggested_correction_id}
|
|
correction={correction}
|
|
masterItems={masterItems}
|
|
categories={categories}
|
|
onProcessed={handleCorrectionProcessed}
|
|
/>
|
|
))
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|