feat(connections): create a new account from the manage-accounts selector (#560)
## What
In the per-connection **Manage accounts** screen, the discovered-account
card now uses a single selector to choose where a newly detected bank
account syncs. The selector lists **"Create new account"** first,
followed by the compatible existing manual accounts — replacing the
previous separate "Create account" / "Link to existing" buttons.
The **"Add accounts"** header now stacks vertically on mobile
(title/description, then a full-width "Load accounts" button) and stays
a row on `sm+`.
## Why
Consolidating *create* and *link* into the same control matches how
users think about the action ("where should this account go?") and
removes the two side-by-side buttons that overflowed horizontally on
small screens.
## Notes
- **Backend unchanged**: `ConnectionAccountController@map` already
supported both `action: create` and `action: link`. This only re-routes
the same calls through the selector (`existingAccountId === null` →
create). Covered by existing tests in
`tests/Feature/OpenBanking/ConnectionAccountTest.php` (9 passing).
- **No new i18n keys**: reuses the existing `Create new account` and
`Select an account` translations.
## Screens
The "Manage accounts" link lives in the per-connection "…" menu and is
gated behind the `ManageBankAccounts` feature flag (admin-only during
rollout).
This commit is contained in:
parent
46568700b2
commit
6cb8d11563
|
|
@ -28,6 +28,7 @@ import {
|
|||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
|
|
@ -40,13 +41,7 @@ import { filterTransactionalAccounts } from '@/types/account';
|
|||
import type { BankingConnection, DiscoveredBankAccount } from '@/types/banking';
|
||||
import { __ } from '@/utils/i18n';
|
||||
import { Head, Link, router, usePage } from '@inertiajs/react';
|
||||
import {
|
||||
ArrowLeft,
|
||||
MoreHorizontal,
|
||||
Plus,
|
||||
RefreshCw,
|
||||
Unplug,
|
||||
} from 'lucide-react';
|
||||
import { ArrowLeft, MoreHorizontal, RefreshCw, Unplug } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
|
|
@ -194,7 +189,7 @@ export default function ManageAccountsPage({
|
|||
</div>
|
||||
|
||||
<div className="border-t pt-6">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4">
|
||||
<div>
|
||||
<h4 className="text-sm font-medium">
|
||||
{__('Add accounts')}
|
||||
|
|
@ -207,6 +202,7 @@ export default function ManageAccountsPage({
|
|||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full sm:w-auto"
|
||||
onClick={handleRefresh}
|
||||
disabled={!isActive || refreshing}
|
||||
>
|
||||
|
|
@ -363,6 +359,8 @@ function SyncedAccountCard({
|
|||
);
|
||||
}
|
||||
|
||||
const CREATE_NEW_ACCOUNT = '__create__';
|
||||
|
||||
function DiscoveredAccountCard({
|
||||
discoveredAccount,
|
||||
targets,
|
||||
|
|
@ -375,15 +373,16 @@ function DiscoveredAccountCard({
|
|||
existingAccountId: string | null,
|
||||
) => void;
|
||||
}) {
|
||||
const [linking, setLinking] = useState(false);
|
||||
const displayName =
|
||||
discoveredAccount.name || discoveredAccount.iban || __('Bank Account');
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<div>
|
||||
<CardTitle className="text-base">{displayName}</CardTitle>
|
||||
<CardHeader className="flex flex-row items-center justify-between gap-4 space-y-0 pb-2">
|
||||
<div className="min-w-0">
|
||||
<CardTitle className="truncate text-base">
|
||||
{displayName}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{discoveredAccount.currency}
|
||||
{discoveredAccount.iban &&
|
||||
|
|
@ -391,47 +390,30 @@ function DiscoveredAccountCard({
|
|||
` · ${discoveredAccount.iban}`}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{targets.length > 0 && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setLinking((prev) => !prev)}
|
||||
>
|
||||
{__('Link to existing')}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => onAdd(discoveredAccount, null)}
|
||||
>
|
||||
<Plus className="mr-1.5 h-3 w-3" />
|
||||
{__('Create account')}
|
||||
</Button>
|
||||
</div>
|
||||
<Select
|
||||
onValueChange={(value) =>
|
||||
onAdd(
|
||||
discoveredAccount,
|
||||
value === CREATE_NEW_ACCOUNT ? null : value,
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-48 shrink-0">
|
||||
<SelectValue placeholder={__('Select an account')} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={CREATE_NEW_ACCOUNT}>
|
||||
{__('Create new account')}
|
||||
</SelectItem>
|
||||
{targets.length > 0 && <SelectSeparator />}
|
||||
{targets.map((target) => (
|
||||
<SelectItem key={target.id} value={target.id}>
|
||||
<AccountName account={target} />
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</CardHeader>
|
||||
{linking && targets.length > 0 && (
|
||||
<CardContent>
|
||||
<Select
|
||||
onValueChange={(value) =>
|
||||
onAdd(discoveredAccount, value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={__('Select an account')}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{targets.map((target) => (
|
||||
<SelectItem key={target.id} value={target.id}>
|
||||
<AccountName account={target} />
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue