# Super Admin Frontend Implementation Plan (NextJS 15)

## Overview
This document outlines the implementation plan for the Super Admin Dashboard frontend using NextJS 15, matching the mobile app theme and providing comprehensive admin functionality.

## Technology Stack

### Core Technologies
- **Framework**: NextJS 15 (App Router)
- **Language**: TypeScript
- **Styling**: TailwindCSS
- **UI Components**: Shadcn/ui or Ant Design
- **State Management**: Zustand
- **HTTP Client**: Axios with React Query (TanStack Query)
- **Forms**: React Hook Form with Zod validation
- **Charts**: Recharts or Chart.js
- **Icons**: Lucide React
- **Date Handling**: date-fns
- **Authentication**: NextAuth.js (optional) or custom JWT handling

### Development Tools
- **Package Manager**: pnpm
- **Linting**: ESLint + Prettier
- **Type Checking**: TypeScript strict mode
- **Testing**: Jest + React Testing Library (optional)

## Project Structure

```
admin-dashboard/
├── src/
│   ├── app/                    # App Router (NextJS 15)
│   │   ├── (auth)/            # Auth group
│   │   │   └── login/
│   │   ├── (dashboard)/       # Dashboard group
│   │   │   ├── dashboard/
│   │   │   ├── users/
│   │   │   ├── vendors/
│   │   │   ├── bookings/
│   │   │   ├── events/
│   │   │   ├── inquiries/
│   │   │   ├── feedback/
│   │   │   ├── notifications/
│   │   │   └── subscriptions/
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   └── page.tsx
│   ├── components/            # Reusable components
│   │   ├── ui/               # Base UI components
│   │   ├── layout/           # Layout components
│   │   ├── forms/            # Form components
│   │   ├── charts/           # Chart components
│   │   └── common/           # Common components
│   ├── hooks/                # Custom React hooks
│   ├── lib/                  # Utility functions
│   ├── services/             # API services
│   ├── stores/               # Zustand stores
│   ├── types/                # TypeScript type definitions
│   └── utils/                # Helper functions
├── public/                   # Static assets
├── tailwind.config.js
├── next.config.js
└── package.json
```

## Design System & Theme

### Color Palette
```css
/* Based on Mobile App Theme */
:root {
  /* Primary Colors */
  --primary-50: #f0f9ff;
  --primary-100: #e0f2fe;
  --primary-500: #0ea5e9;
  --primary-600: #0284c7;
  --primary-700: #0369a1;
  
  /* Secondary Colors */
  --secondary-50: #f8fafc;
  --secondary-100: #f1f5f9;
  --secondary-500: #64748b;
  --secondary-600: #475569;
  
  /* Success */
  --success-50: #f0fdf4;
  --success-500: #22c55e;
  --success-600: #16a34a;
  
  /* Warning */
  --warning-50: #fffbeb;
  --warning-500: #f59e0b;
  --warning-600: #d97706;
  
  /* Error */
  --error-50: #fef2f2;
  --error-500: #ef4444;
  --error-600: #dc2626;
  
  /* Neutral */
  --gray-50: #f9fafb;
  --gray-100: #f3f4f6;
  --gray-200: #e5e7eb;
  --gray-300: #d1d5db;
  --gray-400: #9ca3af;
  --gray-500: #6b7280;
  --gray-600: #4b5563;
  --gray-700: #374151;
  --gray-800: #1f2937;
  --gray-900: #111827;
}
```

### Typography
```css
/* Font Stack */
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

/* Font Sizes */
--text-xs: 0.75rem;    /* 12px */
--text-sm: 0.875rem;   /* 14px */
--text-base: 1rem;     /* 16px */
--text-lg: 1.125rem;   /* 18px */
--text-xl: 1.25rem;    /* 20px */
--text-2xl: 1.5rem;    /* 24px */
--text-3xl: 1.875rem;  /* 30px */
```

## Authentication System

### Login Page Implementation
```tsx
// src/app/(auth)/login/page.tsx
'use client';

import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Loader2, Shield } from 'lucide-react';
import { adminAuthService } from '@/services/admin-auth';
import { useAuthStore } from '@/stores/auth-store';

const loginSchema = z.object({
  email: z.string().email('Please enter a valid email'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
});

type LoginForm = z.infer<typeof loginSchema>;

export default function LoginPage() {
  const router = useRouter();
  const [error, setError] = useState<string>('');
  const [isLoading, setIsLoading] = useState(false);
  const setAuth = useAuthStore((state) => state.setAuth);

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<LoginForm>({
    resolver: zodResolver(loginSchema),
  });

  const onSubmit = async (data: LoginForm) => {
    setIsLoading(true);
    setError('');

    try {
      const response = await adminAuthService.login(data);
      setAuth(response.data.admin, response.data.tokens);
      router.push('/dashboard');
    } catch (err: any) {
      setError(err.response?.data?.message || 'Login failed. Please try again.');
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-primary-50 to-secondary-50 p-4">
      <Card className="w-full max-w-md">
        <CardHeader className="text-center">
          <div className="mx-auto w-12 h-12 bg-primary-500 rounded-full flex items-center justify-center mb-4">
            <Shield className="w-6 h-6 text-white" />
          </div>
          <CardTitle className="text-2xl font-bold">GuideMe Admin</CardTitle>
          <CardDescription>Sign in to your admin dashboard</CardDescription>
        </CardHeader>
        <CardContent>
          <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
            {error && (
              <Alert variant="destructive">
                <AlertDescription>{error}</AlertDescription>
              </Alert>
            )}
            
            <div className="space-y-2">
              <Label htmlFor="email">Email</Label>
              <Input
                id="email"
                type="email"
                placeholder="admin@guideme.com"
                {...register('email')}
                className={errors.email ? 'border-error-500' : ''}
              />
              {errors.email && (
                <p className="text-sm text-error-500">{errors.email.message}</p>
              )}
            </div>

            <div className="space-y-2">
              <Label htmlFor="password">Password</Label>
              <Input
                id="password"
                type="password"
                {...register('password')}
                className={errors.password ? 'border-error-500' : ''}
              />
              {errors.password && (
                <p className="text-sm text-error-500">{errors.password.message}</p>
              )}
            </div>

            <Button type="submit" className="w-full" disabled={isLoading}>
              {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
              Sign In
            </Button>
          </form>
        </CardContent>
      </Card>
    </div>
  );
}
```

