braid-ui 1.0.97 → 1.0.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -327
- package/components.json +20 -0
- package/eslint.config.js +29 -0
- package/index.html +24 -0
- package/package.json +55 -115
- package/postcss.config.js +6 -0
- package/public/favicon.ico +0 -0
- package/public/placeholder.svg +1 -0
- package/public/robots.txt +14 -0
- package/src/App.css +42 -0
- package/src/App.tsx +94 -0
- package/src/components/MainLayout.tsx +15 -0
- package/src/components/alerts/AlertDocuments.tsx +320 -0
- package/src/components/alerts/AlertNotes.tsx +185 -0
- package/src/components/alerts/AlertTimeline.tsx +79 -0
- package/src/components/alerts/ContextSection.tsx +155 -0
- package/src/components/app-sidebar.tsx +341 -0
- package/src/components/form-sections/ACHBankCard.tsx +78 -0
- package/src/components/form-sections/ACHBasicInfoCard.tsx +100 -0
- package/src/components/form-sections/ACHTransferSection.tsx +64 -0
- package/src/components/form-sections/AddressForm.tsx +94 -0
- package/src/components/form-sections/BankAddressCard.tsx +95 -0
- package/src/components/form-sections/BankingDetailsCard.tsx +46 -0
- package/src/components/form-sections/BasicInfoCard.tsx +103 -0
- package/src/components/form-sections/BasicInfoSection.tsx +34 -0
- package/src/components/form-sections/BeneficiaryAddress.tsx +19 -0
- package/src/components/form-sections/BeneficiaryCard.tsx +41 -0
- package/src/components/form-sections/BeneficiaryDomesticWire.tsx +23 -0
- package/src/components/form-sections/BusinessProfileCard.tsx +131 -0
- package/src/components/form-sections/BusinessStatusCard.tsx +53 -0
- package/src/components/form-sections/ContactInfoCard.tsx +63 -0
- package/src/components/form-sections/CounterpartyBasicInfo.tsx +101 -0
- package/src/components/form-sections/CounterpartyProfileCard.tsx +104 -0
- package/src/components/form-sections/CounterpartyRecordsCard.tsx +41 -0
- package/src/components/form-sections/IntermediaryCard.tsx +77 -0
- package/src/components/form-sections/IntermediaryFI.tsx +41 -0
- package/src/components/form-sections/IntermediaryFIAddress.tsx +14 -0
- package/src/components/form-sections/OriginatorCard.tsx +49 -0
- package/src/components/form-sections/OriginatorFI.tsx +42 -0
- package/src/components/form-sections/OriginatorFIAddress.tsx +14 -0
- package/src/components/form-sections/PaymentInformationSection.tsx +163 -0
- package/src/components/form-sections/ReceiverCard.tsx +94 -0
- package/src/components/form-sections/WireTransferSection.tsx +75 -0
- package/src/components/layouts/list-page.tsx +103 -0
- package/src/components/transaction/ACHDetailsSection.tsx +95 -0
- package/src/components/transaction/WireDetailsSection.tsx +112 -0
- package/src/components/ui/account-card.tsx +94 -0
- package/src/components/ui/badge.tsx +75 -0
- package/src/components/ui/breadcrumb.tsx +78 -0
- package/src/components/ui/business-type-badge.tsx +42 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/calendar.tsx +49 -0
- package/src/components/ui/card.tsx +223 -0
- package/src/components/ui/container.tsx +45 -0
- package/src/components/ui/counterparty-type-badge.tsx +53 -0
- package/src/components/ui/data-grid.tsx +99 -0
- package/src/components/ui/data-table.tsx +152 -0
- package/src/components/ui/detail-page-layout.tsx +83 -0
- package/src/components/ui/dialog.tsx +120 -0
- package/src/components/ui/dropdown-menu.tsx +82 -0
- package/src/components/ui/editable-form-card.tsx +106 -0
- package/src/components/ui/editable-info-field.tsx +67 -0
- package/src/components/ui/enhanced-input.tsx +78 -0
- package/src/components/ui/enhanced-select.tsx +101 -0
- package/src/components/ui/enhanced-textarea.tsx +64 -0
- package/src/components/ui/entity-card.tsx +140 -0
- package/src/components/ui/form-card.tsx +40 -0
- package/src/components/ui/form-field.tsx +50 -0
- package/src/components/ui/form-input.tsx +29 -0
- package/src/components/ui/form-provider.tsx +18 -0
- package/src/components/ui/form-section.tsx +66 -0
- package/src/components/ui/form-select.tsx +35 -0
- package/src/components/ui/info-field.tsx +36 -0
- package/src/components/ui/json-viewer.tsx +146 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/metric-card.tsx +80 -0
- package/src/components/ui/page-layout.tsx +183 -0
- package/src/components/ui/popover.tsx +29 -0
- package/src/components/ui/responsive-grid.tsx +46 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/sheet.tsx +140 -0
- package/src/components/ui/sidebar.tsx +775 -0
- package/src/components/ui/sonner.tsx +29 -0
- package/src/components/ui/stack.tsx +77 -0
- package/src/components/ui/status-badge.tsx +68 -0
- package/src/components/ui/tabs.tsx +52 -0
- package/src/components/ui/toast.tsx +127 -0
- package/src/components/ui/toaster.tsx +33 -0
- package/src/components/ui/tooltip.tsx +28 -0
- package/src/components/ui/use-toast.ts +3 -0
- package/src/components/ui-kit/dashboard-demo.tsx +156 -0
- package/src/components/ui-kit/pattern-library.tsx +248 -0
- package/src/components/ui-kit/showcase.tsx +211 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/hooks/use-toast.ts +191 -0
- package/src/hooks/useEditState.ts +70 -0
- package/src/hooks/useFormWithEditState.ts +115 -0
- package/src/{styles.css → index.css} +10 -4
- package/src/lib/constants.ts +25 -0
- package/src/lib/mock-data/alert-data.ts +275 -0
- package/src/lib/mock-data/banking-data.ts +72 -0
- package/src/lib/mock-data/business-data.ts +71 -0
- package/src/lib/mock-data/counterparty-data.ts +70 -0
- package/src/lib/mock-data/index.ts +5 -0
- package/src/lib/mock-data/transaction-data.ts +283 -0
- package/src/lib/mock-data/wire-data.ts +103 -0
- package/src/lib/mock-data.tsx +180 -0
- package/src/lib/schemas/banking-schemas.ts +30 -0
- package/src/lib/schemas/business-schemas.ts +36 -0
- package/src/lib/schemas/counterparty-schemas.ts +43 -0
- package/src/lib/schemas/index.ts +5 -0
- package/src/lib/schemas/wire-schemas.ts +44 -0
- package/src/lib/utils.ts +6 -0
- package/src/main.tsx +10 -0
- package/src/pages/Cases.tsx +16 -0
- package/src/pages/Dashboard.tsx +16 -0
- package/src/pages/NotFound.tsx +27 -0
- package/src/pages/TransactionHistory.tsx +532 -0
- package/src/pages/UIKit.tsx +51 -0
- package/src/pages/alerts/AlertDetail.tsx +193 -0
- package/src/pages/alerts/Alerts.tsx +373 -0
- package/src/pages/business/Business.tsx +48 -0
- package/src/pages/business/Create.tsx +173 -0
- package/src/pages/counterparty/Create.tsx +48 -0
- package/src/pages/counterparty/DomesticWire.tsx +78 -0
- package/src/pages/counterparty/Manage.tsx +79 -0
- package/src/pages/transactions/NewTransaction.tsx +527 -0
- package/src/pages/transactions/TransactionDetail.tsx +192 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.ts +124 -0
- package/tsconfig.app.json +30 -0
- package/tsconfig.json +19 -0
- package/tsconfig.node.json +22 -0
- package/vite.config.ts +22 -0
- package/dist/css/braid-ui-variables.css +0 -88
- package/dist/css/braid-ui.css +0 -4484
- package/dist/css/braid-ui.min.css +0 -1
- package/dist/index.cjs +0 -4
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -2429
- package/dist/index.d.ts +0 -2429
- package/dist/index.js +0 -4
- package/dist/index.js.map +0 -1
- package/src/styles-only.css +0 -121
- /package/{dist/braid-logo-343BOQZ2.png → src/assets/braid-logo.png} +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EnhancedInput } from "@/components/ui/enhanced-input"
|
|
2
|
+
import { EnhancedSelect } from "@/components/ui/enhanced-select"
|
|
3
|
+
import { FI_ID_TYPE_OPTIONS } from "@/lib/constants"
|
|
4
|
+
|
|
5
|
+
export const OriginatorFI = () => {
|
|
6
|
+
return (
|
|
7
|
+
<div className="space-y-6">
|
|
8
|
+
<div className="border-b border-border pb-4">
|
|
9
|
+
<h2 className="text-lg font-semibold text-foreground">Originator FI Details</h2>
|
|
10
|
+
<p className="text-sm text-muted-foreground">Financial institution details for the originator</p>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div className="space-y-6">
|
|
14
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
15
|
+
<EnhancedInput
|
|
16
|
+
label="Originator FI Account Number"
|
|
17
|
+
placeholder="Enter account number"
|
|
18
|
+
required
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
<EnhancedInput
|
|
22
|
+
label="Originator FI Name"
|
|
23
|
+
placeholder="Enter FI name"
|
|
24
|
+
hint="Full name of the originating financial institution"
|
|
25
|
+
/>
|
|
26
|
+
|
|
27
|
+
<EnhancedSelect
|
|
28
|
+
label="Originator FI ID Type"
|
|
29
|
+
placeholder="Select ID type"
|
|
30
|
+
options={FI_ID_TYPE_OPTIONS}
|
|
31
|
+
/>
|
|
32
|
+
|
|
33
|
+
<EnhancedInput
|
|
34
|
+
label="Originator FI ID Number"
|
|
35
|
+
placeholder="Enter ID number"
|
|
36
|
+
hint="Financial institution identification number"
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AddressForm } from "./AddressForm"
|
|
2
|
+
|
|
3
|
+
export const OriginatorFIAddress = () => {
|
|
4
|
+
return (
|
|
5
|
+
<AddressForm
|
|
6
|
+
title="Originator FI Address"
|
|
7
|
+
description="Address of the originating financial institution"
|
|
8
|
+
fieldPrefix="Originator FI"
|
|
9
|
+
fieldOverrides={{
|
|
10
|
+
streetAddress: { hint: "Originating financial institution street address" }
|
|
11
|
+
}}
|
|
12
|
+
/>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { useState } from "react"
|
|
2
|
+
import { Button } from "@/components/ui/button"
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
4
|
+
import { Plus, Trash2, ChevronDown, ChevronUp } from "lucide-react"
|
|
5
|
+
import { ACHBasicInfoCard } from "./ACHBasicInfoCard"
|
|
6
|
+
import { ACHBankCard } from "./ACHBankCard"
|
|
7
|
+
import { BankAddressCard } from "./BankAddressCard"
|
|
8
|
+
import { ReceiverCard } from "./ReceiverCard"
|
|
9
|
+
import { BeneficiaryCard } from "./BeneficiaryCard"
|
|
10
|
+
import { OriginatorCard } from "./OriginatorCard"
|
|
11
|
+
import { IntermediaryCard } from "./IntermediaryCard"
|
|
12
|
+
import { defaultACHTransfer } from "@/lib/mock-data/banking-data"
|
|
13
|
+
import { type ACHTransfer } from "@/lib/schemas/banking-schemas"
|
|
14
|
+
|
|
15
|
+
interface PaymentMethod {
|
|
16
|
+
id: string
|
|
17
|
+
type: "ach" | "wire"
|
|
18
|
+
name: string
|
|
19
|
+
collapsed: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const PaymentInformationSection = () => {
|
|
23
|
+
const [paymentMethods, setPaymentMethods] = useState<PaymentMethod[]>([])
|
|
24
|
+
const [showAddMenu, setShowAddMenu] = useState(false)
|
|
25
|
+
const [achData, setAchData] = useState<ACHTransfer>(defaultACHTransfer)
|
|
26
|
+
|
|
27
|
+
const addPaymentMethod = (type: "ach" | "wire") => {
|
|
28
|
+
const newMethod: PaymentMethod = {
|
|
29
|
+
id: `${type}-${Date.now()}`,
|
|
30
|
+
type,
|
|
31
|
+
name: type === "ach" ? "ACH Payment" : "Wire Transfer",
|
|
32
|
+
collapsed: false
|
|
33
|
+
}
|
|
34
|
+
setPaymentMethods([...paymentMethods, newMethod])
|
|
35
|
+
setShowAddMenu(false)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const removePaymentMethod = (id: string) => {
|
|
39
|
+
setPaymentMethods(paymentMethods.filter(method => method.id !== id))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const toggleCollapse = (id: string) => {
|
|
43
|
+
setPaymentMethods(paymentMethods.map(method =>
|
|
44
|
+
method.id === id ? { ...method, collapsed: !method.collapsed } : method
|
|
45
|
+
))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const handleACHDataChange = (newData: ACHTransfer) => {
|
|
49
|
+
setAchData(newData)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const renderPaymentMethodContent = (method: PaymentMethod) => {
|
|
53
|
+
if (method.type === "ach") {
|
|
54
|
+
return (
|
|
55
|
+
<div className="space-y-4">
|
|
56
|
+
<ACHBasicInfoCard
|
|
57
|
+
data={achData}
|
|
58
|
+
onDataChange={handleACHDataChange}
|
|
59
|
+
isEditing={true}
|
|
60
|
+
hideActions={true}
|
|
61
|
+
/>
|
|
62
|
+
<ACHBankCard
|
|
63
|
+
data={achData}
|
|
64
|
+
onDataChange={handleACHDataChange}
|
|
65
|
+
isEditing={true}
|
|
66
|
+
hideActions={true}
|
|
67
|
+
/>
|
|
68
|
+
<BankAddressCard isEditing={true} hideActions={true} />
|
|
69
|
+
</div>
|
|
70
|
+
)
|
|
71
|
+
} else {
|
|
72
|
+
return (
|
|
73
|
+
<div className="space-y-4">
|
|
74
|
+
<ReceiverCard isEditing={true} hideActions={true} />
|
|
75
|
+
<BeneficiaryCard isEditing={true} hideActions={true} />
|
|
76
|
+
<OriginatorCard isEditing={true} hideActions={true} />
|
|
77
|
+
<IntermediaryCard isEditing={true} hideActions={true} />
|
|
78
|
+
</div>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div className="space-y-6">
|
|
85
|
+
<div className="border-b border-border pb-4">
|
|
86
|
+
<h2 className="text-lg font-semibold text-foreground">Payment Information</h2>
|
|
87
|
+
<p className="text-sm text-muted-foreground">Add payment methods for this counterparty</p>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
{paymentMethods.map((method) => (
|
|
91
|
+
<Card key={method.id} className="relative">
|
|
92
|
+
<CardHeader className="pb-3">
|
|
93
|
+
<div className="flex items-center justify-between">
|
|
94
|
+
<div className="flex items-center gap-3">
|
|
95
|
+
<Button
|
|
96
|
+
variant="ghost"
|
|
97
|
+
size="icon"
|
|
98
|
+
onClick={() => toggleCollapse(method.id)}
|
|
99
|
+
className="h-6 w-6"
|
|
100
|
+
>
|
|
101
|
+
{method.collapsed ? (
|
|
102
|
+
<ChevronDown className="h-4 w-4" />
|
|
103
|
+
) : (
|
|
104
|
+
<ChevronUp className="h-4 w-4" />
|
|
105
|
+
)}
|
|
106
|
+
</Button>
|
|
107
|
+
<CardTitle className="text-base">{method.name}</CardTitle>
|
|
108
|
+
<span className="text-xs bg-muted px-2 py-1 rounded-md uppercase font-medium">
|
|
109
|
+
{method.type}
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
<Button
|
|
113
|
+
variant="ghost"
|
|
114
|
+
size="icon"
|
|
115
|
+
onClick={() => removePaymentMethod(method.id)}
|
|
116
|
+
className="h-6 w-6 text-destructive hover:text-destructive/80 hover:bg-destructive/10"
|
|
117
|
+
>
|
|
118
|
+
<Trash2 className="h-4 w-4" />
|
|
119
|
+
</Button>
|
|
120
|
+
</div>
|
|
121
|
+
</CardHeader>
|
|
122
|
+
{!method.collapsed && (
|
|
123
|
+
<CardContent>
|
|
124
|
+
{renderPaymentMethodContent(method)}
|
|
125
|
+
</CardContent>
|
|
126
|
+
)}
|
|
127
|
+
</Card>
|
|
128
|
+
))}
|
|
129
|
+
|
|
130
|
+
<div className="relative">
|
|
131
|
+
<Button
|
|
132
|
+
variant="outline"
|
|
133
|
+
onClick={() => setShowAddMenu(!showAddMenu)}
|
|
134
|
+
className="w-full border-dashed"
|
|
135
|
+
>
|
|
136
|
+
<Plus className="h-4 w-4 mr-2" />
|
|
137
|
+
Add Payment Information
|
|
138
|
+
</Button>
|
|
139
|
+
|
|
140
|
+
{showAddMenu && (
|
|
141
|
+
<div className="absolute top-full left-0 right-0 mt-2 bg-background border border-border rounded-md shadow-lg z-10">
|
|
142
|
+
<div className="p-2 space-y-1">
|
|
143
|
+
<Button
|
|
144
|
+
variant="ghost"
|
|
145
|
+
onClick={() => addPaymentMethod("ach")}
|
|
146
|
+
className="w-full justify-start"
|
|
147
|
+
>
|
|
148
|
+
Add ACH Payment
|
|
149
|
+
</Button>
|
|
150
|
+
<Button
|
|
151
|
+
variant="ghost"
|
|
152
|
+
onClick={() => addPaymentMethod("wire")}
|
|
153
|
+
className="w-full justify-start"
|
|
154
|
+
>
|
|
155
|
+
Add Wire Transfer
|
|
156
|
+
</Button>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { EditableFormCard } from "@/components/ui/editable-form-card"
|
|
2
|
+
import { DataGrid } from "@/components/ui/data-grid"
|
|
3
|
+
import { FormSection } from "@/components/ui/form-section"
|
|
4
|
+
import { FormProvider } from "@/components/ui/form-provider"
|
|
5
|
+
import { FormInput } from "@/components/ui/form-input"
|
|
6
|
+
import { useFormWithEditState } from "@/hooks/useFormWithEditState"
|
|
7
|
+
import { z } from "zod"
|
|
8
|
+
import { defaultReceiverInfo } from "@/lib/mock-data/wire-data"
|
|
9
|
+
|
|
10
|
+
const receiverSchema = z.object({
|
|
11
|
+
routingNumber: z.string().min(9, "Routing number must be 9 digits").max(9, "Routing number must be 9 digits"),
|
|
12
|
+
bankShortName: z.string().min(1, "Bank short name is required"),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
type ReceiverInfo = z.infer<typeof receiverSchema>
|
|
16
|
+
|
|
17
|
+
interface ReceiverCardProps {
|
|
18
|
+
data?: Partial<ReceiverInfo>
|
|
19
|
+
onDataChange?: (data: ReceiverInfo) => void
|
|
20
|
+
isEditing?: boolean
|
|
21
|
+
onToggleEdit?: () => void
|
|
22
|
+
className?: string
|
|
23
|
+
hideActions?: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const ReceiverCard = ({
|
|
27
|
+
data,
|
|
28
|
+
onDataChange,
|
|
29
|
+
isEditing,
|
|
30
|
+
onToggleEdit,
|
|
31
|
+
className,
|
|
32
|
+
hideActions
|
|
33
|
+
}: ReceiverCardProps) => {
|
|
34
|
+
const form = useFormWithEditState<ReceiverInfo>({
|
|
35
|
+
schema: receiverSchema,
|
|
36
|
+
defaultValues: { ...defaultReceiverInfo, ...data },
|
|
37
|
+
initialEditing: isEditing,
|
|
38
|
+
onToggleEdit,
|
|
39
|
+
onSave: onDataChange,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const editContent = (
|
|
43
|
+
<FormProvider form={form}>
|
|
44
|
+
<FormSection>
|
|
45
|
+
<div className="space-y-6">
|
|
46
|
+
<div className="border-b border-border pb-4">
|
|
47
|
+
<h2 className="text-lg font-semibold text-foreground">Receiver Details</h2>
|
|
48
|
+
<p className="text-sm text-muted-foreground">Receiving bank information</p>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div className="grid grid-cols-1 gap-6">
|
|
52
|
+
<FormInput
|
|
53
|
+
name="routingNumber"
|
|
54
|
+
label="Receiver Routing Number"
|
|
55
|
+
placeholder="Enter routing number"
|
|
56
|
+
hint="9-digit routing number"
|
|
57
|
+
pattern="[0-9]{9}"
|
|
58
|
+
maxLength={9}
|
|
59
|
+
required
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
<FormInput
|
|
63
|
+
name="bankShortName"
|
|
64
|
+
label="Receiver Bank Short Name"
|
|
65
|
+
placeholder="Enter bank short name"
|
|
66
|
+
required
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</FormSection>
|
|
71
|
+
</FormProvider>
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
const formValues = form.watch()
|
|
75
|
+
const viewData = [
|
|
76
|
+
{ label: "Routing Number", value: formValues?.routingNumber },
|
|
77
|
+
{ label: "Bank Short Name", value: formValues?.bankShortName }
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<EditableFormCard
|
|
82
|
+
title="FedWire Receiver"
|
|
83
|
+
variant="subtle"
|
|
84
|
+
className={className}
|
|
85
|
+
isEditing={form.isEditing}
|
|
86
|
+
onToggleEdit={form.handleToggleEdit}
|
|
87
|
+
onSave={form.handleSave}
|
|
88
|
+
onCancel={form.handleCancel}
|
|
89
|
+
hideActions={hideActions}
|
|
90
|
+
editContent={editContent}
|
|
91
|
+
viewContent={<DataGrid data={viewData} columns={2} />}
|
|
92
|
+
/>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useState } from "react"
|
|
2
|
+
import { EditableFormCard } from "@/components/ui/editable-form-card"
|
|
3
|
+
import { ResponsiveGrid } from "@/components/ui/responsive-grid"
|
|
4
|
+
import { EnhancedSelect } from "@/components/ui/enhanced-select"
|
|
5
|
+
import { ReceiverCard } from "./ReceiverCard"
|
|
6
|
+
import { BeneficiaryCard } from "./BeneficiaryCard"
|
|
7
|
+
import { OriginatorCard } from "./OriginatorCard"
|
|
8
|
+
import { IntermediaryCard } from "./IntermediaryCard"
|
|
9
|
+
|
|
10
|
+
interface WireTransferSectionProps {
|
|
11
|
+
isEditing?: boolean
|
|
12
|
+
onToggleEdit?: () => void
|
|
13
|
+
className?: string
|
|
14
|
+
hideActions?: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const WireTransferSection = ({ isEditing, onToggleEdit, className, hideActions }: WireTransferSectionProps) => {
|
|
18
|
+
const [wireTransferType, setWireTransferType] = useState("INTERNATIONAL")
|
|
19
|
+
|
|
20
|
+
const editContent = (
|
|
21
|
+
<div className="space-y-6">
|
|
22
|
+
<div className="flex items-center gap-4">
|
|
23
|
+
<EnhancedSelect
|
|
24
|
+
label="Transfer Type"
|
|
25
|
+
value={wireTransferType}
|
|
26
|
+
onValueChange={setWireTransferType}
|
|
27
|
+
options={[
|
|
28
|
+
{ value: "DOMESTIC", label: "Domestic" },
|
|
29
|
+
{ value: "INTERNATIONAL", label: "International" }
|
|
30
|
+
]}
|
|
31
|
+
placeholder="Select transfer type"
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<ResponsiveGrid type="forms" gap="md" editMode={isEditing}>
|
|
36
|
+
<ReceiverCard isEditing={isEditing} hideActions={true} />
|
|
37
|
+
<BeneficiaryCard isEditing={isEditing} hideActions={true} />
|
|
38
|
+
<OriginatorCard isEditing={isEditing} hideActions={true} />
|
|
39
|
+
<IntermediaryCard isEditing={isEditing} hideActions={true} />
|
|
40
|
+
</ResponsiveGrid>
|
|
41
|
+
</div>
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const viewContent = (
|
|
45
|
+
<div className="space-y-6">
|
|
46
|
+
<div className="flex items-center gap-2">
|
|
47
|
+
<span className="text-sm font-medium text-muted-foreground">Transfer Type:</span>
|
|
48
|
+
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-secondary text-secondary-foreground">
|
|
49
|
+
{wireTransferType}
|
|
50
|
+
</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<ResponsiveGrid type="forms" gap="md">
|
|
54
|
+
<ReceiverCard isEditing={false} hideActions={true} />
|
|
55
|
+
<BeneficiaryCard isEditing={false} hideActions={true} />
|
|
56
|
+
<OriginatorCard isEditing={false} hideActions={true} />
|
|
57
|
+
<IntermediaryCard isEditing={false} hideActions={true} />
|
|
58
|
+
</ResponsiveGrid>
|
|
59
|
+
</div>
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<EditableFormCard
|
|
64
|
+
title="Wire Transfer Configuration"
|
|
65
|
+
description="Configure wire transfer settings and participants"
|
|
66
|
+
variant="subtle"
|
|
67
|
+
className={className}
|
|
68
|
+
isEditing={isEditing}
|
|
69
|
+
onToggleEdit={onToggleEdit}
|
|
70
|
+
hideActions={hideActions}
|
|
71
|
+
editContent={editContent}
|
|
72
|
+
viewContent={viewContent}
|
|
73
|
+
/>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Container } from "@/components/ui/container"
|
|
3
|
+
import { Stack } from "@/components/ui/stack"
|
|
4
|
+
import { Button } from "@/components/ui/button"
|
|
5
|
+
import { Breadcrumb, type BreadcrumbItem } from "@/components/ui/breadcrumb"
|
|
6
|
+
import { ResponsiveGrid } from "@/components/ui/responsive-grid"
|
|
7
|
+
import { cn } from "@/lib/utils"
|
|
8
|
+
|
|
9
|
+
interface PageAction {
|
|
10
|
+
label: string
|
|
11
|
+
onClick: () => void
|
|
12
|
+
variant?: "default" | "outline" | "secondary"
|
|
13
|
+
icon?: React.ReactNode
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ListPageProps {
|
|
17
|
+
title: string
|
|
18
|
+
description?: string
|
|
19
|
+
breadcrumbs?: BreadcrumbItem[]
|
|
20
|
+
actions?: PageAction[]
|
|
21
|
+
children: React.ReactNode
|
|
22
|
+
maxWidth?: "sm" | "md" | "lg" | "xl" | "full"
|
|
23
|
+
loading?: boolean
|
|
24
|
+
emptyState?: React.ReactNode
|
|
25
|
+
className?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const ListPage = React.forwardRef<HTMLDivElement, ListPageProps>(
|
|
29
|
+
({
|
|
30
|
+
title,
|
|
31
|
+
description,
|
|
32
|
+
breadcrumbs,
|
|
33
|
+
actions,
|
|
34
|
+
children,
|
|
35
|
+
maxWidth = "xl",
|
|
36
|
+
loading = false,
|
|
37
|
+
emptyState,
|
|
38
|
+
className
|
|
39
|
+
}, ref) => {
|
|
40
|
+
const hasData = React.Children.count(children) > 0
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div ref={ref} className={cn("min-h-screen bg-gradient-subtle", className)}>
|
|
44
|
+
<Container size={maxWidth}>
|
|
45
|
+
<Stack spacing="lg">
|
|
46
|
+
{/* Breadcrumbs */}
|
|
47
|
+
{breadcrumbs && breadcrumbs.length > 0 && (
|
|
48
|
+
<Breadcrumb items={breadcrumbs} />
|
|
49
|
+
)}
|
|
50
|
+
|
|
51
|
+
{/* Page Header */}
|
|
52
|
+
<div className="flex items-start justify-between">
|
|
53
|
+
<Stack spacing="sm">
|
|
54
|
+
<h1 className="text-3xl font-bold text-foreground">{title}</h1>
|
|
55
|
+
{description && (
|
|
56
|
+
<p className="text-muted-foreground max-w-2xl">{description}</p>
|
|
57
|
+
)}
|
|
58
|
+
</Stack>
|
|
59
|
+
|
|
60
|
+
{actions && actions.length > 0 && (
|
|
61
|
+
<Stack direction="horizontal" spacing="sm">
|
|
62
|
+
{actions.map((action, index) => (
|
|
63
|
+
<Button
|
|
64
|
+
key={index}
|
|
65
|
+
variant={action.variant || "default"}
|
|
66
|
+
onClick={action.onClick}
|
|
67
|
+
>
|
|
68
|
+
{action.icon}
|
|
69
|
+
{action.label}
|
|
70
|
+
</Button>
|
|
71
|
+
))}
|
|
72
|
+
</Stack>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
{/* Content */}
|
|
77
|
+
{loading ? (
|
|
78
|
+
<div className="flex items-center justify-center py-12">
|
|
79
|
+
<div className="animate-pulse text-muted-foreground">Loading...</div>
|
|
80
|
+
</div>
|
|
81
|
+
) : hasData ? (
|
|
82
|
+
<ResponsiveGrid type="cards" gap="lg">
|
|
83
|
+
{children}
|
|
84
|
+
</ResponsiveGrid>
|
|
85
|
+
) : emptyState ? (
|
|
86
|
+
<div className="flex items-center justify-center py-12">
|
|
87
|
+
{emptyState}
|
|
88
|
+
</div>
|
|
89
|
+
) : (
|
|
90
|
+
<div className="flex items-center justify-center py-12">
|
|
91
|
+
<div className="text-center">
|
|
92
|
+
<p className="text-muted-foreground">No items found</p>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</Stack>
|
|
97
|
+
</Container>
|
|
98
|
+
</div>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
ListPage.displayName = "ListPage"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { FormCard } from "@/components/ui/form-card"
|
|
2
|
+
import { InfoField } from "@/components/ui/info-field"
|
|
3
|
+
import { Button } from "@/components/ui/button"
|
|
4
|
+
import { JsonViewer } from "@/components/ui/json-viewer"
|
|
5
|
+
|
|
6
|
+
interface ACHDetails {
|
|
7
|
+
type: string
|
|
8
|
+
originatorName: string
|
|
9
|
+
originatorAccountNumber: string
|
|
10
|
+
receiverName: string
|
|
11
|
+
receiverAccountNumber: string
|
|
12
|
+
receiverRoutingNumber: string
|
|
13
|
+
amount: number
|
|
14
|
+
secCode: string
|
|
15
|
+
companyEntryDescription: string
|
|
16
|
+
companyDiscretionaryData?: string
|
|
17
|
+
individualIdNumber?: string
|
|
18
|
+
individualName?: string
|
|
19
|
+
traceNumber: string
|
|
20
|
+
raw?: any
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface ACHDetailsSectionProps {
|
|
24
|
+
data: ACHDetails
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const ACHDetailsSection = ({ data }: ACHDetailsSectionProps) => {
|
|
28
|
+
const formatCurrency = (value: number) => {
|
|
29
|
+
return new Intl.NumberFormat('en-US', {
|
|
30
|
+
style: 'currency',
|
|
31
|
+
currency: 'USD',
|
|
32
|
+
minimumFractionDigits: 2
|
|
33
|
+
}).format(value)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<FormCard title="ACH Transfer Details">
|
|
38
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-x-8 gap-y-4">
|
|
39
|
+
<InfoField label="Type" value={data.type} layout="horizontal" />
|
|
40
|
+
<InfoField label="Originator Name" value={data.originatorName} layout="horizontal" />
|
|
41
|
+
<InfoField
|
|
42
|
+
label="Originator Account Number"
|
|
43
|
+
value={
|
|
44
|
+
<Button variant="link" className="h-auto p-0 text-sm">
|
|
45
|
+
{data.originatorAccountNumber}
|
|
46
|
+
</Button>
|
|
47
|
+
}
|
|
48
|
+
layout="horizontal"
|
|
49
|
+
/>
|
|
50
|
+
<InfoField label="Receiver Name" value={data.receiverName} layout="horizontal" />
|
|
51
|
+
<InfoField
|
|
52
|
+
label="Receiver Account Number"
|
|
53
|
+
value={
|
|
54
|
+
<Button variant="link" className="h-auto p-0 text-sm">
|
|
55
|
+
{data.receiverAccountNumber}
|
|
56
|
+
</Button>
|
|
57
|
+
}
|
|
58
|
+
layout="horizontal"
|
|
59
|
+
/>
|
|
60
|
+
<InfoField
|
|
61
|
+
label="Receiver Routing Number"
|
|
62
|
+
value={
|
|
63
|
+
<Button variant="link" className="h-auto p-0 text-sm">
|
|
64
|
+
{data.receiverRoutingNumber}
|
|
65
|
+
</Button>
|
|
66
|
+
}
|
|
67
|
+
layout="horizontal"
|
|
68
|
+
/>
|
|
69
|
+
<InfoField label="Amount" value={formatCurrency(data.amount)} layout="horizontal" />
|
|
70
|
+
<InfoField label="SEC Code" value={data.secCode} layout="horizontal" />
|
|
71
|
+
<InfoField label="Company Entry Description" value={data.companyEntryDescription} layout="horizontal" />
|
|
72
|
+
{data.companyDiscretionaryData && (
|
|
73
|
+
<InfoField label="Company Discretionary Data" value={data.companyDiscretionaryData} layout="horizontal" />
|
|
74
|
+
)}
|
|
75
|
+
{data.individualIdNumber && (
|
|
76
|
+
<InfoField label="Individual ID Number" value={data.individualIdNumber} layout="horizontal" />
|
|
77
|
+
)}
|
|
78
|
+
{data.individualName && (
|
|
79
|
+
<InfoField label="Individual Name" value={data.individualName} layout="horizontal" />
|
|
80
|
+
)}
|
|
81
|
+
<InfoField label="Trace Number" value={data.traceNumber} layout="horizontal" />
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{/* Raw JSON - Full Width */}
|
|
85
|
+
{data.raw && (
|
|
86
|
+
<div className="mt-6 pt-6 border-t border-border">
|
|
87
|
+
<InfoField
|
|
88
|
+
label="Raw"
|
|
89
|
+
value={<JsonViewer data={data.raw} className="mt-2" compact={true} />}
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
</FormCard>
|
|
94
|
+
)
|
|
95
|
+
}
|