'use client' import { useState } from 'react' import { useTranslations } from 'next-intl' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { Badge } from '@/components/ui/badge' import { Settings2, Loader2 } from 'lucide-react' import { useToast } from '@/components/ui/use-toast' import { formatCurrency } from '@/lib/utils' import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message' interface SalaryOverridePanelProps { runId: string employeeId: string taxWithheld: number taxOverride: number | null avgifterAmount: number avgifterOverride: number | null avgifterBasis: number avgifterBasisOverride: number | null reason: string | null onSaved: () => void disabled?: boolean } function num(v: string): number | null { const trimmed = v.trim() if (!trimmed) return null const n = Number(trimmed.replace(',', '.')) return Number.isFinite(n) ? n : null } export function SalaryOverridePanel(props: SalaryOverridePanelProps) { const t = useTranslations('salary_override') const { toast } = useToast() const [expanded, setExpanded] = useState( props.taxOverride !== null || props.avgifterOverride !== null || props.avgifterBasisOverride !== null, ) const [taxStr, setTaxStr] = useState(props.taxOverride !== null ? String(props.taxOverride) : '') const [avgStr, setAvgStr] = useState( props.avgifterOverride !== null ? String(props.avgifterOverride) : '', ) const [basisStr, setBasisStr] = useState( props.avgifterBasisOverride !== null ? String(props.avgifterBasisOverride) : '', ) const [reason, setReason] = useState(props.reason ?? '') const [saving, setSaving] = useState(false) const hasOverride = props.taxOverride !== null || props.avgifterOverride !== null || props.avgifterBasisOverride !== null async function handleSave() { setSaving(true) try { const body = { tax_withheld_override: num(taxStr), avgifter_amount_override: num(avgStr), avgifter_basis_override: num(basisStr), reason: reason.trim() || null, } const res = await fetch(`/api/salary/runs/${props.runId}/employees/${props.employeeId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) const data = await res.json() if (!res.ok) { toast({ title: t('save_failed'), description: typeof data?.error === 'string' ? data.error : t('unknown_error'), variant: 'destructive', }) return } toast({ title: t('saved') }) props.onSaved() } catch (err) { toast({ title: t('save_failed'), description: err instanceof Error ? getUserErrorMessage(err) : t('unknown_error'), variant: 'destructive', }) } finally { setSaving(false) } } async function handleClear() { setSaving(true) try { const res = await fetch(`/api/salary/runs/${props.runId}/employees/${props.employeeId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tax_withheld_override: null, avgifter_amount_override: null, avgifter_basis_override: null, reason: null, }), }) if (!res.ok) { const data = await res.json() toast({ title: t('clear_failed'), description: typeof data?.error === 'string' ? data.error : t('unknown_error'), variant: 'destructive', }) return } setTaxStr('') setAvgStr('') setBasisStr('') setReason('') toast({ title: t('cleared') }) props.onSaved() } finally { setSaving(false) } } return (
{t('title')} {hasOverride && {t('adjusted_badge')}}
{expanded && (

{t('description')}

setTaxStr(e.target.value)} disabled={props.disabled || saving} className="tabular-nums" />

{t('calculated')} {formatCurrency(props.taxWithheld)}

setAvgStr(e.target.value)} disabled={props.disabled || saving} className="tabular-nums" />

{t('calculated')} {formatCurrency(props.avgifterAmount)}

setBasisStr(e.target.value)} disabled={props.disabled || saving} className="tabular-nums" />

{t('calculated')} {formatCurrency(props.avgifterBasis)}