'use client' import { useState, useEffect } from 'react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Label } from '@/components/ui/label' import { Switch } from '@/components/ui/switch' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { useToast } from '@/components/ui/use-toast' import { createClient } from '@/lib/supabase/client' import { Bell, BellOff, Loader2, Moon } from 'lucide-react' import type { NotificationSettings as NotificationSettingsType } from '@/types' interface NotificationSettingsProps { onSettingsChange?: () => void } export function NotificationSettings({ onSettingsChange }: NotificationSettingsProps) { const { toast } = useToast() const supabase = createClient() const [isLoading, setIsLoading] = useState(true) const [isSaving, setIsSaving] = useState(false) const [settings, setSettings] = useState(null) const [isPushSupported, setIsPushSupported] = useState(false) const [isPushSubscribed, setIsPushSubscribed] = useState(false) useEffect(() => { fetchSettings() checkPushSupport() }, []) const checkPushSupport = async () => { if ('serviceWorker' in navigator && 'PushManager' in window) { setIsPushSupported(true) try { const registration = await navigator.serviceWorker.ready const subscription = await registration.pushManager.getSubscription() setIsPushSubscribed(!!subscription) } catch (error) { console.error('Error checking push subscription:', error) } } } const fetchSettings = async () => { setIsLoading(true) // Notification settings are per user, not per company: quiet hours and the // per-category toggles belong to the person, and push_subscriptions are // keyed on a device endpoint. Neither table carries a company_id. const { data: { user } } = await supabase.auth.getUser() if (!user) { setIsLoading(false) return } const { data, error } = await supabase .from('notification_settings') .select('*') .eq('user_id', user.id) .single() if (!error && data) { setSettings(data) } else { // Create default settings if not found const { data: newSettings, error: insertError } = await supabase .from('notification_settings') .insert({ user_id: user.id, tax_deadlines_enabled: true, invoice_reminders_enabled: true, push_enabled: true, email_enabled: true, quiet_start: '21:00', quiet_end: '08:00', }) .select() .single() if (!insertError && newSettings) { setSettings(newSettings) } } setIsLoading(false) } const updateSetting = async (key: keyof NotificationSettingsType, value: boolean | string) => { if (!settings) return setIsSaving(true) const { error } = await supabase .from('notification_settings') .update({ [key]: value }) .eq('id', settings.id) if (error) { toast({ title: 'Fel', description: 'Kunde inte spara inställning', variant: 'destructive', }) } else { setSettings({ ...settings, [key]: value }) onSettingsChange?.() } setIsSaving(false) } const subscribeToPush = async () => { try { const permission = await Notification.requestPermission() if (permission !== 'granted') { toast({ title: 'Aviseringar avslagna', description: 'Du behöver ge tillåtelse för push-aviseringar i webbläsaren.', }) return } const vapidResponse = await fetch('/api/extensions/ext/push-notifications/subscribe') const { vapidPublicKey } = await vapidResponse.json() if (!vapidPublicKey) { throw new Error('Push not configured') } const registration = await navigator.serviceWorker.ready const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(vapidPublicKey), }) const response = await fetch('/api/extensions/ext/push-notifications/subscribe', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(subscription.toJSON()), }) if (!response.ok) { throw new Error('Failed to save subscription') } setIsPushSubscribed(true) toast({ title: 'Push-aviseringar aktiverade', description: 'Du kommer nu få push-aviseringar.', }) } catch (error) { toast({ title: 'Fel', description: 'Kunde inte aktivera push-aviseringar.', variant: 'destructive', }) } } const unsubscribeFromPush = async () => { try { const registration = await navigator.serviceWorker.ready const subscription = await registration.pushManager.getSubscription() if (subscription) { await subscription.unsubscribe() await fetch('/api/extensions/ext/push-notifications/subscribe', { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ endpoint: subscription.endpoint }), }) } setIsPushSubscribed(false) toast({ title: 'Push-aviseringar inaktiverade', description: 'Du kommer inte längre få push-aviseringar.', }) } catch (error) { toast({ title: 'Fel', description: 'Kunde inte inaktivera push-aviseringar.', variant: 'destructive', }) } } if (isLoading) { return (
) } if (!settings) { return null } return (
{/* Push notification status */} Push-aviseringar Få påminnelser direkt i din webbläsare {isPushSupported ? (

{isPushSubscribed ? 'Aktiverade' : 'Inaktiverade'}

{isPushSubscribed ? 'Du får push-aviseringar på denna enhet' : 'Aktivera för att få push-aviseringar'}

) : (

Din webbläsare stöder inte push-aviseringar.

)}
{/* Category settings */} Aviseringskategorier Välj vilka typer av aviseringar du vill få

Moms, F-skatt, inkomstdeklaration m.m.

updateSetting('tax_deadlines_enabled', checked) } disabled={isSaving} />

Fakturor som förfaller eller är försenade

updateSetting('invoice_reminders_enabled', checked) } disabled={isSaving} />
{/* Quiet hours */} Tysta timmar Inga aviseringar skickas under dessa timmar
updateSetting('quiet_start', e.target.value)} disabled={isSaving} />
updateSetting('quiet_end', e.target.value)} disabled={isSaving} />

Standard: 21:00 - 08:00 (Sveriges tid)

) } function urlBase64ToUint8Array(base64String: string): ArrayBuffer { const padding = '='.repeat((4 - (base64String.length % 4)) % 4) const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/') const rawData = window.atob(base64) const outputArray = new Uint8Array(rawData.length) for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i) } return outputArray.buffer }