## Dashboard Layout System

### Main Layout Component
```tsx
// src/components/layout/dashboard-layout.tsx
'use client';

import { useState } from 'react';
import { Sidebar } from '@/components/layout/sidebar';
import { Header } from '@/components/layout/header';
import { cn } from '@/lib/utils';

interface DashboardLayoutProps {
  children: React.ReactNode;
}

export function DashboardLayout({ children }: DashboardLayoutProps) {
  const [sidebarOpen, setSidebarOpen] = useState(true);

  return (
    <div className="min-h-screen bg-gray-50">
      <Sidebar open={sidebarOpen} />
      <div className={cn(
        "transition-all duration-300",
        sidebarOpen ? "ml-64" : "ml-16"
      )}>
        <Header onMenuClick={() => setSidebarOpen(!sidebarOpen)} />
        <main className="p-6">
          {children}
        </main>
      </div>
    </div>
  );
}
```

### Sidebar Component
```tsx
// src/components/layout/sidebar.tsx
'use client';

import { usePathname } from 'next/navigation';
import Link from 'next/link';
import { cn } from '@/lib/utils';
import {
  LayoutDashboard,
  Users,
  Store,
  Calendar,
  MessageSquare,
  HelpCircle,
  Bell,
  CreditCard,
  BookOpen,
  ChevronLeft
} from 'lucide-react';

interface SidebarProps {
  open: boolean;
}

const navigation = [
  { name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard },
  { name: 'Users', href: '/users', icon: Users },
  { name: 'Vendors', href: '/vendors', icon: Store },
  { name: 'Bookings', href: '/bookings', icon: BookOpen },
  { name: 'Events', href: '/events', icon: Calendar },
  { name: 'Inquiries', href: '/inquiries', icon: MessageSquare },
  { name: 'Support', href: '/feedback', icon: HelpCircle },
  { name: 'Notifications', href: '/notifications', icon: Bell },
  { name: 'Subscriptions', href: '/subscriptions', icon: CreditCard },
];

export function Sidebar({ open }: SidebarProps) {
  const pathname = usePathname();

  return (
    <div className={cn(
      "fixed inset-y-0 left-0 z-50 bg-white shadow-lg transition-all duration-300",
      open ? "w-64" : "w-16"
    )}>
      <div className="flex h-16 items-center justify-center border-b bg-primary-600">
        {open ? (
          <h1 className="text-xl font-bold text-white">GuideMe Admin</h1>
        ) : (
          <div className="w-8 h-8 bg-white rounded-md flex items-center justify-center">
            <span className="text-primary-600 font-bold">G</span>
          </div>
        )}
      </div>
      
      <nav className="mt-8 px-4">
        <ul className="space-y-2">
          {navigation.map((item) => {
            const isActive = pathname === item.href;
            return (
              <li key={item.name}>
                <Link
                  href={item.href}
                  className={cn(
                    "flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors",
                    isActive
                      ? "bg-primary-100 text-primary-700"
                      : "text-gray-600 hover:bg-gray-100 hover:text-gray-900"
                  )}
                >
                  <item.icon className={cn("flex-shrink-0", open ? "mr-3 h-5 w-5" : "h-5 w-5")} />
                  {open && item.name}
                </Link>
              </li>
            );
          })}
        </ul>
      </nav>
    </div>
  );
}
```

## Dashboard Overview Implementation

### Dashboard Page
```tsx
// src/app/(dashboard)/dashboard/page.tsx
'use client';

import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { StatCard } from '@/components/dashboard/stat-card';
import { RecentActivityFeed } from '@/components/dashboard/recent-activity-feed';
import { QuickActions } from '@/components/dashboard/quick-actions';
import { OverviewCharts } from '@/components/dashboard/overview-charts';
import { adminDashboardService } from '@/services/admin-dashboard';
import { Skeleton } from '@/components/ui/skeleton';
import { Users, Store, Calendar, BookOpen, MessageSquare, TrendingUp } from 'lucide-react';

export default function DashboardPage() {
  const { data: overview, isLoading } = useQuery({
    queryKey: ['dashboard-overview'],
    queryFn: adminDashboardService.getOverview,
    refetchInterval: 30000, // Refresh every 30 seconds
  });

  if (isLoading) {
    return (
      <div className="space-y-6">
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
          {[...Array(4)].map((_, i) => (
            <Card key={i}>
              <CardHeader>
                <Skeleton className="h-4 w-24" />
                <Skeleton className="h-8 w-16" />
              </CardHeader>
            </Card>
          ))}
        </div>
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
          <Card>
            <CardHeader>
              <Skeleton className="h-6 w-32" />
            </CardHeader>
            <CardContent>
              <Skeleton className="h-64 w-full" />
            </CardContent>
          </Card>
          <Card>
            <CardHeader>
              <Skeleton className="h-6 w-32" />
            </CardHeader>
            <CardContent>
              <Skeleton className="h-64 w-full" />
            </CardContent>
          </Card>
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-6">
      {/* Welcome Header */}
      <div>
        <h1 className="text-3xl font-bold text-gray-900">Dashboard Overview</h1>
        <p className="text-gray-600 mt-2">
          Welcome back! Here's what's happening with your platform today.
        </p>
      </div>

      {/* Statistics Cards */}
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
        <StatCard
          title="Total Users"
          value={overview?.statistics.totalUsers}
          change={overview?.statistics.newUsersThisWeek}
          changeLabel="new this week"
          icon={Users}
          color="blue"
        />
        <StatCard
          title="Total Vendors"
          value={overview?.statistics.totalVendors}
          change={overview?.statistics.newVendorsThisWeek}
          changeLabel="new this week"
          icon={Store}
          color="green"
        />
        <StatCard
          title="Active Events"
          value={overview?.statistics.totalEvents}
          icon={Calendar}
          color="purple"
        />
        <StatCard
          title="Total Bookings"
          value={overview?.statistics.totalBookings}
          icon={BookOpen}
          color="orange"
        />
      </div>

      {/* Quick Actions */}
      <QuickActions quickAccess={overview?.quickAccess} />

      {/* Charts and Activity */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        <OverviewCharts />
        <RecentActivityFeed activities={overview?.recentActivity} />
      </div>
    </div>
  );
}
```

