profit-planet-frontend/src/app/admin/finance-management/vat-edit/page.tsx

159 lines
7.1 KiB
TypeScript

'use client'
import React, { useState } from 'react'
import PageLayout from '../../../components/PageLayout'
import { useRouter } from 'next/navigation'
import { useVatRates } from '../hooks/getTaxes'
import { importVatCsv } from './hooks/TaxImporter'
import { exportVatCsv, exportVatPdf } from './hooks/TaxExporter'
export default function VatEditPage() {
const router = useRouter()
const { rates, loading, error, reload } = useVatRates()
const [filter, setFilter] = useState('')
const [importResult, setImportResult] = useState<string | null>(null)
const [importing, setImporting] = useState(false)
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(10)
const onImport = async (file?: File | null) => {
if (!file) return
setImportResult(null)
setImporting(true)
const res = await importVatCsv(file)
if (res.ok) {
setImportResult(res.summary ? JSON.stringify(res.summary) : res.message || 'Import successful')
await reload()
} else {
setImportResult(res.message || 'Import failed')
}
setImporting(false)
}
const filtered = rates.filter(v =>
v.country_name.toLowerCase().includes(filter.toLowerCase()) ||
v.country_code.toLowerCase().includes(filter.toLowerCase())
)
const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize))
const pageData = filtered.slice((page - 1) * pageSize, page * pageSize)
return (
<PageLayout>
<div className="bg-gradient-to-tr from-blue-50 via-white to-blue-100 min-h-screen">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-6">
<div className="rounded-2xl bg-white border border-blue-100 shadow-lg px-8 py-8 flex items-center justify-between">
<div>
<h1 className="text-3xl font-extrabold text-blue-900">Edit VAT rates</h1>
<p className="text-sm text-blue-700">Import, export, and review (dummy data).</p>
</div>
<button
onClick={() => router.push('/admin/finance-management')}
className="rounded-lg border border-gray-300 px-4 py-2 text-sm font-semibold text-blue-900 hover:bg-gray-50"
>
Back
</button>
</div>
<div className="rounded-2xl bg-white border border-gray-100 shadow-lg p-6 space-y-3">
<div className="flex flex-wrap gap-2 text-sm items-center">
<label className="rounded-lg border border-gray-200 px-3 py-2 hover:bg-gray-50 cursor-pointer">
<input
type="file"
accept=".csv"
className="hidden"
onChange={e => onImport(e.target.files?.[0] || null)}
disabled={importing}
/>
{importing ? 'Importing...' : 'Import CSV'}
</label>
<button
onClick={() => exportVatCsv(rates)}
className="rounded-lg border border-gray-200 px-3 py-2 hover:bg-gray-50"
>
Export CSV
</button>
<button
onClick={() => exportVatPdf(rates)}
className="rounded-lg border border-gray-200 px-3 py-2 hover:bg-gray-50"
>
Export PDF
</button>
{importResult && <span className="text-xs text-blue-900 break-all">{importResult}</span>}
</div>
<div className="text-sm">
{error && <div className="mb-3 text-red-600">{error}</div>}
<input
value={filter}
onChange={e => { setFilter(e.target.value); setPage(1); }}
placeholder="Filter by country or code"
className="w-full rounded-lg border border-gray-200 px-3 py-2 mb-3 focus:ring-2 focus:ring-blue-900 focus:border-transparent"
/>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="bg-blue-50 text-left text-blue-900">
<th className="px-3 py-2 font-semibold">Country</th>
<th className="px-3 py-2 font-semibold">Code</th>
<th className="px-3 py-2 font-semibold">Standard</th>
<th className="px-3 py-2 font-semibold">Reduced</th>
<th className="px-3 py-2 font-semibold">Super reduced</th>
<th className="px-3 py-2 font-semibold">Parking</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
{loading && (
<tr><td colSpan={6} className="px-3 py-4 text-center text-gray-500">Loading VAT rates</td></tr>
)}
{!loading && pageData.map(v => (
<tr key={v.country_code} className="border-b last:border-0">
<td className="px-3 py-2">{v.country_name}</td>
<td className="px-3 py-2">{v.country_code}</td>
<td className="px-3 py-2">{v.standard_rate ?? '—'}</td>
<td className="px-3 py-2">{v.reduced_rate_1 ?? '—'}</td>
<td className="px-3 py-2">{v.super_reduced_rate ?? '—'}</td>
<td className="px-3 py-2">{v.parking_rate ?? '—'}</td>
</tr>
))}
{!loading && !error && pageData.length === 0 && (
<tr><td colSpan={6} className="px-3 py-4 text-center text-gray-500">No entries found.</td></tr>
)}
</tbody>
</table>
</div>
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mt-4 text-sm text-gray-700">
<div className="flex items-center gap-2">
<span>Rows per page:</span>
<select
value={pageSize}
onChange={e => { setPageSize(Number(e.target.value)); setPage(1); }}
className="rounded border border-gray-300 px-2 py-1 text-sm"
>
{[10, 20, 50, 100].map(n => <option key={n} value={n}>{n}</option>)}
</select>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => setPage(p => Math.max(1, p - 1))}
disabled={page === 1}
className="px-3 py-1 rounded border border-gray-300 bg-white disabled:opacity-50"
>
Prev
</button>
<span>Page {page} / {totalPages}</span>
<button
onClick={() => setPage(p => Math.min(totalPages, p + 1))}
disabled={page === totalPages}
className="px-3 py-1 rounded border border-gray-300 bg-white disabled:opacity-50"
>
Next
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</PageLayout>
)
}