diff --git a/src/components/settings/AccountProfileTab.tsx b/src/components/settings/AccountProfileTab.tsx index cc2b221e..43c0bc18 100644 --- a/src/components/settings/AccountProfileTab.tsx +++ b/src/components/settings/AccountProfileTab.tsx @@ -16,6 +16,7 @@ import { useAuth } from '@/hooks/useAuth'; import { supabase } from '@/integrations/supabase/client'; import { User, Upload, Trash2 } from 'lucide-react'; import { PhotoUpload } from '@/components/upload/PhotoUpload'; +import { notificationService } from '@/lib/notificationService'; const profileSchema = z.object({ username: z.string().min(3).max(30).regex(/^[a-zA-Z0-9_-]+$/), @@ -54,6 +55,8 @@ export function AccountProfileTab() { setLoading(true); try { + const usernameChanged = profile?.username !== data.username; + const { error } = await supabase .from('profiles') .update({ @@ -69,6 +72,15 @@ export function AccountProfileTab() { if (error) throw error; + // Update Novu subscriber if username changed + if (usernameChanged && notificationService.isEnabled()) { + await notificationService.updateSubscriber({ + subscriberId: user.id, + email: user.email, + firstName: data.username, // Send username as firstName to Novu + }); + } + await refreshProfile(); toast({ title: 'Profile updated', diff --git a/src/components/settings/NotificationsTab.tsx b/src/components/settings/NotificationsTab.tsx index 266db976..c9eb2cc1 100644 --- a/src/components/settings/NotificationsTab.tsx +++ b/src/components/settings/NotificationsTab.tsx @@ -111,6 +111,14 @@ export function NotificationsTab() { if (result.success) { toast.success("Notification preferences saved successfully"); + + // Also update Novu subscriber profile to sync channel preferences + if (notificationService.isEnabled()) { + await notificationService.updateSubscriber({ + subscriberId: user.id, + email: user.email, + }); + } } else { throw new Error(result.error || 'Failed to save preferences'); } diff --git a/src/lib/notificationService.ts b/src/lib/notificationService.ts index e34a1e71..6cdbeebc 100644 --- a/src/lib/notificationService.ts +++ b/src/lib/notificationService.ts @@ -71,6 +71,30 @@ class NotificationService { } } + /** + * Update an existing Novu subscriber's profile information + */ + async updateSubscriber(subscriberData: SubscriberData): Promise<{ success: boolean; error?: string }> { + if (!this.isNovuEnabled) { + console.warn('Novu is not configured. Skipping subscriber update.'); + return { success: false, error: 'Novu not configured' }; + } + + try { + const { data, error } = await supabase.functions.invoke('update-novu-subscriber', { + body: subscriberData, + }); + + if (error) throw error; + + console.log('Novu subscriber updated successfully'); + return { success: true }; + } catch (error: any) { + console.error('Error updating Novu subscriber:', error); + return { success: false, error: error.message }; + } + } + /** * Update subscriber preferences in Novu */ diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx index 1f1e51e5..f19c5368 100644 --- a/src/pages/Auth.tsx +++ b/src/pages/Auth.tsx @@ -147,7 +147,7 @@ export default function Auth() { notificationService.createSubscriber({ subscriberId: data.user.id, email: formData.email, - firstName: formData.displayName || formData.username, + firstName: formData.username, // Send username as firstName to Novu data: { username: formData.username, } diff --git a/supabase/functions/create-novu-subscriber/index.ts b/supabase/functions/create-novu-subscriber/index.ts index 20e08504..f53a5996 100644 --- a/supabase/functions/create-novu-subscriber/index.ts +++ b/supabase/functions/create-novu-subscriber/index.ts @@ -24,7 +24,7 @@ serve(async (req) => { const { subscriberId, email, firstName, lastName, phone, avatar, data } = await req.json(); - console.log('Creating Novu subscriber:', { subscriberId, email }); + console.log('Creating Novu subscriber:', { subscriberId, email, firstName }); const subscriber = await novu.subscribers.identify(subscriberId, { email, diff --git a/supabase/functions/update-novu-subscriber/index.ts b/supabase/functions/update-novu-subscriber/index.ts new file mode 100644 index 00000000..d138b1e8 --- /dev/null +++ b/supabase/functions/update-novu-subscriber/index.ts @@ -0,0 +1,64 @@ +import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; +import { Novu } from "npm:@novu/node@2.0.2"; + +const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', +}; + +serve(async (req) => { + if (req.method === 'OPTIONS') { + return new Response(null, { headers: corsHeaders }); + } + + try { + const novuApiKey = Deno.env.get('NOVU_API_KEY'); + + if (!novuApiKey) { + throw new Error('NOVU_API_KEY is not configured'); + } + + const novu = new Novu(novuApiKey, { + backendUrl: Deno.env.get('VITE_NOVU_API_URL') || 'https://api.novu.co', + }); + + const { subscriberId, email, firstName, lastName, phone, avatar, data } = await req.json(); + + console.log('Updating Novu subscriber:', { subscriberId, email, firstName }); + + const subscriber = await novu.subscribers.update(subscriberId, { + email, + firstName, + lastName, + phone, + avatar, + data, + }); + + console.log('Subscriber updated successfully:', subscriber.data); + + return new Response( + JSON.stringify({ + success: true, + subscriberId: subscriber.data._id, + }), + { + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + status: 200, + } + ); + } catch (error: any) { + console.error('Error updating Novu subscriber:', error); + + return new Response( + JSON.stringify({ + success: false, + error: error.message, + }), + { + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + status: 500, + } + ); + } +});