diff --git a/components/transactions/TransactionBookingDialog.tsx b/components/transactions/TransactionBookingDialog.tsx index 185430c3..137d3967 100644 --- a/components/transactions/TransactionBookingDialog.tsx +++ b/components/transactions/TransactionBookingDialog.tsx @@ -1,8 +1,8 @@ 'use client' -import { useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { useTranslations } from 'next-intl' -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog' +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogVeil } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { useToast } from '@/components/ui/use-toast' import { formatCurrency, formatDate } from '@/lib/utils' @@ -158,6 +158,21 @@ export default function TransactionBookingDialog({ return { bankAccount: account, bankAccountName: matched?.name ?? null } }, [transaction, cashAccounts, cashAccountsLoading]) + // The dialog is non-modal (see the Dialog below), so Radix does not trap + // focus or inert the page. Restore page modality by hand: `inert` on the + // dash shell blocks pointer, keyboard, and AT access to the page behind + // (including the mobile bottom nav, which sits above the veil), while the + // agent sheet (outside the shell) stays live. Same as NewInvoiceDialog. + useEffect(() => { + if (!open) return + const shell = document.getElementById('dash-shell') + if (!shell) return + shell.inert = true + return () => { + shell.inert = false + } + }, [open]) + if (!transaction) return null const isIncome = transaction.amount > 0 @@ -253,8 +268,21 @@ export default function TransactionBookingDialog({ setInboxPickerOpen(false) } onOpenChange(o) - }}> - + }} modal={false}> + + e.preventDefault()} + onPointerDownOutside={(e) => e.preventDefault()} + onInteractOutside={(e) => e.preventDefault()} + > {t('title')}