### Statistics Card Component
```tsx
// src/components/dashboard/stat-card.tsx
import { Card, CardContent } from '@/components/ui/card';
import { cn } from '@/lib/utils';
import { LucideIcon, TrendingUp, TrendingDown } from 'lucide-react';

interface StatCardProps {
  title: string;
  value?: number;
  change?: number;
  changeLabel?: string;
  icon: LucideIcon;
  color?: 'blue' | 'green' | 'purple' | 'orange' | 'red';
}

const colorClasses = {
  blue: 'bg-blue-500 text-blue-50',
  green: 'bg-green-500 text-green-50',
  purple: 'bg-purple-500 text-purple-50',
  orange: 'bg-orange-500 text-orange-50',
  red: 'bg-red-500 text-red-50',
};

export function StatCard({ title, value = 0, change, changeLabel, icon: Icon, color = 'blue' }: StatCardProps) {
  const isPositiveChange = change !== undefined && change > 0;

  return (
    <Card>
      <CardContent className="p-6">
        <div className="flex items-center justify-between">
          <div className="space-y-2">
            <p className="text-sm text-gray-600">{title}</p>
            <p className="text-2xl font-bold">{value.toLocaleString()}</p>
            {change !== undefined && (
              <div className="flex items-center space-x-1">
                {isPositiveChange ? (
                  <TrendingUp className="h-4 w-4 text-green-500" />
                ) : (
                  <TrendingDown className="h-4 w-4 text-red-500" />
                )}
                <span className={cn(
                  "text-sm font-medium",
                  isPositiveChange ? "text-green-500" : "text-red-500"
                )}>
                  +{change} {changeLabel}
                </span>
              </div>
            )}
          </div>
          <div className={cn("p-3 rounded-lg", colorClasses[color])}>
            <Icon className="h-6 w-6" />
          </div>
        </div>
      </CardContent>
    </Card>
  );
}
```

## User Management Implementation

### Users Page
```tsx
// src/app/(dashboard)/users/page.tsx
'use client';

import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Badge } from '@/components/ui/badge';
import { DataTable } from '@/components/ui/data-table';
import { UserActionsDropdown } from '@/components/users/user-actions-dropdown';
import { UserDetailModal } from '@/components/users/user-detail-modal';
import { adminUserService } from '@/services/admin-users';
import { Search, Users, UserCheck, UserX, Plus } from 'lucide-react';

export default function UsersPage() {
  const [search, setSearch] = useState('');
  const [status, setStatus] = useState('all');
  const [page, setPage] = useState(1);
  const [selectedUser, setSelectedUser] = useState(null);

  const { data: usersData, isLoading, refetch } = useQuery({
    queryKey: ['admin-users', { search, status, page }],
    queryFn: () => adminUserService.getAll({ search, status, page, limit: 10 }),
  });

  const columns = [
    {
      accessorKey: 'email',
      header: 'User',
      cell: ({ row }) => (
        <div className="flex items-center space-x-3">
          <div className="w-10 h-10 bg-gray-200 rounded-full flex items-center justify-center">
            <Users className="w-5 h-5 text-gray-500" />
          </div>
          <div>
            <p className="font-medium">{row.original.profile?.firstName} {row.original.profile?.lastName}</p>
            <p className="text-sm text-gray-500">{row.original.email}</p>
          </div>
        </div>
      ),
    },
    {
      accessorKey: 'isVerified',
      header: 'Status',
      cell: ({ row }) => (
        <Badge variant={row.original.isVerified ? 'default' : 'secondary'}>
          {row.original.isVerified ? 'Verified' : 'Unverified'}
        </Badge>
      ),
    },
    {
      accessorKey: 'isDeleted',
      header: 'Account Status',
      cell: ({ row }) => (
        <Badge variant={row.original.isDeleted ? 'destructive' : 'success'}>
          {row.original.isDeleted ? 'Blocked' : 'Active'}
        </Badge>
      ),
    },
    {
      accessorKey: 'createdAt',
      header: 'Joined',
      cell: ({ row }) => new Date(row.original.createdAt).toLocaleDateString(),
    },
    {
      id: 'actions',
      cell: ({ row }) => (
        <UserActionsDropdown 
          user={row.original} 
          onUserUpdated={() => refetch()}
          onViewDetails={() => setSelectedUser(row.original)}
        />
      ),
    },
  ];

  return (
    <div className="space-y-6">
      <div className="flex justify-between items-center">
        <div>
          <h1 className="text-3xl font-bold">User Management</h1>
          <p className="text-gray-600">Manage platform users and their accounts</p>
        </div>
      </div>

      {/* Filters */}
      <Card>
        <CardHeader>
          <CardTitle>Filters</CardTitle>
        </CardHeader>
        <CardContent>
          <div className="flex flex-col sm:flex-row gap-4">
            <div className="relative flex-1">
              <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
              <Input
                placeholder="Search users..."
                value={search}
                onChange={(e) => setSearch(e.target.value)}
                className="pl-10"
              />
            </div>
            <select
              value={status}
              onChange={(e) => setStatus(e.target.value)}
              className="px-3 py-2 border border-gray-300 rounded-md"
            >
              <option value="all">All Status</option>
              <option value="active">Active</option>
              <option value="blocked">Blocked</option>
              <option value="verified">Verified</option>
              <option value="unverified">Unverified</option>
            </select>
          </div>
        </CardContent>
      </Card>

      {/* Users Table */}
      <Card>
        <CardHeader>
          <CardTitle>Users ({usersData?.pagination.totalUsers || 0})</CardTitle>
        </CardHeader>
        <CardContent>
          <DataTable
            columns={columns}
            data={usersData?.users || []}
            loading={isLoading}
          />
          
          {usersData?.pagination && (
            <div className="flex justify-between items-center mt-4">
              <p className="text-sm text-gray-600">
                Showing {((page - 1) * 10) + 1} to {Math.min(page * 10, usersData.pagination.totalUsers)} of {usersData.pagination.totalUsers} users
              </p>
              <div className="flex space-x-2">
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setPage(page - 1)}
                  disabled={!usersData.pagination.hasPrevPage}
                >
                  Previous
                </Button>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setPage(page + 1)}
                  disabled={!usersData.pagination.hasNextPage}
                >
                  Next
                </Button>
              </div>
            </div>
          )}
        </CardContent>
      </Card>

      {/* User Detail Modal */}
      {selectedUser && (
        <UserDetailModal
          user={selectedUser}
          open={!!selectedUser}
          onClose={() => setSelectedUser(null)}
          onUserUpdated={() => refetch()}
        />
      )}
    </div>
  );
}
```

