Skip to content

Eneza Admin Dashboard

The Admin Dashboard is a React + TypeScript application for internal management of the Eneza platform.

Technology Stack

ComponentTechnology
FrameworkReact 18
Build ToolVite
LanguageTypeScript
StateReact Query
RoutingReact Router
UITailwind CSS, Radix UI
ChartsRecharts
HostingCloudflare Pages

Project Structure

admin-dashboard/
├── src/
│   ├── main.tsx
│   ├── App.tsx
│   ├── pages/                 # Page components (14 modules)
│   │   ├── admins/
│   │   ├── ads/
│   │   ├── advertisers/
│   │   ├── auth/
│   │   ├── dashboard/
│   │   ├── finance/
│   │   ├── kanban/
│   │   ├── notifications/
│   │   ├── screenshots/
│   │   ├── settings/
│   │   ├── subscriptions/
│   │   ├── support/
│   │   ├── system/
│   │   └── users/
│   ├── components/            # Reusable components
│   ├── hooks/                 # Custom hooks
│   ├── services/              # API clients
│   ├── stores/                # Global state
│   ├── types/                 # TypeScript types
│   └── utils/                 # Utilities
├── tailwind.config.js
└── vite.config.ts

Page Modules

Dashboard (/dashboard)

Main analytics overview.

Files:

  • DashboardPage.tsx - Overview with key metrics

Features:

  • Total users, advertisers, earnings
  • Active campaigns
  • Real-time graphs
  • Recent activity feed

Users (/users)

User (poster) management.

Files:

  • UsersPage.tsx - User list with filters
  • UserDetailsPage.tsx - Individual user details
  • UserActivitiesPage.tsx - User activity log

Features:

  • Search by phone/name
  • Filter by country, status, KYC
  • View/edit user profiles
  • Ban/unban users
  • View transaction history
  • View screenshot submissions

Advertisers (/advertisers)

Advertiser account management.

Files:

  • AdvertisersPage.tsx - Advertiser list
  • AdvertiserDetailsPage.tsx - Advertiser profile
  • AdvertiserEmailPage.tsx - Email management

Features:

  • Search by company/email
  • View campaigns
  • Credit balance manually
  • View invoices
  • Manage email preferences

Ads (/ads)

Ad campaign moderation.

Files:

  • AdsPage.tsx - Ad list with status tabs
  • AdDetailsPage.tsx - Full ad details

Features:

  • Moderation queue (pending review)
  • Approve/reject ads
  • View campaign statistics
  • Edit ad details
  • Pause/resume campaigns
  • Process refunds

Status Tabs:

  • Under Review
  • Active
  • Paused
  • Completed
  • Rejected

Screenshots (/screenshots)

Screenshot verification queue.

Files:

  • ScreenshotsPage.tsx - Screenshot queue
  • ScreenshotDetailsPage.tsx - Individual review

Features:

  • Pending review queue
  • Manual approve/reject
  • View AI verification results
  • View fraud scores
  • Bulk approve
  • Request additional proof

Finance (/finance)

Financial operations.

Files:

  • FinancePage.tsx - Financial overview
  • TransactionsPage.tsx - All transactions
  • TransactionDetailsPage.tsx
  • DepositsPage.tsx - Advertiser deposits
  • DepositDetailsPage.tsx
  • InvoicesPage.tsx - All invoices
  • InvoiceDetailsPage.tsx
  • RefundsPage.tsx - Refund requests
  • RefundDetailsPage.tsx

Features:

  • Pending withdrawals queue
  • Process payouts (mark as paid)
  • Download invoices
  • View deposit history
  • Process refunds

Settings (/settings)

Platform configuration.

Files:

  • SettingsPage.tsx - Settings overview
  • CategoriesPage.tsx - Ad categories
  • CountriesPage.tsx - Country management
  • CountryDetailsPage.tsx
  • CitiesPage.tsx - City management
  • PaymentProcessorsPage.tsx - Mobile money providers
  • AppVersionPage.tsx - Mobile app versions
  • EmailTemplatesPage.tsx - Email templates
  • TestingToolsPage.tsx - Dev tools

