feat: enhance Navbar with user profile and configuration links

- Updated Navbar component to include a link to the configuration page.
- Added a new Settings icon and link for user configuration.
- Improved user session handling and UI updates based on authentication state.

feat: implement OnboardingDialog for user setup

- Created OnboardingDialog component to guide users through initial setup.
- Added functionality to collect additional email addresses during onboarding.
- Integrated toast notifications for error handling during email addition.

feat: extend Supabase admin functions for user management

- Added functions to retrieve user IDs and full user information by email.
- Implemented error handling and logging for database operations.

feat: update Supabase schema with new user features

- Created new tables: user_profiles, additional_emails, and email_processing_usage.
- Enabled Row Level Security (RLS) on new tables with appropriate policies.
- Added triggers and functions for automatic user profile creation and email usage tracking.

feat: create public users table for simplified access

- Established a public.users table to mirror relevant auth.users data.
- Implemented triggers to automatically populate public.users upon user creation.
- Set up RLS policies to restrict access to user data.

chore: add configuration files for Supabase local development

- Included .gitignore and config.toml for local Supabase setup.
- Configured email testing server and other development settings.

feat: add configuration page for user settings

- Created configuration.astro page to manage user settings.
- Integrated AuthGuard to protect the configuration route.
This commit is contained in:
2025-06-07 04:37:03 -03:00
parent d37509338e
commit 0d2ab87519
17 changed files with 1584 additions and 101 deletions

View File

