Project

General

Profile

Actions

Bug #19

open

Extract Shared UI Components from IVR Modules Page (Bounded Refactor)

Added by Redmine Admin 5 days ago.

Status:
New
Priority:
Normal
Assignee:
-
Start date:
10/12/2026
Due date:
% Done:

0%

Estimated time:

Description

User Story

As a frontend engineer maintaining the IVR section of the application, I want the duplicated status-colour logic, table markup, and search-form markup extracted into shared, typed components, so that the IVR Modules page is easier to maintain, the dead Show.tsx page is removed, and a baseline of characterization tests pins the current backend behaviour before any future changes.

Background

The IVR section currently has three copies of a status-colour map (statusClass / statusBadge) spread across Pages/Ivr/Module/Index.tsx, Pages/Ivr/Hub/Index.tsx, and Pages/Ivr/Module/Show.tsx. The Hub map has 11 entries; the Module and Show copies have only 8, silently dropping badge rendering for Sale, Escalated, and Callback values. Show.tsx is dead code — the controller at /ivr/{slug} only redirects and never renders it. There are no tests today for /ivr/modules or /ivr/{slug}.

This is a frontend-only, single-screen bounded refactor. No PHP, no routes, no config, no legacy modules.

Scope

New files:

  • resources/js/types/ivr.ts — IvrColumn, IvrRow, IvrModuleTab interfaces
  • resources/js/utils/ivr/statusTone.ts — STATUS_TONES (11-entry map) + statusTone()
  • resources/js/utils/ivr/statusTone.test.ts — Vitest/node tests
  • resources/js/components/ivr/StatusBadge.tsx
  • resources/js/components/ivr/IvrDataTable.tsx
  • resources/js/components/ivr/IvrSearchForm.tsx
  • tests/Feature/Ivr/IvrModuleTest.php — 6 characterization test cases

Modified files:

  • resources/js/Pages/Ivr/Module/Index.tsx — use new components and types
  • resources/js/Pages/Ivr/Hub/Index.tsx — badge-only change (3 <span>s replaced)

Deleted:

  • resources/js/Pages/Ivr/Module/Show.tsx — confirmed dead (grep evidence required before deletion)

Acceptance Criteria

  • STATUS_TONES has exactly 11 entries matching the Hub map; statusTone() returns null for unknowns and empty string.
  • All 13 Vitest assertions pass (npm test).
  • StatusBadge renders a coloured badge or gray fallback; no router calls, no any.
  • IvrDataTable replicates current Module table markup exactly, applying badge only when statusTone(text) !== null.
  • IvrSearchForm replicates current search form markup; navigation stays in the page.
  • Module/Index.tsx removes local type aliases and statusClass; same router behaviour preserved.
  • Hub/Index.tsx diff contains only the statusBadge removal, StatusBadge import, and 3 badge replacements — nothing else.
  • Show.tsx deleted only after both reachability greps return no callers.
  • IvrModuleTest.php covers all 6 characterization cases (guest redirect, component+props shape, account isolation, call-flow rows, search filter, unknown-slug fallback, slug redirect).
  • All gates pass with real output: php artisan test, phpstan, npm test, tsc --noEmit (no new TS errors), eslint (0 problems), npm run build.
  • git diff --name-status lists only allowlisted files; no PHP changed except the new test file.
  • Four atomic commits in order with specified messages and Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>.

Accepted Visual Changes (the only two)

  1. On /ivr/modules, Sale, Escalated, and Callback values in status/disposition columns now render as coloured badges (were plain text before — omitted from the 8-entry map).
  2. On the Hub page, badge <span>s in Recent calls and Agent snapshot tables gain font-medium (queue table already had it).

Technical Notes

  • Stack: Laravel 11 / PHP 8.2+, React 19 / TypeScript, Inertia.js, Tailwind 3, Vite 7, PHPUnit 11, Vitest 4 (node env).
  • Use @/ imports. 4-space indent, no semicolons, single quotes, function components, no any. Do not run npm run fix-code-style.
  • Vitest tests run in node env — no jsdom, no React Testing Library.
  • PHPUnit runs against database/database.sqlite with RefreshDatabase — do not modify phpunit.xml.
  • IvrDataTable badge condition: col.key in badgeKeys AND statusTone(text) !== null — prevents phantom badges.
  • Pre-existing Hub/Index.tsx preserveScroll TS error must not be touched.
  • ivr_call_flows table must exist in SQLite for the call-flow characterization test; document as blocker if absent.

Dependencies

  • Prior pipeline artifacts in agent-runs/20261012T141334_c3pr8j/ (code analysis, design doc, task list).
  • No new npm or composer packages.
  • tests/Feature/ContactsTest.php is the modelling template — must stay passing.

Labels

ai-created, frontend, refactor, ivr, bounded-scope, no-backend-changes

Follow-ups (out of scope — future tickets)

  • loadQueueRows/loadAgentRows have no row limit — potential memory pressure.
  • loadConfigRows silently swallows exceptions via catch (\Throwable).
  • Hub sub-component extraction (stat cards, filters).
  • ESLint/Prettier 2-vs-4-space indent conflict.
  • tableForModule regex fragility.
  • ivr_legacy.php credential removal.
  • StatCard/formatDuration extraction (Hub and Reports).

Labels: ai-created, frontend, refactor, ivr, bounded-scope, no-backend-changes

No data to display

Actions

Also available in: Atom PDF