Pre-Final Backup
This commit is contained in:
@@ -6,7 +6,16 @@ import { ContractsList } from "@/features/contracts/components/list/contracts-li
|
||||
import { ContractsHeader } from "@/components/layout/contacts-header";
|
||||
import { useState, useEffect } from "react";
|
||||
import { getContracts } from "@/features/contracts/api/contract.action";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { motion, AnimatePresence } from "motion/react";
|
||||
import {
|
||||
Upload,
|
||||
FileText,
|
||||
Sparkles,
|
||||
Shield,
|
||||
Zap,
|
||||
ChevronRight,
|
||||
Loader2,
|
||||
} from "lucide-react";
|
||||
|
||||
export default function ContactsPage() {
|
||||
const [refreshTrigger, setRefreshTrigger] = useState(0);
|
||||
@@ -42,69 +51,217 @@ export default function ContactsPage() {
|
||||
|
||||
if (isChecking) {
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-screen bg-background text-foreground overflow-hidden">
|
||||
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
||||
<div className="absolute top-0 left-1/4 w-96 h-96 bg-primary/20 rounded-full blur-3xl animate-blob"></div>
|
||||
<div className="absolute top-1/2 right-1/4 w-96 h-96 bg-accent/20 rounded-full blur-3xl animate-blob animation-delay-2000"></div>
|
||||
<div className="absolute -bottom-8 right-1/3 w-96 h-96 bg-secondary/20 rounded-full blur-3xl animate-blob animation-delay-4000"></div>
|
||||
</div>
|
||||
|
||||
<main className="relative z-10 flex flex-col h-screen overflow-auto items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="mb-4 inline-block p-4 bg-background dark:bg-card rounded-full border border-border/50">
|
||||
<div className="w-8 h-8 rounded-full border-2 border-primary border-t-transparent animate-spin"></div>
|
||||
</div>
|
||||
<p className="text-muted-foreground">Loading...</p>
|
||||
</div>
|
||||
</main>
|
||||
<div className="min-h-screen bg-background text-foreground relative overflow-hidden">
|
||||
{/* Ambient loading background */}
|
||||
<div className="fixed inset-0 pointer-events-none">
|
||||
<div className="absolute top-1/4 left-1/3 w-[500px] h-[500px] bg-primary/10 rounded-full blur-[120px] animate-pulse" />
|
||||
<div className="absolute bottom-1/4 right-1/3 w-[400px] h-[400px] bg-violet-500/10 rounded-full blur-[100px] animate-pulse delay-700" />
|
||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.03)_1px,transparent_1px)] bg-[size:64px_64px] [mask-image:radial-gradient(ellipse_60%_60%_at_50%_50%,#000_30%,transparent_100%)]" />
|
||||
</div>
|
||||
</>
|
||||
|
||||
<main className="relative z-10 flex flex-col h-screen items-center justify-center">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
className="text-center space-y-6"
|
||||
>
|
||||
<div className="relative inline-flex">
|
||||
<div className="absolute inset-0 bg-primary/30 blur-2xl rounded-full" />
|
||||
<div className="relative p-6 bg-background/80 dark:bg-card/80 rounded-3xl border border-border/50 backdrop-blur-xl shadow-2xl">
|
||||
<Loader2 className="w-10 h-10 text-primary animate-spin" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="text-lg font-semibold text-foreground">
|
||||
Loading workspace
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Preparing your contract environment...
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-screen bg-background text-foreground">
|
||||
<main className="flex flex-col min-h-screen">
|
||||
<ContractsHeader />
|
||||
<div className="min-h-screen bg-background text-foreground relative overflow-hidden">
|
||||
{/* Ambient Background */}
|
||||
<div className="fixed inset-0 pointer-events-none">
|
||||
<div className="absolute top-[-10%] left-[-5%] w-[600px] h-[600px] bg-primary/5 rounded-full blur-[120px]" />
|
||||
<div className="absolute top-[20%] right-[-10%] w-[500px] h-[500px] bg-violet-500/5 rounded-full blur-[100px]" />
|
||||
<div className="absolute bottom-[-10%] left-[20%] w-[400px] h-[400px] bg-emerald-500/5 rounded-full blur-[100px]" />
|
||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.02)_1px,transparent_1px)] bg-[size:64px_64px] [mask-image:radial-gradient(ellipse_80%_80%_at_50%_50%,#000_20%,transparent_100%)]" />
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div className="max-w-7xl mx-auto px-6 py-8 space-y-8">
|
||||
<Card className="rounded-2xl border-border/60 p-6 md:p-8">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-2xl md:text-3xl font-semibold tracking-tight">
|
||||
<ContractsHeader />
|
||||
|
||||
<main className="relative z-10 flex flex-col min-h-[calc(100vh-64px)]">
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div className="max-w-7xl mx-auto px-6 lg:px-8 py-10 space-y-10">
|
||||
{/* Upload Section */}
|
||||
<motion.section
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.1, duration: 0.5 }}
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-5">
|
||||
<div className="p-2 rounded-xl bg-primary/10 border border-primary/20">
|
||||
<Upload className="w-4 h-4 text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-bold tracking-tight">
|
||||
Upload Contract
|
||||
</h2>
|
||||
<p className="mt-2 text-sm md:text-base text-muted-foreground">
|
||||
Add PDF contracts and let the AI pipeline extract summary,
|
||||
key points, and legal-business insights.
|
||||
<p className="text-xs text-muted-foreground">
|
||||
PDF documents supported
|
||||
</p>
|
||||
</div>
|
||||
<ContractUploadForm onUploadSuccess={handleUploadSuccess} />
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card className="rounded-2xl border-border/60 p-6 md:p-8">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-2xl md:text-3xl font-semibold tracking-tight">
|
||||
Your Contracts
|
||||
</h2>
|
||||
<p className="mt-2 text-sm md:text-base text-muted-foreground">
|
||||
Review contract lifecycle, trigger analysis, and ask AI
|
||||
questions per file.
|
||||
</p>
|
||||
<div className="relative group">
|
||||
<div className="absolute -inset-0.5 bg-gradient-to-r from-primary/20 via-violet-500/20 to-primary/20 rounded-2xl blur opacity-30 group-hover:opacity-50 transition duration-500" />
|
||||
<div className="relative rounded-2xl border border-border/60 bg-background/60 backdrop-blur-2xl p-6 md:p-8 shadow-xl shadow-black/5">
|
||||
<div className="mb-6 flex items-start justify-between">
|
||||
<div className="space-y-1">
|
||||
<h3 className="text-sm font-semibold text-foreground">
|
||||
New Document
|
||||
</h3>
|
||||
<p className="text-xs text-muted-foreground max-w-md">
|
||||
Our AI pipeline will automatically extract summaries,
|
||||
key clauses, risk factors, and generate actionable
|
||||
business insights.
|
||||
</p>
|
||||
</div>
|
||||
<div className="hidden sm:flex items-center gap-1.5 text-[10px] font-medium px-3 py-1.5 rounded-full bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border border-emerald-500/20">
|
||||
<span className="relative flex h-1.5 w-1.5">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" />
|
||||
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-emerald-500" />
|
||||
</span>
|
||||
AI Ready
|
||||
</div>
|
||||
</div>
|
||||
<ContractUploadForm onUploadSuccess={handleUploadSuccess} />
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
|
||||
{/* Contracts List Section */}
|
||||
<motion.section
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2, duration: 0.5 }}
|
||||
>
|
||||
<div className="flex items-center justify-between mb-5">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 rounded-xl bg-violet-500/10 border border-violet-500/20">
|
||||
<FileText className="w-4 h-4 text-violet-500" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-bold tracking-tight">
|
||||
Your Contracts
|
||||
</h2>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Manage, analyze, and query your document library
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showContracts ? (
|
||||
<ContractsList refreshTrigger={refreshTrigger} />
|
||||
) : (
|
||||
<EmptyContractsState />
|
||||
{showContracts && (
|
||||
<motion.button
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
onClick={() => setRefreshTrigger((prev) => prev + 1)}
|
||||
className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors px-3 py-1.5 rounded-lg hover:bg-muted/50"
|
||||
>
|
||||
<Zap className="w-3 h-3" />
|
||||
Refresh
|
||||
</motion.button>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative rounded-2xl border border-border/40 bg-background/40 backdrop-blur-2xl overflow-hidden shadow-xl shadow-black/5 min-h-[400px]">
|
||||
<div className="absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-primary/20 to-transparent" />
|
||||
|
||||
<AnimatePresence mode="wait">
|
||||
{showContracts ? (
|
||||
<motion.div
|
||||
key="list"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="p-6 md:p-8"
|
||||
>
|
||||
<ContractsList refreshTrigger={refreshTrigger} />
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="empty"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="p-6 md:p-8"
|
||||
>
|
||||
<EmptyContractsState />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</motion.section>
|
||||
|
||||
{/* Bottom Info Cards */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="grid grid-cols-1 md:grid-cols-3 gap-4 pb-8"
|
||||
>
|
||||
{[
|
||||
{
|
||||
icon: <Shield className="w-4 h-4" />,
|
||||
title: "Secure Processing",
|
||||
desc: "Documents are encrypted in transit and at rest. Your data never leaves your infrastructure.",
|
||||
color: "emerald",
|
||||
},
|
||||
{
|
||||
icon: <Sparkles className="w-4 h-4" />,
|
||||
title: "AI Extraction",
|
||||
desc: "Advanced NLP models identify parties, obligations, risks, and key dates automatically.",
|
||||
color: "primary",
|
||||
},
|
||||
{
|
||||
icon: <Zap className="w-4 h-4" />,
|
||||
title: "Instant Insights",
|
||||
desc: "Get executive summaries and red-flag alerts within seconds of upload completion.",
|
||||
color: "violet",
|
||||
},
|
||||
].map((feature, i) => (
|
||||
<motion.div
|
||||
key={feature.title}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.4 + i * 0.05 }}
|
||||
className="group relative rounded-2xl border border-border/40 bg-background/40 backdrop-blur-xl p-5 hover:bg-background/60 transition-all duration-300"
|
||||
>
|
||||
<div
|
||||
className={`p-2 rounded-lg bg-${feature.color}-500/10 border border-${feature.color}-500/20 w-fit mb-3 text-${feature.color}-500`}
|
||||
>
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h4 className="text-sm font-semibold mb-1">
|
||||
{feature.title}
|
||||
</h4>
|
||||
<p className="text-xs text-muted-foreground leading-relaxed">
|
||||
{feature.desc}
|
||||
</p>
|
||||
<ChevronRight className="w-4 h-4 text-muted-foreground/30 absolute bottom-5 right-5 group-hover:text-muted-foreground group-hover:translate-x-0.5 transition-all" />
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user