chore: post-#580 follow-ups (rolling collection)#587
Merged
Conversation
Empty seed commit so a draft PR can exist before the actual follow-ups land. Real changes (further goldens state-coverage, BitBox-aware variant pinning, additional handbook slots, etc.) get pushed on top of this branch and are visible incrementally in the PR diff.
…586) ## Summary Both `TransactionIssue` and `LimitRequest` options in the in-app support ticket type picker silently fail with HTTP 400 on submit because the app never sends the API-required nested DTOs (`transaction` / `limitRequest`). The reproduction in the field is `RealUnitApiException: limitRequest should not be empty (statusCode: 400)` for LimitRequest; the TransactionIssue equivalent has not surfaced because realunit-app users typically file transaction issues via services.dfx.swiss instead. This PR hides both options from the picker until the proper forms are implemented. The enum values, i18n keys (`supportTransactionIssue`, `supportLimitRequest`), icons, and the cubit's `_getTicketName` mapping are intentionally left in place so re-enabling is a one-tuple revert per type once the structured input UI (dropdowns, transaction picker, document upload) lands. ## Why not implement the forms now - `LimitRequest` needs three dropdowns (`limit` / `investmentDate` / `fundOrigin`), an optional `fundOriginText` field mapped from message, a KYC ≥ 50 gate, and a mandatory document upload (PNG / JPEG / PDF). Requires a new `file_picker` dependency for PDF support. - `TransactionIssue` needs a transaction picker (list of the user's recent transactions via `GET /v1/transactions`) plus a reason dropdown filtered to `[FundsNotReceived, TransactionMissing, Other]`. - Both are independent feature PRs of meaningful scope; hiding now removes the user-facing failure immediately. ## Scope - `lib/screens/support/subpages/support_create_ticket_page.dart` — remove two tuples from the `items:` array of `TagSelection<SupportIssueType>`. - No API, model, cubit, service, or i18n changes. ## Test plan - [x] `flutter analyze` → `No issues found! (ran in 4.7s)` - [x] `flutter test test/screens/support/` → 62 / 62 passed - [ ] Manual smoke: open `Neues Ticket erstellen`, confirm only `Allgemeines Anliegen`, `Fehlerbericht`, `KYC-Problem` are selectable. - [ ] Manual smoke: submit each of the three remaining types with a short message and verify a ticket is created (no 400).
Re-opens [#584](#584) (closed because its base \`chore/post-541-followups\` was deleted after the collection-merge [#571](#571)). Cherry-picked Jana's original commit (\`517170a\`) onto the new collection branch \`chore/post-580-followups\`. ## Summary The "Support kontaktieren" tile under Settings → Kontakt must always be visible — including pre-signin onboarding flows where the user has not yet registered an email. Render it unconditionally and drop the surrounding cubit/state machinery that only existed to gate this single tile. ## Pair PR Pairs with [DFXswiss/api#3761](DFXswiss/api#3761) (drops \`UserCapabilitiesDto.supportAvailable\`). **Merge order is unconstrained — both PRs are independent-safe:** | Order | Backend sends | App reads | Crash? | |---|---|---|---| | App-PR alone merged | \`supportAvailable: true/false\` still in JSON | Field no longer read in \`fromJson\` — Dart \`Map<String,dynamic>\` silently ignores unknown keys | No | | API-PR alone merged | Field gone from JSON | Old app code reads \`json['supportAvailable'] as bool? ?? false\` → \`false\` → tile stays hidden (existing bug persists) | No | | Both merged | Backend stops sending, app stops reading | — | No | The DTO uses \`as bool? ?? false\` (nullable cast with default fallback) for every capability flag, so neither side is brittle to the other's deploy timing. Earlier "Merge order: API first" claim was inaccurate. ## Review history Audited via subagent during the #584 cycle (clean, no MAJORs). Main-repo mirror was needed for Visual Regression on the dfx01 self-hosted runner (same Fork-PR pattern as [#585](#585)). Credit: code-diff by Jana Rüttimann (\`Blume1977\`). --------- Co-authored-by: Blume1977 <jana.ruettimann@dfx.swiss> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…set (#589) ## Summary Mirror the API-side `@IsSwissPaymentText()` validator (DFXswiss/api#3766) in the four user flows that write into `user_data`: - KYC registration — personal step (`firstName`, `lastName`) - KYC registration — address step (`street`, `houseNumber`, `postalCode`, `city`) - Settings → edit name (`firstName`, `lastName`) - Settings → edit address (`street`, `houseNumber`, `postalCode`, `city`) Users now get immediate field-level feedback in the form if they enter a character outside the SIX SIG IG QR-Bill v2.3 permitted character set, instead of submitting and waiting for a generic 400 from the backend. ## Why DFX business decision: only characters valid in Swiss payment systems are supported end-to-end. Pairs with the umlaut-preservation fix in DFXswiss/api#3766 — now that diacritics survive storage and PDF rendering, we also lock the input surface so CJK / Cyrillic / Arabic / emoji never enter the system. ## Character set ``` [\x20-\x7E] (printable ASCII) + À Á Â Ä Ç È É Ê Ë Ì Í Î Ï Ñ Ò Ó Ô Ö Ù Ú Û Ü Ý ß + à á â ä ç è é ê ë ì í î ï ñ ò ó ô ö ù ú û ü ý + \n (line feed) ``` Covers German, French, Italian, Romansh. Regex is byte-for-byte aligned with the API regex (`Config.formats.swissPaymentText`) so any input the client accepts the backend also accepts. ## Changes - `lib/packages/utils/swiss_payment_text.dart`: new `isSwissPaymentText(String?)` helper (empty/null = valid). - Four screen files: add the helper call to existing `validator:` callbacks; missing validator on house-number in settings edit-address page added. - `assets/languages/strings_en.arb`, `strings_de.arb`: new `swissPaymentTextInvalid` translation key, inserted in alphabetical order. - Generated `lib/generated/i18n.dart` is gitignored — built by `dart run tool/generate_localization.dart` after pulling. ## Test plan - [ ] `dart run tool/generate_localization.dart` runs without errors after checkout - [ ] `flutter analyze` — passes (verified locally, no new issues) - [ ] Type `Rüttimann` / `Münchwilen` / `Genève` / `Saint-Légier` in any of the four flows → no error, form accepts - [ ] Type `王小明` / `Иван` / `日本語` / an emoji → field shows the Swiss-payment-text error message - [ ] Submit a valid form → API call succeeds (i.e. client and server regex match) - [ ] German UI shows German error message; English UI shows English message - [ ] `flutter test` — pre-existing golden failures unchanged (verified locally — same 88 failures on clean develop)
Add the missing test coverage for `lib/packages/utils/swiss_payment_text.dart` (introduced in #589) so the regex character set is locked in against regressions when the API-side `Config.formats.swissPaymentText` drifts. 33 cases across 8 groups: - empty / null → valid (matches the docstring contract: callers chain a non-empty check) - printable ASCII (0x20–0x7E): digits, punctuation, full 95-char band - uppercase + lowercase Latin diacritics for CH / DE / FR / IT - real Swiss names + addresses (Rüttimann, Münchwilen, Genève, Saint-Légier, D'Hauterive, François) - non-Latin scripts rejected (CJK, Cyrillic, Arabic, Hebrew, emoji) - mixed-script attacks (Latin word with a Cyrillic homoglyph е inside) - whitespace: newline accepted (multi-line memos), tab + CR rejected - uncommon Latin diacritics rejected (Polish ąć, Portuguese ã, Norwegian øå, French ligature œ, French Ÿ) — explicitly documents what is NOT in the Swiss payment set so the regex is hand-verifiable Run: `flutter test --no-pub test/packages/utils/swiss_payment_text_test.dart` → 33/33 pass.
## Summary - Handbook (`docs/handbook/de/index.html:1088-1090`) behauptet, die Wallet-Sicherung-Kachel ist bei BitBox-Wallet ausgeblendet - Bestehender Golden deckt nur die Software-Wallet-Variante ab — Invertierung der Bedingung in `settings_page.dart:100` würde nicht auffallen - Neuer `goldenTest` „bitbox wallet open hides the Wallet-Sicherung tile" sichert die hidden-tile-Logik ab - `MockBitboxWallet` in `test/helper/golden_mocks.dart` ergänzt (analog zu `MockSoftwareWallet`) Schließt Reviewer-Finding #2 aus dem #582-Review. ## Test plan - [ ] CI grün (Visual Regression, Analyze & Test, Coverage Floor Gate, Handbook Build Check) - [ ] Goldens via `golden-regenerate.yaml` auf dfx01 generiert (erwartet: 1 neuer PNG `settings_page_bitbox.png`) - [ ] Manuell verifiziert: PNG zeigt Settings-Page ohne Wallet-Sicherung-Tile --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…592) Follow-up to the BitBox-Goldens deep-dive done after [#580](#580). Of the 8 candidate BitBox connection sub-states, 3 are pixel-distinct UI patterns worth pinning; the other 5 are either identical to the baseline, near-variants of the top-3, or have no UI at all. ## Added (top-3 by ROI) | File | State | Why pinned | |---|---|---| | `connect_bitbox_page_connecting.png` | `BitboxConnecting` | Only spinner-only state with neither confirm nor cancel — distinct \`ConnectContent\` branch | | `connect_bitbox_page_check_hash.png` | `BitboxCheckHash` | Highest pixel-drift risk: alpha-blended pairing-code pill with custom BoxDecoration | | `connect_bitbox_page_signature_failed.png` | `BitboxSignatureFailed` | Only state with two override-labelled buttons (Retry + Continue anyway) | ## Out of scope (deliberately) | State | Reason | |---|---| | `BitboxFound` | Renders identical to \`BitboxNotConnected\` — view's switch has no case, falls to \`_ =>\` default | | `BitboxPairing` | Spinner subtitle variant of \`BitboxConnecting\` — near-duplicate | | `BitboxCapturingSignature` | Title-only variant of \`BitboxPairing\` | | `BitboxConnected` | Button + title variant of the connected SVG branch — close to \`SignatureFailed\` | | `BitboxFinishSetup` | Emits no UI, only a BlocListener \`onFinish(wallet)\` callback | ## Coverage gap closed The view file \`lib/screens/hardware_connect_bitbox/connect_bitbox_view.dart\` has three orthogonal branches in its state-switch (spinner-only, hash-pill, two-button-with-override-labels). Before this PR, only the default \"no UI ceremony\" branch (\`BitboxNotConnected\`) was pixel-locked. Cubit-tests (16 in \`connect_bitbox_cubit_test.dart\`) cover the state-machine logic, view-tests cover button wiring — but pixel-layout regression of these three branches was structurally unguarded. ## Mock setup Lifted verbatim from \`test/screens/hardware_connect_bitbox/connect_bitbox_view_test.dart\`: \`_FakeBitboxDevice extends Fake\`, \`_MockBitboxWallet extends Mock\`. No new helper file, no new pubspec entries. ## Pending CI dance - Bot golden-regen workflow will commit the three new baselines on the dfx01 self-hosted runner. - Empty re-trigger commit needed afterwards per the GITHUB_TOKEN gotcha documented in \`docs/visual-regression-tests.md\`. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rolling collection branch for follow-ups after #580 (goldens max coverage + handbook 52 slots) merged into develop via #571. Same pattern as the previous
chore/post-541-followupscollection.Mechanics
Known follow-up topics
Tracked from the #580 audit + day-2 fixes:
settings_page_bitbox) — die HTML-Erklärung im Handbook erwähnt das Hiding der Wallet-Sicherung-Tile bei BitBox, kein Golden pinnt es derzeit.BitboxNotConnectedist als Golden. Weitere 8 States (Found, Connecting, CheckHash, Pairing, CapturingSignature, SignatureFailed, Connected, FinishSetup) sind theoretisch renderbar via Mock-Wallet.en-Goldens für die Pages, wo lange deutsche Strings Layout-relevant sind (Buy/Sell Banner).