Skip to content

feat(compliance): show preferred phone-call time in the call queue - #1449

Draft
Blume1977 wants to merge 1 commit into
DFXswiss:developfrom
Blume1977:feat/call-queue-phone-times
Draft

Blume1977 wants to merge 1 commit into
DFXswiss:developfrom
Blume1977:feat/call-queue-phone-times

Conversation

@Blume1977

@Blume1977 Blume1977 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

EN:
The call-queue overview shows the customer's preferred phone-call time as a new last column before Date, only in the ManualCheckPhone and ManualCheckIpCountryPhone queues. Compliance staff no longer have to open every entry to see when a customer wants to be called. Column labels of the queue list are translated in German, French and Italian.

DE:
Die Call-Queue-Übersicht zeigt die vom Kunden gewählte Anrufzeit als neue letzte Spalte vor Datum, nur in den Queues ManualCheckPhone und ManualCheckIpCountryPhone. Compliance muss nicht mehr jeden Eintrag öffnen, um zu sehen, wann ein Kunde angerufen werden will. Die Spaltenbeschriftungen der Queue-Liste sind auf Deutsch, Französisch und Italienisch übersetzt.

Details

Change: src/screens/compliance-call-queue.screen.tsx gets a showPhoneCallTimes flag (same pattern as showIp/showCountry/showStatus), a header and a cell column, and columnCount includes it. The value is the raw, semicolon-separated slot list the customer selected (e.g. H9To10;H10To11), identical to the detail view. The cell uses item.phoneCallTimes || '-' rather than the neighbours' ?? on purpose: the API stores the slots as a joined string, so an empty selection arrives as '' and must render the dash like a missing value. The limitation to the two queues is a deliberate compliance decision (ManualCheckIpPhone and ManualCheckExternalAccountPhone keep the value in the detail view only); the code comment says so. The unreachable if (!queue) return; in openDetail is removed: rows only render once queue is set, so the guard could never execute (CONTRIBUTING: delete rather than exclude).

i18n: Phone Call Times plus the neighbouring column labels of the same table that were already passed through translate() without keys (Call Queue, User, Phone, Lang, Transaction, Country, Status, Date) are added to screens/compliance in de/fr/it, appended at the end of the block like the previous table keys.

