# PRD: Appointment Board — Fix 4 Failed Test Cases (AB_TC_007, 011, 028, 030)

## Context

Four QA test cases in the Appointment Board module are failing. Root causes have been traced to:

- `app/Http/Controllers/Calendar/EventController.php` — reschedule logic sets wrong status on original event
- `app/Http/Controllers/Leads/AppointmentBoardController.php` — weekly grid query excludes rescheduled events
- `resources/views/admin/leads/appointment-board.blade.php` — missing `selected` attribute, no Refresh button, unguarded global search handler
- `public/assets/js/common.js` — global `.module-search` Enter handler reloads board page unintentionally

---

## Fix 1 — AB_TC_007: Rescheduled count not showing under Res. column

### Root Cause

When a user reschedules an appointment from the Calendar, `EventController::rescheduleStore()` (lines 265–267) does two things:

1. Creates a NEW calendar event with `is_rescheduled = 0` (the future appointment).
2. Marks the ORIGINAL event as `status = 2` (Complete) **and** `is_rescheduled = 1`.

The `buildWeeklyGrid()` raw SQL query in `AppointmentBoardController` (line 238) filters:

```sql
AND ce.status = 1
```

This excludes the original event (now `status = 2`) entirely. The new event has `is_rescheduled = 0` so it falls into Set/Conf/Seen. Result: **zero count in the Res. column** even though an appointment was rescheduled.

### Changes

**`app/Http/Controllers/Leads/AppointmentBoardController.php` — `buildWeeklyGrid()` SQL (line ~238)**

Replace:
```php
               AND ce.status = 1
```
With:
```php
               AND (ce.status = 1 OR (ce.is_rescheduled = 1 AND ce.status = 2))
```

This allows the original rescheduled event (status=2, is_rescheduled=1) to appear in the Res. column while still excluding Cancelled (status=3) and incomplete events with status=2 that are not rescheduled.

No changes needed to the PHP column-assignment logic (lines 268–276) — `$col = 'res'` when `is_rescheduled == 1` is already correct.

---

## Fix 2 — AB_TC_011: User dropdown does not default to "All Users"

### Root Cause

In `appointment-board.blade.php` (line 29), the "All Users" option has no explicit `selected` attribute:

```html
<option value="">All Users</option>
```

Although HTML browsers select the first option by default, Select2 (initialized via the `.select2` class on the same element) may not consistently surface the empty-value first option as the selected state, particularly across initialization sequences. The fix is to add an explicit `selected` attribute when `$userId` is empty.

### Changes

**`resources/views/admin/leads/appointment-board.blade.php` — line 29**

Replace:
```html
<option value="">All Users</option>
```
With:
```html
<option value="" {{ $userId === '' ? 'selected' : '' }}>All Users</option>
```

---

## Fix 3 — AB_TC_028: Deleted/cancelled appointment not removed after board refresh

### Root Cause

The `buildWeeklyGrid()` query already correctly excludes:
- Soft-deleted events: `AND ce.deleted_at IS NULL`
- Cancelled events: excluded by the status filter (Fix 1 retains this)

However, the board page has **no "Refresh" button**. After a user deletes or cancels an appointment in the Calendar module, there is no visible way to reload board data without navigating away. The only triggers for AJAX data reload are:
- Clicking "Prev Week" / "Next Week" buttons
- Clicking "Apply" filter button

Neither is labeled as a "Refresh" action, so testers cannot complete the "Refresh board" step.

### Changes

**`resources/views/admin/leads/appointment-board.blade.php` — filter row (line ~38)**

Add a Refresh button after the existing "Apply" button:

```html
<div class="col-auto">
    <button type="button" class="black-btn-inner waves-effect btn-sm" id="btnRefreshBoard">
        <i class="bx bx-refresh me-1"></i> Refresh
    </button>
</div>
```

**`resources/views/admin/leads/appointment-board.blade.php` — JS block (inside the IIFE, after line ~155)**

Wire the Refresh button to `reloadGrid()`:

```javascript
document.getElementById('btnRefreshBoard')?.addEventListener('click', reloadGrid);
```

---

## Fix 4 — AB_TC_030: Global search bar incorrectly affects the board

### Root Cause

`public/assets/js/common.js` (lines 3–10) binds an Enter-key handler to ALL `.module-search` elements:

```javascript
searchInput.on('keypress', function(e) {
    if (e.which === 13) {
        var url = new URL(window.location.href);
        url.searchParams.set('search_text', searchText);
        window.location.href = url.toString();  // full page reload
    }
});
```

The global layout (`layout.blade.php` line 111) renders a notification-panel search input with `class="... module-search"`. When a user types in this search box on the Appointment Board page and presses Enter, the handler fires, appends `search_text=...` to the URL, and reloads the entire page. This:

1. Resets the board's JS variable `currentWeekStart` to the server-rendered current week (any week the user had navigated to via AJAX is lost).
2. Adds an irrelevant `search_text` query parameter to the URL.
3. The controller ignores `search_text`, so the board shows full data — but visually the URL implies a filter is active.

The established fix pattern (used in `helpdesk_tickets.js` line 198) is to override the common.js handler for the specific page.

### Changes

**`resources/views/admin/leads/appointment-board.blade.php` — inside `@push('page_script')`, at the start of the IIFE**

Add the following override before any other JS:

```javascript
// Prevent global search bar from doing a full-page reload on this view.
// common.js would add search_text to the URL, resetting AJAX week state.
$(document).off('keypress', '.module-search').on('keypress', '.module-search', function(e) {
    if (e.which === 13) {
        e.preventDefault();
        e.stopImmediatePropagation();
    }
});
```

---

## Files Modified

| File | Fix |
|------|-----|
| `app/Http/Controllers/Leads/AppointmentBoardController.php` | AB_TC_007 |
| `resources/views/admin/leads/appointment-board.blade.php` | AB_TC_011, AB_TC_028, AB_TC_030 |

---

## Verification

1. **AB_TC_007** — Open Appointment Board. Go to Calendar and reschedule an appointment. Return to the board (same week). The original appointment's day should show a count of 1 in the **Res.** column. The new (rescheduled) appointment should appear in **Set** on its new day.

2. **AB_TC_011** — Open Appointment Board without any `user_id` query param. The User dropdown should visually display **"All Users"** as the selected option. The grid should show appointments for all users.

3. **AB_TC_028** — Open Appointment Board. Observe a user with appointment counts. In a separate tab, go to Calendar and delete or cancel one of those appointments. Return to the board tab and click **Refresh**. The count for the deleted/cancelled appointment should be decremented or removed.

4. **AB_TC_030** — Open Appointment Board. Navigate to a non-current week using the Prev/Next buttons. Open the notification dropdown, type "Luna" in the search box, and press Enter. The board should remain on the same week without full-page reload, and the grid should not show incorrect or reset data.