Features:

  • Manage ad categories
  • Configure countries (currencies, pricing tiers)
  • Manage cities
  • Configure payment processors
  • Set minimum app versions
  • Edit email templates

Admin Users (/admins)

Internal admin management.

Files:

  • AdminUsersPage.tsx - Admin list
  • AdminDetailsPage.tsx - Admin profile
  • PermissionManagementPage.tsx - Role permissions
  • RoleTemplatesPage.tsx - Role templates

Features:

  • Invite new admins
  • Assign roles
  • Configure permissions
  • View admin activity
  • Deactivate admins

Support (/support)

Customer support tickets.

Files:

  • SupportPage.tsx - Ticket list
  • SupportTicketDetailsPage.tsx - Ticket thread

Features:

  • View open tickets
  • Reply to tickets
  • Close/resolve tickets
  • Assign to admin
  • View ticket history

Notifications (/notifications)

Notification management.

Files:

  • NotificationsPage.tsx - Broadcast list
  • NotificationSettingsPage.tsx - Notification config

Features:

  • Create broadcast notifications
  • Schedule broadcasts
  • Target by country/segment
  • View delivery stats

Kanban (/kanban)

Internal task management.

Files:

  • KanbanPage.tsx - Kanban board
  • TaskDetailPage.tsx - Task details

Features:

  • Drag-and-drop tasks
  • Create/edit tasks
  • Assign to admins
  • Track progress

System (/system)

System monitoring.

Files:

  • SystemHealthPage.tsx - Health dashboard
  • AlertsPage.tsx - System alerts
  • FailedJobsPage.tsx - Failed jobs
  • ActivityLogsPage.tsx - Audit logs

Features:

  • Service health status
  • View system alerts
  • Retry failed jobs
  • View admin activity logs

Authentication

Admin authentication uses JWT tokens with role-based access.

typescript
// services/auth.ts
export const authService = {
  async login(email: string, password: string) {
    const response = await api.post('/admin/auth/login', { email, password });
    localStorage.setItem('adminToken', response.data.token);
    return response.data;
  },

  async logout() {
    await api.post('/admin/auth/logout');
    localStorage.removeItem('adminToken');
  },

  async getCurrentAdmin() {
    const response = await api.get('/admin/auth/me');
    return response.data;
  }
};

Permission Checking

typescript
// hooks/usePermission.ts
export function usePermission(permission: string): boolean {
  const { admin } = useAdminStore();

  if (!admin) return false;
  if (admin.role === 'super_admin') return true;

  return admin.permissions.includes(permission);
}

// Usage in components
function AdApproveButton({ adId }: { adId: string }) {
  const canApprove = usePermission('ads:moderate');

  if (!canApprove) return null;

  return <Button onClick={() => approveAd(adId)}>Approve</Button>;
}

API Client

typescript
// services/api.ts
import axios from 'axios';

export const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL || 'https://api.eneza.app',
  headers: {
    'Content-Type': 'application/json',
  },
});

// Add auth header
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('adminToken');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Handle auth errors
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('adminToken');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

Data Fetching with React Query

typescript
// hooks/useUsers.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { api } from '../services/api';

export function useUsers(filters: UserFilters) {
  return useQuery({
    queryKey: ['users', filters],
    queryFn: async () => {
      const { data } = await api.get('/admin/users', { params: filters });
      return data;
    },
  });
}

export function useBanUser() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (userId: string) => {
      await api.post(`/admin/users/${userId}/ban`);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });
}

Deployment

Hosted on Cloudflare Pages with automatic deployments.

bash
# Build
npm run build

# Deploy
npx wrangler pages deploy dist --project-name=eneza-admin-dashboard

URLs:

  • Production: https://admin.eneza.app
  • Preview: https://dev-admin.eneza.app

Environment Variables

bash
VITE_API_URL=https://api.eneza.app
VITE_STRIPE_PUBLISHABLE_KEY=pk_live_...

One chat. Everything done.