From 7349ae477c3b62a46bb3710ee5c6f03905e28006 Mon Sep 17 00:00:00 2001
From: Francisco Pessano <76450203+FranP-code@users.noreply.github.com>
Date: Fri, 6 Jun 2025 21:16:33 -0300
Subject: [PATCH] Add authentication system with landing page
---
src/components/AuthForm.tsx | 164 ++++++++++++++++++++++++++++++
src/components/Dashboard.tsx | 27 +++--
src/components/Navbar.tsx | 102 +++++++++++++++++++
src/components/ProtectedRoute.tsx | 52 ++++++++++
src/pages/dashboard.astro | 15 +++
src/pages/index.astro | 132 +++++++++++++++++++++++-
src/pages/login.astro | 21 ++++
src/pages/signup.astro | 21 ++++
8 files changed, 523 insertions(+), 11 deletions(-)
create mode 100644 src/components/AuthForm.tsx
create mode 100644 src/components/Navbar.tsx
create mode 100644 src/components/ProtectedRoute.tsx
create mode 100644 src/pages/dashboard.astro
create mode 100644 src/pages/login.astro
create mode 100644 src/pages/signup.astro
diff --git a/src/components/AuthForm.tsx b/src/components/AuthForm.tsx
new file mode 100644
index 0000000..2b8b305
--- /dev/null
+++ b/src/components/AuthForm.tsx
@@ -0,0 +1,164 @@
+import React, { useState } from 'react';
+import { supabase } from '../lib/supabase';
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import { Alert, AlertDescription } from '@/components/ui/alert';
+import { Loader2, Mail, Lock, User } from 'lucide-react';
+
+interface AuthFormProps {
+ mode: 'login' | 'signup';
+}
+
+export function AuthForm({ mode }: AuthFormProps) {
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const [fullName, setFullName] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [message, setMessage] = useState('');
+ const [error, setError] = useState('');
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+ setError('');
+ setMessage('');
+
+ try {
+ if (mode === 'signup') {
+ const { error } = await supabase.auth.signUp({
+ email,
+ password,
+ options: {
+ data: {
+ full_name: fullName,
+ }
+ }
+ });
+
+ if (error) throw error;
+ setMessage('Check your email for the confirmation link!');
+ } else {
+ const { error } = await supabase.auth.signInWithPassword({
+ email,
+ password,
+ });
+
+ if (error) throw error;
+
+ // Redirect to dashboard on successful login
+ window.location.href = '/dashboard';
+ }
+ } catch (error: any) {
+ setError(error.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+ {mode === 'login' ? 'Welcome back' : 'Create account'}
+
+
+ {mode === 'login'
+ ? 'Enter your credentials to access your dashboard'
+ : 'Enter your details to create your account'
+ }
+
+
+
+
+
+
+ {mode === 'login' ? (
+
+ Don't have an account?{' '}
+
+ Sign up
+
+
+ ) : (
+
+ Already have an account?{' '}
+
+ Sign in
+
+
+ )}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx
index 04d5d34..947eca9 100644
--- a/src/components/Dashboard.tsx
+++ b/src/components/Dashboard.tsx
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react';
import { supabase, type Debt } from '../lib/supabase';
+import { Button } from '@/components/ui/button';
import { DebtCard } from './DebtCard';
import { DebtTimeline } from './DebtTimeline';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
@@ -13,7 +14,8 @@ import {
CheckCircle,
AlertTriangle,
RefreshCw,
- BarChart3
+ BarChart3,
+ LogOut
} from 'lucide-react';
export function Dashboard() {
@@ -96,6 +98,11 @@ export function Dashboard() {
});
};
+ const handleSignOut = async () => {
+ await supabase.auth.signOut();
+ window.location.href = '/';
+ };
+
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
@@ -125,14 +132,16 @@ export function Dashboard() {
{/* Header */}
-
-
-
- InboxNegotiator Dashboard
-
-
- AI-powered debt resolution platform with real-time updates
-
+
+
+
+
+ InboxNegotiator Dashboard
+
+
+ AI-powered debt resolution platform with real-time updates
+
+
{/* Stats Cards */}
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
new file mode 100644
index 0000000..9bb704d
--- /dev/null
+++ b/src/components/Navbar.tsx
@@ -0,0 +1,102 @@
+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';
+
+export function Navbar() {
+ const [user, setUser] = useState
(null);
+
+ useEffect(() => {
+ supabase.auth.getSession().then(({ data: { session } }) => {
+ setUser(session?.user ?? null);
+ });
+
+ const { data: { subscription } } = supabase.auth.onAuthStateChange(
+ (event, session) => {
+ setUser(session?.user ?? null);
+ }
+ );
+
+ return () => subscription.unsubscribe();
+ }, []);
+
+ const handleSignOut = async () => {
+ await supabase.auth.signOut();
+ window.location.href = '/';
+ };
+
+ const getInitials = (email: string) => {
+ return email.substring(0, 2).toUpperCase();
+ };
+
+ return (
+
+
+
+
+
+
+ {user ? (
+
+
+
+
+
+ {getInitials(user.email || '')}
+
+
+
+
+
+
+
+
{user.user_metadata?.full_name || 'User'}
+
+ {user.email}
+
+
+
+
+
+
+
+ Dashboard
+
+
+
+
+
+ Sign out
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx
new file mode 100644
index 0000000..53f3aeb
--- /dev/null
+++ b/src/components/ProtectedRoute.tsx
@@ -0,0 +1,52 @@
+import React, { useEffect, useState } from 'react';
+import { supabase } from '../lib/supabase';
+import type { User } from '@supabase/supabase-js';
+import { Loader2 } from 'lucide-react';
+
+interface ProtectedRouteProps {
+ children: React.ReactNode;
+}
+
+export function ProtectedRoute({ children }: ProtectedRouteProps) {
+ const [user, setUser] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ // Get initial session
+ supabase.auth.getSession().then(({ data: { session } }) => {
+ setUser(session?.user ?? null);
+ setLoading(false);
+ });
+
+ // Listen for auth changes
+ const { data: { subscription } } = supabase.auth.onAuthStateChange(
+ (event, session) => {
+ setUser(session?.user ?? null);
+ setLoading(false);
+ }
+ );
+
+ return () => subscription.unsubscribe();
+ }, []);
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ if (!user) {
+ // Redirect to login if not authenticated
+ if (typeof window !== 'undefined') {
+ window.location.href = '/login';
+ }
+ return null;
+ }
+
+ return <>{children}>;
+}
\ No newline at end of file
diff --git a/src/pages/dashboard.astro b/src/pages/dashboard.astro
new file mode 100644
index 0000000..1445b35
--- /dev/null
+++ b/src/pages/dashboard.astro
@@ -0,0 +1,15 @@
+---
+import '@/styles/globals.css'
+import Layout from '../layouts/Layout.astro';
+import { Dashboard } from '../components/Dashboard';
+import { ProtectedRoute } from '../components/ProtectedRoute';
+import { Navbar } from '../components/Navbar';
+---
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/index.astro b/src/pages/index.astro
index e5366a8..911e415 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -1,9 +1,137 @@
---
import '@/styles/globals.css'
import Layout from '../layouts/Layout.astro';
-import { Dashboard } from '../components/Dashboard';
+import { Navbar } from '../components/Navbar';
---
-
+
+
+
+
+
+
+
+
+ AI-Powered
+
+ Debt Resolution
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+
How It Works
+
Simple, automated, and compliant debt resolution
+
+
+
+
+
+
Forward Emails
+
Simply forward your debt collection emails to our secure processing address.
+
+
+
+
+
AI Analysis
+
Our AI analyzes the debt and generates FDCPA-compliant negotiation strategies.
+
+
+
+
+
Track Progress
+
Monitor negotiations in real-time and track your potential savings.
+
+
+
+
+
+
+
+
+
+
Why Choose InboxNegotiator?
+
+
+
+
+
FDCPA Compliant
+
All responses follow Fair Debt Collection Practices Act guidelines.
+
+
+
+
Save Money
+
Potentially reduce your debt by up to 40% through strategic negotiations.
+
+
+
+
Real-time Updates
+
Track your negotiations with live dashboard updates.
+
+
+
+
Secure & Private
+
Your financial information is encrypted and protected.
+
+
+
+
+
+
+
+
+
Ready to Take Control of Your Debt?
+
Join thousands who have successfully negotiated their debts with AI assistance.
+
+ Start Your Free Account
+
+
+
+
+
+
+
+
+
+
+
+
+
+
InboxNegotiator
+
+
AI-powered debt resolution platform
+
© 2025 InboxNegotiator. All rights reserved.
+
+
+
\ No newline at end of file
diff --git a/src/pages/login.astro b/src/pages/login.astro
new file mode 100644
index 0000000..593e6d8
--- /dev/null
+++ b/src/pages/login.astro
@@ -0,0 +1,21 @@
+---
+import '@/styles/globals.css'
+import Layout from '../layouts/Layout.astro';
+import { AuthForm } from '../components/AuthForm';
+import { Navbar } from '../components/Navbar';
+---
+
+
+
+
+
+
+
+
Sign In
+
Access your debt resolution dashboard
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/signup.astro b/src/pages/signup.astro
new file mode 100644
index 0000000..70306a2
--- /dev/null
+++ b/src/pages/signup.astro
@@ -0,0 +1,21 @@
+---
+import '@/styles/globals.css'
+import Layout from '../layouts/Layout.astro';
+import { AuthForm } from '../components/AuthForm';
+import { Navbar } from '../components/Navbar';
+---
+
+
+
+
+
+
+
+
Create Account
+
Start resolving your debts with AI assistance
+
+
+
+
+
+
\ No newline at end of file