@@ -0,0 +1,400 @@
import React, { useEffect, useState } from "react";
import {
supabase,
type AdditionalEmail,
type UserProfile,
type EmailProcessingUsage,
} from "../lib/supabase";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Progress } from "@/components/ui/progress";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Separator } from "@/components/ui/separator";
import {
Settings,
Mail,
Plus,
Trash2,
Check,
X,
TrendingUp,
Infinity,
AlertCircle,
} from "lucide-react";
import { toast } from "../hooks/use-toast";
export function Configuration() {
const [profile, setProfile] = useState<UserProfile | null>(null);
const [additionalEmails, setAdditionalEmails] = useState<AdditionalEmail[]>(
[]
);
const [usage, setUsage] = useState<EmailProcessingUsage | null>(null);
const [loading, setLoading] = useState(true);
const [newEmail, setNewEmail] = useState("");
const [addingEmail, setAddingEmail] = useState(false);
useEffect(() => {
fetchUserData();
}, []);
const fetchUserData = async () => {
try {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
// Fetch user profile
const { data: profileData } = await supabase
.from("user_profiles")
.select("*")
.eq("user_id", user.id)
.single();
// Fetch additional emails
const { data: emailsData } = await supabase
.from("additional_emails")
.select("*")
.eq("user_id", user.id)
.order("created_at", { ascending: false });
// Fetch current month usage
const currentMonth = new Date().toISOString().slice(0, 7); // YYYY-MM
const { data: usageData } = await supabase
.from("email_processing_usage")
.select("*")
.eq("user_id", user.id)
.eq("month_year", currentMonth)
.single();
setProfile(profileData);
setAdditionalEmails(emailsData || []);
setUsage(usageData);
} catch (error) {
console.error("Error fetching user data:", error);
} finally {
setLoading(false);
}
};
const addAdditionalEmail = async () => {
if (!newEmail || !profile) return;
setAddingEmail(true);
try {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
const { data, error } = await supabase
.from("additional_emails")
.insert({
user_id: user.id,
email_address: newEmail.trim().toLowerCase(),
})
.select()
.single();
if (error) throw error;
setAdditionalEmails([data, ...additionalEmails]);
setNewEmail("");
toast({
title: "Email added successfully",
description: "Additional email has been added to your account.",
});
} catch (error: any) {
toast({
title: "Error adding email",
description: error.message,
variant: "destructive",
});
} finally {
setAddingEmail(false);
}
};
const removeAdditionalEmail = async (emailId: string) => {
try {
const { error } = await supabase
.from("additional_emails")
.delete()
.eq("id", emailId);
if (error) throw error;
setAdditionalEmails(
additionalEmails.filter((email) => email.id !== emailId)
);
toast({
title: "Email removed",
description: "Additional email has been removed from your account.",
});
} catch (error: any) {
toast({
title: "Error removing email",
description: error.message,
variant: "destructive",
});
}
};
const getUsagePercentage = () => {
if (!profile || !usage) return 0;
return Math.min(
(usage.emails_processed / profile.email_processing_limit) * 100,
100
);
};
const getRemainingEmails = () => {
if (!profile || !usage) return profile?.email_processing_limit || 1000;
return Math.max(profile.email_processing_limit - usage.emails_processed, 0);
};
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen bg-gray-50 dark:bg-background">
<div className="flex items-center gap-2 text-lg text-gray-900 dark:text-foreground">
<Settings className="h-5 w-5 animate-spin" />
Loading configuration...
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gray-50 dark:bg-background">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900 dark:text-foreground flex items-center gap-3">
<Settings className="h-8 w-8 text-primary" />
Configuration
</h1>
<p className="text-gray-600 dark:text-gray-300 mt-2">
Manage your account settings and email processing options
</p>
</div>
<div className="space-y-6">
{/* Email Processing Usage */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<TrendingUp className="h-5 w-5" />
Email Processing Usage
</CardTitle>
<CardDescription>
Track your monthly email processing usage and limits
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium">
Emails Processed This Month
</p>
<p className="text-2xl font-bold">
{usage?.emails_processed || 0} /{" "}
{profile?.email_processing_limit || 1000}
</p>
</div>
<div className="text-right">
<p className="text-sm text-muted-foreground">Remaining</p>
<p className="text-lg font-semibold text-green-600 dark:text-green-400">
{getRemainingEmails() ===
(profile?.email_processing_limit || 1000) ? (
<span className="flex items-center gap-1">
<Infinity className="h-4 w-4" />
Unlimited
</span>
) : (
getRemainingEmails()
)}
</p>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>Progress</span>
<span>{getUsagePercentage().toFixed(1)}%</span>
</div>
<Progress value={getUsagePercentage()} className="h-2" />
</div>
{getUsagePercentage() > 80 && (
<Alert>
<AlertCircle className="h-4 w-4" />
<AlertDescription>
You're approaching your monthly email processing limit.
Consider upgrading your plan if you need to process more
emails.
</AlertDescription>
</Alert>
)}
</CardContent>
</Card>
{/* Additional Emails */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Mail className="h-5 w-5" />
Additional Email Addresses
</CardTitle>
<CardDescription>
Add additional email addresses to process debt emails from
multiple accounts
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* Add new email */}
<div className="flex gap-2">
<div className="flex-1">
<Label htmlFor="newEmail" className="sr-only">
Additional Email
</Label>
<Input
id="newEmail"
type="email"
placeholder="additional@example.com"
value={newEmail}
onChange={(e) => setNewEmail(e.target.value)}
onKeyPress={(e) => {
if (e.key === "Enter") {
addAdditionalEmail();
}
}}
/>
</div>
<Button
onClick={addAdditionalEmail}
disabled={!newEmail || addingEmail}
className="shrink-0"
>
<Plus className="h-4 w-4 mr-2" />
Add Email
</Button>
</div>
<Separator />
{/* List of additional emails */}
<div className="space-y-3">
{additionalEmails.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
<Mail className="h-12 w-12 mx-auto mb-4 opacity-50" />
<p className="text-lg font-medium">No additional emails</p>
<p className="text-sm">
Add additional email addresses to expand your debt
processing capabilities.
</p>
</div>
) : (
additionalEmails.map((email) => (
<div
key={email.id}
className="flex items-center justify-between p-3 border rounded-lg"
>
<div className="flex items-center gap-3">
<Mail className="h-4 w-4 text-muted-foreground" />
<div>
<p className="font-medium">{email.email_address}</p>
<p className="text-sm text-muted-foreground">
Added{" "}
{new Date(email.created_at).toLocaleDateString()}
</p>
</div>
</div>
<div className="flex items-center gap-2">
<Badge
variant={email.verified ? "default" : "secondary"}
>
{email.verified ? (
<>
<Check className="h-3 w-3 mr-1" />
Verified
</>
) : (
<>
<X className="h-3 w-3 mr-1" />
Unverified
</>
)}
</Badge>
<Button
variant="ghost"
size="sm"
onClick={() => removeAdditionalEmail(email.id)}
className="text-destructive hover:text-destructive"
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</div>
))
)}
</div>
</CardContent>
</Card>
{/* Account Information */}
<Card>
<CardHeader>
<CardTitle>Account Information</CardTitle>
<CardDescription>
Your account details and settings
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<Label>Email Processing Limit</Label>
<p className="text-lg font-semibold">
{profile?.email_processing_limit || 1000} emails/month
</p>
</div>
<div>
<Label>Account Created</Label>
<p className="text-lg font-semibold">
{profile?.created_at
? new Date(profile.created_at).toLocaleDateString()
: "N/A"}
</p>
</div>
<div className="flex items-center gap-2">
<Label>Onboarding Status</Label>
<Badge
variant={
profile?.onboarding_completed ? "default" : "secondary"
}
>
{profile?.onboarding_completed ? "Completed" : "Pending"}
</Badge>
</div>
<div>
<Label>Additional Emails</Label>
<p className="text-lg font-semibold">
{additionalEmails.length} configured
</p>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
);
}

