mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 17:29:45 +00:00
Complete WhatsApp CRM application built with Next.js 14 (App Router), Supabase (PostgreSQL + Auth + Realtime), and shadcn/ui. Features: - Auth: Login, signup, forgot password with Supabase Auth - Dashboard: Analytics overview with stats, recent activity - Inbox: Real-time WhatsApp conversations with message threading - Contacts: CRUD with tags, custom fields, notes, CSV import - Broadcasts: 4-step wizard with audience selection, template sending - Pipelines: Kanban board with deal management - Settings: WhatsApp API config, templates, tags - WhatsApp API: Webhook (verify + receive), send, broadcast, media proxy - Database: 16 tables with RLS policies, indexes, realtime subscriptions - Dark theme throughout with emerald accents Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
126 lines
4.2 KiB
TypeScript
126 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { cn } from "@/lib/utils";
|
|
import { useAuth } from "@/hooks/use-auth";
|
|
import {
|
|
LayoutDashboard,
|
|
MessageSquare,
|
|
Users,
|
|
GitBranch,
|
|
Radio,
|
|
Zap,
|
|
Settings,
|
|
LogOut,
|
|
} from "lucide-react";
|
|
|
|
const navItems = [
|
|
{ href: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
|
|
{ href: "/dashboard/inbox", label: "Inbox", icon: MessageSquare },
|
|
{ href: "/dashboard/contacts", label: "Contacts", icon: Users },
|
|
{ href: "/dashboard/pipelines", label: "Pipelines", icon: GitBranch },
|
|
{ href: "/dashboard/broadcasts", label: "Broadcasts", icon: Radio },
|
|
{ href: "/dashboard/automations", label: "Automations", icon: Zap },
|
|
];
|
|
|
|
const bottomNavItems = [
|
|
{ href: "/dashboard/settings", label: "Settings", icon: Settings },
|
|
];
|
|
|
|
export function Sidebar() {
|
|
const pathname = usePathname();
|
|
const { profile, signOut } = useAuth();
|
|
|
|
return (
|
|
<aside className="flex h-screen w-60 flex-col border-r border-slate-800 bg-slate-900">
|
|
{/* Logo */}
|
|
<div className="flex h-14 items-center gap-2 border-b border-slate-800 px-4">
|
|
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-emerald-500">
|
|
<MessageSquare className="h-4 w-4 text-white" />
|
|
</div>
|
|
<span className="text-lg font-semibold text-white">WaCRM</span>
|
|
</div>
|
|
|
|
{/* Main navigation */}
|
|
<nav className="flex-1 overflow-y-auto px-3 py-4">
|
|
<ul className="flex flex-col gap-1">
|
|
{navItems.map((item) => {
|
|
const isActive =
|
|
pathname === item.href ||
|
|
(item.href !== "/dashboard" && pathname.startsWith(item.href));
|
|
|
|
return (
|
|
<li key={item.href}>
|
|
<Link
|
|
href={item.href}
|
|
className={cn(
|
|
"flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors",
|
|
isActive
|
|
? "bg-emerald-500/10 text-emerald-500"
|
|
: "text-slate-400 hover:bg-slate-800 hover:text-white"
|
|
)}
|
|
>
|
|
<item.icon className="h-4 w-4" />
|
|
{item.label}
|
|
</Link>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
|
|
{/* Divider */}
|
|
<div className="my-4 border-t border-slate-800" />
|
|
|
|
{/* Bottom nav items */}
|
|
<ul className="flex flex-col gap-1">
|
|
{bottomNavItems.map((item) => {
|
|
const isActive = pathname.startsWith(item.href);
|
|
|
|
return (
|
|
<li key={item.href}>
|
|
<Link
|
|
href={item.href}
|
|
className={cn(
|
|
"flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors",
|
|
isActive
|
|
? "bg-emerald-500/10 text-emerald-500"
|
|
: "text-slate-400 hover:bg-slate-800 hover:text-white"
|
|
)}
|
|
>
|
|
<item.icon className="h-4 w-4" />
|
|
{item.label}
|
|
</Link>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
</nav>
|
|
|
|
{/* User section */}
|
|
<div className="border-t border-slate-800 p-3">
|
|
<div className="flex items-center gap-3 rounded-lg px-3 py-2">
|
|
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-emerald-500/10 text-sm font-medium text-emerald-500">
|
|
{profile?.full_name?.charAt(0)?.toUpperCase() ?? "U"}
|
|
</div>
|
|
<div className="min-w-0 flex-1">
|
|
<p className="truncate text-sm font-medium text-white">
|
|
{profile?.full_name ?? "User"}
|
|
</p>
|
|
<p className="truncate text-xs text-slate-400">
|
|
{profile?.email ?? ""}
|
|
</p>
|
|
</div>
|
|
<button
|
|
onClick={signOut}
|
|
className="rounded-md p-1.5 text-slate-400 transition-colors hover:bg-slate-800 hover:text-white"
|
|
title="Sign out"
|
|
>
|
|
<LogOut className="h-4 w-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|