64 lines
3.4 KiB
React
64 lines
3.4 KiB
React
import { useEffect, useState } from 'react'
|
|
import { FaSpinner } from 'react-icons/fa6'
|
|
import { Card, Badge, Button } from '../ui'
|
|
import { listCredits } from '../../lib/teamApi'
|
|
import { creditStatus } from '../../lib/creditFormat'
|
|
import { fmtDate, fmtDateTime, formatCents } from '../../lib/format'
|
|
import '../../styles/admin-areas.css'
|
|
|
|
// Liste der Uebernahmegutschriften (Filter "Offen"/"Alle"), wie im frueheren Admin-Panel; optional nur ein Kunde
|
|
export default function CreditList({ customerId, selectedId, onSelect, reloadKey }) {
|
|
const [filter, setFilter] = useState('open')
|
|
const [rows, setRows] = useState(null)
|
|
const [error, setError] = useState(null)
|
|
|
|
useEffect(() => {
|
|
let alive = true
|
|
setError(null)
|
|
listCredits({ status: filter, customerId })
|
|
.then(({ requests }) => { if (alive) setRows(requests || []) })
|
|
.catch((err) => { if (alive) setError(err.message || 'Anträge konnten nicht geladen werden.') })
|
|
return () => { alive = false }
|
|
}, [filter, customerId, reloadKey])
|
|
|
|
return (
|
|
<div>
|
|
<div className="area-filter seg">
|
|
<button type="button" className={filter === 'open' ? 'active' : ''} onClick={() => setFilter('open')}>Offen</button>
|
|
<button type="button" className={filter === 'all' ? 'active' : ''} onClick={() => setFilter('all')}>Alle</button>
|
|
</div>
|
|
<Card pad={false}>
|
|
{error && <div className="area-error" style={{ margin: 12 }}>{error}</div>}
|
|
{!rows && !error && <div style={{ padding: 16 }}><FaSpinner className="spinner" /></div>}
|
|
{rows && (
|
|
<div className="area-rows">
|
|
<div className="area-row credit-row head"><span>Eingang</span><span>Kunde</span><span>Leistung / bisher bei</span><span>Rechnung</span><span>Bezahlt bis</span><span>Status</span><span /></div>
|
|
{rows.length === 0 && <div className="area-row"><span className="area-muted">{filter === 'open' ? 'Keine offenen Anträge.' : 'Noch keine Anträge.'}</span></div>}
|
|
{rows.map((r) => {
|
|
const st = creditStatus(r.status)
|
|
return (
|
|
<div key={r.id} className={`area-row credit-row ${r.id === selectedId ? 'active' : ''}`}>
|
|
<span>{fmtDateTime(r.createdAt)}<br /><span className="area-muted">{r.ref}</span></span>
|
|
<span><strong>{r.customerName}</strong>{r.customerCode && <><br /><span className="area-muted">Kd.-Nr. {r.customerCode}</span></>}</span>
|
|
<span>{r.services}<br /><span className="area-muted">{r.provider}{r.domain ? ` · ${r.domain}` : ''}</span></span>
|
|
<span>{formatCents(r.invoiceAmountCents)}<br /><span className="area-muted">für {r.billingMonths} Mon.</span></span>
|
|
<span>{fmtDate(r.paidUntil)}</span>
|
|
<span>
|
|
<Badge tone={st.tone}>{st.label}</Badge>
|
|
{r.status === 'genehmigt' && <><br /><span className="area-muted">{formatCents(r.amountCents)}{r.appliedAt ? '' : ' · nicht gebucht'}</span></>}
|
|
</span>
|
|
<span>
|
|
<Button size="sm" variant="primary" onClick={() => onSelect(r.id)}>
|
|
{['offen', 'rueckfrage'].includes(r.status) ? 'Prüfen' : 'Ansehen'}
|
|
</Button>
|
|
</span>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
)}
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|