'use client' import { useEffect, useState } from 'react' 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Plus, Trash2, Loader2 } from 'lucide-react' import { useToast } from '@/components/ui/use-toast' import { formatCurrency, formatDate } from '@/lib/utils' import { getErrorMessage } from '@/lib/errors/get-error-message' type BenefitType = 'bike' | 'car' | 'meals' | 'housing' | 'wellness' | 'other' interface EmployeeBenefit { id: string benefit_type: BenefitType description: string monthly_value: number valid_from: string valid_to: string | null metadata: Record is_active: boolean } const BENEFIT_LABELS: Record = { bike: 'Cykelförmån', car: 'Bilförmån', meals: 'Kostförmån', housing: 'Bostadsförmån', wellness: 'Friskvård (skattepliktig del)', other: 'Övrig förmån', } export function EmployeeBenefitsPanel({ employeeId, canWrite }: { employeeId: string; canWrite: boolean }) { const { toast } = useToast() const [benefits, setBenefits] = useState([]) const [loading, setLoading] = useState(true) const [adding, setAdding] = useState(false) const [submitting, setSubmitting] = useState(false) const [type, setType] = useState('bike') const [description, setDescription] = useState('') const [monthlyValue, setMonthlyValue] = useState('') const [annualMarketValue, setAnnualMarketValue] = useState('') const [validFrom, setValidFrom] = useState(() => new Date().toISOString().slice(0, 10)) const [validTo, setValidTo] = useState('') async function load() { setLoading(true) const res = await fetch(`/api/salary/employees/${employeeId}/benefits`) if (res.ok) { const { data } = await res.json() setBenefits(data || []) } setLoading(false) } useEffect(() => { load() // eslint-disable-next-line react-hooks/exhaustive-deps }, [employeeId]) function reset() { setType('bike') setDescription('') setMonthlyValue('') setAnnualMarketValue('') setValidFrom(new Date().toISOString().slice(0, 10)) setValidTo('') setAdding(false) } async function handleAdd() { setSubmitting(true) const body: Record = { benefit_type: type, description: description || BENEFIT_LABELS[type], valid_from: validFrom, } if (validTo) body.valid_to = validTo if (type === 'bike') { body.annual_market_value = parseFloat(annualMarketValue) || 0 } else { body.monthly_value = parseFloat(monthlyValue) || 0 } const res = await fetch(`/api/salary/employees/${employeeId}/benefits`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) if (res.ok) { toast({ title: 'Förmån tillagd' }) reset() await load() } else { const result = await res.json() toast({ title: 'Kunde inte spara förmån', description: getErrorMessage(result, { statusCode: res.status }), variant: 'destructive', }) } setSubmitting(false) } async function handleDelete(id: string) { const res = await fetch(`/api/salary/employees/${employeeId}/benefits/${id}`, { method: 'DELETE' }) if (res.ok) { toast({ title: 'Förmån borttagen' }) await load() } else { toast({ title: 'Kunde inte ta bort', variant: 'destructive' }) } } const previewMonthlyBike = (() => { const annual = parseFloat(annualMarketValue) || 0 return Math.max(0, annual - 3000) / 12 })() return ( Förmåner {canWrite && !adding && ( )} {loading ? (

Laddar…

) : benefits.length === 0 && !adding ? (

Inga förmåner registrerade. Aktiva förmåner läggs till automatiskt som rader vid lönekörning.

) : ( benefits.length > 0 && ( Typ Beskrivning Värde/mån Period {benefits.map(b => ( {BENEFIT_LABELS[b.benefit_type]} {b.description} {formatCurrency(b.monthly_value)} {formatDate(b.valid_from)} {b.valid_to ? ` – ${formatDate(b.valid_to)}` : ' – löpande'} {canWrite && ( )} ))}
) )} {adding && (
setDescription(e.target.value)} placeholder={BENEFIT_LABELS[type]} />
{type === 'bike' ? (
setAnnualMarketValue(e.target.value)} placeholder="t.ex. 8 400 (700 kr/mån)" className="max-w-xs" />

Skatteverkets schablon: första 3 000 kr/år är skattefri. Resterande beskattas månadsvis. {parseFloat(annualMarketValue) > 0 && ( Månatligt förmånsvärde: {formatCurrency(previewMonthlyBike)} )}

) : (
setMonthlyValue(e.target.value)} className="max-w-xs" />
)}
setValidFrom(e.target.value)} />
setValidTo(e.target.value)} />
)}
) }