Tests:

  • New src/__tests__/compliance-call-queue.screen.test.tsx (29 tests): column shown in ManualCheckPhone and ManualCheckIpCountryPhone as the last column before Date, hidden in ManualCheckIpPhone, ManualCheckExternalAccountPhone and UnavailableSuspicious; '' and undefined render -; full and sparse cell rendering; empty-state colspan (9 and 7); unknown and missing queue param; logged-out; loading spinner; rejection with Error and with a non-Error value; row click with and without txId; back navigation; row keys without duplicate-key warnings.
  • Measured coverage on Node 20 for src/screens/compliance-call-queue.screen.tsx: 100 / 100 / 100 / 100 (statements / branches / functions / lines). src/__tests__/compliance-call-queue.screen.test.tsx is a test file and not instrumented; translation JSON, typings/*.d.ts, e2e/, e2e-stack/, docs/ and scripts/handbook/metadata.json carry no coverage.
  • LC_ALL=en_US.UTF-8 npm run test -- --findRelatedTests <changed src files> --coverage: 102 suites, 1714 tests green.
  • npm run lint (--max-warnings 0) and npm run format:md:check green; npx eslint --max-warnings 0 and npx prettier --check green on every changed file except e2e-stack/specs/fixtures/factories.ts; tsc --noEmit -p e2e/tsconfig.json and -p e2e-stack/tsconfig.json without errors in the changed specs. factories.ts is not Prettier-clean on develop (pre-existing hunks from line 1779 on, outside the lint glob); the three inserted lines follow the Prettier style and the pre-existing hunks are left untouched to keep the diff to this change.
  • Full-stack: e2e-stack/specs/compliance-cases.spec.ts gets a case that seeds a ManualCheckPhone entry with phoneCallTimes (factory option createCallQueueEntry({ phoneCallTimes })), asserts the column header scoped to the queue table, its position directly before Date, and its absence in ManualCheckIpPhone. Not run locally (no Docker); route claims unchanged, the file already claims /compliance/call-queues/:queue.

Declared deviations:

  • Handbook baselines: e2e/compliance-call-queue.spec.ts is new (synthetic API, two visual variants) and scripts/handbook/metadata.json has the compliance-call-queue entry, but the two PNGs e2e/screenshots/baseline/compliance-call-queue.spec.ts-compliance-call-queue-01-phone-queue-chromium-darwin.png and ...-02-ip-phone-queue-chromium-darwin.png are not in this PR: no Playwright browsers on this machine. The metadata entry is orphaned until the baselines exist (build prints a warning, does not fail).
  • SDK rule ("API access goes through the SDK"): the value is read from CallQueueItem.phoneCallTimes, which @dfx.swiss/core does not expose yet (feat(core): add phoneCallTimes to CallQueueItem packages#180 open, latest core 0.7.1 without the field). typings/dfx-core-call-queue.d.ts augments the interface with the optional field so the screen stays type-safe and the PR does not depend on the package release. This moves one optional response field into this repository against the rule; the bridge is deleted in the PR that bumps @dfx.swiss/react after packages#180 publishes.
  • Reality declaration (docs/test-architecture.md): the visual spec answers GET /v1/support/call-queues/{queue}/items itself; the full-stack case SQL-writes user_data.phoneCallTimes and accepts the - placeholder in the cell because the API in the stack does not deliver the field until DFXswiss/backend#5542 is merged.

Dependencies: real values appear once DFXswiss/backend#5542 (fills phoneCallTimes in toTxCallQueueItem) is live; order is not critical, the field is optional and the column renders - until then. DFXswiss/packages#180 adds the field to @dfx.swiss/core.

Pre-existing, not changed (reported per CONTRIBUTING, out of scope here):

  • useEffect (lines 43-50) has no in-flight guard: switching the queue while a request is pending lets a slower older response overwrite the newer list; no mounted guard either.
  • error is never reset on a queue change (line 45 sets loading, not error), so a previous failure keeps showing after the next queue loads.
  • catch((e) => setError(e.message)) on a non-Error rejection sets undefined and shows an empty table without a hint (covered by a test to pin the current behaviour).
  • The KYC and IP headers are hard-coded without translate().

Overlap: none of the currently open PRs touches compliance-call-queue.screen.tsx.

@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown

EN:
Thanks for your contribution! This repository follows the A38 quality rules.

DE:
Danke für deinen Beitrag! In diesem Repository gelten die A38-Qualitätsregeln.

The customer's preferred phone-call time was only visible in the call-queue
detail view. Compliance staff calling through a phone queue could not see it in
the overview and had to open each entry.

A new "Phone Call Times" column is shown as the last column before Date, only
in the ManualCheckPhone and ManualCheckIpCountryPhone queues (deliberate
decision; the other phone queues keep the value in the detail view). The value
is the raw, semicolon-separated time slots the customer selected; an empty
value shows "-". The neighbouring column labels of the queue list get their
missing de/fr/it translations.

The value is delivered by the API on CallQueueItem (DFXswiss/backend#3924).
Until @dfx.swiss/core carries the field (DFXswiss/packages#180), a small typings
bridge exposes phoneCallTimes on CallQueueItem so the screen reads it
type-safely; the bridge is removed once core publishes the field.

Tests: a unit test brings compliance-call-queue.screen.tsx to full coverage
(column visibility per queue, dash for empty values, cell rendering, empty
state, error and loading paths, row navigation). The full-stack compliance
cases assert the column in the phone queue and its absence in the IP queue;
the factory can seed user_data.phoneCallTimes. A visual spec and its handbook
metadata are added; the darwin baselines and the reality declarations for the
synthetic queue response and the seeded value are declared in the pull request.
@Blume1977
Blume1977 force-pushed the feat/call-queue-phone-times branch from a270955 to 4db9edf Compare September 14, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant