Spaces:
Sleeping
Sleeping
v3.0: Fix analyze page — fetch plan/role from DB via /api/me, no hardcoded emails or limits
Browse files
web/app/dashboard-pages/analyze/page.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
-
import { useState, useRef } from "react";
|
| 4 |
import {
|
| 5 |
ScanText, ScanLine, TriangleAlert, CircleAlert, CircleCheck, Info,
|
| 6 |
FileDown, ChevronDown, ChevronUp, Copy, Check, Upload, FileText,
|
|
@@ -165,11 +165,28 @@ export default function AnalyzePage() {
|
|
| 165 |
const [copied, setCopied] = useState(false);
|
| 166 |
const [scanCount, setScanCount] = useState(0);
|
| 167 |
const [userPlan, setUserPlan] = useState("free");
|
|
|
|
|
|
|
|
|
|
| 168 |
const [showUpgrade, setShowUpgrade] = useState(false);
|
| 169 |
const fileInputRef = useRef<HTMLInputElement>(null);
|
| 170 |
|
| 171 |
-
|
| 172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
|
| 174 |
async function handleAnalyze() {
|
| 175 |
if (!text || text.trim().length < 50) { setError("Enter at least 50 characters."); return; }
|
|
@@ -187,7 +204,7 @@ export default function AnalyzePage() {
|
|
| 187 |
async function handleFileUpload(e: React.ChangeEvent<HTMLInputElement>) {
|
| 188 |
const file = e.target.files?.[0];
|
| 189 |
if (!file) return;
|
| 190 |
-
if (
|
| 191 |
setLoading(true); setError("");
|
| 192 |
try {
|
| 193 |
const formData = new FormData(); formData.append("file", file);
|
|
@@ -255,10 +272,10 @@ export default function AnalyzePage() {
|
|
| 255 |
<div className="w-10 h-10 rounded-xl bg-amber-50 flex items-center justify-center"><Lock className="w-5 h-5 text-amber-600" /></div>
|
| 256 |
<button onClick={() => setShowUpgrade(false)} className="p-1 hover:bg-zinc-100 rounded-md"><X className="w-4 h-4 text-zinc-400" /></button>
|
| 257 |
</div>
|
| 258 |
-
<h3 className="mt-4 text-lg font-semibold">{
|
| 259 |
<p className="mt-1.5 text-sm text-zinc-500 leading-relaxed">
|
| 260 |
-
{
|
| 261 |
-
?
|
| 262 |
: "File upload is available on the Pro plan."}
|
| 263 |
</p>
|
| 264 |
<div className="mt-5 flex gap-2">
|
|
@@ -279,8 +296,8 @@ export default function AnalyzePage() {
|
|
| 279 |
</h1>
|
| 280 |
<p className="mt-1 text-xs sm:text-sm text-zinc-500 max-w-xl">Paste text or upload a file. Get 41-category clause detection, risk scoring, ML NER, NLI contradictions, compliance checks, and obligation tracking.</p>
|
| 281 |
</div>
|
| 282 |
-
{userPlan === "free" && (
|
| 283 |
-
<span className="self-start text-xs text-zinc-400 border border-zinc-200 px-2.5 py-1 rounded-md whitespace-nowrap">{scanCount}/{
|
| 284 |
)}
|
| 285 |
</div>
|
| 286 |
|
|
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
+
import { useState, useRef, useEffect } from "react";
|
| 4 |
import {
|
| 5 |
ScanText, ScanLine, TriangleAlert, CircleAlert, CircleCheck, Info,
|
| 6 |
FileDown, ChevronDown, ChevronUp, Copy, Check, Upload, FileText,
|
|
|
|
| 165 |
const [copied, setCopied] = useState(false);
|
| 166 |
const [scanCount, setScanCount] = useState(0);
|
| 167 |
const [userPlan, setUserPlan] = useState("free");
|
| 168 |
+
const [userRole, setUserRole] = useState("user");
|
| 169 |
+
const [scanLimit, setScanLimit] = useState(10);
|
| 170 |
+
const [canUpload, setCanUpload] = useState(false);
|
| 171 |
const [showUpgrade, setShowUpgrade] = useState(false);
|
| 172 |
const fileInputRef = useRef<HTMLInputElement>(null);
|
| 173 |
|
| 174 |
+
// Fetch user profile from DB on mount — no hardcoded emails or plans
|
| 175 |
+
useEffect(() => {
|
| 176 |
+
fetch("/api/me")
|
| 177 |
+
.then(res => res.json())
|
| 178 |
+
.then(data => {
|
| 179 |
+
setUserPlan(data.plan || "free");
|
| 180 |
+
setUserRole(data.role || "user");
|
| 181 |
+
setScanCount(data.analyses_this_month || 0);
|
| 182 |
+
setScanLimit(data.scan_limit === Infinity || data.scan_limit > 9999 ? Infinity : (data.scan_limit || 10));
|
| 183 |
+
setCanUpload(data.can_upload || false);
|
| 184 |
+
})
|
| 185 |
+
.catch(() => {});
|
| 186 |
+
}, []);
|
| 187 |
+
|
| 188 |
+
const isAdmin = userRole === "admin";
|
| 189 |
+
const canScan = isAdmin || userPlan !== "free" || scanCount < scanLimit;
|
| 190 |
|
| 191 |
async function handleAnalyze() {
|
| 192 |
if (!text || text.trim().length < 50) { setError("Enter at least 50 characters."); return; }
|
|
|
|
| 204 |
async function handleFileUpload(e: React.ChangeEvent<HTMLInputElement>) {
|
| 205 |
const file = e.target.files?.[0];
|
| 206 |
if (!file) return;
|
| 207 |
+
if (!canUpload) { setShowUpgrade(true); return; }
|
| 208 |
setLoading(true); setError("");
|
| 209 |
try {
|
| 210 |
const formData = new FormData(); formData.append("file", file);
|
|
|
|
| 272 |
<div className="w-10 h-10 rounded-xl bg-amber-50 flex items-center justify-center"><Lock className="w-5 h-5 text-amber-600" /></div>
|
| 273 |
<button onClick={() => setShowUpgrade(false)} className="p-1 hover:bg-zinc-100 rounded-md"><X className="w-4 h-4 text-zinc-400" /></button>
|
| 274 |
</div>
|
| 275 |
+
<h3 className="mt-4 text-lg font-semibold">{scanCount >= scanLimit ? "Scan limit reached" : "Pro feature"}</h3>
|
| 276 |
<p className="mt-1.5 text-sm text-zinc-500 leading-relaxed">
|
| 277 |
+
{scanCount >= scanLimit
|
| 278 |
+
? "You have used all your free scans. Upgrade to Pro for unlimited scans and full analysis."
|
| 279 |
: "File upload is available on the Pro plan."}
|
| 280 |
</p>
|
| 281 |
<div className="mt-5 flex gap-2">
|
|
|
|
| 296 |
</h1>
|
| 297 |
<p className="mt-1 text-xs sm:text-sm text-zinc-500 max-w-xl">Paste text or upload a file. Get 41-category clause detection, risk scoring, ML NER, NLI contradictions, compliance checks, and obligation tracking.</p>
|
| 298 |
</div>
|
| 299 |
+
{userPlan === "free" && !isAdmin && (
|
| 300 |
+
<span className="self-start text-xs text-zinc-400 border border-zinc-200 px-2.5 py-1 rounded-md whitespace-nowrap">{scanCount}/{scanLimit === Infinity ? "\u221E" : scanLimit} scans</span>
|
| 301 |
)}
|
| 302 |
</div>
|
| 303 |
|