View File

@@ -1,8 +1,9 @@
import React, { useEffect, useState } from "react";
import { supabase, type Debt } from "../lib/supabase";
import { supabase, type Debt, type UserProfile } from "../lib/supabase";
import { Button } from "@/components/ui/button";
import { DebtCard } from "./DebtCard";
import { DebtTimeline } from "./DebtTimeline";
import { OnboardingDialog } from "./OnboardingDialog";
import {
Card,
CardContent,
@@ -22,11 +23,14 @@ import {
RefreshCw,
BarChart3,
LogOut,
Settings,
} from "lucide-react";
export function Dashboard() {
const [debts, setDebts] = useState<Debt[]>([]);
const [loading, setLoading] = useState(true);
const [userProfile, setUserProfile] = useState<UserProfile | null>(null);
const [showOnboarding, setShowOnboarding] = useState(false);
const [stats, setStats] = useState({
totalDebts: 0,
totalAmount: 0,
@@ -35,6 +39,7 @@ export function Dashboard() {
});
useEffect(() => {
fetchUserProfile();
fetchDebts();
setupRealtimeSubscription();
}, []);
@@ -43,11 +48,41 @@ export function Dashboard() {
calculateStats();
}, [debts]);
const fetchUserProfile = async () => {
try {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
const { data: profile } = await supabase
.from("user_profiles")
.select("*")
.eq("user_id", user.id)
.single();
setUserProfile(profile);
// Show onboarding if user hasn't completed it
if (profile && !profile.onboarding_completed) {
setShowOnboarding(true);
}
} catch (error) {
console.error("Error fetching user profile:", error);
}
};
const fetchDebts = async () => {
try {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
const { data, error } = await supabase
.from("debts")
.select("*")
.eq("user_id", user.id)
.order("created_at", { ascending: false });
if (error) throw error;
@@ -111,6 +146,12 @@ export function Dashboard() {
});
};
const handleOnboardingComplete = () => {
setShowOnboarding(false);
// Refresh user profile to reflect onboarding completion
fetchUserProfile();
};
const handleSignOut = async () => {
await supabase.auth.signOut();
window.location.href = "/";
@@ -152,13 +193,18 @@ export function Dashboard() {
<div className="mb-8 flex justify-between items-start">
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-foreground flex items-center gap-3">
<BarChart3 className="h-8 w-8 text-primary" />
InboxNegotiator Dashboard
Dashboard
</h1>
<p className="text-gray-600 dark:text-gray-300 mt-2">
AI-powered debt resolution platform with real-time updates
</p>
</div>
<Button asChild>
<a href="/configuration" className="flex items-center gap-2">
<Settings className="h-4 w-4" />
Configuration
</a>
</Button>
</div>
{/* Stats Cards */}
@@ -290,6 +336,12 @@ export function Dashboard() {
<p className="mt-1">Real-time updates powered by Supabase</p>
</div>
</div>
{/* Onboarding Dialog */}
<OnboardingDialog
open={showOnboarding}
onComplete={handleOnboardingComplete}
/>
</div>
);
}

View File

@@ -1,104 +1,118 @@
import React, { useEffect, useState } from 'react';
import { supabase } from '../lib/supabase';
import type { User } from '@supabase/supabase-js';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import { BarChart3, LogOut, User as UserIcon } from 'lucide-react';
import { ModeToggle } from './ModeToggle';
import React, { useEffect, useState } from "react";
import { supabase } from "../lib/supabase";
import type { User } from "@supabase/supabase-js";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { BarChart3, LogOut, User as UserIcon, Settings } from "lucide-react";
import { ModeToggle } from "./ModeToggle";
export function Navbar() {
const [user, setUser] = useState<User | null>(null);
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setUser(session?.user ?? null);
});
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setUser(session?.user ?? null);
});
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
setUser(session?.user ?? null);
}
);
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((event, session) => {
setUser(session?.user ?? null);
});
return () => subscription.unsubscribe();
}, []);
return () => subscription.unsubscribe();
}, []);
const handleSignOut = async () => {
await supabase.auth.signOut();
window.location.href = '/';
};
const handleSignOut = async () => {
await supabase.auth.signOut();
window.location.href = "/";
};
const getInitials = (email: string) => {
return email.substring(0, 2).toUpperCase();
};
const getInitials = (email: string) => {
return email.substring(0, 2).toUpperCase();
};
return (
<nav className="border-b bg-white dark:bg-background">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center gap-3">
<BarChart3 className="h-8 w-8 text-primary" />
<a href="/" className="text-xl font-bold text-gray-900 dark:text-foreground">
InboxNegotiator
</a>
</div>
return (
<nav className="border-b bg-white dark:bg-background">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center gap-3">
<BarChart3 className="h-8 w-8 text-primary" />
<a
href={user ? "/dashboard" : "/"}
className="text-xl font-bold text-gray-900 dark:text-foreground"
>
InboxNegotiator
</a>
</div>
<div className="flex items-center gap-4">
<ModeToggle />
{user ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
<Avatar className="h-8 w-8">
<AvatarFallback className="text-xs">
{getInitials(user.email || '')}
</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="end">
<div className="flex items-center justify-start gap-2 p-2">
<div className="flex flex-col space-y-1 leading-none">
<p className="font-medium text-sm">{user.user_metadata?.full_name || 'User'}</p>
<p className="w-[200px] truncate text-xs text-muted-foreground">
{user.email}
</p>
</div>
</div>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<a href="/dashboard" className="flex items-center">
<UserIcon className="mr-2 h-4 w-4" />
Dashboard
</a>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleSignOut}>
<LogOut className="mr-2 h-4 w-4" />
Sign out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
) : (
<div className="flex items-center gap-2">
<Button variant="ghost" asChild>
<a href="/login">Sign In</a>
</Button>
<Button asChild>
<a href="/signup">Get Started</a>
</Button>
</div>
)}
</div>
</div>
</div>
</nav>
);
}
<div className="flex items-center gap-4">
<ModeToggle />
{user ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="relative h-8 w-8 rounded-full"
>
<Avatar className="h-8 w-8">
<AvatarFallback className="text-xs">
{getInitials(user.email || "")}
</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="end">
<div className="flex items-center justify-start gap-2 p-2">
<div className="flex flex-col space-y-1 leading-none">
<p className="font-medium text-sm">
{user.user_metadata?.full_name || "User"}
</p>
<p className="w-[200px] truncate text-xs text-muted-foreground">
{user.email}
</p>
</div>
</div>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<a href="/dashboard" className="flex items-center">
<UserIcon className="mr-2 h-4 w-4" />
Dashboard
</a>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href="/configuration" className="flex items-center">
<Settings className="mr-2 h-4 w-4" />
Configuration
</a>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleSignOut}>
<LogOut className="mr-2 h-4 w-4" />
Sign out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
) : (
<div className="flex items-center gap-2">
<Button variant="ghost" asChild>
<a href="/login">Sign In</a>
</Button>
<Button asChild>
<a href="/signup">Get Started</a>
</Button>
</div>
)}
</div>
</div>
</div>
</nav>
);
}

