profit-planet-frontend/src/app/admin/finance-management/page.tsx
DeathKaioken 646c293bc1 .
Co-authored-by: Copilot <copilot@github.com>
2026-05-04 06:22:10 +02:00

527 lines
30 KiB
TypeScript

'use client'
import React from 'react'
import PageLayout from '../../components/PageLayout'
import InvoiceDetailModal from './components/InvoiceDetailModal'
import { type AdminInvoice } from './hooks/getInvoices'
import { useFinanceManagementPageState } from './hooks/useFinanceManagementPageState'
function getStatusBadgeClass(status?: string) {
if (status === 'paid') return 'bg-green-100 text-green-700'
if (status === 'issued') return 'bg-indigo-100 text-indigo-700'
if (status === 'draft') return 'bg-slate-100 text-slate-700'
if (status === 'overdue') return 'bg-red-100 text-red-700'
return 'bg-amber-100 text-amber-700'
}
function getStatusLabel(t: (key: string) => string, status?: string) {
if (status === 'draft') return t('autofix.k5f6d9f11')
if (status === 'issued') return t('autofix.kdc8f2ab2')
if (status === 'paid') return t('autofix.k9d5b2d74')
if (status === 'overdue') return t('autofix.k2f44ec11')
if (status === 'canceled') return t('autofix.kcf31ed66')
return status
}
function FinanceInvoiceActions({
invoice,
pdfLoading,
onViewPdf,
onOpenDetails,
t,
}: {
invoice: AdminInvoice
pdfLoading: string | number | null
onViewPdf: (invoice: AdminInvoice) => void
onOpenDetails: (invoice: AdminInvoice) => void
t: (key: string) => string
}) {
return (
<td className="px-3 py-2 space-x-2">
<button
onClick={() => onViewPdf(invoice)}
disabled={pdfLoading === invoice.id || !invoice.pdf_storage_key}
className="text-xs rounded-lg border border-slate-200 px-2.5 py-1.5 hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed"
>
{pdfLoading === invoice.id ? t('autofix.k79d12c2e') : t('autofix.kfbe29d11')}
</button>
<button
onClick={() => onOpenDetails(invoice)}
className="text-xs rounded-lg border border-slate-200 px-2.5 py-1.5 hover:bg-slate-50"
>
{t('autofix.kf67200af')}
</button>
</td>
)
}
export default function FinanceManagementPage() {
const {
t,
router,
rates,
vatLoading,
vatError,
timeframe,
setTimeframe,
billFilter,
setBillFilter,
diagLoading,
diagError,
diagData,
selectedInvoice,
setSelectedInvoice,
detailModalOpen,
setDetailModalOpen,
emailDialogOpen,
setEmailDialogOpen,
reportEmail,
setReportEmail,
sendingReport,
reportMsg,
setReportMsg,
invLoading,
invError,
reload,
totals,
filteredBills,
exportBills,
runPoolCheck,
exportInvoice,
pdfLoading,
uploadModalOpen,
setUploadModalOpen,
uploadForm,
setUploadForm,
uploadFile,
setUploadFile,
uploading,
uploadError,
setUploadError,
viewInvoicePdf,
submitUploadInvoice,
sendEmailReport,
uploadPreview,
} = useFinanceManagementPageState()
return (
<PageLayout contentClassName="flex-1 relative w-full">
<div className="min-h-screen bg-[radial-gradient(circle_at_top_left,rgba(251,191,36,0.10),transparent_22%),radial-gradient(circle_at_top_right,rgba(56,189,248,0.10),transparent_24%),linear-gradient(180deg,#f8fafc_0%,#f8fafc_50%,#eef2ff_100%)]">
<div className="max-w-[1820px] mx-auto px-4 sm:px-6 xl:px-10 py-8 space-y-5">
<header className="rounded-[28px] border border-white/80 bg-white/90 p-8 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur">
<div className="inline-flex items-center rounded-full border border-slate-200 bg-white px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.28em] text-slate-500">
{t('autofix.k8070cd52')}
</div>
<h1 className="mt-3 text-3xl sm:text-4xl font-extrabold text-slate-900 tracking-tight break-words">{t('autofix.k777299de')}</h1>
<p className="text-sm sm:text-base text-slate-600 mt-2 break-words">{t('autofix.k01ad6d49')}</p>
</header>
<section className="grid [grid-template-columns:repeat(auto-fit,minmax(16rem,1fr))] gap-4">
<div className="rounded-3xl border border-white/80 bg-white/90 p-5 shadow-[0_24px_70px_-44px_rgba(15,23,42,0.3)] backdrop-blur">
<div className="text-xs text-slate-500 mb-1">{t('autofix.k73f7184d')}</div>
<div className="text-2xl font-semibold text-slate-900">EUR {totals.totalAll.toFixed(2)}</div>
</div>
<div className="rounded-3xl border border-white/80 bg-white/90 p-5 shadow-[0_24px_70px_-44px_rgba(15,23,42,0.3)] backdrop-blur">
<div className="text-xs text-slate-500 mb-1">{t('autofix.k9b3082af')}</div>
<div className="text-2xl font-semibold text-slate-900">EUR {totals.totalRange.toFixed(2)}</div>
</div>
<div className="rounded-3xl border border-white/80 bg-white/90 p-5 shadow-[0_24px_70px_-44px_rgba(15,23,42,0.3)] backdrop-blur">
<div className="text-xs text-slate-500 mb-1">{t('autofix.k9f4ec5e2')}</div>
<div className="text-2xl font-semibold text-slate-900">{filteredBills.length}</div>
</div>
<div className="rounded-3xl border border-white/80 bg-white/90 p-5 shadow-[0_24px_70px_-44px_rgba(15,23,42,0.3)] backdrop-blur">
<div className="text-xs text-slate-500 mb-1">{t('autofix.kafb65833')}</div>
<select
value={timeframe}
onChange={(event) => setTimeframe(event.target.value as '7d' | '30d' | '90d' | 'ytd')}
className="mt-2 w-full rounded-lg border border-slate-200 px-3 py-2 text-sm focus:ring-2 focus:ring-slate-900 focus:border-transparent"
>
<option value="7d">{t('autofix.k502a0057')}</option>
<option value="30d">{t('autofix.k5f74c123')}</option>
<option value="90d">{t('autofix.k915115a9')}</option>
<option value="ytd">{t('autofix.k0f5d95a1')}</option>
</select>
</div>
</section>
<section className="rounded-[28px] border border-white/80 bg-white/90 p-8 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur space-y-3">
<div className="flex flex-wrap items-center justify-between gap-3">
<div>
<h2 className="text-lg font-semibold text-slate-900">{t('autofix.kf2180ff6')}</h2>
<p className="text-xs text-slate-600">{t('autofix.k5ce7a5b0')}</p>
</div>
<button
onClick={() => router.push('/admin/finance-management/vat-edit')}
className="rounded-xl bg-slate-900 px-4 py-2 text-sm font-semibold text-white shadow hover:bg-slate-800 transition"
>
{t('autofix.k4191cdba')}
</button>
</div>
<div className="text-sm text-slate-700">
{vatLoading && t('autofix.ka5d50257')}
{vatError && <span className="text-red-600">{vatError}</span>}
{!vatLoading && !vatError && (
<>
{t('autofix.k3e4a95bc').replace('{count}', String(rates.length)).replace('{examples}', rates.slice(0, 5).map((rate) => rate.country_code).join(', '))}
</>
)}
</div>
</section>
<section className="rounded-[28px] border border-white/80 bg-white/90 p-8 shadow-[0_24px_70px_-40px_rgba(15,23,42,0.3)] backdrop-blur space-y-4">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<h2 className="text-lg font-semibold text-slate-900">{t('autofix.k21f123af')}</h2>
<div className="flex flex-wrap gap-2 text-sm">
<button
onClick={() => {
setUploadError(null)
setUploadModalOpen(true)
}}
className="rounded-xl bg-slate-900 px-3 py-2 text-white font-medium hover:bg-slate-800 transition"
>
{t('autofix.kec5a5357')}
</button>
<button
onClick={() => {
setReportMsg(null)
setEmailDialogOpen(true)
}}
className="rounded-xl border border-sky-200 bg-sky-50 px-3 py-2 text-sky-900 font-medium hover:bg-sky-100 transition"
>
{t('autofix.kfdcad59b')}
</button>
<button onClick={() => exportBills('csv')} className="rounded-xl border border-slate-200 px-3 py-2 hover:bg-slate-50 transition">{t('autofix.k4c5e8e87')}</button>
<button onClick={() => exportBills('pdf')} className="rounded-xl border border-slate-200 px-3 py-2 hover:bg-slate-50 transition">{t('autofix.k4c5ecd73')}</button>
<button onClick={reload} className="rounded-xl border border-slate-200 px-3 py-2 hover:bg-slate-50 transition">{t('autofix.kddf7ca98')}</button>
</div>
</div>
<div className="grid gap-3 lg:grid-cols-4 text-sm">
<input
placeholder={t('autofix.k8bb2fe26')}
value={billFilter.query}
onChange={(event) => setBillFilter((current) => ({ ...current, query: event.target.value }))}
className="rounded-lg border border-slate-200 px-3 py-2 focus:ring-2 focus:ring-slate-900 focus:border-transparent"
/>
<select
value={billFilter.status}
onChange={(event) => setBillFilter((current) => ({ ...current, status: event.target.value }))}
className="rounded-lg border border-slate-200 px-3 py-2 focus:ring-2 focus:ring-slate-900 focus:border-transparent"
>
<option value="all">{t('autofix.kec99a6cc')}</option>
<option value="draft">{t('autofix.k5f6d9f11')}</option>
<option value="issued">{t('autofix.kdc8f2ab2')}</option>
<option value="paid">{t('autofix.k9d5b2d74')}</option>
<option value="overdue">{t('autofix.k2f44ec11')}</option>
<option value="canceled">{t('autofix.kcf31ed66')}</option>
</select>
<input
type="date"
value={billFilter.from}
onChange={(event) => setBillFilter((current) => ({ ...current, from: event.target.value }))}
className="rounded-lg border border-slate-200 px-3 py-2 focus:ring-2 focus:ring-slate-900 focus:border-transparent"
/>
<input
type="date"
value={billFilter.to}
onChange={(event) => setBillFilter((current) => ({ ...current, to: event.target.value }))}
className="rounded-lg border border-slate-200 px-3 py-2 focus:ring-2 focus:ring-slate-900 focus:border-transparent"
/>
</div>
<div className="overflow-x-auto rounded-2xl border border-slate-200/70 bg-white/70 p-1">
{reportMsg && (
<div className={`rounded-xl border px-3 py-2 text-sm mb-3 ${reportMsg.type === 'success' ? 'border-green-200 bg-green-50 text-green-700' : 'border-red-200 bg-red-50 text-red-700'}`}>
{reportMsg.text}
</div>
)}
{invError && (
<div className="rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 mb-3">
{invError}
</div>
)}
{(diagLoading || diagError || diagData) && (
<div className="rounded-xl border border-sky-200 bg-sky-50/60 px-3 py-3 text-sm mb-3">
{diagLoading && <div className="text-sky-800">{t('autofix.k37d7b9c4')}</div>}
{!diagLoading && diagError && <div className="text-red-700">{diagError}</div>}
{!diagLoading && !diagError && diagData && (
<div className="space-y-2">
<div className="text-sky-900 font-semibold">
{t('autofix.kf6a5a971').replace('{invoice}', String(diagData.invoice_id ?? '—'))}
</div>
<div className="text-slate-700">
{t('autofix.k81c0b74b')}
<span className="font-medium">{diagData.ok ? t('autofix.kaf7e90cc') : t('autofix.k6ba7f5b1')}</span>
{t('autofix.k77049179')}
<span className="font-mono">{diagData.reason}</span>
</div>
{diagData.ok && (
<div className="text-slate-700">
{t('autofix.k4968eb2a')}
<span className="font-medium">{diagData.abonement_id}</span>
{t('autofix.kfaa8fc4a')}
<span className="font-medium">{diagData.will_book_count}</span>
{t('autofix.kd2e5e813')}
<span className="font-medium">{diagData.already_booked_count}</span>
</div>
)}
{Array.isArray(diagData.candidates) && diagData.candidates.length > 0 && (
<div className="overflow-x-auto">
<table className="min-w-full text-xs">
<thead>
<tr className="text-left text-sky-900">
<th className="pr-3 py-1">{t('autofix.kf1b73a92')}</th>
<th className="pr-3 py-1">{t('autofix.k2f9cd1e0')}</th>
<th className="pr-3 py-1">{t('autofix.k1ddc3f42')}</th>
<th className="pr-3 py-1">{t('autofix.kdb79aa30')}</th>
<th className="pr-3 py-1">{t('autofix.k93e61ad1')}</th>
</tr>
</thead>
<tbody>
{diagData.candidates.map((candidate: any) => (
<tr key={`${candidate.pool_id}-${candidate.coffee_table_id}`}>
<td className="pr-3 py-1">{candidate.pool_name}</td>
<td className="pr-3 py-1">#{candidate.coffee_table_id}</td>
<td className="pr-3 py-1">{candidate.capsules_count}</td>
<td className="pr-3 py-1">EUR {Number(candidate.amount_gross ?? candidate.amount_net ?? 0).toFixed(2)}</td>
<td className="pr-3 py-1">{candidate.already_booked ? t('common.yes') : t('common.no')}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
)}
</div>
)}
<table className="min-w-full text-sm rounded-xl overflow-hidden">
<thead>
<tr className="bg-slate-50 text-left text-slate-900">
<th className="px-3 py-2 font-semibold">{t('autofix.kf8f0c1f3')}</th>
<th className="px-3 py-2 font-semibold">{t('autofix.kf2b5c1a6')}</th>
<th className="px-3 py-2 font-semibold">{t('autofix.kd4af6368')}</th>
<th className="px-3 py-2 font-semibold">{t('autofix.k867f8265')}</th>
<th className="px-3 py-2 font-semibold">{t('autofix.k762eef76')}</th>
<th className="px-3 py-2 font-semibold">{t('autofix.k81c0b74b')}</th>
<th className="px-3 py-2 font-semibold">{t('autofix.k0afbbac4')}</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-100">
{invLoading ? (
<>
<tr><td colSpan={7} className="px-3 py-3"><div className="h-4 w-40 bg-slate-200 animate-pulse rounded" /></td></tr>
<tr><td colSpan={7} className="px-3 py-3"><div className="h-4 w-3/4 bg-slate-200 animate-pulse rounded" /></td></tr>
</>
) : filteredBills.length === 0 ? (
<tr>
<td colSpan={7} className="px-3 py-4 text-center text-slate-500">{t('autofix.kbdb02e32')}</td>
</tr>
) : (
filteredBills.map((invoice) => (
<tr key={invoice.id} className="border-b border-slate-100 last:border-0">
<td className="px-3 py-2">{invoice.invoice_number ?? invoice.id}</td>
<td className="px-3 py-2">{invoice.buyer_name ?? '—'}</td>
<td className="px-3 py-2">{invoice.issued_at ? new Date(invoice.issued_at).toLocaleDateString() : '—'}</td>
<td className="px-3 py-2">
{(() => {
if (!invoice.due_at) return <span className="text-slate-400"></span>
const due = new Date(invoice.due_at)
const now = new Date()
const diffDays = Math.ceil((due.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
let cls = 'bg-green-100 text-green-700'
if (invoice.status === 'paid') cls = 'bg-green-100 text-green-700'
else if (diffDays < 0) cls = 'bg-red-100 text-red-700'
else if (diffDays <= 3) cls = 'bg-red-100 text-red-700'
else if (diffDays <= 7) cls = 'bg-amber-100 text-amber-700'
return <span className={`rounded-full px-2 py-0.5 text-xs font-semibold ${cls}`}>{due.toLocaleDateString()}</span>
})()}
</td>
<td className="px-3 py-2">
EUR {Number(invoice.total_gross ?? 0).toFixed(2)} <span className="text-xs text-slate-500">{invoice.currency ?? 'EUR'}</span>
</td>
<td className="px-3 py-2">
<span className={`rounded-full px-2 py-0.5 text-xs font-semibold ${getStatusBadgeClass(invoice.status ?? '')}`}>
{getStatusLabel(t, invoice.status ?? '')}
</span>
</td>
<FinanceInvoiceActions
invoice={invoice}
pdfLoading={pdfLoading}
onViewPdf={viewInvoicePdf}
onOpenDetails={(value) => {
setSelectedInvoice(value)
setDetailModalOpen(true)
}}
t={t}
/>
</tr>
))
)}
</tbody>
</table>
</div>
{selectedInvoice && (
<InvoiceDetailModal
invoice={selectedInvoice}
open={detailModalOpen}
onClose={() => {
setDetailModalOpen(false)
setTimeout(() => setSelectedInvoice(null), 200)
}}
onStatusChanged={reload}
onRunPoolCheck={(id) => {
setDetailModalOpen(false)
runPoolCheck(id)
}}
onExport={(invoice) => exportInvoice(invoice)}
/>
)}
{uploadModalOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/35 backdrop-blur-sm">
<div className="w-full max-w-2xl rounded-[28px] border border-white/80 bg-white/95 p-6 shadow-[0_24px_70px_-30px_rgba(15,23,42,0.35)] overflow-y-auto max-h-[90vh]">
<h3 className="text-lg font-semibold text-slate-900 mb-4">{t('autofix.kec5a5357')}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.kf2b5c1a6')}</label>
<input className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.buyer_name} onChange={(event) => setUploadForm((current) => ({ ...current, buyer_name: event.target.value }))} placeholder={t('autofix.k1882bd75')} />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k48852b8d')}</label>
<input type="email" className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.buyer_email} onChange={(event) => setUploadForm((current) => ({ ...current, buyer_email: event.target.value }))} placeholder={t('autofix.kf8c220d3')} />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.kba8ee9b1')}</label>
<input className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.buyer_street} onChange={(event) => setUploadForm((current) => ({ ...current, buyer_street: event.target.value }))} placeholder={t('autofix.k81c7c2f2')} />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.kc9d9d15d')}</label>
<input className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.buyer_postal_code} onChange={(event) => setUploadForm((current) => ({ ...current, buyer_postal_code: event.target.value }))} placeholder="8010" />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k5d52917f')}</label>
<input className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.buyer_city} onChange={(event) => setUploadForm((current) => ({ ...current, buyer_city: event.target.value }))} placeholder="Graz" />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k9e39e560')}</label>
<input className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.buyer_country} onChange={(event) => setUploadForm((current) => ({ ...current, buyer_country: event.target.value }))} placeholder="Austria" />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k002455d8')}<span className="text-red-500">*</span></label>
<input type="number" step="0.01" min="0" className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.total_gross} onChange={(event) => setUploadForm((current) => ({ ...current, total_gross: event.target.value }))} placeholder="0.00" />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k57d5f250')}</label>
<input type="number" step="0.01" min="0" max="100" className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.vat_rate} onChange={(event) => setUploadForm((current) => ({ ...current, vat_rate: event.target.value }))} placeholder="20" />
</div>
<div className="sm:col-span-2 grid grid-cols-2 gap-3">
<div className="rounded-lg bg-slate-50 border border-slate-100 px-3 py-2">
<div className="text-xs text-slate-500 mb-0.5">{t('autofix.k1f5a403a')}</div>
<div className="font-semibold text-slate-800">{uploadForm.currency} {uploadPreview.net.toFixed(2)}</div>
</div>
<div className="rounded-lg bg-slate-50 border border-slate-100 px-3 py-2">
<div className="text-xs text-slate-500 mb-0.5">{t('autofix.k089e8c08')}</div>
<div className="font-semibold text-slate-800">{uploadForm.currency} {uploadPreview.tax.toFixed(2)}</div>
</div>
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k3466b0e0')}</label>
<select className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.currency} onChange={(event) => setUploadForm((current) => ({ ...current, currency: event.target.value }))}>
<option value="EUR">EUR</option>
<option value="CHF">CHF</option>
<option value="USD">USD</option>
</select>
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k81c0b74b')}</label>
<select className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.status} onChange={(event) => setUploadForm((current) => ({ ...current, status: event.target.value }))}>
<option value="issued">{t('autofix.kdc8f2ab2')}</option>
<option value="paid">{t('autofix.k9d5b2d74')}</option>
<option value="draft">{t('autofix.k5f6d9f11')}</option>
<option value="overdue">{t('autofix.k2f44ec11')}</option>
</select>
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.kd4af6368')}</label>
<input type="date" className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.issued_at} onChange={(event) => setUploadForm((current) => ({ ...current, issued_at: event.target.value }))} />
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.k867f8265')}</label>
<input type="date" className="w-full rounded-lg border border-slate-200 px-3 py-2" value={uploadForm.due_at} onChange={(event) => setUploadForm((current) => ({ ...current, due_at: event.target.value }))} />
</div>
<div className="sm:col-span-2">
<label className="block text-xs font-medium text-slate-700 mb-1">{t('autofix.kd6024811')}</label>
<input
type="file"
accept="application/pdf"
className="w-full text-sm text-slate-700 file:mr-3 file:rounded-lg file:border-0 file:bg-sky-50 file:px-3 file:py-2 file:text-sky-900 file:font-medium hover:file:bg-sky-100"
onChange={(event) => setUploadFile(event.target.files?.[0] ?? null)}
/>
{uploadFile && <p className="mt-1 text-xs text-slate-500">{uploadFile.name}</p>}
</div>
</div>
{uploadError && <div className="mt-3 rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">{uploadError}</div>}
<div className="mt-5 flex items-center justify-end gap-2">
<button onClick={() => { setUploadModalOpen(false); setUploadError(null) }} disabled={uploading} className="rounded-xl border border-slate-200 px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 disabled:opacity-60">{t('common.cancel')}</button>
<button onClick={submitUploadInvoice} disabled={uploading} className="rounded-xl bg-slate-900 px-4 py-2 text-sm font-semibold text-white shadow hover:bg-slate-800 disabled:opacity-60 disabled:cursor-not-allowed">
{uploading ? t('autofix.k3bc9a0f1') : t('autofix.k1139753d')}
</button>
</div>
</div>
</div>
)}
{emailDialogOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/35 backdrop-blur-sm">
<div className="w-full max-w-md rounded-[28px] border border-white/80 bg-white/95 p-6 shadow-[0_24px_70px_-30px_rgba(15,23,42,0.35)]">
<h3 className="text-lg font-semibold text-slate-900 mb-1">{t('autofix.kfdcad59b')}</h3>
<div className="text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded-lg px-3 py-2 mb-4">
{t('autofix.k45c3fd51').replace('{paid}', t('autofix.k9d5b2d74').toLowerCase())}
{(billFilter.from || billFilter.to) && (
<span> {t('autofix.kdd22a5f2').replace('{from}', billFilter.from || '…').replace('{to}', billFilter.to || '…')}</span>
)}
</div>
<label className="block text-sm font-medium text-slate-700 mb-1">{t('autofix.kd56a13f2')}</label>
<input
type="email"
value={reportEmail}
onChange={(event) => setReportEmail(event.target.value)}
placeholder={t('autofix.k51ee3aae')}
className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:ring-2 focus:ring-slate-900 focus:border-transparent"
autoFocus
onKeyDown={(event) => {
if (event.key === 'Enter' && !sendingReport) sendEmailReport()
}}
/>
<div className="mt-4 flex items-center justify-end gap-2">
<button onClick={() => { setEmailDialogOpen(false); setReportEmail('') }} disabled={sendingReport} className="rounded-xl border border-slate-200 px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 disabled:opacity-60">{t('common.cancel')}</button>
<button onClick={sendEmailReport} disabled={sendingReport || !reportEmail.trim()} className="rounded-xl bg-slate-900 px-4 py-2 text-sm font-semibold text-white shadow hover:bg-slate-800 disabled:opacity-60 disabled:cursor-not-allowed">
{sendingReport ? t('autofix.k795911e8') : t('autofix.kf6f9b3c0')}
</button>
</div>
</div>
</div>
)}
</section>
</div>
</div>
</PageLayout>
)
}