/* * ============================================================================= * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform * ----------------------------------------------------------------------------- * File: client/src/pages/auth.tsx * * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * Website: https://www.spboucher.ai * Demo: https://www.vquant.ai * License: MIT (see LICENSE) * * Copyright © 2026 Simon-Pierre Boucher. All rights reserved. * ============================================================================= */ import { useState } from "react"; import { User, KeyRound, Sparkles, Copy, Check, ArrowLeft } from "lucide-react"; 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 { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { useLocation } from "wouter"; export default function Auth() { const [, setLocation] = useLocation(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(""); const [success, setSuccess] = useState(""); // Create account state const [name, setName] = useState(""); const [generatedToken, setGeneratedToken] = useState(""); const [copied, setCopied] = useState(false); // Login state const [loginToken, setLoginToken] = useState(""); const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); setError(""); setSuccess(""); setGeneratedToken(""); setIsLoading(true); try { const response = await fetch("/api/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: name.trim() }), }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || "Erreur lors de la création du compte"); } setGeneratedToken(data.token); setSuccess(`Compte créé avec succès! Bienvenue, ${data.user.displayName}!`); } catch (err: any) { setError(err.message || "Erreur lors de la création du compte"); } finally { setIsLoading(false); } }; const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); setError(""); setSuccess(""); setIsLoading(true); try { const response = await fetch("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: loginToken.trim() }), }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || "Token invalide"); } setSuccess(`Bienvenue, ${data.user.displayName}!`); setTimeout(() => { setLocation('/'); }, 1000); } catch (err: any) { setError(err.message || "Erreur de connexion"); } finally { setIsLoading(false); } }; const handleCopyToken = async () => { try { await navigator.clipboard.writeText(generatedToken); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch { // Fallback for mobile const textarea = document.createElement('textarea'); textarea.value = generatedToken; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; const handleGoHome = () => { setLocation('/'); }; return (
{/* Subtle Background */}
{/* Header */}
{/* Main Content */}
{/* Welcome message */}

Mon Compte

Créez un compte pour garder vos analyses privées

Créer un compte Se connecter {/* Create Account Tab */}
Créer un compte
Entrez votre nom pour recevoir un token d'accès unique. Vos générations resteront privées.
setName(e.target.value)} required minLength={2} disabled={isLoading || !!generatedToken} className="pl-10 h-11 bg-background/50 border-border focus:border-primary transition-all" />
{error && ( {error} )} {success && !generatedToken && ( {success} )} {generatedToken && (

Votre token d'accès

{generatedToken}

IMPORTANT: Sauvegardez ce token! C'est votre SEUL moyen de vous reconnecter.

)} {!generatedToken && ( )}
{/* Login Tab */}
Se connecter
Entrez votre token pour accéder à votre historique privé
setLoginToken(e.target.value)} required disabled={isLoading} className="pl-10 h-11 bg-background/50 border-border focus:border-primary transition-all font-mono" />
{error && ( {error} )} {success && ( {success} )}
); }