Added dark modes

This commit is contained in:
2025-06-07 03:01:36 -03:00
parent 239c9cf313
commit d37509338e
6 changed files with 856 additions and 639 deletions

View File

@@ -1,12 +1,18 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from "react";
import { supabase, type Debt } from '../lib/supabase'; import { supabase, type Debt } from "../lib/supabase";
import { Button } from '@/components/ui/button'; import { Button } from "@/components/ui/button";
import { DebtCard } from './DebtCard'; import { DebtCard } from "./DebtCard";
import { DebtTimeline } from './DebtTimeline'; import { DebtTimeline } from "./DebtTimeline";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import {
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; Card,
import { Badge } from '@/components/ui/badge'; CardContent,
import { Separator } from '@/components/ui/separator'; CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator";
import { import {
DollarSign, DollarSign,
TrendingUp, TrendingUp,
@@ -15,8 +21,8 @@ import {
AlertTriangle, AlertTriangle,
RefreshCw, RefreshCw,
BarChart3, BarChart3,
LogOut LogOut,
} from 'lucide-react'; } from "lucide-react";
export function Dashboard() { export function Dashboard() {
const [debts, setDebts] = useState<Debt[]>([]); const [debts, setDebts] = useState<Debt[]>([]);
@@ -25,7 +31,7 @@ export function Dashboard() {
totalDebts: 0, totalDebts: 0,
totalAmount: 0, totalAmount: 0,
projectedSavings: 0, projectedSavings: 0,
settledCount: 0 settledCount: 0,
}); });
useEffect(() => { useEffect(() => {
@@ -40,14 +46,14 @@ export function Dashboard() {
const fetchDebts = async () => { const fetchDebts = async () => {
try { try {
const { data, error } = await supabase const { data, error } = await supabase
.from('debts') .from("debts")
.select('*') .select("*")
.order('created_at', { ascending: false }); .order("created_at", { ascending: false });
if (error) throw error; if (error) throw error;
setDebts(data || []); setDebts(data || []);
} catch (error) { } catch (error) {
console.error('Error fetching debts:', error); console.error("Error fetching debts:", error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
@@ -55,25 +61,27 @@ export function Dashboard() {
const setupRealtimeSubscription = () => { const setupRealtimeSubscription = () => {
const subscription = supabase const subscription = supabase
.channel('debts_changes') .channel("debts_changes")
.on( .on(
'postgres_changes', "postgres_changes",
{ {
event: '*', event: "*",
schema: 'public', schema: "public",
table: 'debts' table: "debts",
}, },
(payload) => { (payload) => {
if (payload.eventType === 'INSERT') { if (payload.eventType === "INSERT") {
setDebts(prev => [payload.new as Debt, ...prev]); setDebts((prev) => [payload.new as Debt, ...prev]);
} else if (payload.eventType === 'UPDATE') { } else if (payload.eventType === "UPDATE") {
setDebts(prev => setDebts((prev) =>
prev.map(debt => prev.map((debt) =>
debt.id === payload.new.id ? payload.new as Debt : debt debt.id === payload.new.id ? (payload.new as Debt) : debt
) )
); );
} else if (payload.eventType === 'DELETE') { } else if (payload.eventType === "DELETE") {
setDebts(prev => prev.filter(debt => debt.id !== payload.old.id)); setDebts((prev) =>
prev.filter((debt) => debt.id !== payload.old.id)
);
} }
} }
) )
@@ -87,40 +95,49 @@ export function Dashboard() {
const calculateStats = () => { const calculateStats = () => {
const totalDebts = debts.length; const totalDebts = debts.length;
const totalAmount = debts.reduce((sum, debt) => sum + debt.amount, 0); const totalAmount = debts.reduce((sum, debt) => sum + debt.amount, 0);
const projectedSavings = debts.reduce((sum, debt) => sum + debt.projected_savings, 0); const projectedSavings = debts.reduce(
const settledCount = debts.filter(debt => debt.status === 'settled').length; (sum, debt) => sum + debt.projected_savings,
0
);
const settledCount = debts.filter(
(debt) => debt.status === "settled"
).length;
setStats({ setStats({
totalDebts, totalDebts,
totalAmount, totalAmount,
projectedSavings, projectedSavings,
settledCount settledCount,
}); });
}; };
const handleSignOut = async () => { const handleSignOut = async () => {
await supabase.auth.signOut(); await supabase.auth.signOut();
window.location.href = '/'; window.location.href = "/";
}; };
const formatCurrency = (amount: number) => { const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', { return new Intl.NumberFormat("en-US", {
style: 'currency', style: "currency",
currency: 'USD' currency: "USD",
}).format(amount); }).format(amount);
}; };
const groupedDebts = { const groupedDebts = {
all: debts, all: debts,
active: debts.filter(debt => ['received', 'negotiating'].includes(debt.status)), active: debts.filter((debt) =>
settled: debts.filter(debt => debt.status === 'settled'), ["received", "negotiating"].includes(debt.status)
failed: debts.filter(debt => ['failed', 'opted_out'].includes(debt.status)) ),
settled: debts.filter((debt) => debt.status === "settled"),
failed: debts.filter((debt) =>
["failed", "opted_out"].includes(debt.status)
),
}; };
if (loading) { if (loading) {
return ( return (
<div className="flex items-center justify-center min-h-screen"> <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"> <div className="flex items-center gap-2 text-lg text-gray-900 dark:text-foreground">
<RefreshCw className="h-5 w-5 animate-spin" /> <RefreshCw className="h-5 w-5 animate-spin" />
Loading dashboard... Loading dashboard...
</div> </div>
@@ -129,16 +146,16 @@ export function Dashboard() {
} }
return ( return (
<div className="min-h-screen bg-gray-50"> <div className="min-h-screen bg-gray-50 dark:bg-background">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Header */} {/* Header */}
<div className="mb-8 flex justify-between items-start"> <div className="mb-8 flex justify-between items-start">
<div> <div>
<h1 className="text-3xl font-bold text-gray-900 flex items-center gap-3"> <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" /> <BarChart3 className="h-8 w-8 text-primary" />
InboxNegotiator Dashboard InboxNegotiator Dashboard
</h1> </h1>
<p className="text-gray-600 mt-2"> <p className="text-gray-600 dark:text-gray-300 mt-2">
AI-powered debt resolution platform with real-time updates AI-powered debt resolution platform with real-time updates
</p> </p>
</div> </div>
@@ -153,43 +170,45 @@ export function Dashboard() {
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{stats.totalDebts}</div> <div className="text-2xl font-bold">{stats.totalDebts}</div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">Emails processed</p>
Emails processed
</p>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Amount</CardTitle> <CardTitle className="text-sm font-medium">
Total Amount
</CardTitle>
<DollarSign className="h-4 w-4 text-muted-foreground" /> <DollarSign className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">{formatCurrency(stats.totalAmount)}</div> <div className="text-2xl font-bold">
<p className="text-xs text-muted-foreground"> {formatCurrency(stats.totalAmount)}
Across all debts </div>
</p> <p className="text-xs text-muted-foreground">Across all debts</p>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Projected Savings</CardTitle> <CardTitle className="text-sm font-medium">
Projected Savings
</CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" /> <TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold text-green-600"> <div className="text-2xl font-bold text-green-600 dark:text-green-400">
{formatCurrency(stats.projectedSavings)} {formatCurrency(stats.projectedSavings)}
</div> </div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">From negotiations</p>
From negotiations
</p>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Settled Cases</CardTitle> <CardTitle className="text-sm font-medium">
Settled Cases
</CardTitle>
<CheckCircle className="h-4 w-4 text-muted-foreground" /> <CheckCircle className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -235,13 +254,14 @@ export function Dashboard() {
{debtList.length === 0 ? ( {debtList.length === 0 ? (
<Card> <Card>
<CardContent className="flex flex-col items-center justify-center py-12"> <CardContent className="flex flex-col items-center justify-center py-12">
<AlertTriangle className="h-12 w-12 text-gray-400 mb-4" /> <AlertTriangle className="h-12 w-12 text-gray-400 dark:text-gray-500 mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">No debts found</h3> <h3 className="text-lg font-medium text-gray-900 dark:text-foreground mb-2">
<p className="text-gray-600 text-center max-w-md"> No debts found
{key === 'all' </h3>
? 'Forward your first debt email to get started with automated negotiations.' <p className="text-gray-600 dark:text-gray-300 text-center max-w-md">
: `No debts with ${key} status found.` {key === "all"
} ? "Forward your first debt email to get started with automated negotiations."
: `No debts with ${key} status found.`}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
@@ -250,7 +270,7 @@ export function Dashboard() {
{debtList.map((debt) => ( {debtList.map((debt) => (
<div key={debt.id} className="space-y-4"> <div key={debt.id} className="space-y-4">
<DebtCard debt={debt} /> <DebtCard debt={debt} />
<Card className="bg-gray-50"> <Card className="bg-gray-50 dark:bg-gray-800/50">
<CardContent className="p-4"> <CardContent className="p-4">
<DebtTimeline debt={debt} /> <DebtTimeline debt={debt} />
</CardContent> </CardContent>
@@ -265,7 +285,7 @@ export function Dashboard() {
{/* Footer */} {/* Footer */}
<Separator className="my-8" /> <Separator className="my-8" />
<div className="text-center text-sm text-gray-600"> <div className="text-center text-sm text-gray-600 dark:text-gray-300">
<p>InboxNegotiator - FDCPA-compliant debt resolution platform</p> <p>InboxNegotiator - FDCPA-compliant debt resolution platform</p>
<p className="mt-1">Real-time updates powered by Supabase</p> <p className="mt-1">Real-time updates powered by Supabase</p>
</div> </div>

View File

@@ -1,46 +1,64 @@
import React from 'react'; import React from "react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import {
import { Badge } from '@/components/ui/badge'; Card,
import { Button } from '@/components/ui/button'; CardContent,
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; CardDescription,
import { Calendar, DollarSign, Mail, FileText, TrendingUp } from 'lucide-react'; CardHeader,
import type { Debt } from '../lib/supabase'; CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Calendar, DollarSign, Mail, FileText, TrendingUp } from "lucide-react";
import type { Debt } from "../lib/supabase";
interface DebtCardProps { interface DebtCardProps {
debt: Debt; debt: Debt;
} }
const statusColors = { const statusColors = {
received: 'bg-blue-100 text-blue-800 border-blue-200', received:
negotiating: 'bg-yellow-100 text-yellow-800 border-yellow-200', "bg-blue-100 text-blue-800 border-blue-200 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800",
settled: 'bg-green-100 text-green-800 border-green-200', negotiating:
failed: 'bg-red-100 text-red-800 border-red-200', "bg-yellow-100 text-yellow-800 border-yellow-200 dark:bg-yellow-900/20 dark:text-yellow-300 dark:border-yellow-800",
opted_out: 'bg-gray-100 text-gray-800 border-gray-200' settled:
"bg-green-100 text-green-800 border-green-200 dark:bg-green-900/20 dark:text-green-300 dark:border-green-800",
failed:
"bg-red-100 text-red-800 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800",
opted_out:
"bg-gray-100 text-gray-800 border-gray-200 dark:bg-gray-800/20 dark:text-gray-300 dark:border-gray-700",
}; };
const statusLabels = { const statusLabels = {
received: 'Received', received: "Received",
negotiating: 'Negotiating', negotiating: "Negotiating",
settled: 'Settled', settled: "Settled",
failed: 'Failed', failed: "Failed",
opted_out: 'Opted Out' opted_out: "Opted Out",
}; };
export function DebtCard({ debt }: DebtCardProps) { export function DebtCard({ debt }: DebtCardProps) {
const formatCurrency = (amount: number) => { const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', { return new Intl.NumberFormat("en-US", {
style: 'currency', style: "currency",
currency: 'USD' currency: "USD",
}).format(amount); }).format(amount);
}; };
const formatDate = (dateString: string) => { const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('en-US', { return new Date(dateString).toLocaleDateString("en-US", {
year: 'numeric', year: "numeric",
month: 'short', month: "short",
day: 'numeric', day: "numeric",
hour: '2-digit', hour: "2-digit",
minute: '2-digit' minute: "2-digit",
}); });
}; };
@@ -48,7 +66,7 @@ export function DebtCard({ debt }: DebtCardProps) {
<Card className="w-full hover:shadow-lg transition-all duration-300 border-l-4 border-l-primary"> <Card className="w-full hover:shadow-lg transition-all duration-300 border-l-4 border-l-primary">
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<CardTitle className="text-lg font-semibold text-gray-900"> <CardTitle className="text-lg font-semibold text-gray-900 dark:text-foreground">
{debt.vendor} {debt.vendor}
</CardTitle> </CardTitle>
<Badge <Badge
@@ -58,7 +76,7 @@ export function DebtCard({ debt }: DebtCardProps) {
{statusLabels[debt.status]} {statusLabels[debt.status]}
</Badge> </Badge>
</div> </div>
<CardDescription className="flex items-center gap-2 text-sm text-gray-600"> <CardDescription className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300">
<Calendar className="h-4 w-4" /> <Calendar className="h-4 w-4" />
{formatDate(debt.created_at)} {formatDate(debt.created_at)}
</CardDescription> </CardDescription>
@@ -67,14 +85,14 @@ export function DebtCard({ debt }: DebtCardProps) {
<CardContent className="space-y-4"> <CardContent className="space-y-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<DollarSign className="h-5 w-5 text-gray-500" /> <DollarSign className="h-5 w-5 text-gray-500 dark:text-gray-400" />
<span className="text-2xl font-bold text-gray-900"> <span className="text-2xl font-bold text-gray-900 dark:text-foreground">
{formatCurrency(debt.amount)} {formatCurrency(debt.amount)}
</span> </span>
</div> </div>
{debt.projected_savings > 0 && ( {debt.projected_savings > 0 && (
<div className="flex items-center gap-1 text-green-600"> <div className="flex items-center gap-1 text-green-600 dark:text-green-400">
<TrendingUp className="h-4 w-4" /> <TrendingUp className="h-4 w-4" />
<span className="text-sm font-medium"> <span className="text-sm font-medium">
Save {formatCurrency(debt.projected_savings)} Save {formatCurrency(debt.projected_savings)}
@@ -99,8 +117,8 @@ export function DebtCard({ debt }: DebtCardProps) {
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
<div className="mt-4"> <div className="mt-4">
<pre className="whitespace-pre-wrap text-sm bg-gray-50 p-4 rounded-lg border"> <pre className="whitespace-pre-wrap text-sm bg-gray-50 dark:bg-gray-800 p-4 rounded-lg border dark:border-gray-700">
{debt.raw_email || 'No email content available'} {debt.raw_email || "No email content available"}
</pre> </pre>
</div> </div>
</DialogContent> </DialogContent>
@@ -122,7 +140,7 @@ export function DebtCard({ debt }: DebtCardProps) {
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
<div className="mt-4"> <div className="mt-4">
<pre className="whitespace-pre-wrap text-sm bg-gray-50 p-4 rounded-lg border"> <pre className="whitespace-pre-wrap text-sm bg-gray-50 dark:bg-gray-800 p-4 rounded-lg border dark:border-gray-700">
{debt.negotiated_plan} {debt.negotiated_plan}
</pre> </pre>
</div> </div>

View File

@@ -1,15 +1,21 @@
import React from 'react'; import React from "react";
import { CheckCircle, Clock, AlertCircle, XCircle, StopCircle } from 'lucide-react'; import {
import type { Debt } from '../lib/supabase'; CheckCircle,
Clock,
AlertCircle,
XCircle,
StopCircle,
} from "lucide-react";
import type { Debt } from "../lib/supabase";
interface DebtTimelineProps { interface DebtTimelineProps {
debt: Debt; debt: Debt;
} }
const timelineSteps = [ const timelineSteps = [
{ key: 'received', label: 'Email Received', icon: CheckCircle }, { key: "received", label: "Email Received", icon: CheckCircle },
{ key: 'negotiating', label: 'Negotiating', icon: Clock }, { key: "negotiating", label: "Negotiating", icon: Clock },
{ key: 'settled', label: 'Settled', icon: CheckCircle }, { key: "settled", label: "Settled", icon: CheckCircle },
]; ];
const statusIcons = { const statusIcons = {
@@ -17,19 +23,21 @@ const statusIcons = {
negotiating: Clock, negotiating: Clock,
settled: CheckCircle, settled: CheckCircle,
failed: XCircle, failed: XCircle,
opted_out: StopCircle opted_out: StopCircle,
}; };
const statusColors = { const statusColors = {
received: 'text-blue-600', received: "text-blue-600 dark:text-blue-400",
negotiating: 'text-yellow-600', negotiating: "text-yellow-600 dark:text-yellow-400",
settled: 'text-green-600', settled: "text-green-600 dark:text-green-400",
failed: 'text-red-600', failed: "text-red-600 dark:text-red-400",
opted_out: 'text-gray-600' opted_out: "text-gray-600 dark:text-gray-400",
}; };
export function DebtTimeline({ debt }: DebtTimelineProps) { export function DebtTimeline({ debt }: DebtTimelineProps) {
const currentStepIndex = timelineSteps.findIndex(step => step.key === debt.status); const currentStepIndex = timelineSteps.findIndex(
(step) => step.key === debt.status
);
return ( return (
<div className="space-y-4"> <div className="space-y-4">
@@ -43,36 +51,47 @@ export function DebtTimeline({ debt }: DebtTimelineProps) {
return ( return (
<div key={step.key} className="flex items-center gap-3"> <div key={step.key} className="flex items-center gap-3">
<div className={` <div
className={`
flex items-center justify-center w-8 h-8 rounded-full border-2 flex items-center justify-center w-8 h-8 rounded-full border-2
${isCompleted ${
? 'bg-primary border-primary text-white' isCompleted
: 'border-gray-300 text-gray-300' ? "bg-primary border-primary text-white"
: "border-gray-300 dark:border-gray-600 text-gray-300 dark:text-gray-600"
} }
${isActive ? 'ring-2 ring-primary/20' : ''} ${isActive ? "ring-2 ring-primary/20" : ""}
`}> `}
>
<Icon className="h-4 w-4" /> <Icon className="h-4 w-4" />
</div> </div>
<div className="flex-1"> <div className="flex-1">
<div className={` <div
className={`
font-medium font-medium
${isCompleted ? 'text-gray-900' : 'text-gray-400'} ${
`}> isCompleted
? "text-gray-900 dark:text-foreground"
: "text-gray-400 dark:text-gray-500"
}
`}
>
{step.label} {step.label}
</div> </div>
{isActive && ( {isActive && (
<div className="text-sm text-gray-600 mt-1"> <div className="text-sm text-gray-600 dark:text-gray-300 mt-1">
{debt.status === 'received' && 'Processing email and generating response...'} {debt.status === "received" &&
{debt.status === 'negotiating' && 'Response generated, waiting for creditor reply'} "Processing email and generating response..."}
{debt.status === 'settled' && 'Payment plan agreed upon'} {debt.status === "negotiating" &&
"Response generated, waiting for creditor reply"}
{debt.status === "settled" && "Payment plan agreed upon"}
</div> </div>
)} )}
</div> </div>
{isActive && ( {isActive && (
<div className="text-sm text-gray-500"> <div className="text-sm text-gray-500 dark:text-gray-400">
{new Date(debt.updated_at).toLocaleDateString()} {new Date(debt.updated_at).toLocaleDateString()}
</div> </div>
)} )}
@@ -81,28 +100,35 @@ export function DebtTimeline({ debt }: DebtTimelineProps) {
})} })}
{/* Special cases for failed and opted_out */} {/* Special cases for failed and opted_out */}
{(debt.status === 'failed' || debt.status === 'opted_out') && ( {(debt.status === "failed" || debt.status === "opted_out") && (
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className={` <div
className={`
flex items-center justify-center w-8 h-8 rounded-full border-2 flex items-center justify-center w-8 h-8 rounded-full border-2
${debt.status === 'failed' ? 'border-red-500 text-red-500' : 'border-gray-500 text-gray-500'} ${
`}> debt.status === "failed"
{React.createElement(statusIcons[debt.status], { className: 'h-4 w-4' })} ? "border-red-500 text-red-500 dark:border-red-400 dark:text-red-400"
: "border-gray-500 text-gray-500 dark:border-gray-400 dark:text-gray-400"
}
`}
>
{React.createElement(statusIcons[debt.status], {
className: "h-4 w-4",
})}
</div> </div>
<div className="flex-1"> <div className="flex-1">
<div className={`font-medium ${statusColors[debt.status]}`}> <div className={`font-medium ${statusColors[debt.status]}`}>
{debt.status === 'failed' ? 'Negotiation Failed' : 'Opted Out'} {debt.status === "failed" ? "Negotiation Failed" : "Opted Out"}
</div> </div>
<div className="text-sm text-gray-600 mt-1"> <div className="text-sm text-gray-600 dark:text-gray-300 mt-1">
{debt.status === 'failed' {debt.status === "failed"
? 'Creditor declined the negotiation proposal' ? "Creditor declined the negotiation proposal"
: 'User requested to stop communication' : "User requested to stop communication"}
}
</div> </div>
</div> </div>
<div className="text-sm text-gray-500"> <div className="text-sm text-gray-500 dark:text-gray-400">
{new Date(debt.updated_at).toLocaleDateString()} {new Date(debt.updated_at).toLocaleDateString()}
</div> </div>
</div> </div>

View File

@@ -1,32 +1,47 @@
--- ---
import '@/styles/globals.css' import "@/styles/globals.css";
import Layout from '../layouts/Layout.astro'; import Layout from "../layouts/Layout.astro";
import { Navbar } from '../components/Navbar'; import { Navbar } from "../components/Navbar";
--- ---
<Layout title="InboxNegotiator - AI-Powered Debt Resolution"> <Layout title="InboxNegotiator - AI-Powered Debt Resolution">
<Navbar client:load /> <Navbar client:load />
<main class="min-h-screen bg-gradient-to-br from-blue-50 via-white to-purple-50"> <main
class="min-h-screen bg-gradient-to-br from-blue-50 via-white to-purple-50 dark:from-gray-900 dark:via-background dark:to-gray-800"
>
<!-- Hero Section --> <!-- Hero Section -->
<section class="relative overflow-hidden"> <section class="relative overflow-hidden">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-20 pb-16"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-20 pb-16">
<div class="text-center"> <div class="text-center">
<h1 class="text-4xl md:text-6xl font-bold text-gray-900 mb-6"> <h1
class="text-4xl md:text-6xl font-bold text-gray-900 dark:text-foreground mb-6"
>
AI-Powered AI-Powered
<span class="text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-purple-600"> <span
class="text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-purple-600 dark:from-blue-400 dark:to-purple-400"
>
Debt Resolution Debt Resolution
</span> </span>
</h1> </h1>
<p class="text-xl text-gray-600 mb-8 max-w-3xl mx-auto"> <p
Forward your debt emails and let our AI negotiate FDCPA-compliant payment plans automatically. class="text-xl text-gray-600 dark:text-gray-300 mb-8 max-w-3xl mx-auto"
Save time, reduce stress, and potentially save thousands on your debts. >
Forward your debt emails and let our AI negotiate FDCPA-compliant
payment plans automatically. Save time, reduce stress, and
potentially save thousands on your debts.
</p> </p>
<div class="flex flex-col sm:flex-row gap-4 justify-center"> <div class="flex flex-col sm:flex-row gap-4 justify-center">
<a href="/signup" class="inline-flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 transition-colors"> <a
href="/signup"
class="inline-flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 transition-colors"
>
Get Started Free Get Started Free
</a> </a>
<a href="#how-it-works" class="inline-flex items-center justify-center px-8 py-3 border border-gray-300 text-base font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 transition-colors"> <a
href="#how-it-works"
class="inline-flex items-center justify-center px-8 py-3 border border-gray-300 dark:border-gray-600 text-base font-medium rounded-md text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
Learn More Learn More
</a> </a>
</div> </div>
@@ -35,84 +50,192 @@ import { Navbar } from '../components/Navbar';
</section> </section>
<!-- Features Section --> <!-- Features Section -->
<section id="how-it-works" class="py-16 bg-white"> <section id="how-it-works" class="py-16 bg-white dark:bg-background">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center mb-16"> <div class="text-center mb-16">
<h2 class="text-3xl font-bold text-gray-900 mb-4">How It Works</h2> <h2
<p class="text-lg text-gray-600">Simple, automated, and compliant debt resolution</p> class="text-3xl font-bold text-gray-900 dark:text-foreground mb-4"
>
How It Works
</h2>
<p class="text-lg text-gray-600 dark:text-gray-300">
Simple, automated, and compliant debt resolution
</p>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="text-center"> <div class="text-center">
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div
<svg class="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> class="w-16 h-16 bg-blue-100 dark:bg-blue-900 rounded-full flex items-center justify-center mx-auto mb-4"
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path> >
<svg
class="w-8 h-8 text-blue-600 dark:text-blue-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
></path>
</svg> </svg>
</div> </div>
<h3 class="text-xl font-semibold text-gray-900 mb-2">Forward Emails</h3> <h3
<p class="text-gray-600">Simply forward your debt collection emails to our secure processing address.</p> class="text-xl font-semibold text-gray-900 dark:text-foreground mb-2"
>
Forward Emails
</h3>
<p class="text-gray-600 dark:text-gray-300">
Simply forward your debt collection emails to our secure
processing address.
</p>
</div> </div>
<div class="text-center"> <div class="text-center">
<div class="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div
<svg class="w-8 h-8 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> class="w-16 h-16 bg-purple-100 dark:bg-purple-900 rounded-full flex items-center justify-center mx-auto mb-4"
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path> >
<svg
class="w-8 h-8 text-purple-600 dark:text-purple-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
></path>
</svg> </svg>
</div> </div>
<h3 class="text-xl font-semibold text-gray-900 mb-2">AI Analysis</h3> <h3
<p class="text-gray-600">Our AI analyzes the debt and generates FDCPA-compliant negotiation strategies.</p> class="text-xl font-semibold text-gray-900 dark:text-foreground mb-2"
>
AI Analysis
</h3>
<p class="text-gray-600 dark:text-gray-300">
Our AI analyzes the debt and generates FDCPA-compliant negotiation
strategies.
</p>
</div> </div>
<div class="text-center"> <div class="text-center">
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div
<svg class="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> class="w-16 h-16 bg-green-100 dark:bg-green-900 rounded-full flex items-center justify-center mx-auto mb-4"
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path> >
<svg
class="w-8 h-8 text-green-600 dark:text-green-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg> </svg>
</div> </div>
<h3 class="text-xl font-semibold text-gray-900 mb-2">Track Progress</h3> <h3
<p class="text-gray-600">Monitor negotiations in real-time and track your potential savings.</p> class="text-xl font-semibold text-gray-900 dark:text-foreground mb-2"
>
Track Progress
</h3>
<p class="text-gray-600 dark:text-gray-300">
Monitor negotiations in real-time and track your potential
savings.
</p>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<!-- Benefits Section --> <!-- Benefits Section -->
<section class="py-16 bg-gray-50"> <section class="py-16 bg-gray-50 dark:bg-gray-900">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center mb-16"> <div class="text-center mb-16">
<h2 class="text-3xl font-bold text-gray-900 mb-4">Why Choose InboxNegotiator?</h2> <h2
class="text-3xl font-bold text-gray-900 dark:text-foreground mb-4"
>
Why Choose InboxNegotiator?
</h2>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
<div class="bg-white p-6 rounded-lg shadow-sm"> <div
<h3 class="text-lg font-semibold text-gray-900 mb-2">FDCPA Compliant</h3> class="bg-white dark:bg-card p-6 rounded-lg shadow-sm border dark:border-border"
<p class="text-gray-600">All responses follow Fair Debt Collection Practices Act guidelines.</p> >
<h3
class="text-lg font-semibold text-gray-900 dark:text-foreground mb-2"
>
FDCPA Compliant
</h3>
<p class="text-gray-600 dark:text-gray-300">
All responses follow Fair Debt Collection Practices Act
guidelines.
</p>
</div> </div>
<div class="bg-white p-6 rounded-lg shadow-sm"> <div
<h3 class="text-lg font-semibold text-gray-900 mb-2">Save Money</h3> class="bg-white dark:bg-card p-6 rounded-lg shadow-sm border dark:border-border"
<p class="text-gray-600">Potentially reduce your debt by up to 40% through strategic negotiations.</p> >
<h3
class="text-lg font-semibold text-gray-900 dark:text-foreground mb-2"
>
Save Money
</h3>
<p class="text-gray-600 dark:text-gray-300">
Potentially reduce your debt by up to 40% through strategic
negotiations.
</p>
</div> </div>
<div class="bg-white p-6 rounded-lg shadow-sm"> <div
<h3 class="text-lg font-semibold text-gray-900 mb-2">Real-time Updates</h3> class="bg-white dark:bg-card p-6 rounded-lg shadow-sm border dark:border-border"
<p class="text-gray-600">Track your negotiations with live dashboard updates.</p> >
<h3
class="text-lg font-semibold text-gray-900 dark:text-foreground mb-2"
>
Real-time Updates
</h3>
<p class="text-gray-600 dark:text-gray-300">
Track your negotiations with live dashboard updates.
</p>
</div> </div>
<div class="bg-white p-6 rounded-lg shadow-sm"> <div
<h3 class="text-lg font-semibold text-gray-900 mb-2">Secure & Private</h3> class="bg-white dark:bg-card p-6 rounded-lg shadow-sm border dark:border-border"
<p class="text-gray-600">Your financial information is encrypted and protected.</p> >
<h3
class="text-lg font-semibold text-gray-900 dark:text-foreground mb-2"
>
Secure & Private
</h3>
<p class="text-gray-600 dark:text-gray-300">
Your financial information is encrypted and protected.
</p>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<!-- CTA Section --> <!-- CTA Section -->
<section class="py-16 bg-blue-600"> <section class="py-16 bg-blue-600 dark:bg-blue-700">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 class="text-3xl font-bold text-white mb-4">Ready to Take Control of Your Debt?</h2> <h2 class="text-3xl font-bold text-white mb-4">
<p class="text-xl text-blue-100 mb-8">Join thousands who have successfully negotiated their debts with AI assistance.</p> Ready to Take Control of Your Debt?
<a href="/signup" class="inline-flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-blue-600 bg-white hover:bg-gray-50 transition-colors"> </h2>
<p class="text-xl text-blue-100 dark:text-blue-200 mb-8">
Join thousands who have successfully negotiated their debts with AI
assistance.
</p>
<a
href="/signup"
class="inline-flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-blue-600 bg-white hover:bg-gray-50 dark:text-blue-700 dark:bg-gray-100 dark:hover:bg-gray-200 transition-colors"
>
Start Your Free Account Start Your Free Account
</a> </a>
</div> </div>
@@ -120,17 +243,31 @@ import { Navbar } from '../components/Navbar';
</main> </main>
<!-- Footer --> <!-- Footer -->
<footer class="bg-gray-900 text-white py-12"> <footer class="bg-gray-900 dark:bg-gray-950 text-white py-12">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center"> <div class="text-center">
<div class="flex items-center justify-center gap-3 mb-4"> <div class="flex items-center justify-center gap-3 mb-4">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path> class="w-8 h-8"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
></path>
</svg> </svg>
<span class="text-xl font-bold">InboxNegotiator</span> <span class="text-xl font-bold">InboxNegotiator</span>
</div> </div>
<p class="text-gray-400 mb-4">AI-powered debt resolution platform</p> <p class="text-gray-400 dark:text-gray-500 mb-4">
<p class="text-sm text-gray-500">© 2025 InboxNegotiator. All rights reserved.</p> AI-powered debt resolution platform
</p>
<p class="text-sm text-gray-500 dark:text-gray-600">
© 2025 InboxNegotiator. All rights reserved.
</p>
</div> </div>
</div> </div>
</footer> </footer>

View File

@@ -1,20 +1,28 @@
--- ---
import '@/styles/globals.css' import "@/styles/globals.css";
import Layout from '../layouts/Layout.astro'; import Layout from "../layouts/Layout.astro";
import { AuthForm } from '../components/AuthForm'; import { AuthForm } from "../components/AuthForm";
import { Navbar } from '../components/Navbar'; import { Navbar } from "../components/Navbar";
import { AuthGuard } from '../components/AuthGuard'; import { AuthGuard } from "../components/AuthGuard";
--- ---
<Layout title="Sign In - InboxNegotiator"> <Layout title="Sign In - InboxNegotiator">
<Navbar client:load /> <Navbar client:load />
<AuthGuard requireAuth={false} client:load> <AuthGuard requireAuth={false} client:load>
<main class="min-h-screen bg-gray-50 flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"> <main
class="min-h-screen bg-gray-50 dark:bg-background flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"
>
<div class="w-full max-w-md"> <div class="w-full max-w-md">
<div class="text-center mb-8"> <div class="text-center mb-8">
<h1 class="text-3xl font-bold text-gray-900 mb-2">Sign In</h1> <h1
<p class="text-gray-600">Access your debt resolution dashboard</p> class="text-3xl font-bold text-gray-900 dark:text-foreground mb-2"
>
Sign In
</h1>
<p class="text-gray-600 dark:text-gray-300">
Access your debt resolution dashboard
</p>
</div> </div>
<AuthForm mode="login" client:load /> <AuthForm mode="login" client:load />

View File

@@ -1,20 +1,28 @@
--- ---
import '@/styles/globals.css' import "@/styles/globals.css";
import Layout from '../layouts/Layout.astro'; import Layout from "../layouts/Layout.astro";
import { AuthForm } from '../components/AuthForm'; import { AuthForm } from "../components/AuthForm";
import { Navbar } from '../components/Navbar'; import { Navbar } from "../components/Navbar";
import { AuthGuard } from '../components/AuthGuard'; import { AuthGuard } from "../components/AuthGuard";
--- ---
<Layout title="Sign Up - InboxNegotiator"> <Layout title="Sign Up - InboxNegotiator">
<Navbar client:load /> <Navbar client:load />
<AuthGuard requireAuth={false} client:load> <AuthGuard requireAuth={false} client:load>
<main class="min-h-screen bg-gray-50 flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"> <main
class="min-h-screen bg-gray-50 dark:bg-background flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"
>
<div class="w-full max-w-md"> <div class="w-full max-w-md">
<div class="text-center mb-8"> <div class="text-center mb-8">
<h1 class="text-3xl font-bold text-gray-900 mb-2">Create Account</h1> <h1
<p class="text-gray-600">Start resolving your debts with AI assistance</p> class="text-3xl font-bold text-gray-900 dark:text-foreground mb-2"
>
Create Account
</h1>
<p class="text-gray-600 dark:text-gray-300">
Start resolving your debts with AI assistance
</p>
</div> </div>
<AuthForm mode="signup" client:load /> <AuthForm mode="signup" client:load />