Skip to content

Show the preferred call time without a consent step first - #1261

Closed
joshuakrueger-dfx wants to merge 2 commits into
DFXswiss:developfrom
joshuakrueger-dfx:fix/settings-call-time-visible
Closed

Show the preferred call time without a consent step first#1261
joshuakrueger-dfx wants to merge 2 commits into
DFXswiss:developfrom
joshuakrueger-dfx:fix/settings-call-time-visible

Conversation

@joshuakrueger-dfx

@joshuakrueger-dfx joshuakrueger-dfx commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Problem

The mail that asks a customer for a verification call links to app.dfx.swiss/settings?a=call and
tells them to pick a preferred time there. On that page the time dropdown was rendered only while
the consent dropdown above it said "Yes, call me":

{acceptCall && (
  <StyledDropdownMultiChoice<PhoneCallTime> name="preferredPhoneTimes"  />
)}

acceptCall is only pre-filled from user.kyc.phoneCallAccepted, and that is null for everyone
who has never been called. So the customers the mail addresses arrive at the section it points them
to, see a single dropdown reading Select..., and have no way to pick a time.

More than ten support tickets in the last seven days say exactly that: "I cannot select an
appointment."

Measured in the browser against the Dev API with a freshly created account, before the change: the
"Verification Call" heading and the consent dropdown are visible, the label "Preferred call time"
is not.

Change

Render the time dropdown unconditionally.

Both fields keep saving themselves independently through their own effect, exactly as before — the
consent dropdown sends acceptCall, the time dropdown sends preferredPhoneTimes. Nothing is
coupled.

A save that fails now shows the reason via ErrorHint instead of disappearing as an unhandled
rejection, and the dropdown returns to its saved value so the next choice is a real change again —
otherwise picking the same option twice produced no second request and the customer was stuck with
an error and no way to retry. Each field owns its error state and renders it under itself: with a
single shared state, a failed consent save followed by a successful time save would silently wipe
the message. The context functions in @dfx.swiss/react stay untouched: not catching there is the
convention across all of them, the caller is responsible — transaction.screen.tsx and
tfa.screen.tsx use the same .catch((error: ApiError) => …) one-liner.

The time dropdown is the field this change makes reachable for customers without consent; the
consent dropdown was always rendered, so its error path existed before. Both are handled here
because they are the same two lines in the same block.

Verification

  • New unit tests, 11 cases: the reported failure mode (time dropdown visible without prior consent),
    a time selection sends only preferredPhoneTimes, "No, don't call me" still sends acceptCall
    alone, each field surfaces its own save error under its own field, a failed save returns the
    dropdown to the server value, the same choice afterwards sends another request, and an error
    clears when the next save on that field starts.
  • Five mutations, each on a different axis, all caught: restoring {acceptCall && …} → 6 of 11 red;
    removing the rollback in the consent catch → 3 of 11; removing the error resets → 2 of 11;
    rolling back to the rejected value instead of the saved one → 3 of 11; making the time effect
    write into the neighbouring field's error state → 1 of 11.
  • Repo gate as the PR workflow runs it (lint, test, build:dev, widget:dev): lint clean,
    71 suites / 789 tests passing.
  • e2e/settings-call-time.spec.ts covers the same visibility check in a real browser against the
    Dev API. Per CONTRIBUTING these specs are a local review aid and do not run in CI.

Deliberately not in this PR

  • The block is still hidden entirely when phoneCallStatus is Completed or Failed. That is
    existing, intended behaviour.
  • No implicit consent: picking a time does not set phoneCallAccepted. It does not need to —
    phoneCallAccepted is only evaluated when phoneCallStatus === UserRejected, and customers are
    called from the AML reason of their transaction. Their chosen time is visible to the caller in the
    user detail panel.
  • The section still renders when the user object failed to load, where saving is a silent no-op.
    That is pre-existing and unrelated to the visibility bug.
  • Pre-existing and better fixed in the API: after a save that carries only acceptCall, the
    response comes back with preferredPhoneTimes: [] even when times are stored, because
    setUserDataSettings assigns undefined onto the entity and the client adopts that response
    without refetching. Clearing all times right after such a save therefore sends no request. This
    was reachable before as well; it is not introduced here.
  • The visual baseline for this screen dates from 2026-01-06 and predates the whole verification call
    section (added 2026-03-12, Feat: support improvements #989). Regenerating it would pull four months of unrelated drift into
    this diff, which CONTRIBUTING explicitly warns against.

The mail that asks a customer for a verification call links to /settings?a=call
and tells them to pick a preferred time there. The time dropdown was rendered
only while the consent dropdown above it said yes, and that one starts empty for
everyone who has never been called - so the customers the mail addresses arrived
at the section it pointed them to and found no way to pick a time. More than ten
support tickets in the last seven days say exactly that.

Render the time dropdown unconditionally. Both fields keep saving themselves
independently, as before. A save that fails now shows the reason instead of
disappearing as an unhandled rejection.
The screen showed the reason a save failed but left the rejected choice in the
dropdown. Picking the same option again changed nothing, so the effect watching
that value never ran and no second request went out - the customer was left with
an error and no way to retry in place.

Put the saved value back when a request fails, so the next choice is a real
change again. Each field's error now renders in its own container so a test can
tell them apart.
@joshuakrueger-dfx
joshuakrueger-dfx marked this pull request as ready for review August 4, 2026 11:28
@joshuakrueger-dfx

Copy link
Copy Markdown
Contributor Author

Closing this: the reported problem has a different cause. Two support tickets with the account state at the time of reporting show the customers never reached the section at all - the deep link from the mail loses its anchor across the login redirect, so they land on the settings page without being taken to the verification call block. Fix follows in a separate PR against that redirect.

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