# Dashboard Integration Notes & Requirements: Admin & Provider

This document specifies frontend integration requirements, UI behaviors, and endpoint consumption rules for both the **Admin Dashboard** and **Provider Dashboard/App**.

---

## 📋 Architectural Review: Is the "Resend Contract" Endpoint Needed?

**Endpoint:** `POST /api/dashboard/admin/provider-contracts/{id}/resend`

### Review & Verdict:
**YES, it is needed and should be maintained alongside the Edit endpoint.** They address two distinct user journeys:

| Feature / Action | `POST /provider-contracts/{id}/resend` | `PUT /provider-contracts/{id}` |
|---|---|---|
| **Primary Intent** | 1-Click action without changing terms, or reset to master template | Modifying clauses, title, or duration |
| **Payload Required** | Minimal query/body: `{"reset_to_unified": true/false}` | Full contract payload including clauses array |
| **Use Case 1** | **Quick Resend from Table:** Provider claims they didn't see the contract, or rejected it accidentally and wants the exact same contract sent back. Admin clicks "Resend" directly from the table actions dropdown with 1 click. | Not suitable (would require opening an edit form and resubmitting all clauses). |
| **Use Case 2** | **Reset to Master Template:** Provider had a custom contract that was rejected, but now agrees to the standard terms. Admin calls `resend` with `reset_to_unified: true`, which automatically resets all clauses to `ProviderContractTemplate` master template. | Requires admin to manually copy/paste master template clauses. |
| **Use Case 3** | When terms/clauses are being actively renegotiated or customized. | **Use `PUT /{id}`:** Admin edits the clauses in the form and saves. The backend `update()` method automatically resets status to `sent`, clears rejection notes, and dispatches `ContractSent` event. |

**Frontend Recommendation:**
- Keep a **"Resend Contract"** button in the contract details view and table actions menu (for contracts with status `sent` or `rejected`).
- If admin needs to change clauses or contract duration, open the **"Edit Contract"** modal/page which calls `PUT /{id}`.

---

# PART 1: ADMIN DASHBOARD

---

### 0. Complete Reference: Admin Contract Endpoints & Lifecycle Actions

All provider contract endpoints in the Admin Dashboard are verified, fully implemented, and functioning correctly. Below is the complete specification of endpoints, actions, and status rules:

| # | Action | HTTP & Endpoint | Purpose & Description | Allowed Statuses / Guards |
|---|---|---|---|---|
| 1 | **View Master Template** | `GET /api/dashboard/admin/provider-contracts/template` | View the company-wide unified contract template (title, duration, duration unit, clauses). | Any time |
| 2 | **Update Master Template** | `PUT /api/dashboard/admin/provider-contracts/template` | Edit master clauses & terms. Future contracts inherit these by default. | Any time |
| 3 | **List Contracts** | `GET /api/dashboard/admin/provider-contracts` | Paginated listing of all contracts. Supports filters: `status`, `provider_id`, `search`, `sort_by`, `sort_order`. | Any time |
| 4 | **Create & Send Contract** | `POST /api/dashboard/admin/provider-contracts` | Assign and dispatch a contract to a provider. If custom `clauses` are omitted, auto-inherits from the Master Template. Dispatches notification to provider. | When provider is accepted |
| 5 | **View Contract Details** | `GET /api/dashboard/admin/provider-contracts/{id}` | **Full contract view:** Returns all details including `clauses_data` array, provider info, dates, and rejection reason. | Any time |
| 6 | **Edit & Update Contract** | `PUT /api/dashboard/admin/provider-contracts/{id}` | Edit title, duration, or customize clauses. If contract was `rejected`, saving resets status to `sent` and re-notifies provider. | ✅ Allowed on: `sent`, `rejected`<br>❌ **Blocked on:** `accepted` (HTTP 422) |
| 7 | **Resend Contract** | `POST /api/dashboard/admin/provider-contracts/{id}/resend` | Quick 1-click resend without opening editor. Supports `{"reset_to_unified": true}` to revert custom clauses back to master template. | ✅ Allowed on: `sent`, `rejected`<br>❌ **Blocked on:** `accepted` |
| 8 | **Delete Contract** | `DELETE /api/dashboard/admin/provider-contracts/{id}` | Delete contract record. | ✅ Allowed on: `sent`, `rejected`, `expired`<br>❌ **Blocked on:** `accepted` (cannot delete active contract) |