## Vendor Management Implementation

### Vendors Page
```tsx
// src/app/(dashboard)/vendors/page.tsx
'use client';

import { useState } from 'react';
import { useQuery, useMutation } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { DataTable } from '@/components/ui/data-table';
import { VendorApprovalModal } from '@/components/vendors/vendor-approval-modal';
import { adminVendorService } from '@/services/admin-vendors';
import { Store, Star, CheckCircle, XCircle, Clock } from 'lucide-react';
import { toast } from '@/components/ui/use-toast';

export default function VendorsPage() {
  const [selectedVendor, setSelectedVendor] = useState(null);
  const [approvalModalOpen, setApprovalModalOpen] = useState(false);

  const { data: vendorsData, isLoading, refetch } = useQuery({
    queryKey: ['admin-vendors'],
    queryFn: () => adminVendorService.getAll({ page: 1, limit: 50 }),
  });

  const approvalMutation = useMutation({
    mutationFn: ({ vendorId, action, reason }: any) =>
      adminVendorService.updateApproval(vendorId, action, reason),
    onSuccess: () => {
      toast({ title: 'Vendor approval updated successfully' });
      refetch();
      setApprovalModalOpen(false);
    },
    onError: (error: any) => {
      toast({ 
        title: 'Error', 
        description: error.response?.data?.message || 'Failed to update vendor approval',
        variant: 'destructive'
      });
    },
  });

  const handleApproval = (vendor: any, action: 'approve' | 'reject') => {
    setSelectedVendor({ ...vendor, approvalAction: action });
    setApprovalModalOpen(true);
  };

  const columns = [
    {
      accessorKey: 'businessName',
      header: 'Vendor',
      cell: ({ row }) => (
        <div className="flex items-center space-x-3">
          <div className="w-10 h-10 bg-gray-200 rounded-full flex items-center justify-center">
            <Store className="w-5 h-5 text-gray-500" />
          </div>
          <div>
            <p className="font-medium">{row.original.profile?.businessName}</p>
            <p className="text-sm text-gray-500">{row.original.email}</p>
          </div>
        </div>
      ),
    },
    {
      accessorKey: 'businessCategory',
      header: 'Category',
      cell: ({ row }) => (
        <Badge variant="outline">
          {row.original.profile?.businessCategory || 'Uncategorized'}
        </Badge>
      ),
    },
    {
      accessorKey: 'isVerified',
      header: 'Approval Status',
      cell: ({ row }) => {
        const status = row.original.isVerified;
        return (
          <Badge variant={status ? 'success' : 'warning'}>
            {status ? (
              <>
                <CheckCircle className="w-3 h-3 mr-1" />
                Approved
              </>
            ) : (
              <>
                <Clock className="w-3 h-3 mr-1" />
                Pending
              </>
            )}
          </Badge>
        );
      },
    },
    {
      accessorKey: 'services',
      header: 'Services',
      cell: ({ row }) => (
        <span className="text-sm text-gray-600">
          {row.original.servicesCount || 0} services
        </span>
      ),
    },
    {
      accessorKey: 'averageRating',
      header: 'Rating',
      cell: ({ row }) => (
        <div className="flex items-center space-x-1">
          <Star className="w-4 h-4 text-yellow-400 fill-current" />
          <span>{row.original.averageRating?.toFixed(1) || 'N/A'}</span>
        </div>
      ),
    },
    {
      id: 'actions',
      cell: ({ row }) => (
        <div className="flex space-x-2">
          {!row.original.isVerified && (
            <>
              <Button
                size="sm"
                variant="outline"
                onClick={() => handleApproval(row.original, 'approve')}
                className="text-green-600 hover:text-green-700"
              >
                <CheckCircle className="w-4 h-4 mr-1" />
                Approve
              </Button>
              <Button
                size="sm"
                variant="outline"
                onClick={() => handleApproval(row.original, 'reject')}
                className="text-red-600 hover:text-red-700"
              >
                <XCircle className="w-4 h-4 mr-1" />
                Reject
              </Button>
            </>
          )}
        </div>
      ),
    },
  ];

  const pendingCount = vendorsData?.vendors.filter(v => !v.isVerified).length || 0;
  const approvedCount = vendorsData?.vendors.filter(v => v.isVerified).length || 0;

  return (
    <div className="space-y-6">
      <div className="flex justify-between items-center">
        <div>
          <h1 className="text-3xl font-bold">Vendor Management</h1>
          <p className="text-gray-600">Manage vendor accounts and approvals</p>
        </div>
      </div>

      {/* Statistics */}
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        <Card>
          <CardContent className="p-6">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm text-gray-600">Total Vendors</p>
                <p className="text-2xl font-bold">{vendorsData?.vendors.length || 0}</p>
              </div>
              <Store className="h-8 w-8 text-primary-500" />
            </div>
          </CardContent>
        </Card>
        <Card>
          <CardContent className="p-6">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm text-gray-600">Pending Approval</p>
                <p className="text-2xl font-bold text-orange-600">{pendingCount}</p>
              </div>
              <Clock className="h-8 w-8 text-orange-500" />
            </div>
          </CardContent>
        </Card>
        <Card>
          <CardContent className="p-6">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm text-gray-600">Approved</p>
                <p className="text-2xl font-bold text-green-600">{approvedCount}</p>
              </div>
              <CheckCircle className="h-8 w-8 text-green-500" />
            </div>
          </CardContent>
        </Card>
      </div>

      {/* Vendors Table */}
      <Card>
        <CardHeader>
          <CardTitle>All Vendors</CardTitle>
        </CardHeader>
        <CardContent>
          <DataTable
            columns={columns}
            data={vendorsData?.vendors || []}
            loading={isLoading}
          />
        </CardContent>
      </Card>

      {/* Vendor Approval Modal */}
      <VendorApprovalModal
        vendor={selectedVendor}
        open={approvalModalOpen}
        onClose={() => {
          setApprovalModalOpen(false);
          setSelectedVendor(null);
        }}
        onConfirm={(reason) => {
          approvalMutation.mutate({
            vendorId: selectedVendor._id,
            action: selectedVendor.approvalAction,
            reason,
          });
        }}
        loading={approvalMutation.isPending}
      />
    </div>
  );
}
```

