'use client' import { useState, useEffect, useMemo, useRef } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { InfoTooltip } from '@/components/ui/info-tooltip' import MunicipalityCombobox from './MunicipalityCombobox' import { TAX_COLUMN_OPTIONS, deriveTaxColumn } from '@/lib/salary/tax-column' export interface EmployeeTaxValue { f_skatt_status: string is_sidoinkomst: boolean tax_table_number: number | null tax_column: number tax_municipality: string } interface EmployeeTaxCardProps { /** Live personnummer (full or masked) — drives the column suggestion. */ personnummer: string initial?: Partial /** Income year the table/column applies to. Defaults to the current year. */ year?: number disabled?: boolean onChange: (value: EmployeeTaxValue) => void } function RequiredMark() { return * } /** * The "Skatt" card on the employee form. Instead of asking the user to look up * an opaque skattetabell (29-42) and kolumn (1-6), it derives both from data we * already have: the folkbokföringskommun fills the tax table, and the * personnummer fills the column. Manual overrides remain for edge cases. */ export default function EmployeeTaxCard({ personnummer, initial, year, disabled, onChange, }: EmployeeTaxCardProps) { const incomeYear = year ?? new Date().getFullYear() const [fSkatt, setFSkatt] = useState(initial?.f_skatt_status ?? 'a_skatt') const [sido, setSido] = useState(initial?.is_sidoinkomst ?? false) const [municipality, setMunicipality] = useState(initial?.tax_municipality ?? '') const [tableNumber, setTableNumber] = useState(initial?.tax_table_number ?? null) const [rate, setRate] = useState(null) const [tableManual, setTableManual] = useState(false) const [column, setColumn] = useState(initial?.tax_column ?? 1) // Editing an existing employee: respect their saved column. New employee: // let the personnummer drive it until the user picks one. const [columnTouched, setColumnTouched] = useState(initial?.tax_column != null) const requiresTable = fSkatt === 'a_skatt' && !sido const derivedColumn = useMemo( () => deriveTaxColumn(personnummer, incomeYear), [personnummer, incomeYear] ) const isSenior = personnummer.replace(/\D/g, '').length >= 8 && derivedColumn === null // The effective column is the user's explicit choice once they've made one, // otherwise the value suggested from the personnummer (falling back to 1). // Derived in render — no setState-in-effect needed. const effectiveColumn = columnTouched ? column : (derivedColumn ?? 1) // Report the current value up. onChange via ref so an unstable parent callback // doesn't retrigger the effect (deps are the primitive values only). const onChangeRef = useRef(onChange) useEffect(() => { onChangeRef.current = onChange }) useEffect(() => { onChangeRef.current({ f_skatt_status: fSkatt, is_sidoinkomst: sido, tax_table_number: requiresTable ? tableNumber : null, tax_column: effectiveColumn, tax_municipality: municipality.trim(), }) }, [fSkatt, sido, tableNumber, effectiveColumn, municipality, requiresTable]) return ( Skatt
{requiresTable ? ( <>
{ setMunicipality(value) // Clearing the field must clear the derived table/rate too — // otherwise we'd report an empty kommun alongside a stale // table number (an inconsistent pair). Manual entry keeps its // own value. if (!value && !tableManual) { setTableNumber(null) setRate(null) } }} onSelect={(kommun, table, totalRate) => { setMunicipality(kommun) setRate(totalRate) if (!tableManual) setTableNumber(table) }} />
{tableManual ? ( setTableNumber(parseInt(e.target.value) || null)} disabled={disabled} /> ) : tableNumber ? (
{tableNumber} {(municipality || rate != null) && ( {municipality} {rate != null ? ` · ${rate.toLocaleString('sv-SE')} %` : ''} )}
) : (

Välj kommun ovan

)} {!disabled && ( )}
{!columnTouched && derivedColumn != null ? (

Föreslås automatiskt: anställd under 66 år.

) : isSenior && !columnTouched ? (

Personen har fyllt 66 år — välj kolumn manuellt (lön = kolumn 3, pension = kolumn 2).

) : null}
) : (

{sido ? 'Sidoinkomst: ett fast skatteavdrag på 30 % görs — ingen skattetabell behövs.' : 'Med F-skatt eller FA-skatt sköter personen sin egen skatt — inget skatteavdrag görs och ingen skattetabell behövs.'}

)}
) }