#### Contract Status Lifecycle State Machine:
```
[Admin Creates] ─────────► status: "sent"
                               │
            ┌──────────────────┴──────────────────┐
            ▼                                     ▼
 status: "accepted"                      status: "rejected"
 (ACTIVE CONTRACT)                       (WITH REASON)
 • Cannot edit (PUT blocked)             • Admin can Resend (POST resend)
 • Cannot delete (DELETE blocked)        • Admin can Edit (PUT updates & sets back to "sent")
 • End date reached ──► "expired"        • Admin can Delete (DELETE allowed)
```

---

### 1. Contract Details View (`GET` Show Endpoint Requirement)

#### ⚠️ Problem Identified:
The frontend was opening the contract view using only the row data from `GET /api/dashboard/admin/provider-contracts` (Index). As a result:
- The Index resource **does not include clauses content** (`clauses_data`); it only provides `clauses_count`.
- Full details (clause text, provider profile, rejection audit trail) are missing.

#### ✅ Integration Requirement:
When an admin clicks on any contract row or "View Contract":
1. The frontend **MUST** make an API call to:
   ```http
   GET /api/dashboard/admin/provider-contracts/{id}
   ```
2. Render the full contract from the response object (`ProviderContractShowResource`):
   - `contract_number`: Reference number (e.g. `CNT-202610-0001`).
   - `title`: Contract title.
   - `duration` & `duration_unit`: e.g. `6 month` or `1 year`.
   - `start_date` & `end_date`: Contract validity period.
   - `status`: `sent`, `accepted`, `rejected`, or `expired`.
   - `rejection_reason`: Displayed prominently if status is `rejected`.
   - `clauses_data`: Array of full clauses:
     ```json
     "clauses_data": [
       {
         "id": 1,
         "clause_number": 1,
         "title": "نطاق العمل",
         "content": "يلتزم مزود الخدمة بتقديم..."
       }
     ]
     ```
   - `provider_data`: Provider details (name, phone, email, avatar).

---

### 2. Contract Edit Flow (`PUT` Endpoint Requirement)

#### ⚠️ Problem Identified:
Opening the "Edit Contract" screen was showing an empty form or partial data rather than the existing contract content.

#### ✅ Integration Requirement:
1. **Pre-fetching:** Before displaying the edit form, fetch the contract details via `GET /api/dashboard/admin/provider-contracts/{id}`.
2. **Pre-populating:** Populate the edit form with:
   - Contract Title (`title`)
   - Duration (`duration`)
   - Duration Unit (`duration_unit`)
   - The full list of existing clauses (`clauses`), allowing inline editing of title and text, reordering, adding new clauses, or removing existing ones.
3. **Submission Endpoint:**
   ```http
   PUT /api/dashboard/admin/provider-contracts/{id}
   Content-Type: application/json
   ```
   **Payload:**
   ```json
   {
     "title": "عقد تقديم خدمات هندسية - محدث",
     "duration": 1,
     "duration_unit": "year",
     "clauses": [
       {
         "order": 1,
         "title": "التمهيد والتعريفات",
         "content": "نص البند الأول بعد التعديل..."
       },
       {
         "order": 2,
         "title": "الالتزامات المالية",
         "content": "نص البند المالي المتفق عليه..."
       }
     ]
   }
   ```
4. **Behavior on Save:**
   - If the contract was previously `rejected`, saving automatically resets status to `sent`, clears the rejection reason, and notifies the provider.
   - **Guard:** If status is `accepted`, the contract is legally binding and active — the backend will reject updates with HTTP 422 (`Cannot edit an accepted and active contract.`). The Edit button must be hidden or disabled for `accepted` contracts.

---

### 3. Contract Duration: Removal of "Days"

#### ✅ Requirement:
- Provider partnership contracts are medium-to-long term agreements.
- In the **Duration Unit** dropdown for contracts (both in master template creation/editing and individual contract creation/editing):
  - ❌ **Remove "Days" (`day`) from the dropdown options.**
  - ✅ **Keep only:**
    - **Months** (`month` - شهور)
    - **Years** (`year` - سنوات)

---

### 4. Package Creation: Platform Share / App Fee Informative Hint

