'use client' import Link from 'next/link' import { useState } from 'react' import { useTranslations } from 'next-intl' import { Label } from '@/components/ui/label' import { Input } from '@/components/ui/input' import { SettingsFormWrapper } from '@/components/settings/SettingsFormWrapper' import { SettingsLoadError } from '@/components/settings/SettingsLoadError' import { SettingsLoadingSkeleton } from '@/components/settings/SettingsLoadingSkeleton' import { TaxTableStatus } from '@/components/salary/TaxTableStatus' import { useSettings } from '@/components/settings/useSettings' import { resolveDefaultSeriesForSource } from '@/lib/bookkeeping/voucher-series-resolver' import { AlertTriangle } from 'lucide-react' import type { CompanySettings } from '@/types' const SERIES_OPTIONS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('') const BANK_OPTIONS = ['swedbank', 'seb', 'handelsbanken', 'nordea'] as const const BANK_LABEL: Record<(typeof BANK_OPTIONS)[number], string> = { swedbank: 'Swedbank', seb: 'SEB', handelsbanken: 'Handelsbanken', nordea: 'Nordea', } const selectClassName = 'flex h-10 w-full max-w-xs rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2' export function SalarySettingsContent() { const t = useTranslations('settings_salary') const { settings, isLoading, updateSettings, refetch } = useSettings() // Controlled so the LB sunset note reacts to the selection before save. const [format, setFormat] = useState<'bg_lb' | 'pain001' | null>(null) if (isLoading) return if (!settings) return const effectiveFormat = format ?? settings.preferred_payment_format ?? 'pain001' const currentSeries = resolveDefaultSeriesForSource(settings, 'salary_payment') function handleSave(formData: FormData) { const payDayRaw = parseInt((formData.get('salary_pay_day') as string) || '25', 10) const payDay = Number.isFinite(payDayRaw) ? Math.min(28, Math.max(1, payDayRaw)) : 25 const paymentFormat = (formData.get('preferred_payment_format') as string) || 'pain001' const bank = (formData.get('salary_default_bank') as string) || 'none' const series = (formData.get('salary_voucher_series') as string) || 'A' const updates: Record = { salary_pay_day: payDay, preferred_payment_format: paymentFormat, salary_default_bank: bank === 'none' ? null : bank, } // The booking engine resolves the series from the per-source-type map; // salary entries pass run.voucher_series explicitly, seeded from this // entry at run creation. Merge — never replace — the map so other // source-type overrides survive. if (series !== currentSeries) { updates.default_voucher_series_per_source_type = { ...(settings?.default_voucher_series_per_source_type || {}), salary_payment: series, } } return { updates, onSuccess: (data: Record) => { updateSettings(data as Partial) }, } } return (
{/* Payment */}

{t('payments_heading')}

{t('pay_day_help')}

{t('format_help')}

{effectiveFormat === 'bg_lb' && (
{t('sunset_warning')}
)}

{t('bank_help')}

{/* Accounting */}

{t('accounting_heading')}

{t('voucher_series_help')}

{/* Tax tables (read-only status) */}

{t('tax_tables_heading')}

{t('tax_tables_help')}

{/* Vacation (informational — the rule is per-employee) */}

{t('vacation_heading')}

{t('vacation_info')}{' '} {t('vacation_info_link')}

{/* Info */}

{t('info_heading')}

{t('info_payroll_scope')}

{t.rich('info_current_year', { strong: (chunks) => {chunks}, })}

) }