feat: expand tax settings form, refactor settings save flow, and update docs (#159)
Expand the tax settings page with F-skatt, VAT registration, fiscal year start month, and salary payment toggles. Refactor SettingsFormWrapper to support onSuccess callbacks so local state only updates after server confirmation. Fix logo upload to use service client for storage RLS bypass. Allow empty email in settings schema. Update CLAUDE.md with comprehensive multi-tenant, auth, and engine documentation. Remove unused langchain skills. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
d0b3f21bde
commit
197beb1c58
@@ -25,8 +25,12 @@ export default function BookkeepingSettingsPage() {
|
||||
auto_lock_period_days: autoLockValue === 'none' ? null : parseInt(autoLockValue),
|
||||
accounting_method: accountingMethod,
|
||||
}
|
||||
updateSettings(updates as Partial<CompanySettings>)
|
||||
return updates
|
||||
return {
|
||||
updates,
|
||||
onSuccess: (data: Record<string, unknown>) => {
|
||||
updateSettings(data as Partial<CompanySettings>)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -24,8 +24,12 @@ export default function CompanySettingsPage() {
|
||||
email: (formData.get('email') as string) || '',
|
||||
website: (formData.get('website') as string) || '',
|
||||
}
|
||||
updateSettings(updates as Partial<CompanySettings>)
|
||||
return updates
|
||||
return {
|
||||
updates,
|
||||
onSuccess: (data: Record<string, unknown>) => {
|
||||
updateSettings(data as Partial<CompanySettings>)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -36,8 +36,12 @@ export default function InvoicingSettingsPage() {
|
||||
invoice_default_days: parseInt(formData.get('invoice_default_days') as string) || 30,
|
||||
invoice_default_notes: (formData.get('invoice_default_notes') as string) || null,
|
||||
}
|
||||
updateSettings(updates as Partial<CompanySettings>)
|
||||
return updates
|
||||
return {
|
||||
updates,
|
||||
onSuccess: (data: Record<string, unknown>) => {
|
||||
updateSettings(data as Partial<CompanySettings>)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -12,15 +12,27 @@ export default function TaxSettingsPage() {
|
||||
if (isLoading || !settings) return <SettingsLoadingSkeleton />
|
||||
|
||||
function handleSave(formData: FormData) {
|
||||
const vatRegistered = formData.get('vat_registered') === 'true'
|
||||
|
||||
const updates: Record<string, unknown> = {
|
||||
f_skatt: formData.get('f_skatt') === 'true',
|
||||
vat_registered: vatRegistered,
|
||||
vat_number: vatRegistered ? ((formData.get('vat_number') as string) || null) : null,
|
||||
moms_period: vatRegistered ? ((formData.get('moms_period') as string) || null) : null,
|
||||
fiscal_year_start_month: parseInt(formData.get('fiscal_year_start_month') as string) || 1,
|
||||
pays_salaries: formData.get('pays_salaries') === 'true',
|
||||
preliminary_tax_monthly: parseFloat(formData.get('preliminary_tax_monthly') as string) || null,
|
||||
}
|
||||
updateSettings(updates as Partial<CompanySettings>)
|
||||
return updates
|
||||
return {
|
||||
updates,
|
||||
onSuccess: (data: Record<string, unknown>) => {
|
||||
updateSettings(data as Partial<CompanySettings>)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsFormWrapper onSave={handleSave} className="space-y-8">
|
||||
<SettingsFormWrapper onSave={handleSave} className="space-y-0">
|
||||
<TaxSettingsForm settings={settings} />
|
||||
</SettingsFormWrapper>
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { createClient, createServiceClient } from '@/lib/supabase/server'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { requireCompanyId } from '@/lib/company/context'
|
||||
|
||||
@@ -32,8 +32,9 @@ export async function POST(request: Request) {
|
||||
const ext = file.name.split('.').pop() || 'png'
|
||||
const storagePath = `logos/${companyId}/logo.${ext}`
|
||||
|
||||
// Upload (upsert to replace existing)
|
||||
const { error: uploadError } = await supabase.storage
|
||||
// Upload with service client to bypass storage RLS (auth already verified above)
|
||||
const serviceClient = createServiceClient()
|
||||
const { error: uploadError } = await serviceClient.storage
|
||||
.from('documents')
|
||||
.upload(storagePath, buffer, {
|
||||
contentType: file.type,
|
||||
@@ -45,7 +46,7 @@ export async function POST(request: Request) {
|
||||
}
|
||||
|
||||
// Get public URL
|
||||
const { data: urlData } = supabase.storage
|
||||
const { data: urlData } = serviceClient.storage
|
||||
.from('documents')
|
||||
.getPublicUrl(storagePath)
|
||||
|
||||
@@ -82,7 +83,8 @@ export async function DELETE() {
|
||||
const url = new URL(settings.logo_url)
|
||||
const pathMatch = url.pathname.match(/\/object\/public\/documents\/(.+)/)
|
||||
if (pathMatch) {
|
||||
await supabase.storage.from('documents').remove([pathMatch[1]])
|
||||
const serviceClient = createServiceClient()
|
||||
await serviceClient.storage.from('documents').remove([pathMatch[1]])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user