# Business & Birthdays — Frontend Implementation Guide

> **Version:** 1.0  
> **Last Updated:** 2026-07-10  
> **Base URL:** `{{APP_URL}}/api/v1`  
> **Auth:** Sanctum Bearer Token (returned on login/register)

---

## Table of Contents

1. [Quick Start](#1-quick-start)
2. [Authentication & Auth Flow](#2-authentication--auth-flow)
3. [User Dashboard Screens](#3-user-dashboard-screens)
4. [Admin Dashboard Screens](#4-admin-dashboard-screens)
5. [API Endpoint Reference](#5-api-endpoint-reference)
6. [Data Types & Interfaces](#6-data-types--interfaces)
7. [Permission Checking Utilities](#7-permission-checking-utilities)
8. [Error Handling](#8-error-handling)
9. [Key Workflows](#9-key-workflows)

---

## 1. Quick Start

### Base Configuration

```typescript
const API_BASE_URL = 'https://yourdomain.com/api/v1';

// Axios instance with auth interceptor
const api = axios.create({
    baseURL: API_BASE_URL,
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    }
});

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

### Auth Token Storage

On login/register, the API returns:
```json
{
    "success": true,
    "message": "...",
    "data": {
        "token": "1|sanctum_token_here...",
        "user": { ... }
    }
}
```

Store the `token` in `localStorage` or `sessionStorage`. Send it as `Authorization: Bearer <token>` for all protected routes.

---

## 2. Authentication & Auth Flow

### 2.1 POST /auth/register

**Request:**
```json
{
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "phone_number": "+2348012345678",
    "password": "Password123!",
    "password_confirmation": "Password123!",
    "ref": "JOH5A3F9K2B"
}
```

**Response (201):**
```json
{
    "success": true,
    "message": "User registered successfully. Please verify your email.",
    "data": {
        "user": { "first_name": "Jane", "last_name": "Doe", ... },
        "token": "1|abc123...",
        "email_verification_sent": true
    }
}
```

### 2.2 POST /auth/login

**Request:**
```json
{ "email": "jane@example.com", "password": "Password123!" }
```

**Response (200):**
```json
{
    "success": true,
    "data": {
        "token": "1|sanctum_token...",
        "user": {
            "id": 1,
            "membership_id": "TITAN-0001",
            "first_name": "Jane",
            "last_name": "Doe",
            "email": "jane@example.com",
            "roles": ["titan_member"],
            "permissions": ["navigate_application", "view_wallet", ...],
            "is_titan_member": true,
            "current_rank": "regular",
            "wallet_balance": 0,
            "total_subscription_months": 0,
            "subscription": null,
            "referral": {
                "code": "JAN1A3F9K2B",
                "link": "https://domain.com/register?ref=JAN1A3F9K2B",
                "total_referrals": 0
            }
        }
    }
}
```

### 2.3 GET /auth/verify (check token validity)

**Response:**
```json
{
    "success": true,
    "data": { "valid": true, "user": { ... } }
}
```

### 2.4 POST /auth/logout

Just sends `Authorization: Bearer <token>`. Returns `{ "success": true, "message": "Logged out successfully" }`.

### 2.5 Email Verification Flow

```
Register/Login → Email OTP sent → Show OTP input screen → 
POST /auth/verify-email-with-otp { email, otp } → Email verified
```

---

## 3. User Dashboard Screens

### Screen 1: Dashboard Home

**Purpose:** Show user's subscription status, rank, quick stats.

**APIs to call on mount:**
- `GET /subscriptions/my-subscription` — active subscription info
- `GET /rankings/my` — current rank + progress
- `GET /birthdays/upcoming` — upcoming birthday this month

**UI Layout:**
```
┌──────────────────────────────────┐
│  👋 Welcome, {firstName}!        │
│  Membership: TITAN-0042          │
├──────────────────────────────────┤
│  ┌── Active Subscription ──────┐ │
│  │ Plan: Basic - ₦2,000/mo     │ │
│  │ Status: ████████░░ 8d left  │ │
│  │ Hours Today: 3h 45m / 6h    │ │
│  └──────────────────────────────┘ │
├──────────────────────────────────┤
│  ┌── Your Rank ────────────────┐ │
│  │  ⭐ VIP Member              │ │
│  │  10 months subscribed       │ │
│  │  🎯 2 more months to VVIP  │ │
│  └──────────────────────────────┘ │
├──────────────────────────────────┤
│  [My Portfolio] [Catalogue]      │
│  [Wallet: ₦12,500] [Referrals]   │
├──────────────────────────────────┤
│  🎂 Upcoming Birthdays           │
│  • Jane D. - Jul 15              │
│  • Bob S. - Jul 22               │
└──────────────────────────────────┘
```

### Screen 2: Subscription Plans

**Purpose:** Show available plans and allow user to subscribe.

**API:** `GET /subscriptions/plans`

**UI Layout:**
```
┌──────────────────────────────────┐
│  Choose Your Plan                │
├──────────────────────────────────┤
│  ┌── Basic ────────────────────┐ │
│  │  ₦2,000 / month             │ │
│  │  • 6 hours daily access     │ │
│  │  • Portfolio creation       │ │
│  │  [Subscribe]                │ │
│  └──────────────────────────────┘ │
│  ┌── Standard ─────────────────┐ │
│  │  ₦3,500 / month             │ │
│  │  • 12 hours daily access    │ │
│  │  [Subscribe]   ★ POPULAR    │ │
│  └──────────────────────────────┘ │
│  ┌── Premium ──────────────────┐ │
│  │  ₦5,000 / month             │ │
│  │  • Unlimited daily access   │ │
│  │  [Subscribe]                │ │
│  └──────────────────────────────┘ │
└──────────────────────────────────┘
```

**Subscribe flow:**
```javascript
const response = await api.post('/subscriptions/subscribe', {
    plan_id: 2,
    payment_reference: 'PAY-REF-123', // from payment gateway
    auto_renew: true
});
// On success → redirect to dashboard
```

### Screen 3: Portfolio Management

**Purpose:** Member manages their business portfolio.

**APIs:**
- `GET /portfolios/my` — get own portfolio with items
- `POST /portfolios` — upsert portfolio
- `POST /portfolios/items` — add item
- `PUT /portfolios/items/{id}` — edit item
- `DELETE /portfolios/items/{id}` — delete item

**UI Layout:**
```
┌──────────────────────────────────┐
│  My Business Portfolio           │
├──────────────────────────────────┤
│  Business Name: [___________]    │
│  Category: [Fashion  ▼]         │
│  WhatsApp: [+2348012345678]     │
│  Description: [________________] │
│  [Save Portfolio]               │
├──────────────────────────────────┤
│  Catalogue Items:                │
│  ┌── Women's Ankara Gown ──────┐│
│  │  ₦25,000   [Edit] [Delete]  ││
│  │  → DM: wa.me/2348012345678  ││
│  └──────────────────────────────┘│
│  [+ Add New Item]               │
└──────────────────────────────────┘
```

### Screen 4: Browse Member Catalogues

**Purpose:** Browse all approved member portfolios.

**APIs:**
- `GET /portfolios?category=Fashion&search=` — browse
- `GET /portfolios/categories` — get category list
- `GET /portfolios/{id}` — view single portfolio + items

**UI Layout:**
```
┌──────────────────────────────────┐
│  Browse Member Catalogues        │
├──────────────────────────────────┤
│  🔍 [Search businesses...]       │
│  Categories: All | Fashion | Art │
├──────────────────────────────────┤
│  ┌── Portfolio Card ───────────┐ │
│  │  [Profile Image]            │ │
│  │  Jane's Fashion House       │ │
│  │  Fashion • Lagos            │ │
│  │  [View Catalogue] [DM]      │ │
│  └──────────────────────────────┘ │
└──────────────────────────────────┘
```

### Screen 5: Birthday Rewards

**Purpose:** Check birthday eligibility and upcoming birthdays.

**APIs:**
- `GET /birthdays/eligibility` — check eligibility
- `GET /birthdays/upcoming` — upcoming birthdays
- `GET /birthdays/my-reward` — view own reward

**UI Layout:**
```
┌──────────────────────────────────┐
│  🎂 Birthday Rewards             │
├──────────────────────────────────┤
│  Your Birthday: Dec 25           │
│  Eligibility: ✅ Active (10mo)    │
│  Reward Status: Processing       │
├──────────────────────────────────┤
│  Upcoming Birthdays This Month:  │
│  ┌─── Birthday Card ───────────┐│
│  │  🎉 John D. - Jul 15        ││
│  │  VIP Member • 10 months     ││
│  │  [View Portfolio]           ││
│  └──────────────────────────────┘│
└──────────────────────────────────┘
```

### Screen 6: Refer & Earn

**Purpose:** Share referral link and track earnings.

**APIs:**
- `GET /referrals/my-link` — get referral code + link
- `GET /referrals/stats` — get earnings
- `GET /referrals/referred-users` — referred users list

**UI Layout:**
```
┌──────────────────────────────────┐
│  Refer & Earn                    │
├──────────────────────────────────┤
│  Your Referral Link:             │
│  ┌────────────────────────────┐  │
│  │ domain.com/ref=JAN1A3F9K2B│  │
│  └────────────────────────────┘  │
│  [Copy] [WhatsApp] [Facebook]    │
├──────────────────────────────────┤
│  Total Referrals: 12             │
│  Total Earned:   ₦6,000         │
│  Available:      ₦6,000         │
│  [Withdraw Earnings]             │
├──────────────────────────────────┤
│  Referral History:               │
│  ┌── Jane Doe - Jul 4 ─────────┐│
│  │  Status: ✅ Active           ││
│  └──────────────────────────────┘│
└──────────────────────────────────┘
```

### Screen 7: Wallet

**Purpose:** View balance and transaction history.

**APIs:**
- `GET /wallet/balance` — get balance
- `GET /wallet/transactions` — transaction history
- `POST /wallet/withdraw` — withdraw funds

**UI Layout:**
```
┌──────────────────────────────────┐
│  My Wallet                       │
├──────────────────────────────────┤
│  Balance: ₦12,500                │
│  [Withdraw]                      │
├──────────────────────────────────┤
│  Recent Transactions:            │
│  ┌── Referral Bonus ───────────┐│
│  │  +₦500    Jul 8, 2026       ││
│  └──────────────────────────────┘│
│  ┌── Withdrawal ───────────────┐│
│  │  -₦5,000   Jun 10, 2026    ││
│  └──────────────────────────────┘│
└──────────────────────────────────┘
```

### Screen 8: Content Submission

**Purpose:** Submit content for 72-hour review.

**API:** `POST /content/submit`

```
┌──────────────────────────────────┐
│  Submit Content for Review       │
├──────────────────────────────────┤
│  Title: [__________________]     │
│  Type: [Advertisement ▼]        │
│  Media URL: [_______________]   │
│  Duration (seconds): [___]      │
│  Description: [________________] │
│  [Submit for Review]             │
├──────────────────────────────────┤
│  ⏳ Estimated review: 72 hours  │
└──────────────────────────────────┘
```

---

## 4. Admin Dashboard Screens

### Screen A1: Admin Dashboard Home

**API:** `GET /admin/stats`

**Response includes new sections:**
```json
{
    "stats": {
        "user_overview": { ... },
        "subscription_analytics": {
            "total_active_subscriptions": 155,
            "total_revenue": 425000,
            "revenue_this_month": 425000,
            "subscriptions_by_plan": [
                { "plan": "Basic", "count": 45, "revenue": 90000 },
                { "plan": "Standard", "count": 78, "revenue": 273000 },
                { "plan": "Premium", "count": 32, "revenue": 160000 }
            ]
        },
        "member_rankings": {
            "total_titan_members": 62,
            "rank_distribution": { "regular": 25, "vip": 20, "vvip": 17 }
        },
        "birthday_analytics": {
            "eligible_members_this_month": 8,
            "rewards_this_month": 5,
            "pending_rewards": 3,
            "delivered_rewards": 2
        },
        "content_review": {
            "pending_reviews": 12,
            "approved": 45,
            "rejected": 8
        },
        "portfolio_stats": {
            "total_portfolios": 62,
            "approved": 58,
            "pending_approval": 4
        }
    }
}
```

**UI Layout:**
```
┌──────────────────────────────────┐
│  📊 Admin Dashboard              │
├──────────────────────────────────┤
│  ┌────┐ ┌────┐ ┌────┐ ┌────┐   │
│  │ 245│ │155 │ │62  │ │ 8  │   │
│  │Users│ │Subs│ │Titan│ │B'day│  │
│  └────┘ └────┘ └────┘ └────┘   │
├──────────────────────────────────┤
│  Revenue: ₦425,000 this month    │
│  [Line chart: last 6 months]     │
├──────────────────────────────────┤
│  Quick Actions:                  │
│  [Users] [Subs] [Birthdays]      │
│  [Content Review] [Portfolios]   │
└──────────────────────────────────┘
```

### Screen A2: Subscription Management

**APIs:**
- `GET /admin/subscriptions` — all subscriptions
- `POST /admin/subscriptions/plans` — create plan
- `PUT /admin/subscriptions/plans/{id}` — update plan
- `DELETE /admin/subscriptions/plans/{id}` — deactivate plan

**UI Layout:**
```
┌──────────────────────────────────┐
│  Subscription Management         │
├──────────────────────────────────┤
│  Plans:                          │
│  ┌── Basic ─── ₦2,000 ─────────┐│
│  │  Active: 45  Revenue: ₦90K  ││
│  │  [Edit] [Toggle]             ││
│  └──────────────────────────────┘│
│  ┌── Standard ─── ₦3,500 ──────┐│
│  │  Active: 78  Revenue: ₦273K ││
│  │  [Edit] [Toggle]             ││
│  └──────────────────────────────┘│
│  [+ Add New Plan]               │
├──────────────────────────────────┤
│  Recent Subscribers:             │
│  ┌── John D. - Premium ────────┐│
│  │  Paid: ₦5,000  Exp: Aug 9  ││
│  └──────────────────────────────┘│
└──────────────────────────────────┘
```

### Screen A3: Content Review Queue

**APIs:**
- `GET /admin/content/pending` — pending queue
- `POST /admin/content/{id}/approve` — approve
- `POST /admin/content/{id}/reject` — reject with reason
- `GET /admin/content/all?status=approved|rejected` — history

**UI Layout:**
```
┌──────────────────────────────────┐
│  📝 Content Review Queue         │
│  12 items pending review         │
├──────────────────────────────────┤
│  Tab: [Pending] [Approved] [Rejected] │
├──────────────────────────────────┤
│  ┌── Submission ────────────────┐│
│  │  Title: Summer Collection    ││
│  │  Type: Advertisement         ││
│  │  By: Jane D. (Member)        ││
│  │  ⏳ Auto-approve in 70h      ││
│  │  [Preview] [Approve] [Rej.]  ││
│  └──────────────────────────────┘│
└──────────────────────────────────┘
```

### Screen A4: Birthday Management

**APIs:**
- `GET /admin/birthdays?month=2026-07` — all rewards
- `GET /admin/birthdays/eligible` — eligible members
- `POST /admin/birthdays/assign-gift` — assign gift
- `POST /admin/birthdays/{id}/mark-delivered`

**Assign Gift Request:**
```json
{
    "user_id": 5,
    "gift_provider_user_id": 12,
    "gift_portfolio_item_id": 8,
    "reward_type": "physical_delivery"
}
```

**UI Layout:**
```
┌──────────────────────────────────┐
│  🎂 Birthday Management          │
│  This Month: 8 eligible members  │
├──────────────────────────────────┤
│  ┌── Jul 15 - John D. (VIP) ───┐│
│  │  Portfolio: Tech Solutions   ││
│  │  [Assign Gift] [Mark Done]   ││
│  └──────────────────────────────┘│
│  ┌── Jul 22 - Sarah K. (VVIP) ┐│
│  │  Portfolio: Art Gallery      ││
│  │  [Assign Gift] [Mark Done]   ││
│  └──────────────────────────────┘│
└──────────────────────────────────┘
```

### Screen A5: Portfolio Approvals

**APIs:**
- `GET /admin/portfolios?status=pending` — pending portfolios
- `PUT /admin/portfolios/{id}` — approve/feature

### Screen A6: Ad Management

**APIs:**
- `GET /admin/ads?status=active` — all ads
- `PUT /admin/ads/{id}` — update status

---

## 5. API Endpoint Reference

### 5.1 Authentication

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| POST | `/auth/register` | No | Register new user |
| POST | `/auth/login` | No | Login |
| POST | `/auth/logout` | Yes | Logout |
| GET | `/auth/user` | Yes | Get authenticated user |
| GET | `/auth/verify` | Yes | Verify token validity |
| GET | `/auth/profile` | Yes | Get profile data |
| PUT | `/auth/profile` | Yes | Update profile |
| POST | `/auth/change-password` | Yes | Change password |
| POST | `/auth/forgot-password` | No | Send reset OTP |
| POST | `/auth/verify-password-reset-otp` | No | Verify reset OTP |
| POST | `/auth/reset-password` | No | Reset password |
| POST | `/auth/resend-email-verification-otp` | No | Resend verification OTP |
| POST | `/auth/verify-email-with-otp` | No | Verify email with OTP |
| POST | `/auth/update-location` | Yes | Update GPS location |
| POST | `/auth/delete-account` | Yes | Request account deletion |

### 5.2 Subscriptions

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/subscriptions/plans` | No | List all available plans |
| POST | `/subscriptions/subscribe` | Yes | Subscribe to a plan |
| GET | `/subscriptions/my-subscription` | Yes | Get current subscription |
| GET | `/subscriptions/history` | Yes | Subscription history |
| POST | `/subscriptions/cancel-auto-renew` | Yes | Cancel auto-renewal |
| GET | `/subscriptions/remaining-hours` | Yes | Daily remaining hours |
| GET | `/admin/subscriptions` | Admin | All subscriptions |
| POST | `/admin/subscriptions/plans` | Admin | Create plan |
| PUT | `/admin/subscriptions/plans/{id}` | Admin | Update plan |
| DELETE | `/admin/subscriptions/plans/{id}` | Admin | Deactivate plan |

### 5.3 Session Tracking

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| POST | `/sessions/start` | Yes | Start login session |
| POST | `/sessions/end` | Yes | End session + calc duration |
| GET | `/sessions/today` | Yes | Today's logged time |
| GET | `/sessions/remaining` | Yes | Remaining time today |

### 5.4 Portfolios

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/portfolios` | No | Browse approved portfolios |
| GET | `/portfolios/categories` | No | List categories |
| GET | `/portfolios/{id}` | No | View single portfolio |
| GET | `/portfolios/my` | Yes | Get own portfolio |
| POST | `/portfolios` | Yes | Create/update portfolio |
| POST | `/portfolios/items` | Yes | Add portfolio item |
| PUT | `/portfolios/items/{id}` | Yes | Update item |
| DELETE | `/portfolios/items/{id}` | Yes | Delete item |
| GET | `/admin/portfolios` | Admin | All portfolios |
| PUT | `/admin/portfolios/{id}` | Admin | Approve/feature |

### 5.5 Birthdays

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/birthdays/upcoming` | No | Upcoming birthdays |
| GET | `/birthdays/eligibility` | Yes | Check eligibility |
| GET | `/birthdays/my-reward` | Yes | View own reward |
| GET | `/admin/birthdays` | Admin | All rewards |
| GET | `/admin/birthdays/eligible` | Admin | Eligible members |
| POST | `/admin/birthdays/assign-gift` | Admin | Assign gift |
| POST | `/admin/birthdays/{id}/mark-delivered` | Admin | Mark delivered |

### 5.6 Content Review

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| POST | `/content/submit` | Yes | Submit content |
| GET | `/content/my-submissions` | Yes | My submissions |
| GET | `/content/submission/{id}` | Yes | Submission status |
| GET | `/admin/content/pending` | Admin | Pending queue |
| GET | `/admin/content/all` | Admin | All submissions |
| POST | `/admin/content/{id}/approve` | Admin | Approve |
| POST | `/admin/content/{id}/reject` | Admin | Reject |

### 5.7 Advertisements

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/ads` | No | Active ads |
| POST | `/ads` | Yes | Create ad |
| GET | `/ads/my` | Yes | My ads |
| GET | `/admin/ads` | Admin | All ads |
| PUT | `/admin/ads/{id}` | Admin | Update status |

### 5.8 Wallet

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/wallet/balance` | Yes | Wallet balance |
| GET | `/wallet/transactions` | Yes | Transaction history |
| POST | `/wallet/withdraw` | Yes | Withdraw request |

### 5.9 Rankings

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/rankings/my` | Yes | My rank info |
| GET | `/rankings/leaderboard` | No | Top members |

### 5.10 Referrals (Existing)

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/referrals/my-link` | Yes | My referral link |
| GET | `/referrals/stats` | Yes | My stats |
| GET | `/referrals/referred-users` | Yes | Referred users |
| POST | `/referrals/withdraw` | Yes | Withdraw earnings |
| GET | `/referrals` | Admin | All referrals |

### 5.11 Notifications (Existing)

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/notifications` | Yes | List notifications |
| PUT | `/notifications/{id}/read` | Yes | Mark as read |
| PUT | `/notifications/mark-all-read` | Yes | Mark all read |
| GET | `/notifications/preferences` | Yes | Get preferences |
| PUT | `/notifications/preferences` | Yes | Update preferences |

---

## 6. Data Types & Interfaces

```typescript
// ──────────────────────────────────────────
// Auth & User
// ──────────────────────────────────────────
interface AuthUser {
    id: number;
    membership_id: string | null;
    first_name: string;
    last_name: string;
    email: string;
    phone_number: string;
    email_verified_at: string | null;
    phone_verified_at: string | null;
    isPhoneVerified: boolean;
    isEmailVerified: boolean;
    is_titan_member: boolean;
    current_rank: string | null;      // "regular" | "vip" | "vvip"
    wallet_balance: number;
    total_subscription_months: number;
    roles: string[];
    permissions: string[];
    subscription: UserSubscriptionInfo | null;
    referral: {
        code: string | null;
        link: string | null;
        total_referrals: number;
    };
}

// ──────────────────────────────────────────
// Subscription
// ──────────────────────────────────────────
interface SubscriptionPlan {
    id: number;
    name: string;           // "Basic" | "Standard" | "Premium"
    slug: string;           // "basic" | "standard" | "premium"
    price: number;
    daily_hours_limit: number; // 6, 12, or 0 for unlimited
    duration_days: number;
    features: string[] | null;
}

interface UserSubscriptionInfo {
    plan_name: string;
    plan_slug: string;
    start_date: string;        // "2026-07-01"
    end_date: string;          // "2026-07-31"
    days_remaining: number;
    daily_hours_limit: number;
    payment_status: string;    // "paid" | "pending" | "failed"
}

interface ActiveSubscription {
    id: number;
    plan_name: string;
    plan_slug: string;
    price: number;
    start_date: string;
    end_date: string;
    days_remaining: number;
    payment_status: string;
    auto_renew: boolean;
    daily_hours: DailyHoursInfo;
}

interface DailyHoursInfo {
    limit: number;              // 0 = unlimited
    limit_minutes: number;
    used_minutes: number;
    remaining_minutes: number;  // -1 = unlimited
}

// ──────────────────────────────────────────
// Portfolio
// ──────────────────────────────────────────
interface Portfolio {
    id: number;
    business_name: string;
    business_category: string | null;
    business_description: string | null;
    whatsapp_number: string | null;
    profile_image_url: string | null;
    cover_image_url: string | null;
    is_approved: boolean;
    is_featured: boolean;
    views_count: number;
    user?: {
        id: number;
        name: string;
        profile_photo_url: string | null;
    };
    items: PortfolioItem[];
}

interface PortfolioItem {
    id: number;
    title: string;
    description: string | null;
    price: number | null;
    image_urls: string[] | null;
    whatsapp_dm_link: string | null;
    is_active: boolean;
}

// ──────────────────────────────────────────
// Birthday
// ──────────────────────────────────────────
interface BirthdayEligibility {
    date_of_birth: string | null;
    birthday_this_month: boolean;
    total_subscription_months: number;
    is_eligible_for_reward: boolean;
    is_shoutout_only: boolean;
    current_reward: BirthdayReward | null;
}

interface BirthdayReward {
    id: number;
    reward_type: string;        // "physical_delivery" | "service" | "shoutout"
    status: string;             // "pending" | "processing" | "delivered" | "cancelled"
    is_shoutout_only: boolean;
    gift_provider?: { id: number; name: string; };
    gift_item?: { id: number; title: string; price: number | null; };
}

interface UpcomingBirthday {
    user_id: number;
    name: string;
    profile_photo_url: string | null;
    birth_date: string;
    age: number;
    days_until_birthday: number;
    rank: string | null;
    total_subscription_months: number;
    business: { name: string; category: string } | null;
}

// ──────────────────────────────────────────
// Content Submission
// ──────────────────────────────────────────
interface ContentSubmission {
    id: number;
    title: string;
    content_type: string;   // "advertisement" | "promotional_video" | "graphic" | "photo"
    status: string;         // "pending_review" | "approved" | "rejected"
    media_url: string;
    duration_seconds: number | null;
    submitted_at: string;
    reviewed_at: string | null;
    rejection_reason: string | null;
    estimated_review_completion: string;
}

// ──────────────────────────────────────────
// Wallet
// ──────────────────────────────────────────
interface WalletTransaction {
    id: number;
    type: string;           // "referral_bonus" | "subscription_payment" | "birthday_reward" | "withdrawal"
    amount: number;
    balance_before: number;
    balance_after: number;
    reference: string;
    description: string | null;
    status: string;         // "pending" | "completed" | "failed"
    created_at: string;
}

// ──────────────────────────────────────────
// Ranking
// ──────────────────────────────────────────
interface MemberRanking {
    current_rank: string;
    total_months_subscribed: number;
    consecutive_months: number;
    rank_achieved_at: string | null;
    next_rank_info: {
        next_rank: string | null;
        months_remaining: number | null;
        progress_percentage: number;
    };
}

// ──────────────────────────────────────────
// Advertisement
// ──────────────────────────────────────────
interface Advertisement {
    id: number;
    title: string;
    description: string | null;
    media_url: string | null;
    target_url: string | null;
    placement: string;      // "homepage" | "catalogue_page" | "sidebar"
    start_date: string;
    end_date: string;
    status: string;         // "active" | "expired" | "cancelled"
}

// ──────────────────────────────────────────
// API Response Wrapper
// ──────────────────────────────────────────
interface ApiResponse<T> {
    success: boolean;
    message: string;
    data: T;
    code?: number;
}

interface PaginatedResponse<T> {
    data: T[];
    pagination: {
        current_page: number;
        per_page: number;
        total: number;
        last_page: number;
    };
}
```

---

## 7. Permission Checking Utilities

```typescript
type PermissionSlug =
    | 'manage_users'
    | 'manage_roles'
    | 'manage_permissions'
    | 'manage_customers'
    | 'manage_transactions'
    | 'perform_transactions'
    | 'navigate_application'
    | 'view_ledger'
    | 'manage_ledger'
    | 'approve_ledger'
    | 'view_reports'
    | 'manage_subscriptions'
    | 'review_content'
    | 'manage_portfolios'
    | 'manage_birthday_rewards'
    | 'manage_ads'
    | 'view_member_rankings'
    | 'view_wallet'
    | 'submit_content'
    | 'manage_own_portfolio';

type RoleSlug = 'admin' | 'user' | 'customer' | 'titan_member' | 'content_reviewer';

class PermissionGuard {
    private user: { roles: string[]; permissions: string[] } | null;

    constructor(user: { roles: string[]; permissions: string[] } | null) {
        this.user = user;
    }

    hasPermission(permission: PermissionSlug): boolean {
        if (!this.user) return false;
        return this.user.permissions.includes(permission);
    }

    hasRole(role: RoleSlug): boolean {
        if (!this.user) return false;
        return this.user.roles.includes(role);
    }

    hasAnyRole(roles: RoleSlug[]): boolean {
        if (!this.user) return false;
        return roles.some(role => this.user!.roles.includes(role));
    }

    isAdmin(): boolean {
        return this.hasRole('admin');
    }

    isTitanMember(): boolean {
        return this.hasRole('titan_member');
    }

    canManageSubscriptions(): boolean {
        return this.hasPermission('manage_subscriptions');
    }

    canReviewContent(): boolean {
        return this.hasPermission('review_content');
    }

    canViewWallet(): boolean {
        return this.hasPermission('view_wallet');
    }

    canManageOwnPortfolio(): boolean {
        return this.hasPermission('manage_own_portfolio');
    }
}

// Usage in React component:
function AdminDashboard() {
    const { user } = useAuth();
    const guard = new PermissionGuard(user);

    if (!guard.isAdmin()) {
        return <AccessDenied />;
    }

    return (
        <div>
            {guard.canManageSubscriptions() && <SubscriptionPanel />}
            {guard.canReviewContent() && <ContentReviewPanel />}
        </div>
    );
}
```

---

## 8. Error Handling

### Standard Error Responses

```json
// Validation Error (422)
{
    "success": false,
    "message": "The selected ref is invalid.",
    "data": { "ref": ["The selected ref is invalid."] },
    "code": 422
}

// Auth Error (401)
{
    "success": false,
    "message": "Unauthenticated",
    "code": 401
}

// Forbidden (403)
{
    "success": false,
    "message": "No active subscription. Please subscribe to a plan.",
    "code": 403
}

// Not Found (404)
{
    "success": false,
    "message": "Portfolio not found",
    "code": 404
}

// Server Error (500)
{
    "success": false,
    "message": "Failed to fetch plans",
    "code": 500
}
```

### Frontend API Call Helper

```typescript
async function apiCall<T>(
    endpoint: string,
    options: RequestInit = {}
): Promise<ApiResponse<T>> {
    const token = localStorage.getItem('auth_token');
    
    try {
        const response = await fetch(`${API_BASE_URL}${endpoint}`, {
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
                ...(token && { 'Authorization': `Bearer ${token}` }),
                ...options.headers,
            },
            ...options,
        });

        const data = await response.json();

        if (!data.success) {
            // Handle validation errors (422)
            if (response.status === 422 && data.data) {
                // data.data contains field-level errors
                // e.g., { "plan_id": ["The plan_id field is required."] }
                return Promise.reject({ ...data, fieldErrors: data.data });
            }
            
            // Handle auth errors (401) — redirect to login
            if (response.status === 401) {
                localStorage.removeItem('auth_token');
                window.location.href = '/login';
                return Promise.reject(data);
            }
            
            return Promise.reject(data);
        }

        return data;
    } catch (error) {
        return Promise.reject({
            success: false,
            message: 'Network error. Please try again.',
            code: 0,
        });
    }
}
```

---

## 9. Key Workflows

### Workflow 1: User Registration with Referral

```
1. User lands on register page
2. Check URL for ?ref=CODE → extract referral code
3. If ref found, show banner "You were referred!"
4. User fills form + submits
5. POST /auth/register with { ..., ref: "CODE" }
6. On success → store token, redirect to dashboard
7. Show email verification prompt → enter OTP
8. POST /auth/verify-email-with-otp { email, otp }
9. Email verified → full access granted
```

### Workflow 2: User Subscribes to Plan

```
1. User navigates to Subscription Plans page
2. GET /subscriptions/plans → show 3 plan cards
3. User selects a plan
4. Show payment modal (Paystack/Flutterwave integration)
5. On payment success → POST /subscriptions/subscribe
   { plan_id: 2, payment_reference: "PAY-REF-123", auto_renew: true }
6. Backend creates subscription + updates ranking
7. Redirect to dashboard → show active subscription
8. Frontend starts tracking login sessions
```

### Workflow 3: Login Session Tracking (Hour Limits)

```
1. App starts / comes to foreground
2. POST /sessions/start → get session_id
3. Show remaining hours on dashboard
4. App goes to background / user logs out
5. POST /sessions/end { session_id } → records duration
6. Check daily_hours.remaining_minutes — show warning if low
7. If remaining_minutes <= 0 → show "Daily limit reached" message
```

### Workflow 4: Portfolio Management

```
1. User navigates to "My Portfolio"
2. GET /portfolios/my → show current portfolio (or empty)
3. User fills in business name, category, WhatsApp, description
4. POST /portfolios { business_name, category, ... } → save
5. User adds items: title, price, images, WhatsApp DM link
6. POST /portfolios/items { title, price, ... } → item created
7. Portfolio appears in public browse after admin approval
```

### Workflow 5: Birthday Reward Assignment (Admin)

```
1. Admin opens Birthday Management
2. GET /admin/birthdays/eligible → members eligible this month
3. Admin clicks "Assign Gift" on a member
4. Shows list of other members' portfolio items to choose from
5. Admin selects item → POST /admin/birthdays/assign-gift
   { user_id: 5, gift_provider_user_id: 12, gift_portfolio_item_id: 8 }
6. Reward created with status "processing"
7. Admin marks delivered → POST /admin/birthdays/{id}/mark-delivered
```

### Workflow 6: Content Review (Admin)

```
1. Admin opens Content Review page
2. GET /admin/content/pending → shows queue with auto-approval timers
3. Admin reviews content
4. If approved → POST /admin/content/{id}/approve
5. If rejected → POST /admin/content/{id}/reject { reason: "..." }
6. Auto-approval: After 72 hours, cron auto-approves pending items
```

---

## Appendix: Route Protection Summary

| Page/Component | Required Role | Required Permission |
|----------------|---------------|---------------------|
| Login/Register | None | None |
| User Dashboard | any | `navigate_application` |
| Subscription Plans | any | None (public) |
| Subscribe | any | None (uses auth) |
| My Portfolio | `titan_member` or `admin` | `manage_own_portfolio` |
| Browse Catalogues | None | None (public) |
| Birthday Rewards | any | None |
| Refer & Earn | any | None |
| Wallet | any | `view_wallet` |
| Content Submission | any | `submit_content` |
| **Admin Dashboard** | `admin` | — |
| Admin: Users | `admin` | `manage_users` |
| Admin: Subscriptions | `admin` | `manage_subscriptions` |
| Admin: Content Review | `admin` or `content_reviewer` | `review_content` |
| Admin: Birthdays | `admin` | `manage_birthday_rewards` |
| Admin: Portfolios | `admin` | `manage_portfolios` |
| Admin: Ads | `admin` | `manage_ads` |
| Admin: Roles | `admin` | `manage_roles` |
| Admin: Permissions | `admin` | `manage_permissions` |
