Bug #19
openExtract Shared UI Components from IVR Modules Page (Bounded Refactor)
0%
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,IvrModuleTabinterfaces -
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.tsxresources/js/components/ivr/IvrDataTable.tsxresources/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_TONEShas exactly 11 entries matching the Hub map;statusTone()returnsnullfor unknowns and empty string. - All 13 Vitest assertions pass (
npm test). -
StatusBadgerenders a coloured badge or gray fallback; noroutercalls, noany. -
IvrDataTablereplicates current Module table markup exactly, applying badge only whenstatusTone(text) !== null. -
IvrSearchFormreplicates current search form markup; navigation stays in the page. -
Module/Index.tsxremoves local type aliases andstatusClass; same router behaviour preserved. -
Hub/Index.tsxdiff contains only thestatusBadgeremoval,StatusBadgeimport, and 3 badge replacements — nothing else. -
Show.tsxdeleted only after both reachability greps return no callers. -
IvrModuleTest.phpcovers 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-statuslists 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)¶
- On
/ivr/modules,Sale,Escalated, andCallbackvalues in status/disposition columns now render as coloured badges (were plain text before — omitted from the 8-entry map). - On the Hub page, badge
<span>s in Recent calls and Agent snapshot tables gainfont-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, noany. Do not runnpm run fix-code-style. - Vitest tests run in
nodeenv — no jsdom, no React Testing Library. - PHPUnit runs against
database/database.sqlitewithRefreshDatabase— do not modifyphpunit.xml. -
IvrDataTablebadge condition:col.key in badgeKeys AND statusTone(text) !== null— prevents phantom badges. - Pre-existing
Hub/Index.tsx preserveScrollTS error must not be touched. -
ivr_call_flowstable 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.phpis 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/loadAgentRowshave no row limit — potential memory pressure. -
loadConfigRowssilently swallows exceptions viacatch (\Throwable). - Hub sub-component extraction (stat cards, filters).
- ESLint/Prettier 2-vs-4-space indent conflict.
-
tableForModuleregex fragility. -
ivr_legacy.phpcredential removal. -
StatCard/formatDurationextraction (Hub and Reports).
Labels: ai-created, frontend, refactor, ivr, bounded-scope, no-backend-changes
No data to display