## Event Management Implementation

### Events Page
```tsx
// src/app/(dashboard)/events/page.tsx
'use client';

import { useState } from 'react';
import { useQuery, useMutation } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { DataTable } from '@/components/ui/data-table';
import { EventDetailModal } from '@/components/events/event-detail-modal';
import { adminEventService } from '@/services/admin-events';
import { Calendar, Clock, MapPin, Users, Eye, CheckCircle, XCircle } from 'lucide-react';

export default function EventsPage() {
  const [selectedEvent, setSelectedEvent] = useState(null);
  const [statusFilter, setStatusFilter] = useState('all');

  const { data: eventsData, isLoading, refetch } = useQuery({
    queryKey: ['admin-events', statusFilter],
    queryFn: () => adminEventService.getAll({ status: statusFilter }),
  });

  const updateEventMutation = useMutation({
    mutationFn: ({ eventId, action, reason }: any) =>
      adminEventService.updateEvent(eventId, action, reason),
    onSuccess: () => {
      refetch();
      toast({ title: 'Event updated successfully' });
    },
  });

  const trackEventClick = useMutation({
    mutationFn: ({ eventId, url, type }: any) =>
      adminEventService.trackClick(eventId, url, type),
    onSuccess: () => {
      toast({ title: 'Event interaction tracked' });
    },
  });

  const handleEventAction = (event: any, action: string, reason?: string) => {
    updateEventMutation.mutate({ eventId: event._id, action, reason });
  };

  const handleTrackClick = (event: any, type: 'URL' | 'PHONE') => {
    const url = type === 'URL' ? event.contactInfo.url : event.contactInfo.phone;
    trackEventClick.mutate({ eventId: event._id, url, type });
    
    // Open the URL/phone
    if (type === 'URL' && event.contactInfo.url) {
      window.open(event.contactInfo.url, '_blank');
    } else if (type === 'PHONE' && event.contactInfo.phone) {
      window.open(`tel:${event.contactInfo.phone}`);
    }
  };

  const columns = [
    {
      accessorKey: 'name',
      header: 'Event',
      cell: ({ row }) => (
        <div className="flex items-center space-x-3">
          <div className="w-10 h-10 bg-primary-100 rounded-lg flex items-center justify-center">
            <Calendar className="w-5 h-5 text-primary-600" />
          </div>
          <div>
            <p className="font-medium">{row.original.name}</p>
            <p className="text-sm text-gray-500">{row.original.creatorType} Event</p>
          </div>
        </div>
      ),
    },
    {
      accessorKey: 'eventDate',
      header: 'Date & Time',
      cell: ({ row }) => (
        <div>
          <p className="text-sm">{new Date(row.original.eventDate).toLocaleDateString()}</p>
          <p className="text-xs text-gray-500">{row.original.eventTime}</p>
        </div>
      ),
    },
    {
      accessorKey: 'status',
      header: 'Status',
      cell: ({ row }) => {
        const statusColors = {
          pending: 'bg-yellow-100 text-yellow-700',
          approved: 'bg-green-100 text-green-700',
          rejected: 'bg-red-100 text-red-700',
        };
        return (
          <Badge className={statusColors[row.original.status]}>
            {row.original.status}
          </Badge>
        );
      },
    },
    {
      accessorKey: 'eventType',
      header: 'Type',
      cell: ({ row }) => (
        <Badge variant={row.original.eventType === 'Free' ? 'secondary' : 'default'}>
          {row.original.eventType}
          {row.original.eventType === 'Paid' && ` ($${row.original.price})`}
        </Badge>
      ),
    },
    {
      accessorKey: 'viewBy',
      header: 'Views',
      cell: ({ row }) => (
        <div className="flex items-center space-x-1">
          <Eye className="w-4 h-4 text-gray-400" />
          <span>{row.original.viewBy?.length || 0}</span>
        </div>
      ),
    },
    {
      id: 'actions',
      cell: ({ row }) => (
        <div className="flex space-x-2">
          <Button
            size="sm"
            variant="outline"
            onClick={() => setSelectedEvent(row.original)}
          >
            View Details
          </Button>
          
          {row.original.contactInfo?.url && (
            <Button
              size="sm"
              variant="outline"
              onClick={() => handleTrackClick(row.original, 'URL')}
              className="text-blue-600"
            >
              Visit URL
            </Button>
          )}
          
          {row.original.contactInfo?.phone && (
            <Button
              size="sm"
              variant="outline"
              onClick={() => handleTrackClick(row.original, 'PHONE')}
              className="text-green-600"
            >
              Call
            </Button>
          )}
          
          {row.original.status === 'pending' && (
            <>
              <Button
                size="sm"
                variant="outline"
                onClick={() => handleEventAction(row.original, 'approve')}
                className="text-green-600"
              >
                <CheckCircle className="w-4 h-4 mr-1" />
                Approve
              </Button>
              <Button
                size="sm"
                variant="outline"
                onClick={() => handleEventAction(row.original, 'reject', 'Admin rejection')}
                className="text-red-600"
              >
                <XCircle className="w-4 h-4 mr-1" />
                Reject
              </Button>
            </>
          )}
        </div>
      ),
    },
  ];

  const pendingCount = eventsData?.events.filter(e => e.status === 'pending').length || 0;
  const approvedCount = eventsData?.events.filter(e => e.status === 'approved').length || 0;

  return (
    <div className="space-y-6">
      <div className="flex justify-between items-center">
        <div>
          <h1 className="text-3xl font-bold">Event Management</h1>
          <p className="text-gray-600">Manage platform events and approvals</p>
        </div>
      </div>

      {/* Statistics */}
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        <Card>
          <CardContent className="p-6">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm text-gray-600">Total Events</p>
                <p className="text-2xl font-bold">{eventsData?.events.length || 0}</p>
              </div>
              <Calendar className="h-8 w-8 text-primary-500" />
            </div>
          </CardContent>
        </Card>
        <Card>
          <CardContent className="p-6">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm text-gray-600">Pending Review</p>
                <p className="text-2xl font-bold text-orange-600">{pendingCount}</p>
              </div>
              <Clock className="h-8 w-8 text-orange-500" />
            </div>
          </CardContent>
        </Card>
        <Card>
          <CardContent className="p-6">
            <div className="flex items-center justify-between">
              <div>
                <p className="text-sm text-gray-600">Approved</p>
                <p className="text-2xl font-bold text-green-600">{approvedCount}</p>
              </div>
              <CheckCircle className="h-8 w-8 text-green-500" />
            </div>
          </CardContent>
        </Card>
      </div>

      {/* Filters */}
      <Card>
        <CardContent className="p-4">
          <div className="flex space-x-4">
            <select
              value={statusFilter}
              onChange={(e) => setStatusFilter(e.target.value)}
              className="px-3 py-2 border border-gray-300 rounded-md"
            >
              <option value="all">All Events</option>
              <option value="pending">Pending</option>
              <option value="approved">Approved</option>
              <option value="rejected">Rejected</option>
            </select>
          </div>
        </CardContent>
      </Card>

      {/* Events Table */}
      <Card>
        <CardHeader>
          <CardTitle>Events</CardTitle>
        </CardHeader>
        <CardContent>
          <DataTable
            columns={columns}
            data={eventsData?.events || []}
            loading={isLoading}
          />
        </CardContent>
      </Card>

      {/* Event Detail Modal */}
      {selectedEvent && (
        <EventDetailModal
          event={selectedEvent}
          open={!!selectedEvent}
          onClose={() => setSelectedEvent(null)}
          onEventUpdated={() => refetch()}
        />
      )}
    </div>
  );
}
```