#### ⚠️ Clarification:
When creating or editing a Package (`POST /api/dashboard/admin/packages` or `PUT .../packages/{id}`):
- Admin enters `provider_discount_percentage` (what provider bears) and `admin_discount_percentage` (what platform bears).
- The platform discount share must be compared against the **Platform Fee (`app_fee_percentage`)**, **NOT** the VAT percentage (`vat_percentage`).
- The hint must be informative, objective, and professional — avoiding negative words like "خسارة" ("loss").

#### ✅ Frontend UI Implementation:
Under or beside the `admin_discount_percentage` input field, display an informational alert/hint:

```
ℹ️ تنبيه:
يُرجى الانتباه إلى أن نسبة الخصم التي تتحملها المنصة يجب ألا تتجاوز نسبة رسوم المنصة (رسوم التطبيق)، لضمان الحفاظ على أرباح المنصة من الطلبات.
```

*(English equivalent)*:
```
ℹ️ Note:
Please ensure the platform discount share does not exceed the platform fee (app fee percentage) to ensure net platform earnings from orders remain positive.
```

#### 🔒 Package Immutability Guard (Active Subscribers):
- **Rule:** If a package has active subscribers (`remaining_orders > 0`), the package is **100% locked** from editing.
- **Backend Response Flag (Returned in `PackageIndexResource` & `PackageShowResource`):**
  The API provides one clean boolean flag (`has_active_subscribers`):
  ```json
  {
    "id": 1,
    "name": "باقة الاستشارات",
    "is_active": true,
    "has_active_subscribers": true
  }
  ```
- **Frontend UI Implementation:**
  ```html
  <!-- Disable Edit Button if has_active_subscribers is true -->
  <button 
    :disabled="package.has_active_subscribers" 
    :title="package.has_active_subscribers ? 'لا يمكن تعديل باقة بها مشتركون نشطون. أوقف تفعيلها وأنشئ باقة جديدة' : 'تعديل الباقة'">
    تعديل
  </button>

  <!-- Disable Delete Button if has_active_subscribers is true -->
  <button 
    :disabled="package.has_active_subscribers" 
    :title="package.has_active_subscribers ? 'لا يمكن حذف باقة بها مشتركون نشطون' : 'حذف الباقة'">
    حذف
  </button>
  ```
- **Backend Behavior:** If a request is attempted, `PUT /api/dashboard/admin/packages/{id}` and `DELETE /api/dashboard/admin/packages/{id}` throw a 422 DomainException:
  > *"Cannot edit this package while there are active subscribers. You can deactivate it and create a new package instead."*
- **Allowed Action:** `PATCH /api/dashboard/admin/packages/{id}/toggle-status` (Toggling `is_active`) is always permitted so admin can hide/deactivate the package from new buyers at any time.

---

### 5. Provider & Team Tags (Badges) Integration

Admin can classify providers and teams using custom tags/badges.

#### 1. Assigning Tags via Admin API:
- **Assign to Provider:**
  ```http
  POST /api/dashboard/admin/providers/{provider_id}/tags
  Content-Type: application/json

  {
    "tag_ids": [1, 3, 5]
  }
  ```
- **Assign to Team:**
  ```http
  POST /api/dashboard/admin/teams/{team_id}/tags
  Content-Type: application/json

  {
    "tag_ids": [2, 4]
  }
  ```

#### 2. Displaying Tags in Tables & Details:
The backend returns `tags_data` in all Provider and Team endpoints:
- `GET /api/dashboard/admin/providers` (Index)
- `GET /api/dashboard/admin/providers/{id}` (Show)
- `GET /api/dashboard/admin/teams` (Index)
- `GET /api/dashboard/admin/teams/{id}` (Show)

**Response Structure:**
```json
"tags_data": [
  {
    "id": 1,
    "name": "محامي معتمد",
    "color": "#1E40AF"
  },
  {
    "id": 2,
    "name": "VIP",
    "color": "#F59E0B"
  }
]
```

**Frontend Requirement:**
- Render `tags_data` as badge chips in the Provider and Team listings.
- Include a "Manage Tags" action modal in the provider/team view to sync tags via the endpoints above.

---

### 6. Admin Contract Notifications & Deep-Link Routing

