'use client' import { useState, useMemo, useEffect } from 'react' import { useForm, Controller } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import { Card, CardContent, CardDescription, 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 { Checkbox } from '@/components/ui/checkbox' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { InfoTooltip } from '@/components/ui/info-tooltip' import { Loader2, ArrowRight, ArrowLeft, Check, CalendarDays, Info } from 'lucide-react' import { cn } from '@/lib/utils' import { monthsBetween } from '@/lib/bookkeeping/validate-period-duration' import type { MomsPeriod, EntityType } from '@/types' const schema = z.object({ f_skatt: z.boolean(), is_first_fiscal_year: z.boolean(), // First year fields (conditional) first_year_start: z.string().optional(), first_year_end: z.string().optional(), // Ongoing year field (conditional) fiscal_year_end_month: z.number().min(1).max(12).optional(), // Existing fields vat_registered: z.boolean(), vat_number: z.string().optional(), moms_period: z.enum(['monthly', 'quarterly', 'yearly']).optional(), accounting_method: z.enum(['accrual', 'cash']), }) type FormData = z.infer // Output type passed to onNext — includes computed fiscal_year_start_month interface Step3Output { f_skatt: boolean fiscal_year_start_month: number is_first_fiscal_year: boolean first_year_start?: string first_year_end?: string vat_registered: boolean vat_number?: string moms_period?: MomsPeriod accounting_method: 'accrual' | 'cash' } interface Step3Props { initialData: Partial entityType?: EntityType orgNumber?: string onNext: (data: Step3Output) => void onBack: () => void isSaving: boolean } const monthNames = [ 'Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December', ] function formatSwedishDate(dateStr: string): string { const d = new Date(dateStr) const day = d.getDate() const month = monthNames[d.getMonth()].toLowerCase() const year = d.getFullYear() return `${day} ${month} ${year}` } /** * Get the last day of a given month (1-indexed). */ function lastDayOfMonth(year: number, month: number): number { return new Date(year, month, 0).getDate() } /** * Compute valid first-year end dates for enskild firma. * EF must use calendar year, so end is always Dec 31. */ function getEFFirstYearEndDates(startYear: number, startMonth: number): { label: string; value: string }[] { // EF always ends Dec 31 of either same year or (if start is Jan) same year // If start is late in the year, only option is Dec 31 same year // Periods cannot exceed 18 months const options: { label: string; value: string }[] = [] // Option 1: Dec 31 of same year (if startMonth <= 12) const months1 = 12 - startMonth + 1 if (months1 >= 1 && months1 <= 18) { const endDate = `${startYear}-12-31` options.push({ label: `31 december ${startYear} (${months1} mån)`, value: endDate, }) } // Option 2: Dec 31 of next year (if that gives <= 18 months) const months2 = months1 + 12 if (months2 >= 1 && months2 <= 18 && startMonth > 6) { // Only makes sense if start month > June (otherwise > 18 months) const endDate = `${startYear + 1}-12-31` options.push({ label: `31 december ${startYear + 1} (${months2} mån)`, value: endDate, }) } return options } /** * Compute valid first-year end dates for aktiebolag given a chosen end month. * Returns one or two options (ending in the nearest years that give 1-18 months). */ function getABFirstYearEndDates( startYear: number, startMonth: number, endMonth: number ): { label: string; value: string }[] { const options: { label: string; value: string }[] = [] // Try ending in the same year or next year for (const endYear of [startYear, startYear + 1, startYear + 2]) { const months = (endYear - startYear) * 12 + (endMonth - startMonth) + 1 if (months >= 1 && months <= 18) { const day = lastDayOfMonth(endYear, endMonth) const endDate = `${endYear}-${String(endMonth).padStart(2, '0')}-${String(day).padStart(2, '0')}` options.push({ label: `${day} ${monthNames[endMonth - 1].toLowerCase()} ${endYear} (${months} mån)`, value: endDate, }) } } return options } export default function Step3TaxRegistration({ initialData, entityType, orgNumber, onNext, onBack, isSaving, }: Step3Props) { const isEF = entityType === 'enskild_firma' const { register, handleSubmit, watch, control, setValue, formState: { errors }, } = useForm({ resolver: zodResolver(schema), defaultValues: { f_skatt: initialData.f_skatt ?? true, is_first_fiscal_year: initialData.is_first_fiscal_year ?? false, first_year_start: initialData.first_year_start || '', first_year_end: initialData.first_year_end || '', fiscal_year_end_month: initialData.fiscal_year_start_month ? (initialData.fiscal_year_start_month === 1 ? 12 : initialData.fiscal_year_start_month - 1) : 12, vat_registered: initialData.vat_registered ?? false, vat_number: initialData.vat_number || '', moms_period: initialData.moms_period, accounting_method: initialData.accounting_method ?? 'accrual', }, }) const vatRegistered = watch('vat_registered') const isFirstYear = watch('is_first_fiscal_year') const firstYearStart = watch('first_year_start') const firstYearEnd = watch('first_year_end') const fiscalYearEndMonth = watch('fiscal_year_end_month') const accountingMethod = watch('accounting_method') // Auto-fill VAT number when vat_registered toggles on const vatNumber = watch('vat_number') useEffect(() => { if (vatRegistered && !vatNumber && orgNumber) { const cleaned = orgNumber.replace(/[-\s]/g, '') if (cleaned.length >= 10) { setValue('vat_number', `SE${cleaned}01`) } } }, [vatRegistered, vatNumber, orgNumber, setValue]) // State for first-year start date selectors (month/year) const [startMonth, setStartMonth] = useState( initialData.first_year_start ? new Date(initialData.first_year_start).getMonth() + 1 : 0 ) const [startYear, setStartYear] = useState( initialData.first_year_start ? new Date(initialData.first_year_start).getFullYear() : 0 ) // State for AB first-year end month selector const [abEndMonth, setAbEndMonth] = useState( initialData.first_year_end ? new Date(initialData.first_year_end).getMonth() + 1 : 12 ) // Parse first year start for date computations const parsedStart = useMemo(() => { if (!firstYearStart) return null const d = new Date(firstYearStart) if (isNaN(d.getTime())) return null return { year: d.getFullYear(), month: d.getMonth() + 1 } }, [firstYearStart]) // Compute end date options for first year const firstYearEndOptions = useMemo(() => { if (!parsedStart) return [] if (isEF) { return getEFFirstYearEndDates(parsedStart.year, parsedStart.month) } return getABFirstYearEndDates(parsedStart.year, parsedStart.month, abEndMonth) }, [parsedStart, isEF, abEndMonth]) const onSubmit = (data: FormData) => { let fiscalYearStartMonth: number let firstStart: string | undefined let firstEnd: string | undefined if (data.is_first_fiscal_year && data.first_year_start && data.first_year_end) { // Derive start month from end date const endDate = new Date(data.first_year_end) const endMonth = endDate.getMonth() + 1 fiscalYearStartMonth = endMonth === 12 ? 1 : endMonth + 1 firstStart = data.first_year_start firstEnd = data.first_year_end } else if (isEF) { // EF must always be calendar year fiscalYearStartMonth = 1 } else { // AB ongoing: derive from end month const endMonth = data.fiscal_year_end_month || 12 fiscalYearStartMonth = endMonth === 12 ? 1 : endMonth + 1 } const output: Step3Output = { f_skatt: data.f_skatt, fiscal_year_start_month: fiscalYearStartMonth, is_first_fiscal_year: data.is_first_fiscal_year, ...(firstStart && { first_year_start: firstStart }), ...(firstEnd && { first_year_end: firstEnd }), vat_registered: data.vat_registered, vat_number: data.vat_number, moms_period: data.moms_period, accounting_method: data.accounting_method, } onNext(output) } return (

Skatteregistrering

Ange information om din skatteregistrering.

F-skatt och räkenskapsår Dessa uppgifter används för att beräkna din skattesituation.
{/* F-skatt */}
( )} />

Vad är F-skatt?

F-skatt betyder att du själv ansvarar för att betala skatt och avgifter till Skatteverket varje månad.

De flesta som driver företag har F-skatt. Utan F-skatt måste dina kunder göra skatteavdrag på dina fakturor.

} side="right" >

F-skatt innebär att du själv ansvarar för att betala in skatt och avgifter.

{/* Fiscal year section */}

Räkenskapsår

Ditt räkenskapsår bestämmer vilken period du bokför för. De flesta har kalenderår (jan-dec).

{isEF && (

Enskild firma måste använda kalenderår enligt BFL 3 kap.

)}
} side="right" > {/* Toggle: First year vs Ongoing */} (
)} /> {/* First fiscal year options */} {isFirstYear && (
{ const currentYear = new Date().getFullYear() const years = Array.from({ length: 7 }, (_, i) => currentYear - 5 + i) const handleMonthChange = (month: number) => { setStartMonth(month) if (month && startYear) { field.onChange(`${startYear}-${String(month).padStart(2, '0')}-01`) } } const handleYearChange = (year: number) => { setStartYear(year) if (startMonth && year) { field.onChange(`${year}-${String(startMonth).padStart(2, '0')}-01`) } } return (
) }} />

Månaden verksamheten startade. Räkenskapsåret börjar alltid den 1:a.

{/* AB: end month selector */} {!isEF && parsedStart && (
)} {/* End date selector (options depend on entity type + start) */} {parsedStart && firstYearEndOptions.length > 0 && (
( )} />
)} {parsedStart && firstYearEndOptions.length === 0 && (

Ingen giltig slutperiod hittades. Kontrollera startdatumet.

)} {firstYearStart && firstYearEnd && (
Ditt första räkenskapsår

{formatSwedishDate(firstYearStart)} – {formatSwedishDate(firstYearEnd)}

{monthsBetween(firstYearStart, firstYearEnd)} månader

)}
)} {/* Ongoing fiscal year options */} {!isFirstYear && (
{isEF ? (

Kalenderår (januari-december)

Enskild firma måste använda kalenderår enligt BFL 3 kap.

) : (
( )} />

De flesta har kalenderår (december). Brutet räkenskapsår slutar annan månad.

{fiscalYearEndMonth && (
Ditt räkenskapsår

{fiscalYearEndMonth === 12 ? `1 januari \u2013 31 december (kalenderår)` : `1 ${monthNames[fiscalYearEndMonth].toLowerCase()} \u2013 ${lastDayOfMonth(2025, fiscalYearEndMonth)} ${monthNames[fiscalYearEndMonth - 1].toLowerCase()}`}

12 månader

)}
)}
)} {/* VAT section */}