## Notification System Implementation

### Notifications Page
```tsx
// src/app/(dashboard)/notifications/page.tsx
'use client';

import { useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Checkbox } from '@/components/ui/checkbox';
import { adminNotificationService } from '@/services/admin-notifications';
import { Send, Users, Store, Globe, CheckCircle } from 'lucide-react';
import { toast } from '@/components/ui/use-toast';

export default function NotificationsPage() {
  const [recipients, setRecipients] = useState('all');
  const [title, setTitle] = useState('');
  const [body, setBody] = useState('');
  const [selectedUsers, setSelectedUsers] = useState([]);

  const sendNotificationMutation = useMutation({
    mutationFn: adminNotificationService.sendNotifications,
    onSuccess: (data) => {
      toast({
        title: 'Notifications Sent Successfully',
        description: `Sent to ${data.successful} users out of ${data.totalTargets} targets`,
      });
      setTitle('');
      setBody('');
      setSelectedUsers([]);
    },
    onError: (error: any) => {
      toast({
        title: 'Error',
        description: error.response?.data?.message || 'Failed to send notifications',
        variant: 'destructive',
      });
    },
  });

  const handleSendNotifications = () => {
    if (!title.trim() || !body.trim()) {
      toast({
        title: 'Error',
        description: 'Please provide both title and message',
        variant: 'destructive',
      });
      return;
    }

    sendNotificationMutation.mutate({
      recipients: recipients === 'selected' ? selectedUsers : recipients,
      title: title.trim(),
      body: body.trim(),
    });
  };

  return (
    <div className="space-y-6">
      <div>
        <h1 className="text-3xl font-bold">Notification Center</h1>
        <p className="text-gray-600">Send push notifications to users and vendors</p>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        {/* Send Notifications */}
        <Card>
          <CardHeader>
            <CardTitle className="flex items-center space-x-2">
              <Send className="w-5 h-5" />
              <span>Send Notifications</span>
            </CardTitle>
            <CardDescription>
              Send push notifications to users, vendors, or specific recipients
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-6">
            {/* Recipients Selection */}
            <div className="space-y-4">
              <Label className="text-base font-medium">Recipients</Label>
              <RadioGroup value={recipients} onValueChange={setRecipients}>
                <div className="flex items-center space-x-2">
                  <RadioGroupItem value="all" id="all" />
                  <Label htmlFor="all" className="flex items-center space-x-2">
                    <Globe className="w-4 h-4" />
                    <span>All Users & Vendors</span>
                  </Label>
                </div>
                <div className="flex items-center space-x-2">
                  <RadioGroupItem value="users" id="users" />
                  <Label htmlFor="users" className="flex items-center space-x-2">
                    <Users className="w-4 h-4" />
                    <span>Users Only</span>
                  </Label>
                </div>
                <div className="flex items-center space-x-2">
                  <RadioGroupItem value="vendors" id="vendors" />
                  <Label htmlFor="vendors" className="flex items-center space-x-2">
                    <Store className="w-4 h-4" />
                    <span>Vendors Only</span>
                  </Label>
                </div>
              </RadioGroup>
            </div>

            {/* Notification Content */}
            <div className="space-y-4">
              <div>
                <Label htmlFor="title">Notification Title</Label>
                <Input
                  id="title"
                  value={title}
                  onChange={(e) => setTitle(e.target.value)}
                  placeholder="Enter notification title..."
                  maxLength={100}
                />
                <p className="text-xs text-gray-500 mt-1">{title.length}/100 characters</p>
              </div>

              <div>
                <Label htmlFor="body">Notification Message</Label>
                <Textarea
                  id="body"
                  value={body}
                  onChange={(e) => setBody(e.target.value)}
                  placeholder="Enter notification message..."
                  rows={4}
                  maxLength={500}
                />
                <p className="text-xs text-gray-500 mt-1">{body.length}/500 characters</p>
              </div>
            </div>

            {/* Send Button */}
            <Button
              onClick={handleSendNotifications}
              disabled={sendNotificationMutation.isPending || !title.trim() || !body.trim()}
              className="w-full"
            >
              {sendNotificationMutation.isPending ? (
                <>
                  <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2" />
                  Sending Notifications...
                </>
              ) : (
                <>
                  <Send className="w-4 h-4 mr-2" />
                  Send Notifications
                </>
              )}
            </Button>
          </CardContent>
        </Card>

        {/* Notification Templates */}
        <Card>
          <CardHeader>
            <CardTitle>Quick Templates</CardTitle>
            <CardDescription>Use pre-made templates for common notifications</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            {[
              {
                title: 'Platform Maintenance',
                body: 'The platform will be under maintenance from 2 AM to 4 AM tomorrow. We apologize for any inconvenience.',
                type: 'maintenance'
              },
              {
                title: 'New Feature Available',
                body: 'Check out our latest feature updates in the app! We hope you enjoy the improvements.',
                type: 'feature'
              },
              {
                title: 'Special Offer',
                body: 'Limited time offer! Get 20% off on all bookings this weekend. Book now!',
                type: 'offer'
              },
              {
                title: 'Welcome Message',
                body: 'Welcome to GuideMe! Start exploring amazing services and experiences in your area.',
                type: 'welcome'
              },
            ].map((template, index) => (
              <div
                key={index}
                className="p-4 border border-gray-200 rounded-lg cursor-pointer hover:bg-gray-50 transition-colors"
                onClick={() => {
                  setTitle(template.title);
                  setBody(template.body);
                }}
              >
                <h4 className="font-medium text-sm">{template.title}</h4>
                <p className="text-xs text-gray-600 mt-1">{template.body.substring(0, 80)}...</p>
              </div>
            ))}
          </CardContent>
        </Card>
      </div>

      {/* Recent Notifications History */}
      <Card>
        <CardHeader>
          <CardTitle>Recent Notifications</CardTitle>
          <CardDescription>History of recently sent notifications</CardDescription>
        </CardHeader>
        <CardContent>
          <div className="text-center py-8 text-gray-500">
            <Send className="w-12 h-12 mx-auto mb-4 opacity-50" />
            <p>No notifications sent yet</p>
            <p className="text-sm">Notification history will appear here</p>
          </div>
        </CardContent>
      </Card>
    </div>
  );
}
```

