mirror of
https://github.com/arkorty/B.Tech-Project-III.git
synced 2026-04-19 12:41:48 +00:00
352 lines
17 KiB
TypeScript
352 lines
17 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Sidebar from "@/components/Sidebar";
|
|
|
|
function Icon({ name, className = "" }: { name: string; className?: string }) {
|
|
return <span className={`material-symbols-outlined ${className}`}>{name}</span>;
|
|
}
|
|
|
|
const PERSONALITIES = [
|
|
{
|
|
key: "aggressive",
|
|
label: "Aggressive",
|
|
desc: "Direct, concise, and prioritizes speed over nuance. Best for rapid execution.",
|
|
icon: "bolt",
|
|
color: "text-red-400",
|
|
bg: "bg-red-500/10",
|
|
},
|
|
{
|
|
key: "empathetic",
|
|
label: "Empathetic",
|
|
desc: "Prioritizes rapport, tone matching, and emotional intelligence. Human-centric.",
|
|
icon: "favorite",
|
|
color: "text-[#B7A6FB]",
|
|
bg: "bg-[#B7A6FB]/20",
|
|
},
|
|
{
|
|
key: "analytical",
|
|
label: "Analytical",
|
|
desc: "Data-driven, cites sources, and avoids assumptions. Highly logical.",
|
|
icon: "query_stats",
|
|
color: "text-blue-400",
|
|
bg: "bg-blue-500/10",
|
|
},
|
|
{
|
|
key: "balanced",
|
|
label: "Balanced",
|
|
desc: "The default setting. Adaptable tone that shifts based on the query complexity.",
|
|
icon: "balance",
|
|
color: "text-emerald-400",
|
|
bg: "bg-green-500/10",
|
|
},
|
|
];
|
|
|
|
const VOICE_MODELS = [
|
|
"Adam (Deep Narration)",
|
|
"Bella (Soft & Professional)",
|
|
"Charlie (Energetic Male)",
|
|
"Dorothy (Warm & Friendly)",
|
|
];
|
|
|
|
export default function PreferencesPage() {
|
|
const [personality, setPersonality] = useState("empathetic");
|
|
const [voiceModel, setVoiceModel] = useState("Bella (Soft & Professional)");
|
|
const [showApiKey, setShowApiKey] = useState(false);
|
|
const [showWebhook, setShowWebhook] = useState(false);
|
|
const [savedToast, setSavedToast] = useState(false);
|
|
|
|
const handleSave = () => {
|
|
setSavedToast(true);
|
|
setTimeout(() => setSavedToast(false), 2500);
|
|
};
|
|
|
|
return (
|
|
<div className="flex h-screen w-full overflow-hidden bg-[#020105] text-slate-300 relative">
|
|
<div className="absolute inset-0 bg-grid-subtle opacity-20 pointer-events-none" />
|
|
<Sidebar />
|
|
|
|
<main className="flex-1 flex flex-col h-full overflow-hidden relative z-10">
|
|
{/* Top bar */}
|
|
<header className="h-16 flex items-center justify-between px-6 bg-[#050505]/80 backdrop-blur-md border-b border-white/5 sticky top-0 z-30 shrink-0">
|
|
<div>
|
|
<h2 className="text-base font-medium text-white tracking-tight">Settings</h2>
|
|
<p className="text-[10px] text-slate-600 mt-0.5">
|
|
negoT8 <span className="text-[#B7A6FB]/60">| Preferences</span>
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<button className="size-9 rounded-lg bg-[#B7A6FB]/10 border border-[#B7A6FB]/20 text-[#B7A6FB] flex items-center justify-center hover:bg-[#B7A6FB]/20 transition-colors">
|
|
<Icon name="notifications" className="text-lg" />
|
|
</button>
|
|
<div className="size-9 rounded-full bg-gradient-to-tr from-[#B7A6FB] to-purple-500 flex items-center justify-center font-bold text-[#020105] text-sm">
|
|
JD
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="flex-1 overflow-y-auto">
|
|
<div className="max-w-[1100px] mx-auto p-6 grid grid-cols-1 lg:grid-cols-12 gap-8">
|
|
{/* Settings sidebar */}
|
|
<aside className="lg:col-span-3 flex flex-col gap-2">
|
|
<nav className="flex flex-col gap-1">
|
|
{[
|
|
{ icon: "person_outline", label: "User Preferences", active: true },
|
|
{ icon: "smart_toy", label: "Agent Clusters", active: false },
|
|
{ icon: "account_balance_wallet", label: "Billing & Credits", active: false },
|
|
{ icon: "shield", label: "Security", active: false },
|
|
].map(({ icon, label, active }) => (
|
|
<button
|
|
key={label}
|
|
className={`flex items-center gap-3 px-4 py-3 rounded-lg text-sm transition-all text-left ${
|
|
active
|
|
? "bg-[#B7A6FB]/10 text-[#B7A6FB] font-medium"
|
|
: "text-slate-400 hover:bg-[#B7A6FB]/5 hover:text-[#B7A6FB]"
|
|
}`}
|
|
>
|
|
<Icon name={icon} className="text-lg" />
|
|
{label}
|
|
</button>
|
|
))}
|
|
</nav>
|
|
<div className="mt-6 p-4 rounded-xl glass-card">
|
|
<p className="text-[10px] uppercase tracking-widest text-[#B7A6FB]/50 font-bold mb-2">
|
|
Plan Status
|
|
</p>
|
|
<p className="text-sm font-medium text-white">Pro Developer</p>
|
|
<div className="w-full bg-white/10 h-1.5 rounded-full mt-3 overflow-hidden">
|
|
<div className="bg-[#B7A6FB] h-full w-[75%] shadow-[0_0_8px_#B7A6FB]" />
|
|
</div>
|
|
<p className="text-[11px] text-slate-500 mt-2">75% of monthly tokens used</p>
|
|
</div>
|
|
</aside>
|
|
|
|
{/* Main settings content */}
|
|
<div className="lg:col-span-9 flex flex-col gap-8">
|
|
{/* Agent Personality */}
|
|
<section className="flex flex-col gap-5">
|
|
<div className="border-b border-white/5 pb-3">
|
|
<h3 className="text-xl font-bold text-[#B7A6FB]">Agent Personality</h3>
|
|
<p className="text-slate-400 text-sm mt-1">
|
|
Define the behavioral tone for your primary AI interactions.
|
|
</p>
|
|
</div>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{PERSONALITIES.map((p) => {
|
|
const isActive = personality === p.key;
|
|
return (
|
|
<button
|
|
key={p.key}
|
|
onClick={() => setPersonality(p.key)}
|
|
className={`rounded-xl p-5 text-left flex flex-col gap-3 transition-all relative overflow-hidden ${
|
|
isActive
|
|
? "border-2 border-[#B7A6FB] bg-[#B7A6FB]/10 shadow-[0_0_20px_rgba(183,166,251,0.15)]"
|
|
: "glass-card hover:border-[#B7A6FB]/30"
|
|
}`}
|
|
>
|
|
{isActive && (
|
|
<div className="absolute top-2 right-2 text-[#B7A6FB]">
|
|
<Icon name="check_circle" className="text-sm" />
|
|
</div>
|
|
)}
|
|
<div className={`size-11 rounded-lg flex items-center justify-center ${p.bg}`}>
|
|
<Icon name={p.icon} className={`${p.color} text-xl`} />
|
|
</div>
|
|
<div>
|
|
<h4 className="font-bold text-white text-sm">{p.label}</h4>
|
|
<p className="text-[11px] text-slate-400 mt-1 leading-relaxed">{p.desc}</p>
|
|
</div>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</section>
|
|
|
|
{/* Voice Synthesis */}
|
|
<section className="flex flex-col gap-5">
|
|
<div className="border-b border-white/5 pb-3 flex justify-between items-end">
|
|
<div>
|
|
<h3 className="text-xl font-bold text-[#B7A6FB]">Voice Synthesis</h3>
|
|
<p className="text-slate-400 text-sm mt-1">
|
|
Configured via ElevenLabs integration for realistic speech.
|
|
</p>
|
|
</div>
|
|
<span className="text-[10px] font-bold uppercase tracking-widest px-2 py-1 bg-[#B7A6FB]/10 text-[#B7A6FB] rounded border border-[#B7A6FB]/20">
|
|
API Connected
|
|
</span>
|
|
</div>
|
|
<div className="glass-card rounded-xl p-5 flex flex-col md:flex-row gap-5 items-center">
|
|
<div className="flex-1 w-full">
|
|
<label className="block text-[10px] font-bold uppercase tracking-tighter text-slate-500 mb-2">
|
|
Voice Model Selection
|
|
</label>
|
|
<div className="relative">
|
|
<select
|
|
value={voiceModel}
|
|
onChange={(e) => setVoiceModel(e.target.value)}
|
|
className="w-full bg-black/40 border border-white/10 rounded-lg px-4 py-3 text-slate-200 focus:ring-2 focus:ring-[#B7A6FB]/30 focus:border-[#B7A6FB]/40 outline-none appearance-none cursor-pointer text-sm transition-all"
|
|
>
|
|
{VOICE_MODELS.map((m) => (
|
|
<option key={m}>{m}</option>
|
|
))}
|
|
</select>
|
|
<div className="absolute inset-y-0 right-3 flex items-center pointer-events-none text-slate-500">
|
|
<Icon name="expand_more" className="text-lg" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-4 w-full md:w-auto">
|
|
<button className="flex-1 md:flex-none flex items-center justify-center gap-2 px-6 py-3 bg-[#B7A6FB] text-[#020105] font-bold rounded-lg hover:brightness-110 transition-all text-sm">
|
|
<Icon name="play_circle" className="text-xl" />
|
|
Preview
|
|
</button>
|
|
{/* Waveform visualizer */}
|
|
<div className="h-12 w-32 glass-card rounded-lg flex items-center justify-center px-3">
|
|
<div className="flex items-center gap-1">
|
|
{[3, 6, 4, 8, 5, 7, 3].map((h, i) => (
|
|
<div
|
|
key={i}
|
|
className={`w-1 rounded-full ${i % 2 === 0 ? "bg-[#B7A6FB]/40 animate-pulse" : "bg-[#B7A6FB]"}`}
|
|
style={{ height: `${h * 3}px` }}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Payments + Security */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
{/* Default UPI */}
|
|
<section className="flex flex-col gap-4">
|
|
<div className="border-b border-white/5 pb-3">
|
|
<h3 className="text-lg font-bold text-[#B7A6FB]">Default Payments</h3>
|
|
<p className="text-slate-400 text-sm mt-1">Linked UPI ID for automated settlement.</p>
|
|
</div>
|
|
<div className="glass-card rounded-xl p-4 flex flex-col gap-3">
|
|
<div className="flex items-center gap-3 p-3 bg-black/40 rounded-lg border border-white/10">
|
|
<div className="text-[#B7A6FB] bg-[#B7A6FB]/10 p-2 rounded">
|
|
<Icon name="account_balance" className="text-lg" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<p className="text-[9px] text-slate-500 font-bold uppercase">Linked UPI</p>
|
|
<p className="text-sm font-medium text-slate-200 font-mono truncate">
|
|
negot8-hq@okaxis
|
|
</p>
|
|
</div>
|
|
<button className="text-slate-500 hover:text-[#B7A6FB] transition-colors">
|
|
<Icon name="edit" className="text-xl" />
|
|
</button>
|
|
</div>
|
|
<button className="w-full py-2 border border-dashed border-[#B7A6FB]/20 rounded-lg text-xs font-bold text-[#B7A6FB]/60 hover:bg-[#B7A6FB]/5 hover:border-[#B7A6FB]/40 hover:text-[#B7A6FB] transition-all tracking-widest">
|
|
+ ADD SECONDARY METHOD
|
|
</button>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Security / API Keys */}
|
|
<section className="flex flex-col gap-4">
|
|
<div className="border-b border-white/5 pb-3 flex justify-between items-center">
|
|
<div>
|
|
<h3 className="text-lg font-bold text-[#B7A6FB]">Security</h3>
|
|
<p className="text-slate-400 text-sm mt-1">Manage environment access.</p>
|
|
</div>
|
|
<button className="text-[#B7A6FB] text-xs font-bold hover:underline transition-all">
|
|
Revoke All
|
|
</button>
|
|
</div>
|
|
<div className="glass-card rounded-xl p-4 flex flex-col gap-4">
|
|
{/* Production API Key */}
|
|
<div>
|
|
<label className="text-[9px] font-bold text-slate-500 uppercase tracking-tighter block mb-1.5">
|
|
Production API Key
|
|
</label>
|
|
<div className="flex items-center gap-2 bg-black/40 border border-white/10 rounded-lg px-3 py-2">
|
|
<input
|
|
type={showApiKey ? "text" : "password"}
|
|
readOnly
|
|
value="sk_mesh_live_483299283749"
|
|
className="bg-transparent border-none focus:ring-0 text-sm text-slate-300 flex-1 font-mono outline-none min-w-0"
|
|
/>
|
|
<button
|
|
onClick={() => setShowApiKey((v) => !v)}
|
|
className="text-slate-500 hover:text-[#B7A6FB] transition-colors shrink-0"
|
|
>
|
|
<Icon name={showApiKey ? "visibility_off" : "visibility"} className="text-lg" />
|
|
</button>
|
|
<button className="text-slate-500 hover:text-[#B7A6FB] transition-colors shrink-0">
|
|
<Icon name="content_copy" className="text-lg" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{/* Webhook Secret */}
|
|
<div>
|
|
<label className="text-[9px] font-bold text-slate-500 uppercase tracking-tighter block mb-1.5">
|
|
Webhook Secret
|
|
</label>
|
|
<div className="flex items-center gap-2 bg-black/40 border border-white/10 rounded-lg px-3 py-2">
|
|
<input
|
|
type={showWebhook ? "text" : "password"}
|
|
readOnly
|
|
value="wh_mesh_123456"
|
|
className="bg-transparent border-none focus:ring-0 text-sm text-slate-300 flex-1 font-mono outline-none min-w-0"
|
|
/>
|
|
<button
|
|
onClick={() => setShowWebhook((v) => !v)}
|
|
className="text-slate-500 hover:text-[#B7A6FB] transition-colors shrink-0"
|
|
>
|
|
<Icon name={showWebhook ? "visibility_off" : "visibility"} className="text-lg" />
|
|
</button>
|
|
<button className="text-slate-500 hover:text-[#B7A6FB] transition-colors shrink-0">
|
|
<Icon name="content_copy" className="text-lg" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
{/* Footer actions */}
|
|
<div className="flex items-center justify-end gap-4 pt-4 border-t border-white/5">
|
|
<button className="px-6 py-2.5 rounded-lg font-bold text-slate-400 hover:text-slate-200 transition-all text-sm">
|
|
Discard Changes
|
|
</button>
|
|
<button
|
|
onClick={handleSave}
|
|
className="px-8 py-2.5 rounded-lg bg-[#B7A6FB] text-[#020105] font-bold shadow-[0_0_20px_rgba(183,166,251,0.2)] hover:scale-[1.02] transition-all text-sm"
|
|
>
|
|
Save Preferences
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<footer className="border-t border-white/5 py-6 px-6 mt-4">
|
|
<div className="max-w-[1100px] mx-auto flex flex-col md:flex-row justify-between items-center gap-4">
|
|
<div className="flex items-center gap-2 text-slate-600">
|
|
<Icon name="verified_user" className="text-lg" />
|
|
<span className="text-xs">End-to-end encryption active for all preference data.</span>
|
|
</div>
|
|
<div className="flex gap-6 text-xs text-slate-500">
|
|
<button className="hover:text-[#B7A6FB] transition-colors">Privacy Policy</button>
|
|
<button className="hover:text-[#B7A6FB] transition-colors">Terms of Mesh</button>
|
|
<span className="text-emerald-400">Status: Operational</span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
</main>
|
|
|
|
{/* Save toast */}
|
|
{savedToast && (
|
|
<div className="fixed bottom-6 right-6 z-50 flex items-center gap-2 px-4 py-3 bg-[#B7A6FB] text-[#020105] rounded-xl font-bold text-sm shadow-[0_0_30px_rgba(183,166,251,0.4)] animate-pulse">
|
|
<Icon name="check_circle" className="text-lg" />
|
|
Preferences saved
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|