diff --git a/admin-spa/src/components/nav/SubmenuBar.tsx b/admin-spa/src/components/nav/SubmenuBar.tsx index 82726c1..3fdd945 100644 --- a/admin-spa/src/components/nav/SubmenuBar.tsx +++ b/admin-spa/src/components/nav/SubmenuBar.tsx @@ -2,17 +2,22 @@ import React from 'react'; import { Link, useLocation } from 'react-router-dom'; import type { SubItem } from '@/nav/tree'; -type Props = { items?: SubItem[] }; +type Props = { items?: SubItem[]; fullscreen?: boolean }; -export default function SubmenuBar({ items = [] }: Props) { +export default function SubmenuBar({ items = [], fullscreen = false }: Props) { // Always call hooks first const { pathname } = useLocation(); // Single source of truth: props.items. No fallbacks, no demos, no path-based defaults if (items.length === 0) return null; + // Calculate top position based on fullscreen state + // Fullscreen: top-16 (below 64px header) + // Normal: top-[88px] (below 40px WP admin bar + 48px menu bar) + const topClass = fullscreen ? 'top-0' : 'top-[calc(7rem+32px)]'; + return ( -
+
{items.map((it) => { diff --git a/admin-spa/src/components/settings/GenericGatewayForm.tsx b/admin-spa/src/components/settings/GenericGatewayForm.tsx index 6b326fc..a6ddb85 100644 --- a/admin-spa/src/components/settings/GenericGatewayForm.tsx +++ b/admin-spa/src/components/settings/GenericGatewayForm.tsx @@ -13,7 +13,7 @@ import { } from '@/components/ui/select'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Alert, AlertDescription } from '@/components/ui/alert'; -import { ExternalLink, AlertTriangle } from 'lucide-react'; +import { ExternalLink, AlertTriangle, Plus, Trash2 } from 'lucide-react'; interface GatewayField { id: string; @@ -51,7 +51,17 @@ interface GenericGatewayFormProps { } // Supported field types (outside component to avoid re-renders) -const SUPPORTED_FIELD_TYPES = ['text', 'password', 'checkbox', 'select', 'textarea', 'number', 'email', 'url']; +const SUPPORTED_FIELD_TYPES = ['text', 'password', 'checkbox', 'select', 'textarea', 'number', 'email', 'url', 'account']; + +// Bank account interface +interface BankAccount { + account_name: string; + account_number: string; + bank_name: string; + sort_code?: string; + iban?: string; + bic?: string; +} export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = false }: GenericGatewayFormProps) { const [formData, setFormData] = useState>({}); @@ -217,6 +227,160 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
); + case 'account': + // Bank account repeater field + const accounts = (value as BankAccount[]) || []; + + const addAccount = () => { + const newAccounts = [...accounts, { + account_name: '', + account_number: '', + bank_name: '', + sort_code: '', + iban: '', + bic: '' + }]; + handleFieldChange(field.id, newAccounts); + }; + + const removeAccount = (index: number) => { + const newAccounts = accounts.filter((_, i) => i !== index); + handleFieldChange(field.id, newAccounts); + }; + + const updateAccount = (index: number, key: keyof BankAccount, val: string) => { + const newAccounts = [...accounts]; + newAccounts[index] = { ...newAccounts[index], [key]: val }; + handleFieldChange(field.id, newAccounts); + }; + + return ( +
+
+ + {field.description && ( +

+ )} +

+ +
+ {accounts.map((account, index) => ( +
+
+

Account {index + 1}

+ +
+ +
+
+ + updateAccount(index, 'account_name', e.target.value)} + placeholder="e.g., Business Account" + className="h-9" + /> +
+ +
+ + updateAccount(index, 'account_number', e.target.value)} + placeholder="e.g., 12345678" + className="h-9" + /> +
+ +
+ + updateAccount(index, 'bank_name', e.target.value)} + placeholder="e.g., Bank Central Asia" + className="h-9" + /> +
+ +
+ + updateAccount(index, 'sort_code', e.target.value)} + placeholder="e.g., 12-34-56" + className="h-9" + /> +
+ +
+ + updateAccount(index, 'iban', e.target.value)} + placeholder="e.g., GB29 NWBK 6016 1331 9268 19" + className="h-9" + /> +
+ +
+ + updateAccount(index, 'bic', e.target.value)} + placeholder="e.g., NWBKGB2L" + className="h-9" + /> +
+
+
+ ))} +
+ + +
+ ); + default: // text, password, number, email, url return ( diff --git a/admin-spa/src/routes/Settings/Store.tsx b/admin-spa/src/routes/Settings/Store.tsx index d6faed0..5c3301e 100644 --- a/admin-spa/src/routes/Settings/Store.tsx +++ b/admin-spa/src/routes/Settings/Store.tsx @@ -249,11 +249,14 @@ export default function StoreDetailsPage() { updateSetting('country', v)} - options={countries.map((country: { code: string; name: string }) => ({ - value: country.code, - label: country.name, - searchText: country.name, - }))} + options={countries.map((country: { code: string; name: string }) => { + const flagEmoji = countryCodeToEmoji(country.code); + return { + value: country.code, + label: `${flagEmoji} ${country.name}`.trim(), + searchText: `${country.code} ${country.name}`, + }; + })} placeholder="Select country..." />