## API Services Implementation

### Base API Service
```tsx
// src/services/api.ts
import axios from 'axios';
import { useAuthStore } from '@/stores/auth-store';

const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5000';

export const api = axios.create({
  baseURL: `${API_BASE_URL}/admin`,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Request interceptor to add auth token
api.interceptors.request.use(
  (config) => {
    const token = useAuthStore.getState().tokens?.accessToken;
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// Response interceptor for error handling
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      useAuthStore.getState().logout();
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);
```

### Admin Services
```tsx
// src/services/admin-dashboard.ts
import { api } from './api';

export const adminDashboardService = {
  getOverview: async () => {
    const response = await api.get('/dashboard/overview');
    return response.data.data;
  },
  
  getAnalytics: async (period: string) => {
    const response = await api.get(`/dashboard/analytics?period=${period}`);
    return response.data.data;
  },
};

// src/services/admin-users.ts
export const adminUserService = {
  getAll: async (params: any) => {
    const response = await api.get('/users', { params });
    return response.data.data;
  },
  
  updateStatus: async (userId: string, action: string, reason?: string) => {
    const response = await api.put(`/users/${userId}/status`, { action, reason });
    return response.data.data;
  },
  
  getDetails: async (userId: string) => {
    const response = await api.get(`/users/${userId}`);
    return response.data.data;
  },
};

// src/services/admin-vendors.ts
export const adminVendorService = {
  getAll: async (params: any) => {
    const response = await api.get('/vendors', { params });
    return response.data.data;
  },
  
  updateApproval: async (vendorId: string, action: string, reason?: string) => {
    const response = await api.put(`/vendors/${vendorId}/approval`, { action, reason });
    return response.data.data;
  },
};

// src/services/admin-notifications.ts
export const adminNotificationService = {
  sendNotifications: async (data: any) => {
    const response = await api.post('/notifications/send', data);
    return response.data.data;
  },
};
```

