anky2002 commited on
Commit
4f95e90
·
2 Parent(s): 78229a401389c4

Merge branch 'main' of https://huggingface.co/spaces/gaurv007/ClauseGuard

Browse files
web/app/api/me/route.ts CHANGED
@@ -5,7 +5,7 @@ import { createClient } from "@/lib/supabase/server";
5
  * GET /api/me
6
  * Returns the current user's profile from DB.
7
  * Used by client components (analyze page, etc.) to determine plan, role, usage.
8
- * No hardcoded emails everything comes from the database.
9
  */
10
  export async function GET(req: NextRequest) {
11
  try {
@@ -19,17 +19,27 @@ export async function GET(req: NextRequest) {
19
  role: "user",
20
  isAdmin: false,
21
  analyses_this_month: 0,
 
 
 
 
 
 
22
  });
23
  }
24
 
25
  const { data: profile } = await supabase
26
  .from("profiles")
27
- .select("plan, role, is_banned, analyses_this_month, full_name, email")
28
  .eq("id", user.id)
29
  .single();
30
 
31
  const plan = profile?.plan || "free";
32
  const role = profile?.role || "user";
 
 
 
 
33
 
34
  return NextResponse.json({
35
  authenticated: true,
@@ -38,14 +48,20 @@ export async function GET(req: NextRequest) {
38
  full_name: profile?.full_name || "",
39
  plan,
40
  role,
41
- isAdmin: role === "admin",
42
  is_banned: profile?.is_banned || false,
43
  analyses_this_month: profile?.analyses_this_month || 0,
44
- // Admins get unlimited everything
45
- scan_limit: role === "admin" ? Infinity : plan === "free" ? 10 : Infinity,
46
- can_upload: role === "admin" || plan !== "free",
47
- can_compare: role === "admin" || plan !== "free",
48
- can_export_pdf: role === "admin" || plan !== "free",
 
 
 
 
 
 
49
  });
50
  } catch (error) {
51
  return NextResponse.json({
@@ -54,6 +70,12 @@ export async function GET(req: NextRequest) {
54
  role: "user",
55
  isAdmin: false,
56
  analyses_this_month: 0,
 
 
 
 
 
 
57
  });
58
  }
59
  }
 
5
  * GET /api/me
6
  * Returns the current user's profile from DB.
7
  * Used by client components (analyze page, etc.) to determine plan, role, usage.
8
+ * Admin gets FULL access to everything no limits, no restrictions.
9
  */
10
  export async function GET(req: NextRequest) {
11
  try {
 
19
  role: "user",
20
  isAdmin: false,
21
  analyses_this_month: 0,
22
+ scan_limit: 10,
23
+ can_upload: false,
24
+ can_compare: false,
25
+ can_export_pdf: false,
26
+ can_chat: false,
27
+ can_redline_llm: false,
28
  });
29
  }
30
 
31
  const { data: profile } = await supabase
32
  .from("profiles")
33
+ .select("plan, role, is_banned, analyses_this_month, full_name, email, team_id, created_at")
34
  .eq("id", user.id)
35
  .single();
36
 
37
  const plan = profile?.plan || "free";
38
  const role = profile?.role || "user";
39
+ const isAdmin = role === "admin";
40
+
41
+ // Admin gets EVERYTHING — no limits, no restrictions, period.
42
+ const hasFullAccess = isAdmin || plan !== "free";
43
 
44
  return NextResponse.json({
45
  authenticated: true,
 
48
  full_name: profile?.full_name || "",
49
  plan,
50
  role,
51
+ isAdmin,
52
  is_banned: profile?.is_banned || false,
53
  analyses_this_month: profile?.analyses_this_month || 0,
54
+ team_id: profile?.team_id || null,
55
+ created_at: profile?.created_at || null,
56
+ // Use 999999 instead of Infinity (not valid JSON)
57
+ scan_limit: isAdmin ? 999999 : plan === "free" ? 10 : 999999,
58
+ can_upload: hasFullAccess,
59
+ can_compare: hasFullAccess,
60
+ can_export_pdf: hasFullAccess,
61
+ can_chat: hasFullAccess,
62
+ can_redline_llm: hasFullAccess,
63
+ can_api_keys: hasFullAccess,
64
+ can_team: isAdmin || plan === "team",
65
  });
66
  } catch (error) {
67
  return NextResponse.json({
 
70
  role: "user",
71
  isAdmin: false,
72
  analyses_this_month: 0,
73
+ scan_limit: 10,
74
+ can_upload: false,
75
+ can_compare: false,
76
+ can_export_pdf: false,
77
+ can_chat: false,
78
+ can_redline_llm: false,
79
  });
80
  }
81
  }
web/app/dashboard-pages/analyze/page.tsx CHANGED
@@ -196,7 +196,7 @@ export default function AnalyzePage() {
196
  setUserPlan(data.plan || "free");
197
  setUserRole(data.role || "user");
198
  setScanCount(data.analyses_this_month || 0);
199
- setScanLimit(data.scan_limit === Infinity || data.scan_limit > 9999 ? Infinity : (data.scan_limit || 10));
200
  setCanUpload(data.can_upload || false);
201
  })
202
  .catch(() => {});