Behöver jag momsregistrera mig?

Ja, om din omsättning överstiger 80 000 kr per år. Med moms lägger du på 25% extra på dina fakturor, men får också dra av moms på dina inköp.

Om din omsättning överstiger 80 000 kr per år behöver du momsregistrera dig.

} side="right" > Momsregistrering
( )} />

Obligatoriskt om din omsättning överstiger 80 000 kr per år.

{vatRegistered && (

Format: SE + organisationsnummer + 01

Hur ofta rapporterar du moms?

Välj den period som anges på Verksamt eller i ditt beslut från Skatteverket.

  • Under 1 miljon/år = Kan välja årsredovisning
  • 1-40 miljoner = Kvartal
  • Över 40 miljoner = Månad
} side="right" > ( )} />

Välj den period som anges i ditt beslut från Skatteverket. Vanligtvis kvartal eller år.

)} {/* Accounting method */}
( )} />
{accountingMethod === 'accrual' ? 'Faktureringsmetoden' : 'Kontantmetoden'}

{accountingMethod === 'accrual' ? 'Intäkter och kostnader bokförs när fakturan skickas eller tas emot, oavsett när betalningen sker. Detta ger en mer rättvisande bild av verksamhetens ekonomi.' : 'Intäkter och kostnader bokförs först när betalningen faktiskt sker. Enklare att hantera men ger en mindre exakt bild av verksamhetens ekonomi vid varje given tidpunkt.'}

{entityType === 'aktiebolag' && (

Aktiebolag med omsättning över 3 MSEK per år måste använda faktureringsmetoden.

)}
) }