## State Management with Zustand

### Auth Store
```tsx
// src/stores/auth-store.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface User {
  id: string;
  email: string;
  role: string;
  lastLoginAt?: string;
}

interface Tokens {
  accessToken: string;
  refreshToken: string;
}

interface AuthState {
  user: User | null;
  tokens: Tokens | null;
  isAuthenticated: boolean;
  setAuth: (user: User, tokens: Tokens) => void;
  logout: () => void;
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set) => ({
      user: null,
      tokens: null,
      isAuthenticated: false,
      setAuth: (user, tokens) => set({ user, tokens, isAuthenticated: true }),
      logout: () => set({ user: null, tokens: null, isAuthenticated: false }),
    }),
    {
      name: 'admin-auth-storage',
    }
  )
);
```

## Key Features Summary

### ✅ Complete Dashboard System
- **Authentication**: Secure admin login with JWT tokens
- **Dashboard Overview**: Statistics, charts, recent activity
- **Responsive Design**: Mobile-friendly admin interface
- **Real-time Updates**: Auto-refresh capabilities

### ✅ User Management
- **User Listing**: Search, filter, pagination
- **User Details**: Complete profile information
- **Account Management**: Block/unblock users
- **Activity Tracking**: User behavior monitoring

### ✅ Vendor Management
- **Vendor Approval Workflow**: Approve/reject with reasons
- **Category Management**: Vendor categorization
- **Service Monitoring**: Track vendor services
- **Rating System**: Monitor vendor ratings

### ✅ Event Management
- **Event Approval**: Approve/reject events
- **Click Tracking**: Track URL/phone interactions
- **Event Analytics**: View count and engagement
- **Status Management**: Pending, approved, rejected

### ✅ Notification System
- **Bulk Notifications**: Send to all users/vendors
- **Template System**: Pre-made notification templates
- **Targeted Messaging**: User/vendor specific
- **Delivery Tracking**: Success/failure tracking

### ✅ Modern UI/UX
- **Component Library**: Shadcn/ui components
- **Theme Consistency**: Match mobile app design
- **Loading States**: Skeleton loaders
- **Error Handling**: Comprehensive error management

### ✅ Technical Excellence
- **TypeScript**: Full type safety
- **React Query**: Efficient data fetching
- **Form Validation**: Zod schema validation
- **State Management**: Zustand for global state

## Next Steps

1. **Set up project structure** with NextJS 15
2. **Install dependencies** (see package.json below)
3. **Create base components** and layout system
4. **Implement authentication** flow
5. **Build dashboard pages** step by step
6. **Add error boundaries** and loading states
7. **Implement responsive design** for mobile
8. **Add comprehensive testing**
9. **Deploy and configure** environment variables

## Package.json Dependencies

```json
{
  "name": "guideme-admin-dashboard",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@hookform/resolvers": "^3.3.4",
    "@radix-ui/react-alert-dialog": "^1.0.5",
    "@radix-ui/react-avatar": "^1.0.4",
    "@radix-ui/react-badge": "^1.0.4",
    "@radix-ui/react-button": "^1.0.4",
    "@radix-ui/react-card": "^1.0.4",
    "@radix-ui/react-checkbox": "^1.0.4",
    "@radix-ui/react-dialog": "^1.0.5",
    "@radix-ui/react-dropdown-menu": "^2.0.6",
    "@radix-ui/react-input": "^1.0.4",
    "@radix-ui/react-label": "^2.0.2",
    "@radix-ui/react-radio-group": "^1.1.3",
    "@radix-ui/react-select": "^2.0.0",
    "@radix-ui/react-skeleton": "^1.0.4",
    "@radix-ui/react-table": "^1.0.4",
    "@radix-ui/react-tabs": "^1.0.4",
    "@radix-ui/react-textarea": "^1.0.4",
    "@radix-ui/react-toast": "^1.1.5",
    "@tanstack/react-query": "^5.28.6",
    "@tanstack/react-table": "^8.15.0",
    "axios": "^1.6.8",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.0",
    "date-fns": "^3.6.0",
    "lucide-react": "^0.365.0",
    "next": "15.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-hook-form": "^7.51.1",
    "recharts": "^2.12.2",
    "tailwind-merge": "^2.2.2",
    "tailwindcss-animate": "^1.0.7",
    "zod": "^3.22.4",
    "zustand": "^4.5.2"
  },
  "devDependencies": {
    "@types/node": "^20.12.7",
    "@types/react": "^18.2.79",
    "@types/react-dom": "^18.2.23",
    "autoprefixer": "^10.4.19",
    "eslint": "^8.57.0",
    "eslint-config-next": "15.0.0",
    "postcss": "^8.4.38",
    "tailwindcss": "^3.4.3",
    "typescript": "^5.4.5"
  }
}
```

This comprehensive frontend implementation provides a complete admin dashboard matching your mobile app's theme with all the required SOW functionality.