@@ -221,7 +221,7 @@ export default function AnalyzePage() {
221
  async function handleFileUpload(e: React.ChangeEvent<HTMLInputElement>) {
222
  const file = e.target.files?.[0];
223
  if (!file) return;
224
- if (!canUpload) { setShowUpgrade(true); return; }
225
  setLoading(true); setError("");
226
  try {
227
  const formData = new FormData(); formData.append("file", file);
@@ -340,7 +340,7 @@ export default function AnalyzePage() {
340
  </h1>
341
  <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>
342
  </div>
343
- {userPlan === "free" && !isAdmin && (
344
  <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>
345
  )}
346
  </div>
 
196
  setUserPlan(data.plan || "free");
197
  setUserRole(data.role || "user");
198
  setScanCount(data.analyses_this_month || 0);
199
+ setScanLimit(data.scan_limit >= 9999 ? Infinity : (data.scan_limit || 10));
200
  setCanUpload(data.can_upload || false);
201
  })
202
  .catch(() => {});
 
221
  async function handleFileUpload(e: React.ChangeEvent<HTMLInputElement>) {
222
  const file = e.target.files?.[0];
223
  if (!file) return;
224
+ if (!canUpload && !isAdmin) { setShowUpgrade(true); return; }
225
  setLoading(true); setError("");
226
  try {
227
  const formData = new FormData(); formData.append("file", file);
 
340
  </h1>
341
  <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>
342
  </div>
343
+ {userPlan === "free" && !isAdmin && scanLimit !== Infinity && (
344
  <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>
345
  )}
346
  </div>
web/app/dashboard-pages/dashboard/page.tsx CHANGED
@@ -2,7 +2,8 @@ import { createClient } from "@/lib/supabase/server";
2
  import Link from "next/link";
3
  import {
4
  ScanText, ShieldCheck, Tag, AlertTriangle, ClipboardList,
5
- GitCompare, Cpu, Layers, Clock
 
6
  } from "lucide-react";
7
 
8
  export default async function DashboardPage() {
@@ -17,8 +18,10 @@ export default async function DashboardPage() {
17
  .order("created_at", { ascending: false }).limit(10);
18
 
19
  const plan = profile?.plan || "free";
 
 
20
  const usedThisMonth = profile?.analyses_this_month || 0;
21
- const limit = plan === "free" ? 10 : "Unlimited";
22
 
23
  const avgRisk = analyses && analyses.length > 0
24
  ? Math.round(analyses.reduce((s: number, a: any) => s + a.risk_score, 0) / analyses.length)
@@ -36,22 +39,35 @@ export default async function DashboardPage() {
36
  <h1 className="text-xl sm:text-2xl font-bold text-gray-900 flex items-center gap-2">
37
  <ShieldCheck className="w-5 h-5 sm:w-6 sm:h-6 text-indigo-500" />
38
  Dashboard
 
 
 
 
 
39
  </h1>
40
  <p className="text-gray-500 text-sm mt-1">Welcome back, {profile?.full_name || user?.email}</p>
41
  </div>
42
- <Link href="/dashboard-pages/analyze"
43
- className="bg-indigo-600 text-white px-5 sm:px-6 py-2.5 sm:py-3 rounded-xl font-semibold hover:bg-indigo-700 transition text-sm whitespace-nowrap">
44
- + New Scan
45
- </Link>
 
 
 
 
 
 
 
 
46
  </div>
47
 
48
  {/* Primary Stats */}
49
  <div className="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-6 mb-8 sm:mb-10">
50
  {[
51
- { label: "Plan", value: plan, capitalize: true },
52
  { label: "Scans This Month", value: `${usedThisMonth} / ${limit}` },
53
  { label: "Total Scans", value: String(count || 0) },
54
- { label: "Avg Risk Score", value: avgRisk !== null ? String(avgRisk) : "\u2014" },
55
  ].map((s) => (
56
  <div key={s.label} className="bg-white rounded-xl p-4 sm:p-6 border border-gray-200">
57
  <p className="text-xs sm:text-sm text-gray-500">{s.label}</p>
@@ -81,24 +97,33 @@ export default async function DashboardPage() {
81
  </div>
82
 
83
  {/* Quick Actions */}
84
- <div className="grid sm:grid-cols-2 gap-3 sm:gap-6 mb-8 sm:mb-10">
85
- <Link href="/dashboard-pages/analyze" className="bg-white rounded-xl p-5 sm:p-6 border border-gray-200 hover:border-indigo-200 hover:shadow-sm transition-all group">
86
  <div className="flex items-center gap-3 mb-2">
87
- <div className="w-10 h-10 rounded-lg bg-indigo-50 flex items-center justify-center group-hover:bg-indigo-100 transition-colors">
88
- <ScanText className="w-5 h-5 text-indigo-600" />
89
  </div>
90
- <h3 className="font-semibold text-gray-900">Analyze Contract</h3>
91
  </div>
92
- <p className="text-sm text-gray-500">Scan with 3 ML models: clause classifier, Legal NER, and NLI contradiction detection.</p>
93
  </Link>
94
- <Link href="/dashboard-pages/compare" className="bg-white rounded-xl p-5 sm:p-6 border border-gray-200 hover:border-indigo-200 hover:shadow-sm transition-all group">
95
  <div className="flex items-center gap-3 mb-2">
96
- <div className="w-10 h-10 rounded-lg bg-indigo-50 flex items-center justify-center group-hover:bg-indigo-100 transition-colors">
97
- <GitCompare className="w-5 h-5 text-indigo-600" />
98
  </div>
99
- <h3 className="font-semibold text-gray-900">Compare Contracts</h3>
100
  </div>
101
- <p className="text-sm text-gray-500">Side-by-side diff with semantic similarity scoring and risk delta.</p>
 
 
 
 
 
 
 
 
 
102
  </Link>
103
  </div>
104
 
@@ -132,11 +157,6 @@ export default async function DashboardPage() {
132
  <ClipboardList className="w-2.5 h-2.5" />{a.obligations.length}
133
  </span>
134
  )}
135
- {a.model && a.model !== "regex" && (
136
- <span className="inline-flex items-center gap-1 text-[10px] bg-indigo-50 text-indigo-600 px-1.5 py-0.5 rounded border border-indigo-100">
137
- <Cpu className="w-2.5 h-2.5" />ML
138
- </span>
139
- )}
140
  </div>
141
  </div>
142
  <span className={`self-start sm:self-auto text-sm font-bold px-3 py-1 rounded-full whitespace-nowrap ${
@@ -158,12 +178,12 @@ export default async function DashboardPage() {
158
  )}
159
  </div>
160
 
161
- {/* Upgrade CTA */}
162
- {plan === "free" && (
163
  <div className="mt-8 bg-indigo-50 border border-indigo-200 rounded-xl p-5 sm:p-6 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
164
  <div>
165
  <p className="font-semibold text-indigo-900">Upgrade to Pro</p>
166
- <p className="text-sm text-indigo-700 mt-1">Unlimited scans, contract comparison, PDF exports, obligation tracking, and team features.</p>
167
  </div>
168
  <Link href="/#pricing" className="bg-indigo-600 text-white px-6 py-2.5 rounded-lg font-semibold text-sm hover:bg-indigo-700 transition whitespace-nowrap">
169
  View Plans
 
2
  import Link from "next/link";
3
  import {
4
  ScanText, ShieldCheck, Tag, AlertTriangle, ClipboardList,
5
+ GitCompare, Cpu, Layers, Clock, Crown, PenTool, MessageSquare,
6
+ ScanLine, Settings
7
  } from "lucide-react";
8
 
9
  export default async function DashboardPage() {
 
18
  .order("created_at", { ascending: false }).limit(10);
19
 
20
  const plan = profile?.plan || "free";
21
+ const role = profile?.role || "user";
22
+ const isAdmin = role === "admin";
23
  const usedThisMonth = profile?.analyses_this_month || 0;
24
+ const limit = isAdmin ? "∞" : plan === "free" ? 10 : "";
25
 
26
  const avgRisk = analyses && analyses.length > 0
27
  ? Math.round(analyses.reduce((s: number, a: any) => s + a.risk_score, 0) / analyses.length)
 
39
  <h1 className="text-xl sm:text-2xl font-bold text-gray-900 flex items-center gap-2">
40
  <ShieldCheck className="w-5 h-5 sm:w-6 sm:h-6 text-indigo-500" />
41
  Dashboard
42
+ {isAdmin && (
43
+ <span className="text-xs bg-amber-50 text-amber-700 border border-amber-200 px-2 py-0.5 rounded-full flex items-center gap-1">
44
+ <Crown className="w-3 h-3" /> Admin
45
+ </span>
46
+ )}
47
  </h1>
48
  <p className="text-gray-500 text-sm mt-1">Welcome back, {profile?.full_name || user?.email}</p>
49
  </div>
50
+ <div className="flex gap-2">
51
+ {isAdmin && (
52
+ <Link href="/admin"
53
+ className="bg-amber-50 text-amber-700 border border-amber-200 px-4 py-2.5 rounded-xl font-semibold hover:bg-amber-100 transition text-sm whitespace-nowrap flex items-center gap-2">
54
+ <Crown className="w-4 h-4" /> Admin Panel
55
+ </Link>
56
+ )}
57
+ <Link href="/dashboard-pages/analyze"
58
+ className="bg-indigo-600 text-white px-5 sm:px-6 py-2.5 rounded-xl font-semibold hover:bg-indigo-700 transition text-sm whitespace-nowrap">
59
+ + New Scan
60
+ </Link>
61
+ </div>
62
  </div>
63
 
64
  {/* Primary Stats */}
65
  <div className="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-6 mb-8 sm:mb-10">
66
  {[
67
+ { label: "Plan", value: isAdmin ? "Admin" : plan, capitalize: true },
68
  { label: "Scans This Month", value: `${usedThisMonth} / ${limit}` },
69
  { label: "Total Scans", value: String(count || 0) },
70
+ { label: "Avg Risk Score", value: avgRisk !== null ? String(avgRisk) : "" },
71
  ].map((s) => (
72
  <div key={s.label} className="bg-white rounded-xl p-4 sm:p-6 border border-gray-200">
73
  <p className="text-xs sm:text-sm text-gray-500">{s.label}</p>
 
97
  </div>
98
 
99
  {/* Quick Actions */}
100
+ <div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4 mb-8 sm:mb-10">
101
+ <Link href="/dashboard-pages/analyze" className="bg-white rounded-xl p-5 border border-gray-200 hover:border-indigo-200 hover:shadow-sm transition-all group">
102
  <div className="flex items-center gap-3 mb-2">
103
+ <div className="w-9 h-9 rounded-lg bg-indigo-50 flex items-center justify-center group-hover:bg-indigo-100 transition-colors">
104
+ <ScanText className="w-4.5 h-4.5 text-indigo-600" />
105
  </div>
106
+ <h3 className="font-semibold text-gray-900 text-sm">Analyze Contract</h3>
107
  </div>
108
+ <p className="text-xs text-gray-500">6 ML models: classifier, NER, NLI, embeddings, OCR, LLM.</p>
109
  </Link>
110
+ <Link href="/dashboard-pages/compare" className="bg-white rounded-xl p-5 border border-gray-200 hover:border-indigo-200 hover:shadow-sm transition-all group">
111
  <div className="flex items-center gap-3 mb-2">
112
+ <div className="w-9 h-9 rounded-lg bg-indigo-50 flex items-center justify-center group-hover:bg-indigo-100 transition-colors">
113
+ <GitCompare className="w-4.5 h-4.5 text-indigo-600" />
114
  </div>
115
+ <h3 className="font-semibold text-gray-900 text-sm">Compare Contracts</h3>
116
  </div>
117
+ <p className="text-xs text-gray-500">Side-by-side diff with semantic similarity and risk delta.</p>
118
+ </Link>
119
+ <Link href="/dashboard-pages/settings" className="bg-white rounded-xl p-5 border border-gray-200 hover:border-indigo-200 hover:shadow-sm transition-all group">
120
+ <div className="flex items-center gap-3 mb-2">
121
+ <div className="w-9 h-9 rounded-lg bg-zinc-100 flex items-center justify-center group-hover:bg-zinc-200 transition-colors">
122
+ <Settings className="w-4.5 h-4.5 text-zinc-600" />
123
+ </div>
124
+ <h3 className="font-semibold text-gray-900 text-sm">Settings</h3>
125
+ </div>
126
+ <p className="text-xs text-gray-500">Account, subscription, API keys, team management.</p>
127
  </Link>
128
  </div>
129
 
 
157
  <ClipboardList className="w-2.5 h-2.5" />{a.obligations.length}
158
  </span>
159
  )}
 
 
 
 
 
160
  </div>
161
  </div>
162
  <span className={`self-start sm:self-auto text-sm font-bold px-3 py-1 rounded-full whitespace-nowrap ${
 
178
  )}
179
  </div>
180
 
181
+ {/* Upgrade CTA — only for non-admin free users */}
182
+ {plan === "free" && !isAdmin && (
183
  <div className="mt-8 bg-indigo-50 border border-indigo-200 rounded-xl p-5 sm:p-6 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
184
  <div>
185
  <p className="font-semibold text-indigo-900">Upgrade to Pro</p>
186
+ <p className="text-sm text-indigo-700 mt-1">Unlimited scans, file uploads, contract comparison, PDF exports, Q&A chatbot, and LLM-powered redlining.</p>
187
  </div>
188
  <Link href="/#pricing" className="bg-indigo-600 text-white px-6 py-2.5 rounded-lg font-semibold text-sm hover:bg-indigo-700 transition whitespace-nowrap">
189
  View Plans
web/app/dashboard-pages/settings/page.tsx CHANGED
@@ -1,7 +1,10 @@
1
  import { createClient } from "@/lib/supabase/server";
2
  import { redirect } from "next/navigation";
3
  import Link from "next/link";
4
- import { ArrowLeft, User, CreditCard, LogOut, CircleAlert } from "lucide-react";
 
 
 
5
 
6
  async function handleCancel() {
7
  "use server";
@@ -27,6 +30,21 @@ async function handleSignOut() {
27
  redirect("/");
28
  }
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  export default async function SettingsPage() {
31
  const supabase = await createClient();
32
  const { data: { user } } = await supabase.auth.getUser();
@@ -38,10 +56,29 @@ export default async function SettingsPage() {
38
  .single();
39
 
40
  const plan = profile?.plan || "free";
 
 
41
  const used = profile?.analyses_this_month || 0;
42
- const limit = plan === "free" ? "10" : "Unlimited";
43
  const hasSub = !!profile?.razorpay_subscription_id;
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  return (
46
  <div className="min-h-screen bg-white">
47
  <div className="max-w-2xl mx-auto px-5 py-12">
@@ -61,13 +98,52 @@ export default async function SettingsPage() {
61
  <div className="border border-zinc-200 rounded-xl divide-y divide-zinc-100">
62
  <div className="px-5 py-4 flex justify-between items-center">
63
  <div><p className="text-sm font-medium">Email</p><p className="text-sm text-zinc-500">{user?.email}</p></div>
 
64
  </div>
65
  <div className="px-5 py-4 flex justify-between items-center">
66
  <div><p className="text-sm font-medium">Name</p><p className="text-sm text-zinc-500">{profile?.full_name || "Not set"}</p></div>
67
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  </div>
69
  </section>
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  {/* Subscription */}
72
  <section className="mb-8">
73
  <div className="flex items-center gap-2 mb-3">
@@ -76,15 +152,40 @@ export default async function SettingsPage() {
76
  </div>
77
  <div className="border border-zinc-200 rounded-xl divide-y divide-zinc-100">
78
  <div className="px-5 py-4 flex justify-between items-center">
79
- <div><p className="text-sm font-medium">Plan</p><p className="text-sm text-zinc-500 capitalize">{plan}</p></div>
80
- {plan === "free" ? (
 
 
 
 
 
 
81
  <Link href="/#pricing" className="text-sm font-medium border border-zinc-200 px-3 py-1.5 rounded-lg hover:bg-zinc-50 transition-colors">Upgrade</Link>
82
  ) : null}
83
  </div>
84
  <div className="px-5 py-4 flex justify-between items-center">
85
- <div><p className="text-sm font-medium">Usage this month</p><p className="text-sm text-zinc-500">{used} / {limit} scans</p></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  </div>
87
- {hasSub && plan !== "free" && (
88
  <div className="px-5 py-4">
89
  <form action={handleCancel}>
90
  <button type="submit" className="flex items-center gap-2 text-sm text-red-600 font-medium border border-red-200 px-3 py-1.5 rounded-lg hover:bg-red-50 transition-colors">
@@ -98,15 +199,83 @@ export default async function SettingsPage() {
98
  </div>
99
  </section>
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  {/* Sign out */}
102
- <section>
103
  <form action={handleSignOut}>
104
- <button type="submit" className="flex items-center gap-2 text-sm text-zinc-500 font-medium border border-zinc-200 px-4 py-2 rounded-lg hover:bg-zinc-50 transition-colors">
105
  <LogOut className="w-4 h-4" />
106
  Sign out
107
  </button>
108
  </form>
109
  </section>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  </div>
111
  </div>
112
  );
 
1
  import { createClient } from "@/lib/supabase/server";
2
  import { redirect } from "next/navigation";
3
  import Link from "next/link";
4
+ import {
5
+ ArrowLeft, User, CreditCard, LogOut, CircleAlert, Key, Users,
6
+ Shield, Crown, Calendar, Hash, Mail, Globe, Trash2, AlertTriangle
7
+ } from "lucide-react";
8
 
9
  async function handleCancel() {
10
  "use server";
 
30
  redirect("/");
31
  }
32
 
33
+ async function handleDeleteAccount() {
34
+ "use server";
35
+ const supabase = await createClient();
36
+ const { data: { user } } = await supabase.auth.getUser();
37
+ if (!user) redirect("/auth/login");
38
+
39
+ // Delete user data (analyses, api keys)
40
+ await supabase.from("analyses").delete().eq("user_id", user.id);
41
+ await supabase.from("api_keys").delete().eq("user_id", user.id);
42
+ await supabase.from("profiles").delete().eq("id", user.id);
43
+
44
+ await supabase.auth.signOut();
45
+ redirect("/?deleted=true");
46
+ }
47
+
48
  export default async function SettingsPage() {
49
  const supabase = await createClient();
50
  const { data: { user } } = await supabase.auth.getUser();
 
56
  .single();
57
 
58
  const plan = profile?.plan || "free";
59
+ const role = profile?.role || "user";
60
+ const isAdmin = role === "admin";
61
  const used = profile?.analyses_this_month || 0;
62
+ const limit = isAdmin ? "Unlimited" : plan === "free" ? "10" : "Unlimited";
63
  const hasSub = !!profile?.razorpay_subscription_id;
64
 
65
+ // Fetch API keys
66
+ const { data: apiKeys } = await supabase
67
+ .from("api_keys")
68
+ .select("id, name, key_prefix, calls_this_month, calls_limit, is_active, created_at")
69
+ .eq("user_id", user?.id)
70
+ .order("created_at", { ascending: false });
71
+
72
+ // Fetch team info
73
+ let team = null;
74
+ let teamMembers = 0;
75
+ if (profile?.team_id) {
76
+ const { data: t } = await supabase.from("teams").select("name, max_seats").eq("id", profile.team_id).single();
77
+ team = t;
78
+ const { count } = await supabase.from("profiles").select("id", { count: "exact", head: true }).eq("team_id", profile.team_id);
79
+ teamMembers = count || 0;
80
+ }
81
+
82
  return (
83
  <div className="min-h-screen bg-white">
84
  <div className="max-w-2xl mx-auto px-5 py-12">
 
98
  <div className="border border-zinc-200 rounded-xl divide-y divide-zinc-100">
99
  <div className="px-5 py-4 flex justify-between items-center">
100
  <div><p className="text-sm font-medium">Email</p><p className="text-sm text-zinc-500">{user?.email}</p></div>
101
+ <Mail className="w-4 h-4 text-zinc-300" />
102
  </div>
103
  <div className="px-5 py-4 flex justify-between items-center">
104
  <div><p className="text-sm font-medium">Name</p><p className="text-sm text-zinc-500">{profile?.full_name || "Not set"}</p></div>
105
  </div>
106
+ <div className="px-5 py-4 flex justify-between items-center">
107
+ <div><p className="text-sm font-medium">Role</p><p className="text-sm text-zinc-500 capitalize flex items-center gap-1.5">
108
+ {isAdmin && <Crown className="w-3.5 h-3.5 text-amber-500" />}
109
+ {role}
110
+ {isAdmin && <span className="text-[10px] bg-amber-50 text-amber-700 border border-amber-200 px-1.5 py-0.5 rounded">Full access</span>}
111
+ </p></div>
112
+ <Shield className="w-4 h-4 text-zinc-300" />
113
+ </div>
114
+ <div className="px-5 py-4 flex justify-between items-center">
115
+ <div><p className="text-sm font-medium">Account ID</p><p className="text-xs text-zinc-400 font-mono">{user?.id}</p></div>
116
+ <Hash className="w-4 h-4 text-zinc-300" />
117
+ </div>
118
+ <div className="px-5 py-4 flex justify-between items-center">
119
+ <div><p className="text-sm font-medium">Joined</p><p className="text-sm text-zinc-500">{profile?.created_at ? new Date(profile.created_at).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }) : "—"}</p></div>
120
+ <Calendar className="w-4 h-4 text-zinc-300" />
121
+ </div>
122
+ <div className="px-5 py-4 flex justify-between items-center">
123
+ <div><p className="text-sm font-medium">Last Updated</p><p className="text-sm text-zinc-500">{profile?.updated_at ? new Date(profile.updated_at).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }) : "—"}</p></div>
124
+ </div>
125
  </div>
126
  </section>
127
 
128
+ {/* Admin Quick Access */}
129
+ {isAdmin && (
130
+ <section className="mb-8">
131
+ <div className="flex items-center gap-2 mb-3">
132
+ <Crown className="w-4 h-4 text-amber-500" />
133
+ <h2 className="text-sm font-medium text-amber-600 uppercase tracking-wider">Admin</h2>
134
+ </div>
135
+ <Link href="/admin" className="flex items-center gap-3 border border-amber-200 bg-amber-50/50 rounded-xl px-5 py-4 hover:bg-amber-50 transition-colors">
136
+ <div className="w-10 h-10 rounded-lg bg-amber-100 flex items-center justify-center">
137
+ <Crown className="w-5 h-5 text-amber-600" />
138
+ </div>
139
+ <div>
140
+ <p className="text-sm font-semibold text-amber-900">Open Admin Panel</p>
141
+ <p className="text-xs text-amber-600">Manage users, view all scans, teams, API keys, activity logs</p>
142
+ </div>
143
+ </Link>
144
+ </section>
145
+ )}
146
+
147
  {/* Subscription */}
148
  <section className="mb-8">
149
  <div className="flex items-center gap-2 mb-3">
 
152
  </div>
153
  <div className="border border-zinc-200 rounded-xl divide-y divide-zinc-100">
154
  <div className="px-5 py-4 flex justify-between items-center">
155
+ <div>
156
+ <p className="text-sm font-medium">Plan</p>
157
+ <p className="text-sm text-zinc-500 capitalize flex items-center gap-1.5">
158
+ {plan}
159
+ {isAdmin && <span className="text-[10px] bg-indigo-50 text-indigo-700 border border-indigo-200 px-1.5 py-0.5 rounded">Admin override</span>}
160
+ </p>
161
+ </div>
162
+ {!isAdmin && plan === "free" ? (
163
  <Link href="/#pricing" className="text-sm font-medium border border-zinc-200 px-3 py-1.5 rounded-lg hover:bg-zinc-50 transition-colors">Upgrade</Link>
164
  ) : null}
165
  </div>
166
  <div className="px-5 py-4 flex justify-between items-center">
167
+ <div>
168
+ <p className="text-sm font-medium">Usage this month</p>
169
+ <p className="text-sm text-zinc-500">{used} / {limit} scans</p>
170
+ </div>
171
+ </div>
172
+ <div className="px-5 py-4 flex justify-between items-center">
173
+ <div>
174
+ <p className="text-sm font-medium">Features</p>
175
+ <div className="mt-1 flex flex-wrap gap-1.5">
176
+ {(isAdmin || plan !== "free") && <span className="text-[10px] bg-emerald-50 text-emerald-700 border border-emerald-200 px-1.5 py-0.5 rounded">Unlimited scans</span>}
177
+ {(isAdmin || plan !== "free") && <span className="text-[10px] bg-blue-50 text-blue-700 border border-blue-200 px-1.5 py-0.5 rounded">File upload</span>}
178
+ {(isAdmin || plan !== "free") && <span className="text-[10px] bg-purple-50 text-purple-700 border border-purple-200 px-1.5 py-0.5 rounded">PDF export</span>}
179
+ {(isAdmin || plan !== "free") && <span className="text-[10px] bg-indigo-50 text-indigo-700 border border-indigo-200 px-1.5 py-0.5 rounded">Comparison</span>}
180
+ <span className="text-[10px] bg-zinc-50 text-zinc-600 border border-zinc-200 px-1.5 py-0.5 rounded">41 clause types</span>
181
+ <span className="text-[10px] bg-zinc-50 text-zinc-600 border border-zinc-200 px-1.5 py-0.5 rounded">ML NER</span>
182
+ <span className="text-[10px] bg-zinc-50 text-zinc-600 border border-zinc-200 px-1.5 py-0.5 rounded">NLI</span>
183
+ <span className="text-[10px] bg-zinc-50 text-zinc-600 border border-zinc-200 px-1.5 py-0.5 rounded">Redlining</span>
184
+ <span className="text-[10px] bg-zinc-50 text-zinc-600 border border-zinc-200 px-1.5 py-0.5 rounded">OCR</span>
185
+ </div>
186
+ </div>
187
  </div>
188
+ {hasSub && plan !== "free" && !isAdmin && (
189
  <div className="px-5 py-4">
190
  <form action={handleCancel}>
191
  <button type="submit" className="flex items-center gap-2 text-sm text-red-600 font-medium border border-red-200 px-3 py-1.5 rounded-lg hover:bg-red-50 transition-colors">
 
199
  </div>
200
  </section>
201
 
202
+ {/* Team Info */}
203
+ {team && (
204
+ <section className="mb-8">
205
+ <div className="flex items-center gap-2 mb-3">
206
+ <Users className="w-4 h-4 text-zinc-400" />
207
+ <h2 className="text-sm font-medium text-zinc-500 uppercase tracking-wider">Team</h2>
208
+ </div>
209
+ <div className="border border-zinc-200 rounded-xl divide-y divide-zinc-100">
210
+ <div className="px-5 py-4 flex justify-between items-center">
211
+ <div><p className="text-sm font-medium">Team Name</p><p className="text-sm text-zinc-500">{team.name}</p></div>
212
+ <Link href="/dashboard-pages/team" className="text-sm font-medium text-indigo-600 hover:text-indigo-700">Manage →</Link>
213
+ </div>
214
+ <div className="px-5 py-4 flex justify-between items-center">
215
+ <div><p className="text-sm font-medium">Members</p><p className="text-sm text-zinc-500">{teamMembers} / {team.max_seats}</p></div>
216
+ </div>
217
+ </div>
218
+ </section>
219
+ )}
220
+
221
+ {/* API Keys */}
222
+ {(isAdmin || plan !== "free") && (
223
+ <section className="mb-8">
224
+ <div className="flex items-center gap-2 mb-3">
225
+ <Key className="w-4 h-4 text-zinc-400" />
226
+ <h2 className="text-sm font-medium text-zinc-500 uppercase tracking-wider">API Keys</h2>
227
+ </div>
228
+ <div className="border border-zinc-200 rounded-xl divide-y divide-zinc-100">
229
+ {apiKeys && apiKeys.length > 0 ? apiKeys.map((k: any) => (
230
+ <div key={k.id} className="px-5 py-3.5 flex justify-between items-center">
231
+ <div>
232
+ <p className="text-sm font-medium flex items-center gap-2">
233
+ {k.name}
234
+ <span className={`text-[10px] px-1.5 py-0.5 rounded ${k.is_active ? "bg-emerald-50 text-emerald-700 border border-emerald-200" : "bg-red-50 text-red-700 border border-red-200"}`}>
235
+ {k.is_active ? "Active" : "Revoked"}
236
+ </span>
237
+ </p>
238
+ <p className="text-xs text-zinc-400 font-mono mt-0.5">{k.key_prefix} · {k.calls_this_month}/{k.calls_limit} calls</p>
239
+ </div>
240
+ </div>
241
+ )) : (
242
+ <div className="px-5 py-6 text-center text-sm text-zinc-400">
243
+ No API keys yet.
244
+ </div>
245
+ )}
246
+ </div>
247
+ </section>
248
+ )}
249
+
250
  {/* Sign out */}
251
+ <section className="mb-8">
252
  <form action={handleSignOut}>
253
+ <button type="submit" className="flex items-center gap-2 text-sm text-zinc-500 font-medium border border-zinc-200 px-4 py-2.5 rounded-lg hover:bg-zinc-50 transition-colors w-full justify-center">
254
  <LogOut className="w-4 h-4" />
255
  Sign out
256
  </button>
257
  </form>
258
  </section>
259
+
260
+ {/* Danger Zone */}
261
+ {!isAdmin && (
262
+ <section>
263
+ <div className="flex items-center gap-2 mb-3">
264
+ <AlertTriangle className="w-4 h-4 text-red-400" />
265
+ <h2 className="text-sm font-medium text-red-400 uppercase tracking-wider">Danger Zone</h2>
266
+ </div>
267
+ <div className="border border-red-200 rounded-xl p-5 bg-red-50/30">
268
+ <p className="text-sm text-zinc-700 font-medium">Delete account</p>
269
+ <p className="text-xs text-zinc-500 mt-1 mb-3">Permanently delete your account, all analyses, and API keys. This cannot be undone.</p>
270
+ <form action={handleDeleteAccount}>
271
+ <button type="submit" className="flex items-center gap-2 text-sm text-red-600 font-medium border border-red-300 bg-white px-3 py-1.5 rounded-lg hover:bg-red-50 transition-colors">
272
+ <Trash2 className="w-3.5 h-3.5" />
273
+ Delete my account
274
+ </button>
275
+ </form>
276
+ </div>
277
+ </section>
278
+ )}
279
  </div>
280
  </div>
281
  );
web/components/nav.tsx CHANGED
@@ -2,23 +2,20 @@
2
 
3
  import Link from "next/link";
4
  import { usePathname } from "next/navigation";
5
- import { ShieldCheck, Menu, X, Crown, GitCompare, MessageSquare } from "lucide-react";
 
 
 
6
  import { useState, useEffect } from "react";
7
  import { createClient } from "@/lib/supabase/client";
8
 
9
- const links = [
10
- { href: "/#features", label: "Features" },
11
- { href: "/#pricing", label: "Pricing" },
12
- { href: "/dashboard-pages/analyze", label: "Scanner" },
13
- { href: "/dashboard-pages/compare", label: "Compare", icon: GitCompare },
14
- ];
15
-
16
  export function Nav() {
17
  const [open, setOpen] = useState(false);
18
  const [userEmail, setUserEmail] = useState<string | null>(null);
19
  const [userRole, setUserRole] = useState<string | null>(null);
 
20
  const pathname = usePathname();
21
- const isDashboard = pathname?.startsWith("/dashboard");
22
  const isAdmin = userRole === "admin";
23
 
24
  useEffect(() => {
@@ -34,69 +31,128 @@ export function Nav() {
34
  .single();
35
  setUserRole(profile?.role || "user");
36
  }
 
37
  });
38
  }, []);
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  return (
41
  <nav className="sticky top-0 z-50 bg-white/80 backdrop-blur-md border-b border-zinc-100">
42
  <div className="max-w-6xl mx-auto px-4 sm:px-5 h-14 flex items-center justify-between">
 
43
  <Link href="/" className="flex items-center gap-2">
44
  <ShieldCheck className="w-5 h-5 text-zinc-900" strokeWidth={2.2} />
45
  <span className="font-semibold text-[15px] tracking-tight text-zinc-900">ClauseGuard</span>
46
  <span className="hidden sm:inline text-[10px] font-medium text-zinc-400 ml-1 border border-zinc-200 px-1.5 py-0.5 rounded">v4.0</span>
47
  </Link>
48
 
 
49
  <div className="hidden md:flex items-center gap-1">
50
- {links.map((l) => (
51
- <a key={l.href} href={l.href}
52
- className="px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50 transition-colors">
53
- {l.label}
54
- </a>
55
- ))}
 
 
 
 
 
 
 
56
 
 
57
  {isAdmin && (
58
  <Link href="/admin"
59
- className="px-3 py-1.5 text-[13px] text-amber-600 hover:text-amber-700 rounded-md hover:bg-amber-50 transition-colors flex items-center gap-1">
 
 
 
 
60
  <Crown className="w-3.5 h-3.5" /> Admin
61
  </Link>
62
  )}
63
 
64
  <div className="w-px h-4 bg-zinc-200 mx-2" />
65
 
66
- {isDashboard || userEmail ? (
67
- <Link href="/dashboard-pages/settings"
68
- className="px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50">
69
- Settings
70
- </Link>
 
 
 
 
 
 
 
 
71
  ) : (
72
- <Link href="/auth/login"
73
- className="px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50">
74
- Log in
75
- </Link>
 
 
 
 
 
 
 
 
76
  )}
77
- <Link href={isDashboard || userEmail ? "/dashboard-pages/analyze" : "/auth/signup"}
78
- className="ml-1 px-3.5 py-1.5 text-[13px] font-medium text-white bg-zinc-900 rounded-md hover:bg-zinc-800 transition-colors">
79
- {isDashboard || userEmail ? "New scan" : "Get started"}
80
- </Link>
81
  </div>
82
 
 
83
  <button className="md:hidden p-1.5 rounded-md hover:bg-zinc-100" onClick={() => setOpen(!open)}>
84
  {open ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
85
  </button>
86
  </div>
87
 
 
88
  {open && (
89
  <div className="md:hidden border-t border-zinc-100 bg-white px-5 py-3 space-y-1">
90
  {links.map((l) => (
91
- <a key={l.href} href={l.href} onClick={() => setOpen(false)}
92
- className="block px-3 py-2 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">{l.label}</a>
93
  ))}
94
  {isAdmin && (
95
  <Link href="/admin" onClick={() => setOpen(false)}
96
- className="block px-3 py-2 text-sm text-amber-600 rounded-md hover:bg-amber-50">Admin</Link>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  )}
98
- <Link href="/auth/login" onClick={() => setOpen(false)}
99
- className="block px-3 py-2 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">Log in</Link>
100
  </div>
101
  )}
102
  </nav>
 
2
 
3
  import Link from "next/link";
4
  import { usePathname } from "next/navigation";
5
+ import {
6
+ ShieldCheck, Menu, X, Crown, GitCompare, LayoutDashboard,
7
+ ScanText, Settings, LogIn, Zap
8
+ } from "lucide-react";
9
  import { useState, useEffect } from "react";
10
  import { createClient } from "@/lib/supabase/client";
11
 
 
 
 
 
 
 
 
12
  export function Nav() {
13
  const [open, setOpen] = useState(false);
14
  const [userEmail, setUserEmail] = useState<string | null>(null);
15
  const [userRole, setUserRole] = useState<string | null>(null);
16
+ const [loaded, setLoaded] = useState(false);
17
  const pathname = usePathname();
18
+ const isLoggedIn = !!userEmail;
19
  const isAdmin = userRole === "admin";
20
 
21
  useEffect(() => {
 
31
  .single();
32
  setUserRole(profile?.role || "user");
33
  }
34
+ setLoaded(true);
35
  });
36
  }, []);
37
 
38
+ // Build links dynamically based on auth state
39
+ const publicLinks = [
40
+ { href: "/#features", label: "Features" },
41
+ { href: "/#pricing", label: "Pricing" },
42
+ ];
43
+
44
+ const appLinks = [
45
+ { href: "/dashboard-pages/dashboard", label: "Dashboard", icon: LayoutDashboard },
46
+ { href: "/dashboard-pages/analyze", label: "Scanner", icon: ScanText },
47
+ { href: "/dashboard-pages/compare", label: "Compare", icon: GitCompare },
48
+ ];
49
+
50
+ const links = isLoggedIn ? appLinks : publicLinks;
51
+
52
  return (
53
  <nav className="sticky top-0 z-50 bg-white/80 backdrop-blur-md border-b border-zinc-100">
54
  <div className="max-w-6xl mx-auto px-4 sm:px-5 h-14 flex items-center justify-between">
55
+ {/* Logo */}
56
  <Link href="/" className="flex items-center gap-2">
57
  <ShieldCheck className="w-5 h-5 text-zinc-900" strokeWidth={2.2} />
58
  <span className="font-semibold text-[15px] tracking-tight text-zinc-900">ClauseGuard</span>
59
  <span className="hidden sm:inline text-[10px] font-medium text-zinc-400 ml-1 border border-zinc-200 px-1.5 py-0.5 rounded">v4.0</span>
60
  </Link>
61
 
62
+ {/* Desktop Nav */}
63
  <div className="hidden md:flex items-center gap-1">
64
+ {links.map((l) => {
65
+ const Icon = "icon" in l ? l.icon : null;
66
+ const isActive = pathname === l.href;
67
+ return (
68
+ <Link key={l.href} href={l.href}
69
+ className={`flex items-center gap-1.5 px-3 py-1.5 text-[13px] rounded-md transition-colors ${
70
+ isActive ? "text-zinc-900 bg-zinc-100 font-medium" : "text-zinc-500 hover:text-zinc-900 hover:bg-zinc-50"
71
+ }`}>
72
+ {Icon && <Icon className="w-3.5 h-3.5" />}
73
+ {l.label}
74
+ </Link>
75
+ );
76
+ })}
77
 
78
+ {/* Admin link — always visible for admins */}
79
  {isAdmin && (
80
  <Link href="/admin"
81
+ className={`flex items-center gap-1.5 px-3 py-1.5 text-[13px] rounded-md transition-colors ${
82
+ pathname === "/admin"
83
+ ? "text-amber-700 bg-amber-50 font-medium"
84
+ : "text-amber-600 hover:text-amber-700 hover:bg-amber-50"
85
+ }`}>
86
  <Crown className="w-3.5 h-3.5" /> Admin
87
  </Link>
88
  )}
89
 
90
  <div className="w-px h-4 bg-zinc-200 mx-2" />
91
 
92
+ {isLoggedIn ? (
93
+ <>
94
+ <Link href="/dashboard-pages/settings"
95
+ className={`flex items-center gap-1.5 px-3 py-1.5 text-[13px] rounded-md transition-colors ${
96
+ pathname?.includes("settings") ? "text-zinc-900 bg-zinc-100" : "text-zinc-500 hover:text-zinc-900 hover:bg-zinc-50"
97
+ }`}>
98
+ <Settings className="w-3.5 h-3.5" /> Settings
99
+ </Link>
100
+ <Link href="/dashboard-pages/analyze"
101
+ className="ml-1 px-3.5 py-1.5 text-[13px] font-medium text-white bg-zinc-900 rounded-md hover:bg-zinc-800 transition-colors flex items-center gap-1.5">
102
+ <Zap className="w-3.5 h-3.5" /> New scan
103
+ </Link>
104
+ </>
105
  ) : (
106
+ <>
107
+ {!isLoggedIn && loaded && (
108
+ <Link href="/auth/login"
109
+ className="flex items-center gap-1.5 px-3 py-1.5 text-[13px] text-zinc-500 hover:text-zinc-900 rounded-md hover:bg-zinc-50 transition-colors">
110
+ <LogIn className="w-3.5 h-3.5" /> Log in
111
+ </Link>
112
+ )}
113
+ <Link href="/auth/signup"
114
+ className="ml-1 px-3.5 py-1.5 text-[13px] font-medium text-white bg-zinc-900 rounded-md hover:bg-zinc-800 transition-colors">
115
+ Get started
116
+ </Link>
117
+ </>
118
  )}
 
 
 
 
119
  </div>
120
 
121
+ {/* Mobile hamburger */}
122
  <button className="md:hidden p-1.5 rounded-md hover:bg-zinc-100" onClick={() => setOpen(!open)}>
123
  {open ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
124
  </button>
125
  </div>
126
 
127
+ {/* Mobile Menu */}
128
  {open && (
129
  <div className="md:hidden border-t border-zinc-100 bg-white px-5 py-3 space-y-1">
130
  {links.map((l) => (
131
+ <Link key={l.href} href={l.href} onClick={() => setOpen(false)}
132
+ className="block px-3 py-2.5 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">{l.label}</Link>
133
  ))}
134
  {isAdmin && (
135
  <Link href="/admin" onClick={() => setOpen(false)}
136
+ className="block px-3 py-2.5 text-sm text-amber-600 rounded-md hover:bg-amber-50 flex items-center gap-2">
137
+ <Crown className="w-4 h-4" /> Admin Panel
138
+ </Link>
139
+ )}
140
+ <div className="h-px bg-zinc-100 my-2" />
141
+ {isLoggedIn ? (
142
+ <>
143
+ <Link href="/dashboard-pages/settings" onClick={() => setOpen(false)}
144
+ className="block px-3 py-2.5 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">Settings</Link>
145
+ <Link href="/dashboard-pages/analyze" onClick={() => setOpen(false)}
146
+ className="block px-3 py-2.5 text-sm font-medium text-white bg-zinc-900 rounded-lg text-center hover:bg-zinc-800">New Scan</Link>
147
+ </>
148
+ ) : (
149
+ <>
150
+ <Link href="/auth/login" onClick={() => setOpen(false)}
151
+ className="block px-3 py-2.5 text-sm text-zinc-600 rounded-md hover:bg-zinc-50">Log in</Link>
152
+ <Link href="/auth/signup" onClick={() => setOpen(false)}
153
+ className="block px-3 py-2.5 text-sm font-medium text-white bg-zinc-900 rounded-lg text-center hover:bg-zinc-800">Get started</Link>
154
+ </>
155
  )}
 
 
156
  </div>
157
  )}
158
  </nav>