Vat onboarding fixes (#39)
* fix: enhance validation for moms_period and conditionally set vat_number and moms_period based on vat_registered * Enhance preprocessing for first year fields, fiscal year end month, and accounting method in schema validation * fix: simplify schema validation by removing unnecessary preprocessors * fix: prevent setting invalid values in select components across multiple forms * fix: improve layout responsiveness and conditional rendering in onboarding steps
This commit is contained in:
@@ -786,20 +786,8 @@ export default function ImportPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{mode === null && (
|
||||
{mode === null && hasBankingExtension !== null && (
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||
{hasBankingExtension === null && (
|
||||
<Card className="animate-pulse">
|
||||
<CardContent className="pt-6 pb-6 flex flex-col items-center text-center space-y-3">
|
||||
<div className="h-12 w-12 rounded-full bg-muted" />
|
||||
<div className="space-y-2 w-full flex flex-col items-center">
|
||||
<div className="h-5 bg-muted rounded w-24" />
|
||||
<div className="h-4 bg-muted rounded w-48" />
|
||||
<div className="h-4 bg-muted rounded w-40" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
{hasBankingExtension === true && (
|
||||
<Card
|
||||
role="button"
|
||||
|
||||
@@ -84,15 +84,19 @@ export default function AccountCombobox({ value, accounts, onChange }: AccountCo
|
||||
}
|
||||
}, [highlightedIndex, isOpen])
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
// Close dropdown when clicking/tapping outside
|
||||
useEffect(() => {
|
||||
function handleClickOutside(e: MouseEvent) {
|
||||
function handleClickOutside(e: MouseEvent | TouchEvent) {
|
||||
if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
|
||||
setIsOpen(false)
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside)
|
||||
document.addEventListener('touchstart', handleClickOutside)
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
document.removeEventListener('touchstart', handleClickOutside)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const selectAccount = useCallback(
|
||||
|
||||
@@ -146,7 +146,7 @@ export function AddAccountDialog({ open, onOpenChange, onCreated }: AddAccountDi
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>Normal saldo</Label>
|
||||
<Select value={normalBalance} onValueChange={(v) => setNormalBalance(v as 'debit' | 'credit')}>
|
||||
<Select value={normalBalance} onValueChange={(v) => { if (v) setNormalBalance(v as 'debit' | 'credit') }}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -136,7 +136,7 @@ export default function CustomerForm({
|
||||
name="customer_type"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<Select value={field.value} onValueChange={(v) => { if (v) field.onChange(v) }}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj kundtyp" />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -176,7 +176,7 @@ export function DeadlineForm({
|
||||
<Label>Typ *</Label>
|
||||
<Select
|
||||
value={formData.deadline_type}
|
||||
onValueChange={(v) => updateField('deadline_type', v as DeadlineType)}
|
||||
onValueChange={(v) => { if (v) updateField('deadline_type', v as DeadlineType) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
@@ -194,7 +194,7 @@ export function DeadlineForm({
|
||||
<Label>Prioritet</Label>
|
||||
<Select
|
||||
value={formData.priority}
|
||||
onValueChange={(v) => updateField('priority', v as DeadlinePriority)}
|
||||
onValueChange={(v) => { if (v) updateField('priority', v as DeadlinePriority) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
@@ -216,7 +216,7 @@ export function DeadlineForm({
|
||||
<Label>Kund (valfritt)</Label>
|
||||
<Select
|
||||
value={formData.customer_id || 'none'}
|
||||
onValueChange={(v) => updateField('customer_id', v === 'none' ? '' : v)}
|
||||
onValueChange={(v) => { if (v) updateField('customer_id', v === 'none' ? '' : v) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj kund..." />
|
||||
|
||||
@@ -82,7 +82,7 @@ export default function BankFileColumnMappingStep({
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label>Avgränsare</Label>
|
||||
<Select value={delimiter} onValueChange={setDelimiter}>
|
||||
<Select value={delimiter} onValueChange={(v) => { if (v) setDelimiter(v) }}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
@@ -95,7 +95,7 @@ export default function BankFileColumnMappingStep({
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>Decimalavgränsare</Label>
|
||||
<Select value={decimalSep} onValueChange={(v) => setDecimalSep(v as ',' | '.')}>
|
||||
<Select value={decimalSep} onValueChange={(v) => { if (v) setDecimalSep(v as ',' | '.') }}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -47,6 +47,13 @@ const schema = z.object({
|
||||
})
|
||||
}
|
||||
}
|
||||
if (data.vat_registered && !data.moms_period) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'Välj momsredovisningsperiod.',
|
||||
path: ['moms_period'],
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
type FormData = z.infer<typeof schema>
|
||||
@@ -272,8 +279,8 @@ export default function Step3TaxRegistration({
|
||||
...(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,
|
||||
vat_number: data.vat_registered ? data.vat_number : undefined,
|
||||
moms_period: data.vat_registered ? data.moms_period : undefined,
|
||||
accounting_method: data.accounting_method,
|
||||
}
|
||||
|
||||
@@ -431,10 +438,10 @@ export default function Step3TaxRegistration({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||
<Select
|
||||
value={startMonth ? startMonth.toString() : ''}
|
||||
onValueChange={(v) => handleMonthChange(parseInt(v))}
|
||||
onValueChange={(v) => { if (v) handleMonthChange(parseInt(v)) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Månad" />
|
||||
@@ -447,7 +454,7 @@ export default function Step3TaxRegistration({
|
||||
</Select>
|
||||
<Select
|
||||
value={startYear ? startYear.toString() : ''}
|
||||
onValueChange={(v) => handleYearChange(parseInt(v))}
|
||||
onValueChange={(v) => { if (v) handleYearChange(parseInt(v)) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="År" />
|
||||
@@ -476,7 +483,7 @@ export default function Step3TaxRegistration({
|
||||
<Label>Räkenskapsåret slutar (månad)</Label>
|
||||
<Select
|
||||
value={abEndMonth.toString()}
|
||||
onValueChange={(v) => setAbEndMonth(parseInt(v))}
|
||||
onValueChange={(v) => { if (v) setAbEndMonth(parseInt(v)) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj månad" />
|
||||
@@ -502,7 +509,7 @@ export default function Step3TaxRegistration({
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value || ''}
|
||||
onValueChange={field.onChange}
|
||||
onValueChange={(v) => { if (v) field.onChange(v) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj slutdatum" />
|
||||
@@ -565,7 +572,7 @@ export default function Step3TaxRegistration({
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value?.toString() || '12'}
|
||||
onValueChange={(value) => field.onChange(parseInt(value))}
|
||||
onValueChange={(v) => { if (v) field.onChange(parseInt(v)) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj månad" />
|
||||
@@ -644,7 +651,7 @@ export default function Step3TaxRegistration({
|
||||
</div>
|
||||
|
||||
{vatRegistered && (
|
||||
<div className="space-y-4 pl-7">
|
||||
<div className="space-y-4 pl-0 sm:pl-7">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="vat_number">Momsregistreringsnummer</Label>
|
||||
<Input
|
||||
@@ -680,7 +687,7 @@ export default function Step3TaxRegistration({
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
onValueChange={(v) => { if (v) field.onChange(v) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj period" />
|
||||
@@ -716,7 +723,7 @@ export default function Step3TaxRegistration({
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
onValueChange={(v) => { if (v) field.onChange(v) }}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj metod" />
|
||||
|
||||
@@ -95,7 +95,7 @@ export default function Step4PreliminaryTax({
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between pt-4">
|
||||
<div className="flex flex-col-reverse sm:flex-row sm:justify-between gap-3 pt-4">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
@@ -105,17 +105,18 @@ export default function Step4PreliminaryTax({
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Tillbaka
|
||||
</Button>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={onSkip}
|
||||
disabled={isSaving}
|
||||
className="w-full sm:w-auto"
|
||||
>
|
||||
<SkipForward className="mr-2 h-4 w-4" />
|
||||
Hoppa över
|
||||
</Button>
|
||||
<Button type="submit" disabled={isSaving}>
|
||||
<Button type="submit" disabled={isSaving} className="w-full sm:w-auto">
|
||||
{isSaving ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
@@ -179,7 +178,7 @@ export default function Step6ConnectBank({
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
<div className="flex justify-between pt-4">
|
||||
<div className="flex flex-col-reverse sm:flex-row sm:justify-between gap-3 pt-4">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
@@ -192,6 +191,7 @@ export default function Step6ConnectBank({
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={onSkip}
|
||||
className="w-full sm:w-auto"
|
||||
>
|
||||
<SkipForward className="mr-2 h-4 w-4" />
|
||||
Hoppa över
|
||||
|
||||
@@ -91,7 +91,7 @@ export default function SupplierForm({
|
||||
name="supplier_type"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<Select value={field.value} onValueChange={(v) => { if (v) field.onChange(v) }}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Välj typ" />
|
||||
</SelectTrigger>
|
||||
@@ -244,7 +244,7 @@ export default function SupplierForm({
|
||||
name="default_currency"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<Select value={field.value} onValueChange={(v) => { if (v) field.onChange(v) }}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function VatTreatmentSelect({
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
onValueChange={(v) => onValueChange(v as VatTreatment | 'none')}
|
||||
onValueChange={(v) => { if (v) onValueChange(v as VatTreatment | 'none') }}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectTrigger className="h-9">
|
||||
|
||||
Reference in New Issue
Block a user