system-prompts-and-models-o.../salesflow-saas/frontend/src/app/dashboard/page.tsx
Cursor Agent 8c3d91c070
fix(dealix): resolve Python deps, SQLAlchemy metadata, JWT, and frontend CI
- Align httpx, litellm, langchain, openai, mem0ai, crewai, numpy, requests, pydantic
- Rename SequenceEvent ORM attribute to event_metadata (DB column stays metadata)
- Use PyJWT instead of python-jose in security and auth service
- Mem0: MemoryConfig + graceful fallback when init fails (CI without keys)
- Frontend: I18nProvider in root layout, fix dashboard LeadScoreCard props, Section id,
  kpi-card useRef, en.json nameAr parity, e2e assertion for premium landing
- README: troubleshooting for connection refused and local E2E Playwright install

Co-authored-by: VoXc2 <VoXc2@users.noreply.github.com>
2026-04-12 10:32:05 +00:00

263 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { useRequireAuth } from "@/contexts/auth-context";
import {
BarChart3,
Users,
Target,
Zap,
Bell,
Search,
BrainCircuit,
Settings,
BookOpen,
MonitorPlay,
FileSignature,
ShieldCheck,
Phone,
Building2,
DollarSign,
Brain,
LineChart,
ClipboardList,
Receipt,
Layers,
LogOut,
MousePointerClick,
UserCheck,
TrendingUp,
Crosshair,
} from "lucide-react";
import { DashboardView } from "../../components/dealix/dashboard-view";
import { AffiliatesView } from "../../components/dealix/affiliates-view";
import { ChatbotView } from "../../components/dealix/chatbot-view";
import { PresentationsView } from "../../components/dealix/presentations-view";
import { ScriptsView } from "../../components/dealix/scripts-view";
import { AgreementsView } from "../../components/dealix/agreements-view";
import { GuaranteesView } from "../../components/dealix/guarantees-view";
import { OnboardingView } from "../../components/dealix/onboarding-view";
import { PropertiesView } from "../../components/dealix/properties-view";
import { RevenueView } from "../../components/dealix/revenue-view";
import { KnowledgeView } from "../../components/dealix/knowledge-view";
import { AnalyticsView } from "../../components/dealix/analytics-view";
import { BusinessImpactView } from "../../components/dealix/business-impact-view";
import { CustomerOnboardingJourneyView } from "../../components/dealix/customer-onboarding-journey-view";
import { IntelligenceDashboard } from "../../components/dealix/intelligence-dashboard";
import { LeadGeneratorView } from "../../components/dealix/lead-generator-view";
import { SalesOsView } from "../../components/dealix/sales-os-view";
import { FullOpsView } from "../../components/dealix/full-ops-view";
import { PipelineKanban } from "../../components/dealix/pipeline-kanban";
import { UnifiedInbox } from "../../components/dealix/unified-inbox";
import { LeadScoreCard } from "../../components/dealix/lead-score-card";
const dashboardLeadScoreDemo = {
score: 82,
breakdown: [
{ key: "engagement", label: "التفاعل", value: 24, icon: MousePointerClick },
{ key: "profile", label: "الملف الشخصي", value: 20, icon: UserCheck },
{ key: "behavior", label: "السلوك", value: 22, icon: TrendingUp },
{ key: "intent", label: "نية الشراء", value: 16, icon: Crosshair },
],
recommendation: "عميل واعد — تابع خلال ٢٤ ساعة",
};
export default function DashboardPage() {
const auth = useRequireAuth();
const [activeTab, setActiveTab] = useState("overview");
if (auth.loading) {
return (
<div className="min-h-screen flex items-center justify-center text-muted-foreground">
جاري التحقق من الجلسة
</div>
);
}
if (!auth.user) {
return null;
}
const NAV_ITEMS = [
{ id: "overview", label: "لوحة القيادة والمراقبة", icon: BarChart3 },
{ id: "business-impact", label: "القيمة للشركات", icon: LineChart },
{ id: "customer-journey", label: "مسار التشغيل مع العميل", icon: ClipboardList },
{ id: "intelligence", label: "الذكاء المستقل — Manus", icon: BrainCircuit },
{ id: "leads", label: "توليد العملاء — AI", icon: Target },
{ id: "properties", label: "إدارة المخزون العقاري", icon: Building2 },
{ id: "affiliates", label: "المسوقين والموظفين", icon: Users },
{ id: "agents", label: "الوكلاء الأذكياء", icon: BrainCircuit },
{ id: "revenue", label: "المالية والتحصيل", icon: DollarSign },
{ id: "sales-os", label: "دفتر العمولة (Sales OS)", icon: Receipt },
{ id: "full-ops", label: "التشغيل الشامل (Full Ops)", icon: Layers },
{ id: "analytics", label: "التحليلات ونبض السوق", icon: BarChart3 },
{ id: "knowledge", label: "الذكاء والمعرفة", icon: Brain },
{ id: "presentations", label: "البرزنتيشنات القطاعية", icon: MonitorPlay },
{ id: "scripts", label: "سكربتات المبيعات", icon: Phone },
{ id: "agreements", label: "الاتفاقيات واHR", icon: FileSignature },
{ id: "guarantee", label: "الضمان الذهبي", icon: ShieldCheck },
{ id: "pipeline", label: "مسار الصفقات", icon: Target },
{ id: "inbox", label: "صندوق الوارد الموحد", icon: Bell },
{ id: "scoring", label: "تقييم العملاء AI", icon: Zap },
{ id: "onboarding", label: "تأهيل المسوق", icon: BookOpen },
];
const renderContent = () => {
switch (activeTab) {
case "overview":
return <DashboardView />;
case "business-impact":
return <BusinessImpactView />;
case "customer-journey":
return <CustomerOnboardingJourneyView />;
case "intelligence":
return <IntelligenceDashboard />;
case "leads":
return <LeadGeneratorView />;
case "properties":
return <PropertiesView />;
case "affiliates":
return <AffiliatesView />;
case "agents":
return <ChatbotView />;
case "revenue":
return <RevenueView />;
case "sales-os":
return <SalesOsView />;
case "full-ops":
return <FullOpsView />;
case "analytics":
return <AnalyticsView />;
case "knowledge":
return <KnowledgeView />;
case "presentations":
return <PresentationsView />;
case "scripts":
return <ScriptsView />;
case "agreements":
return <AgreementsView />;
case "guarantee":
return <GuaranteesView />;
case "pipeline":
return <PipelineKanban />;
case "inbox":
return <UnifiedInbox />;
case "scoring":
return <LeadScoreCard data={dashboardLeadScoreDemo} />;
case "onboarding":
return <OnboardingView />;
default:
return <DashboardView />;
}
};
return (
<div className="min-h-screen flex w-full">
<aside className="w-72 hidden lg:flex flex-col border-l border-border bg-card/50 backdrop-blur-xl">
<div className="h-20 flex items-center px-8 border-b border-border">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-gradient-to-tr from-primary to-accent flex items-center justify-center shadow-lg shadow-primary/20">
<Zap className="w-5 h-5 text-white" />
</div>
<span className="text-xl font-bold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-white to-white/70">
Dealix OS
</span>
</div>
</div>
<nav className="flex-1 p-4 space-y-1 overflow-y-auto">
{NAV_ITEMS.map((item) => (
<button
key={item.id}
type="button"
onClick={() => setActiveTab(item.id)}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl transition-all duration-200 ${
activeTab === item.id
? "bg-primary/10 text-primary font-bold border border-primary/20 shadow-sm"
: "text-muted-foreground hover:bg-secondary/50 hover:text-foreground font-medium"
}`}
>
<item.icon className={`w-5 h-5 ${activeTab === item.id ? "text-primary" : "opacity-70"}`} />
<span>{item.label}</span>
</button>
))}
</nav>
<div className="p-4 mt-auto border-t border-border/50 bg-secondary/10">
<button
type="button"
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-muted-foreground hover:bg-secondary/50 transition-all font-medium"
>
<Settings className="w-5 h-5" />
<span>الإعدادات المتقدمة</span>
</button>
</div>
</aside>
<main className="flex-1 flex flex-col h-screen overflow-y-auto bg-background/50">
<header className="h-20 flex items-center justify-between px-8 border-b border-border bg-card/50 backdrop-blur-md sticky top-0 z-10 transition-all">
<div className="relative w-96">
<Search className="w-5 h-5 absolute right-4 top-1/2 -translate-y-1/2 text-muted-foreground" />
<input
type="text"
placeholder="البحث الشامل في Dealix (عميل، مسوق، صفقة)..."
className="w-full bg-secondary/50 border border-border rounded-full py-2.5 pr-12 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all font-sans"
/>
</div>
<div className="flex items-center gap-6">
<button type="button" className="relative p-2 text-muted-foreground hover:text-foreground transition-colors">
<Bell className="w-5 h-5" />
<span className="absolute top-1.5 right-1.5 w-2.5 h-2.5 bg-primary border-2 border-background rounded-full animate-pulse" />
</button>
<div className="flex items-center gap-3 pl-4 border-l border-border">
<button
type="button"
onClick={() => auth.logout()}
className="hidden sm:inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground px-2 py-1 rounded-lg border border-border/60"
>
<LogOut className="w-3.5 h-3.5" />
خروج
</button>
<div className="text-left hidden md:block">
<p className="text-sm font-bold truncate max-w-[200px]">{auth.user.email || "مستخدم"}</p>
<p className="text-xs text-muted-foreground">{auth.user.role}</p>
</div>
<div className="w-10 h-10 rounded-full bg-gradient-to-tr from-blue-500 to-primary p-[2px]">
<div className="w-full h-full rounded-full bg-card flex items-center justify-center border-2 border-background">
<span className="text-sm font-bold text-foreground">
{(auth.user.email || "?").slice(0, 2).toUpperCase()}
</span>
</div>
</div>
</div>
</div>
</header>
<div className="flex-1 w-full max-w-[1600px] mx-auto pb-24 lg:pb-0">{renderContent()}</div>
<nav className="lg:hidden fixed bottom-6 left-1/2 -translate-x-1/2 w-[90%] max-w-md bg-card/80 backdrop-blur-2xl border border-white/10 rounded-3xl shadow-2xl flex items-center justify-around py-4 px-4 z-50">
{[
{ id: "overview", icon: BarChart3 },
{ id: "agents", icon: BrainCircuit },
{ id: "presentations", icon: MonitorPlay },
{ id: "scripts", icon: Phone },
].map((item) => (
<button
key={item.id}
type="button"
onClick={() => setActiveTab(item.id)}
className={`flex flex-col items-center gap-1 transition-all ${
activeTab === item.id ? "text-primary scale-110" : "text-muted-foreground opacity-60"
}`}
>
<item.icon className="w-6 h-6" />
{activeTab === item.id && <span className="w-1 h-1 bg-primary rounded-full" />}
</button>
))}
</nav>
</main>
</div>
);
}