# CapEx UX Improvements — Design Spec

**Date:** 2026-03-23
**Scope:** `public/finance/capex_v2/`
**Stakeholder:** Eric Dunn / Henry (demo pending)

---

## Summary

Six UX improvements across the CapEx Tracker and Planning tabs, their popup editors, and shared table output files.

---

## 1. Export Button Cleanup (both tabs)

**Files:** `tracker.php`, `capex_planning_fragment.php`

- Remove the **Export-Reconcile** button from both tabs entirely.
- Keep the single **Export** button; add a `title` attribute tooltip:
  `"This will export all the data in the view — the filtered data."`
- No changes to `export.php` or `export_planning.php`.

---

## 2. Alternating Row Colors (both tables)

**Files:** `tracker.php` (inline `<style>`), `capex_planning_fragment.php` (inline `<style>`)

Add CSS to each file's existing `<style>` block:

```css
/* Tracker table */
#tbl_exporttable_to_xls tbody tr:nth-child(even) {
    background-color: #eef4fb;
}

/* Planning table */
#tbl_exporttable_to_xls2 tbody tr:nth-child(even) {
    background-color: #eef4fb;
}
```

**Note:** Rows with inline `background-color` from status styling (yellow=Requested, red=Denied in tracker; `#D6EEEE`=Requested, green=Ordered in planning) are unaffected — inline styles take precedence over the CSS rule. This is intentional: status color carries more meaning than the stripe.

No changes to `capex_tracker_table.php` or `capex_planning_table.php` row style logic.

---

## 3. Popup Header Cleanup (both editors)

**Files:** `tracker_editor.php`, `capex_planning_editor.php`

- Remove the `<img>` logo (210×155px) from both files.
- Change the `<h2>` tag to `<h3>` (tag name only — do not merge the record ID into the heading text; the existing `<b>` tag with username/ID on the next line stays as-is).
- Result: the editor opens with usable content immediately visible without scrolling past a large logo.

---

## 4. Planning Popup: Add Note / Char Counter Layout Fix

**File:** `capex_planning_editor.php`

**Bug:** `<div id="charCount" style="... margin-top: -28px;">` pulls the counter up over the Add Note button.

**Fix:** Remove `margin-top: -28px`. Restructure the notes row layout so the order reads:
1. Textarea
2. Char counter (below textarea, left-aligned)
3. Add Note button (below char counter, or inline with it)

---

## 5. Remove Refresh Button from Planning Tab

**File:** `capex_planning_fragment.php`

- Remove the `🔄 Refresh Table` button.
- After this change, the table refreshes automatically when a record is saved via the popup (closeCapexModal is called with a rowId). Closing the modal without saving (X button, ESC, backdrop click) does not trigger a refresh — this is intentional.

---

## 6. Row Anchoring After Save/Close (both tabs)

**Approach:** Option A — direct parent function call with row ID.

### Changes

**`capex_tracker_table.php`** — add `data-id` to each data row:
```php
echo '<tr data-id="' . $id . '" ' . $row_style . '>';
```
Grand Total row (`bgcolor="lightgrey"`) is unchanged — no `data-id` needed.

**`capex_planning_table.php`** — add `data-id` alongside existing `data-href`:
```php
echo '<tr data-href="&id=' . (int)$row['id'] . '" data-id="' . (int)$row['id'] . '" ' . $row_style . '>';
```

**`tracker_editor.php`** — in the save handler's `.then()` success block, replace the entire `if (window.parent && typeof window.parent.closeTrackerModal === 'function')` block (currently calls `refreshTrackerTable()` then `closeTrackerModal()`) with a single call:
```js
if (window.parent && typeof window.parent.closeTrackerModal === 'function') {
    window.parent.closeTrackerModal(<?= $edit_id ?>);
} else {
    window.close();
}
```
`closeTrackerModal(rowId)` now triggers the refresh and anchor internally.

**`capex_planning_editor.php`** — in the save handler's `.then()` success block, replace the entire `if (window.parent !== window)` block (currently calls `closeCapexModal()` then `refreshPlanningTable()`) with a single call:
```js
if (window.parent !== window) {
    window.parent.closeCapexModal(<?= $edit_id ?>);
} else {
    localStorage.setItem('capexRefresh', 'planning');
    window.close();
}
```
`closeCapexModal(rowId)` now triggers the refresh and anchor internally.

**`tracker.php`** — update `closeTrackerModal`, update `refreshTrackerTable` to return promise, add anchor CSS + helper:

