import { useState } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { notificationService } from '@/lib/notificationService'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Progress } from '@/components/ui/progress'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { CheckCircle2, XCircle, AlertCircle, Loader2 } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; interface MigrationResult { userId: string; email: string; success: boolean; error?: string; } export function NovuMigrationUtility() { const { toast } = useToast(); const [isRunning, setIsRunning] = useState(false); const [progress, setProgress] = useState(0); const [results, setResults] = useState([]); const [totalUsers, setTotalUsers] = useState(0); const runMigration = async () => { setIsRunning(true); setResults([]); setProgress(0); try { // Fetch users without Novu subscriber IDs const { data: users, error: fetchError } = await supabase .from('profiles') .select('user_id, users:user_id(email)') .not('user_id', 'in', supabase .from('user_notification_preferences') .select('user_id') .not('novu_subscriber_id', 'is', null) ); if (fetchError) throw fetchError; if (!users || users.length === 0) { toast({ title: "No users to migrate", description: "All users are already registered with Novu.", }); setIsRunning(false); return; } setTotalUsers(users.length); const migrationResults: MigrationResult[] = []; // Process users one by one for (let i = 0; i < users.length; i++) { const user = users[i]; const email = (user.users as any)?.email; if (!email) { migrationResults.push({ userId: user.user_id, email: 'No email found', success: false, error: 'User email not found', }); continue; } try { const result = await notificationService.createSubscriber({ subscriberId: user.user_id, email, data: { userId: user.user_id }, }); migrationResults.push({ userId: user.user_id, email, success: result.success, error: result.error, }); // Small delay to avoid overwhelming the API await new Promise(resolve => setTimeout(resolve, 100)); } catch (error: any) { migrationResults.push({ userId: user.user_id, email, success: false, error: error.message, }); } setProgress(((i + 1) / users.length) * 100); setResults([...migrationResults]); } const successCount = migrationResults.filter(r => r.success).length; const failureCount = migrationResults.filter(r => !r.success).length; toast({ title: "Migration completed", description: `Successfully migrated ${successCount} users. ${failureCount} failures.`, }); } catch (error: any) { toast({ variant: "destructive", title: "Migration failed", description: error.message, }); } finally { setIsRunning(false); } }; const successCount = results.filter(r => r.success).length; const failureCount = results.filter(r => !r.success).length; return ( Novu User Migration Register existing users with Novu notification service This utility will register all existing users who don't have a Novu subscriber ID. The process is non-blocking and will continue even if individual registrations fail. {isRunning && totalUsers > 0 && (
Progress {Math.round(progress)}%

Processing {results.length} of {totalUsers} users

)} {results.length > 0 && (
{successCount} succeeded
{failureCount} failed
{results.map((result, idx) => (
{result.email} {result.success ? ( ) : (
{result.error}
)}
))}
)}
); }