'use client' import { useState, useEffect } from 'react' import { useRouter, useSearchParams } from 'next/navigation' import Link from 'next/link' import { createClient } from '@/lib/supabase/client' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Textarea } from '@/components/ui/textarea' import { Label } from '@/components/ui/label' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { useToast } from '@/components/ui/use-toast' import { Separator } from '@/components/ui/separator' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Loader2, CreditCard, LogOut, Sun, Moon, Monitor, ExternalLink, AlertTriangle, } from 'lucide-react' import { useTheme } from 'next-themes' import type { CompanySettings } from '@/types' import { CalendarFeedSettings } from '@/components/settings/CalendarFeedSettings' import { getSettingsPanel } from '@/lib/extensions/settings-panel-registry' const BankingPanel = getSettingsPanel('enable-banking') export default function SettingsPage() { const router = useRouter() const searchParams = useSearchParams() const { toast } = useToast() const supabase = createClient() const [isLoading, setIsLoading] = useState(true) const [isSaving, setIsSaving] = useState(false) const [settings, setSettings] = useState(null) const [hasBankingExtension, setHasBankingExtension] = useState(false) const [hasCalendarExtension, setHasCalendarExtension] = useState(false) const [showDeleteDialog, setShowDeleteDialog] = useState(false) const [deleteConfirmText, setDeleteConfirmText] = useState('') const [isDeleting, setIsDeleting] = useState(false) const { theme, setTheme } = useTheme() const [mounted, setMounted] = useState(false) const initialTab = searchParams.get('tab') || 'company' useEffect(() => { setMounted(true) }, []) useEffect(() => { fetchData() // Handle callback messages const bankConnected = searchParams.get('bank_connected') const bankError = searchParams.get('bank_error') if (bankConnected === 'true') { toast({ title: 'Bank ansluten!', description: 'Din bank är nu kopplad. Transaktioner hämtas...', }) // Auto-sync transactions after connection const connectionId = searchParams.get('connection_id') if (connectionId) { fetch('/api/extensions/ext/enable-banking/sync', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ connection_id: connectionId, days_back: 90 }), }) .then(res => res.json()) .then(data => { if (data.imported > 0) { toast({ title: 'Transaktioner hämtade', description: `${data.imported} transaktioner importerade`, }) } }) .catch(() => {}) } router.replace('/settings?tab=banking') } if (bankError) { toast({ title: 'Anslutning misslyckades', description: decodeURIComponent(bankError), variant: 'destructive', }) router.replace('/settings') } }, [searchParams]) async function fetchData() { setIsLoading(true) const { data: { user } } = await supabase.auth.getUser() if (!user) { router.push('/login') return } // Fetch settings const { data: settingsData } = await supabase .from('company_settings') .select('*') .eq('user_id', user.id) .single() setSettings(settingsData) // Check extension toggles in parallel const [bankingToggleRes, calendarToggleRes] = await Promise.all([ fetch('/api/extensions/toggles/general/enable-banking').catch(() => null), fetch('/api/extensions/toggles/general/calendar').catch(() => null), ]) if (bankingToggleRes?.ok) { const { data } = await bankingToggleRes.json() setHasBankingExtension(data?.enabled || false) } else { // Fallback: check for existing bank connections const { data: connections } = await supabase .from('bank_connections') .select('id') .eq('user_id', user.id) .eq('status', 'active') .limit(1) setHasBankingExtension((connections && connections.length > 0) || false) } if (calendarToggleRes?.ok) { const { data } = await calendarToggleRes.json() setHasCalendarExtension(data?.enabled || false) } setIsLoading(false) } async function handleSaveSettings(e: React.FormEvent) { e.preventDefault() if (!settings) return setIsSaving(true) const formData = new FormData(e.currentTarget) const updates: Record = { company_name: formData.get('company_name') as string, org_number: formData.get('org_number') as string, address_line1: formData.get('address_line1') as string, postal_code: formData.get('postal_code') as string, city: formData.get('city') as string, bank_name: formData.get('bank_name') as string, clearing_number: formData.get('clearing_number') as string, account_number: formData.get('account_number') as string, preliminary_tax_monthly: parseFloat(formData.get('preliminary_tax_monthly') as string) || null, invoice_prefix: formData.get('invoice_prefix') as string || null, next_invoice_number: parseInt(formData.get('next_invoice_number') as string) || 1, invoice_default_days: parseInt(formData.get('invoice_default_days') as string) || 30, accounting_method: formData.get('accounting_method') as string || 'accrual', invoice_default_notes: (formData.get('invoice_default_notes') as string) || null, } try { const response = await fetch('/api/settings', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updates), }) const result = await response.json() if (!response.ok) { throw new Error(result.error || 'Kunde inte spara inställningar') } toast({ title: 'Sparat', description: 'Dina inställningar har uppdaterats', }) setSettings({ ...settings, ...updates } as typeof settings) } catch (error) { toast({ title: 'Fel', description: error instanceof Error ? error.message : 'Kunde inte spara inställningar', variant: 'destructive', }) } setIsSaving(false) } async function handleLogout() { await supabase.auth.signOut() router.push('/login') } async function handleDeleteAccount() { if (deleteConfirmText !== 'RADERA') return setIsDeleting(true) try { const response = await fetch('/api/account/delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ confirm: 'RADERA' }), }) if (!response.ok) { const result = await response.json() throw new Error(result.error || 'Kunde inte radera kontot') } router.push('/login') } catch (error) { toast({ title: 'Fel', description: error instanceof Error ? error.message : 'Kunde inte radera kontot', variant: 'destructive', }) setIsDeleting(false) } } if (isLoading) { return (
) } return (

Inställningar

Hantera dina företags- och kontoinställningar

Företag Bank (PSD2) {hasCalendarExtension && ( Kalender )} Utseende Konto {/* Company settings */}
{/* Företagsuppgifter */} Företagsuppgifter Namn, organisationsnummer och adress
{settings?.onboarding_complete && (

Kan inte ändras efter att kontot skapats

)}
{settings?.onboarding_complete && (

Kan inte ändras efter att kontot skapats

)}
{/* Bankuppgifter */} Bankuppgifter Betalningsuppgifter som visas på dina fakturor
{/* Fakturainställningar */} Fakturainställningar Numrering, betalningsvillkor och bokföringsmetod

{settings?.entity_type === 'aktiebolag' ? 'Aktiebolag med omsättning över 3 MSEK måste använda faktureringsmetoden enligt BFL. Mindre aktiebolag kan välja kontantmetoden.' : 'Kontantmetoden är tillgänglig för enskild firma med omsättning under 3 MSEK.'}