**Note:** The overlay `onclick="closeTrackerModal()"` and the Close button call `closeTrackerModal()` with no argument. This is safe — `rowId` will be `undefined`, the `if (rowId)` guard skips the anchor, and the modal closes normally. No changes needed to those callers.

**Note:** `capex_planning_fragment.php`'s backdrop click and ESC keydown listeners call `closeCapexModal()` with no argument — same situation, also safe.

```css
@keyframes rowFlash {
    0%   { background-color: #c5f3e0; }
    100% { background-color: transparent; }
}
.row-anchor-flash {
    animation: rowFlash 1.5s ease-out forwards;
}
```

```js
// refreshTrackerTable — add return so callers can chain .then()
function refreshTrackerTable() {
    const url = "api/capex_tracker_table.php" + window.location.search;
    return fetch(url)
        .then(res => res.text())
        .then(html => {
            const tbody = document.getElementById("trackerBody");
            if (tbody) tbody.innerHTML = html;
        })
        .catch(err => console.error("Table refresh failed", err));
}

function closeTrackerModal(rowId) {
    document.getElementById("trackerEditorModal").style.display = "none";
    document.getElementById("trackerEditorFrame").src = "";
    if (rowId) {
        refreshTrackerTable().then(() => anchorRow(rowId));
    }
}

function anchorRow(rowId) {
    const row = document.querySelector('#tbl_exporttable_to_xls tr[data-id="' + rowId + '"]');
    if (row) {
        row.scrollIntoView({ behavior: 'smooth', block: 'center' });
        row.classList.add('row-anchor-flash');
        row.addEventListener('animationend', () => row.classList.remove('row-anchor-flash'), { once: true });
    }
}
```

**`capex_planning_fragment.php`** — update `closeCapexModal`, update `refreshPlanningTable` to return promise, add anchor CSS + helper:

```css
@keyframes rowFlash {
    0%   { background-color: #c5f3e0; }
    100% { background-color: transparent; }
}
.row-anchor-flash {
    animation: rowFlash 1.5s ease-out forwards;
}
```

```js
// refreshPlanningTable — add return so callers can chain .then()
function refreshPlanningTable() {
    const allowed = ['plan_status', 'plan_requestor', 'plan_location', 'plan_type',
                     'plan_msa', 'plan_commitment', 'plan_ad', 'plan_rd', 'plan_category',
                     'plan_deploy', 'plan_quote_confirmed', 'plan_priority', 'plan_year',
                     'plan_po', 'plan_startdate_post', 'plan_enddate_post'];
    const params = new URLSearchParams(window.location.search);
    const planParams = new URLSearchParams();
    allowed.forEach(k => {
        params.getAll(k).forEach(v => planParams.append(k, v));
    });
    const url = "api/capex_planning_table.php?" + planParams.toString();
    return fetch(url)
        .then(res => res.text())
        .then(html => {
            const tbody = document.getElementById("planningBody");
            if (tbody) tbody.innerHTML = html;
        })
        .catch(err => console.error("Planning table refresh failed", err));
}

function closeCapexModal(rowId) {
    document.getElementById('capexModal').style.display = 'none';
    document.getElementById('capexModalFrame').src = '';
    if (rowId) {
        refreshPlanningTable().then(() => anchorPlanningRow(rowId));
    }
}

function anchorPlanningRow(rowId) {
    const row = document.querySelector('#tbl_exporttable_to_xls2 tr[data-id="' + rowId + '"]');
    if (row) {
        row.scrollIntoView({ behavior: 'smooth', block: 'center' });
        row.classList.add('row-anchor-flash');
        row.addEventListener('animationend', () => row.classList.remove('row-anchor-flash'), { once: true });
    }
}
```

---

## Files Changed

| File | Change |
|---|---|
| `tracker.php` | Remove Export-Reconcile, add tooltip, add stripe CSS, update modal close + anchor logic |
| `capex_planning_fragment.php` | Remove Export-Reconcile, add tooltip, remove Refresh button, add stripe CSS, update modal close + anchor logic |
| `capex_tracker_table.php` | Add `data-id` to `<tr>` |
| `capex_planning_table.php` | Add `data-id` to `<tr>` |
| `tracker_editor.php` | Remove logo, compact header, pass rowId on close |
| `capex_planning_editor.php` | Remove logo, compact header, fix char counter overlap, pass rowId on close |

---

## Out of Scope

- Changes to `export.php` / `export_planning.php`
- Changes to filter logic or query behavior
- Any changes to other capex_v2 files not listed above
