From 4dbd19aeb0e93d270d93f2ed6b538d7e3670f3c9 Mon Sep 17 00:00:00 2001 From: Jakob Wennberg Date: Sun, 16 Aug 2026 18:06:53 +0200 Subject: [PATCH] fix(transactions): the underlag column is one surface, not a dropzone and an orphan button (#1628) * fix(transactions): the underlag column is one surface, not a dropzone and an orphan button The Bokfor transaktion dialog stretched its empty dropzone into a 45/72vh well and pinned "Valj befintligt underlag" alone at the very bottom of the column, visually disconnected from the dropzone it belongs to. - Empty state: the underlag column now sizes to its content and top-aligns; the inbox picker renders as a quiet full-width dashed row directly under the dropzone ("eller valj befintligt underlag fran inkorgen"), so drop-a-file and pick-from-inbox read as one intake surface. The fixed-height sticky column returns as soon as a document previews there (uploaded, picked, or pre-linked). - Grid rebalanced from 1fr/520px to 2fr/3fr so the kontering side dominates while nothing is being previewed on the left. - QuickReviewDialog gets the same footer-row treatment for its picker trigger inside the underlag collapsible, so both #1620 surfaces present the affordance identically (disabled-while-booking kept). Presentation only: upload path, select-mode picker held until booking, linkDocuments with inbox_item_id, picked-state resets on close and transaction change, and duplicate-match wiring are all unchanged. Co-Authored-By: Claude Fable 5 * docs: record the QuickReviewDialog picker-trigger consistency decision Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 --- DECISIONS.md | 1 + components/transactions/QuickReviewDialog.tsx | 16 ++- .../transactions/TransactionBookingDialog.tsx | 120 ++++++++++-------- messages/en.json | 2 + messages/sv.json | 2 + 5 files changed, 83 insertions(+), 58 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index fb5911d6..0953a887 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1019,3 +1019,4 @@ One line per decision: `[YYYY-MM-DD] : `. Appended by agents and [2026-08-15] Confirmed intentional (Swedish-review note): with override=true and an unresolvable filename, the attach endpoint links a document to any same-company, same-declared-year, posted verifikat, migrated or not. This mirrors /api/documents/[id]/link, which imposes no filename check at all, so it introduces no new capability class; tenant, year and period-lock enforcement always apply. [2026-08-15] BankID tabs bind to a random non-secret `flowId` signed into the shared flow cookie and sent as a request header after start or explicit resume: mode pinning alone cannot distinguish two same-mode tabs, so an older tab could otherwise silently follow, cancel, or complete a newer person's identification after `/start` replaced the origin-wide cookie. This supersedes the 2026-08-15 decision that deliberately skipped mode matching on active polls. [2026-08-15] Did not apply BankID migration `20260815120000` to Supabase staging during PR #1625 follow-through: read-only reconciliation found 14 staging-only and 99 branch-only migration versions, so applying on top of that divergent ledger would violate the no-orphan rule. Production is reconciled with zero remote-only versions and exactly this PR migration local-only; hosted pg-real validates the migration until staging is reconciled. +[2026-08-16] Restyled QuickReviewDialog's inbox-picker trigger to the same full-width dropzone-footer row as TransactionBookingDialog even though it did not share the orphan-button layout: both surfaces come from #1620 and should present the same underlag affordance; the alternative (leaving a small outline button in one dialog and a footer row in the other) would split the visual language of one control. Presentation only, disabled-while-booking kept (PR #1628). diff --git a/components/transactions/QuickReviewDialog.tsx b/components/transactions/QuickReviewDialog.tsx index 2797d33f..2578d588 100644 --- a/components/transactions/QuickReviewDialog.tsx +++ b/components/transactions/QuickReviewDialog.tsx @@ -663,17 +663,19 @@ export default function QuickReviewDialog({ {/* Locked while the booking is in flight: handleConfirm captured pickedInboxDocs when it started, so anything picked now would never be linked and would then be cleared on completion, - vanishing from the list with no error to explain it. */} - + + {t('doc_pick_existing_inline')} + )} diff --git a/components/transactions/TransactionBookingDialog.tsx b/components/transactions/TransactionBookingDialog.tsx index d6ac7e9b..e43a1f90 100644 --- a/components/transactions/TransactionBookingDialog.tsx +++ b/components/transactions/TransactionBookingDialog.tsx @@ -282,10 +282,19 @@ export default function TransactionBookingDialog({

-
- {/* Document column: sticky on desktop so the receipt stays visible - while the form scrolls; stacks above the form on smaller screens. */} -
+
+ {/* Underlag column: one coherent surface. Empty state sizes to its + content (dropzone + attached inbox-picker row) and top-aligns; + once a document exists the column takes the fixed viewer height + and stays sticky on desktop while the form scrolls. Stacks above + the form on smaller screens. */} +
{currentDocId ? ( ) : ( -
- -
+ )} {/* Attach controls: only when the transaction has no pre-linked document (a pre-linked one is already the verifikat's underlag). */} {!preexistingDocId && ( -
- {pickedInboxDocs.length > 0 && ( -
- {pickedInboxDocs.map((doc) => ( -
- - - {doc.supplier_name ?? doc.file_name} - - -
- ))} -
- )} -
- - {inDialogDocId && ( + + + {doc.supplier_name ?? doc.file_name} + + +
+ ))} +
+ )} +
+ - )} +
-
+ ) : ( + /* Secondary intake path, rendered as the dropzone's footer so + "drop a file" and "pick from the inbox" read as one surface. */ + + ) )}
diff --git a/messages/en.json b/messages/en.json index 5c6e1014..effbb5f4 100644 --- a/messages/en.json +++ b/messages/en.json @@ -2785,6 +2785,7 @@ "doc_label": "Receipt", "doc_attached_count": "{count} attached", "doc_pick_existing": "Choose from the inbox", + "doc_pick_existing_inline": "or choose an existing document from the inbox", "doc_picked_remove": "Remove document", "doc_link_failed_title": "Receipt could not be attached", "doc_link_failed_description": "{count} file(s) could not be linked to the journal entry.", @@ -2803,6 +2804,7 @@ "doc_label": "Receipt (optional)", "doc_attached_count": "{count} attached", "doc_pick_existing": "Choose existing document", + "doc_pick_existing_inline": "or choose an existing document from the inbox", "doc_picked_remove": "Remove document", "doc_clear": "Remove document", "doc_link_failed_title": "Receipt could not be attached", diff --git a/messages/sv.json b/messages/sv.json index a588ce25..b99ea0f8 100644 --- a/messages/sv.json +++ b/messages/sv.json @@ -2785,6 +2785,7 @@ "doc_label": "Underlag", "doc_attached_count": "{count} bifogade", "doc_pick_existing": "Välj från inkorgen", + "doc_pick_existing_inline": "eller välj befintligt underlag från inkorgen", "doc_picked_remove": "Ta bort underlag", "doc_link_failed_title": "Underlag kunde inte bifogas", "doc_link_failed_description": "{count} fil(er) kunde inte länkas till verifikationen.", @@ -2803,6 +2804,7 @@ "doc_label": "Underlag (valfritt)", "doc_attached_count": "{count} bifogade", "doc_pick_existing": "Välj befintligt underlag", + "doc_pick_existing_inline": "eller välj befintligt underlag från inkorgen", "doc_picked_remove": "Ta bort underlag", "doc_clear": "Ta bort underlag", "doc_link_failed_title": "Underlag kunde inte bifogas",