View File

@@ -0,0 +1,235 @@
import React, { useState } from "react";
import { supabase } from "../lib/supabase";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Mail, Plus, CheckCircle, ArrowRight, UserCheck } from "lucide-react";
import { toast } from "../hooks/use-toast";
interface OnboardingDialogProps {
open: boolean;
onComplete: () => void;
}
export function OnboardingDialog({ open, onComplete }: OnboardingDialogProps) {
const [step, setStep] = useState<"welcome" | "email" | "complete">("welcome");
const [email, setEmail] = useState("");
const [loading, setLoading] = useState(false);
const [skipEmail, setSkipEmail] = useState(false);
const handleAddEmail = async () => {
if (!email && !skipEmail) return;
setLoading(true);
try {
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) return;
if (email && !skipEmail) {
const { error } = await supabase.from("additional_emails").insert({
user_id: user.id,
email_address: email.trim().toLowerCase(),
});
if (error) throw error;
}
// Mark onboarding as completed
const { error: profileError } = await supabase
.from("user_profiles")
.update({ onboarding_completed: true })
.eq("user_id", user.id);
if (profileError) throw profileError;
setStep("complete");
} catch (error: any) {
toast({
title: "Error",
description: error.message,
variant: "destructive",
});
} finally {
setLoading(false);
}
};
const handleComplete = () => {
onComplete();
};
const handleSkipEmail = () => {
setSkipEmail(true);
};
return (
<Dialog open={open} onOpenChange={() => {}}>
<DialogContent className="sm:max-w-md [&>button]:hidden">
{/* Hide close button */}
{step === "welcome" && (
<>
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<UserCheck className="h-6 w-6 text-green-500" />
Welcome to InboxNegotiator!
</DialogTitle>
</DialogHeader>
<DialogDescription>
Your account has been created successfully. Let's get you set up
to start processing debt emails with AI assistance.
</DialogDescription>
<div className="space-y-4">
<Alert>
<Mail className="h-4 w-4" />
<AlertDescription>
InboxNegotiator helps you automatically negotiate debt
settlements by processing emails sent to your configured email
addresses.
</AlertDescription>
</Alert>
{/* <div className="space-y-2">
<h4 className="font-medium">What you can do:</h4>
<ul className="text-sm space-y-1 text-muted-foreground">
<li>• Process up to 1,000 debt emails per month</li>
<li>• AI-powered debt amount and vendor extraction</li>
<li>• Automated negotiation responses</li>
<li>• Real-time tracking and analytics</li>
</ul>
</div> */}
<div className="flex justify-end">
<Button onClick={() => setStep("email")}>
Get Started
<ArrowRight className="h-4 w-4 ml-2" />
</Button>
</div>
</div>
</>
)}
{step === "email" && (
<>
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Plus className="h-6 w-6 text-primary" />
Add Additional Email (Optional)
</DialogTitle>
</DialogHeader>
<DialogDescription>
Would you like to add an additional email address to process debt
emails from multiple accounts?
</DialogDescription>
<DialogDescription>
You can attach here the Postmark inbound email address for the
additional email.{" "}
<a
className="text-blue-600 dark:text-blue-500 hover:underline"
href="https://postmarkapp.com/blog/an-introduction-to-inbound-email-parsing-what-it-is-and-how-you-can-do-it#how-to-use-postmark-for-email-parsing"
target="_blank"
rel="noopener noreferrer"
>
Postmark Inbound Email Parsing Guide
</a>
</DialogDescription>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="additional-email">
Additional Email Address
</Label>
<Input
id="additional-email"
type="email"
placeholder="additional@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
onKeyPress={(e) => {
if (e.key === "Enter" && email) {
handleAddEmail();
}
}}
/>
<p className="text-xs text-muted-foreground">
You can always add more email addresses later in the
configuration page.
</p>
</div>
<div className="flex gap-2 justify-end">
<Button
variant="outline"
onClick={handleSkipEmail}
disabled={loading}
>
Skip for now
</Button>
<Button
onClick={handleAddEmail}
disabled={!email || loading}
className="min-w-[100px]"
>
{loading ? "Adding..." : "Add Email"}
</Button>
</div>
</div>
</>
)}
{step === "complete" && (
<>
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<CheckCircle className="h-6 w-6 text-green-500" />
Setup Complete!
</DialogTitle>
<DialogDescription>
Your account is now ready to process debt emails with AI
assistance.
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<Alert>
<Mail className="h-4 w-4" />
<AlertDescription>
Start by forwarding debt collection emails to your configured
addresses. Our AI will automatically extract debt information
and begin the negotiation process.
</AlertDescription>
</Alert>
<div className="space-y-2">
<h4 className="font-medium">Next steps:</h4>
<ul className="text-sm space-y-1 text-muted-foreground">
<li> Forward debt emails to your monitored addresses</li>
<li> Monitor negotiations in your dashboard</li>
<li> Review AI-generated settlement offers</li>
<li> Track your savings and progress</li>
</ul>
</div>
<div className="flex justify-end">
<Button onClick={handleComplete}>
Go to Dashboard
<ArrowRight className="h-4 w-4 ml-2" />
</Button>
</div>
</div>
</>
)}
</DialogContent>
</Dialog>
);
}