When a provider interacts with a contract:
1. **Contract Accepted:** Provider accepts -> Super admin and contract admins receive notification.
2. **Contract Rejected:** Provider rejects with reason -> Admins receive notification with reason.
3. **Contract Expired:** Scheduled daily check marks contract expired -> Admins receive notification.

**Notification Payload:**
```json
{
  "notify_type": "contract",
  "notify_id": 15,
  "title": "تم قبول العقد",
  "message": "قام مزود الخدمة بقبول العقد رقم CNT-202610-0015"
}
```

**Frontend Router Handler:**
```typescript
if (notification.notify_type === 'contract') {
  router.push(`/dashboard/provider-contracts/${notification.notify_id}`);
}
```

---

# PART 2: PROVIDER DASHBOARD & APP

---

### 1. Displaying Provider Tags in Profile & Team View

Tags assigned by Admin are now returned in provider-facing profile and team endpoints.

#### 1. Provider Profile (`GET /api/provider/profile`):
The `ProviderProfileResource` now returns `tags_data`:
```json
{
  "id": 24,
  "full_name": "أحمد الشمري",
  "email": "ahmed@example.com",
  "tags_data": [
    {
      "id": 1,
      "name": "محامي معتمد"
    },
    {
      "id": 3,
      "name": "نخبة مميز"
    }
  ]
}
```

**Provider UI Requirement:**
- Display these badges prominently on the **Provider Profile screen** (e.g. underneath the provider's name or under their specialty header).
- Note: Tags are read-only for providers (assigned and managed exclusively by Admin).

#### 2. Provider Team View (`GET /api/provider/teams/{id}`):
The `ProviderTeamResource` returns `tags_data` for the team:
```json
{
  "id": 5,
  "name": "فريق الاستشارات الضريبية",
  "tags_data": [
    {
      "id": 4,
      "name": "فريق معتمد"
    }
  ]
}
```
- Display team badges on the Team Overview page.

---

### 2. Provider Contract Notifications & Direct Routing

When an Admin sends or resends a contract to a provider:
- **Notification Type:** `"contract"`
- **Notification ID:** `<contract_id>`

**Notification Payload:**
```json
{
  "notify_type": "contract",
  "notify_id": 15,
  "title": "عقد جديد في انتظار موافقتك",
  "message": "تم إرسال عقد جديد إليك. يرجى مراجعة البنود واتخاذ الإجراء المناسب."
}
```

**Provider App / Dashboard Router Handler:**
```typescript
if (notification.notify_type === 'contract') {
  // Direct open of the contract acceptance/review screen
  router.push(`/provider/contracts/${notification.notify_id}`);
}
```

#### Provider Actions on Contract:
On the contract review screen (`GET /api/provider/contracts/{id}`):
- **Accept:**
  ```http
  POST /api/provider/contracts/{id}/accept
  ```
- **Reject:**
  ```http
  POST /api/provider/contracts/{id}/reject
  Content-Type: application/json

  {
    "rejection_reason": "يرجى تعديل البند المالي رقم 3"
  }
  ```

---

## 📌 Summary Checklist for Frontend Teams

### Admin Dashboard:
- [ ] Contract View: Call `GET /api/dashboard/admin/provider-contracts/{id}` rather than relying on index row data.
- [ ] Contract Edit: Fetch full contract with clauses -> prefill full editor -> submit via `PUT /api/dashboard/admin/provider-contracts/{id}`.
- [ ] Contract Duration: Remove `day` from duration units dropdown (leave only `month` and `year`).
- [ ] Resend Contract: Wire up `POST /api/dashboard/admin/provider-contracts/{id}/resend` to table action button for quick resend / reset to master template.
- [ ] Package Creation: Display hint that `admin_discount_percentage` should not exceed `app_fee_percentage` to maintain positive net platform profit.
- [ ] Tags: Display `tags_data` chips in Provider and Team index and show views; wire up assign tags modals.
- [ ] Notification Routing: Handle `notify_type === 'contract'` by routing to contract show page.

### Provider App & Dashboard:
- [ ] Profile: Render assigned badges from `tags_data` in provider profile view.
- [ ] Teams: Render team badges from `tags_data` in team view.
- [ ] Notification Routing: Handle `notify_type === 'contract'` by routing directly to contract review & acceptance view.
