braid-ui 1.0.99 → 1.0.100
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 +327 -44
- package/dist/css/braid-ui-variables.css +88 -0
- package/dist/css/braid-ui.css +4702 -0
- package/dist/css/braid-ui.min.css +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2027 -0
- package/dist/index.d.ts +2027 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/package.json +115 -55
- package/src/styles-only.css +121 -0
- package/src/{index.css → styles.css} +4 -10
- package/components.json +0 -20
- package/eslint.config.js +0 -29
- package/index.html +0 -24
- package/postcss.config.js +0 -6
- package/public/favicon.ico +0 -0
- package/public/placeholder.svg +0 -1
- package/public/robots.txt +0 -14
- package/src/App.css +0 -42
- package/src/App.tsx +0 -94
- package/src/components/MainLayout.tsx +0 -15
- package/src/components/alerts/AlertDocuments.tsx +0 -320
- package/src/components/alerts/AlertNotes.tsx +0 -185
- package/src/components/alerts/AlertTimeline.tsx +0 -79
- package/src/components/alerts/ContextSection.tsx +0 -155
- package/src/components/app-sidebar.tsx +0 -341
- package/src/components/form-sections/ACHBankCard.tsx +0 -78
- package/src/components/form-sections/ACHBasicInfoCard.tsx +0 -100
- package/src/components/form-sections/ACHTransferSection.tsx +0 -64
- package/src/components/form-sections/AddressForm.tsx +0 -94
- package/src/components/form-sections/BankAddressCard.tsx +0 -95
- package/src/components/form-sections/BankingDetailsCard.tsx +0 -46
- package/src/components/form-sections/BasicInfoCard.tsx +0 -103
- package/src/components/form-sections/BasicInfoSection.tsx +0 -34
- package/src/components/form-sections/BeneficiaryAddress.tsx +0 -19
- package/src/components/form-sections/BeneficiaryCard.tsx +0 -41
- package/src/components/form-sections/BeneficiaryDomesticWire.tsx +0 -23
- package/src/components/form-sections/BusinessProfileCard.tsx +0 -131
- package/src/components/form-sections/BusinessStatusCard.tsx +0 -53
- package/src/components/form-sections/ContactInfoCard.tsx +0 -63
- package/src/components/form-sections/CounterpartyBasicInfo.tsx +0 -101
- package/src/components/form-sections/CounterpartyProfileCard.tsx +0 -104
- package/src/components/form-sections/CounterpartyRecordsCard.tsx +0 -41
- package/src/components/form-sections/IntermediaryCard.tsx +0 -77
- package/src/components/form-sections/IntermediaryFI.tsx +0 -41
- package/src/components/form-sections/IntermediaryFIAddress.tsx +0 -14
- package/src/components/form-sections/OriginatorCard.tsx +0 -49
- package/src/components/form-sections/OriginatorFI.tsx +0 -42
- package/src/components/form-sections/OriginatorFIAddress.tsx +0 -14
- package/src/components/form-sections/PaymentInformationSection.tsx +0 -163
- package/src/components/form-sections/ReceiverCard.tsx +0 -94
- package/src/components/form-sections/WireTransferSection.tsx +0 -75
- package/src/components/layouts/list-page.tsx +0 -103
- package/src/components/transaction/ACHDetailsSection.tsx +0 -95
- package/src/components/transaction/WireDetailsSection.tsx +0 -112
- package/src/components/ui/account-card.tsx +0 -94
- package/src/components/ui/badge.tsx +0 -75
- package/src/components/ui/breadcrumb.tsx +0 -78
- package/src/components/ui/business-type-badge.tsx +0 -42
- package/src/components/ui/button.tsx +0 -56
- package/src/components/ui/calendar.tsx +0 -49
- package/src/components/ui/card.tsx +0 -223
- package/src/components/ui/container.tsx +0 -45
- package/src/components/ui/counterparty-type-badge.tsx +0 -53
- package/src/components/ui/data-grid.tsx +0 -99
- package/src/components/ui/data-table.tsx +0 -152
- package/src/components/ui/detail-page-layout.tsx +0 -83
- package/src/components/ui/dialog.tsx +0 -120
- package/src/components/ui/dropdown-menu.tsx +0 -82
- package/src/components/ui/editable-form-card.tsx +0 -106
- package/src/components/ui/editable-info-field.tsx +0 -67
- package/src/components/ui/enhanced-input.tsx +0 -78
- package/src/components/ui/enhanced-select.tsx +0 -101
- package/src/components/ui/enhanced-textarea.tsx +0 -64
- package/src/components/ui/entity-card.tsx +0 -140
- package/src/components/ui/form-card.tsx +0 -40
- package/src/components/ui/form-field.tsx +0 -50
- package/src/components/ui/form-input.tsx +0 -29
- package/src/components/ui/form-provider.tsx +0 -18
- package/src/components/ui/form-section.tsx +0 -66
- package/src/components/ui/form-select.tsx +0 -35
- package/src/components/ui/info-field.tsx +0 -36
- package/src/components/ui/json-viewer.tsx +0 -146
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/metric-card.tsx +0 -80
- package/src/components/ui/page-layout.tsx +0 -183
- package/src/components/ui/popover.tsx +0 -29
- package/src/components/ui/responsive-grid.tsx +0 -46
- package/src/components/ui/separator.tsx +0 -31
- package/src/components/ui/sheet.tsx +0 -140
- package/src/components/ui/sidebar.tsx +0 -775
- package/src/components/ui/sonner.tsx +0 -29
- package/src/components/ui/stack.tsx +0 -77
- package/src/components/ui/status-badge.tsx +0 -68
- package/src/components/ui/tabs.tsx +0 -52
- package/src/components/ui/toast.tsx +0 -127
- package/src/components/ui/toaster.tsx +0 -33
- package/src/components/ui/tooltip.tsx +0 -28
- package/src/components/ui/use-toast.ts +0 -3
- package/src/components/ui-kit/dashboard-demo.tsx +0 -156
- package/src/components/ui-kit/pattern-library.tsx +0 -248
- package/src/components/ui-kit/showcase.tsx +0 -211
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/hooks/use-toast.ts +0 -191
- package/src/hooks/useEditState.ts +0 -70
- package/src/hooks/useFormWithEditState.ts +0 -115
- package/src/lib/constants.ts +0 -25
- package/src/lib/mock-data/alert-data.ts +0 -275
- package/src/lib/mock-data/banking-data.ts +0 -72
- package/src/lib/mock-data/business-data.ts +0 -71
- package/src/lib/mock-data/counterparty-data.ts +0 -70
- package/src/lib/mock-data/index.ts +0 -5
- package/src/lib/mock-data/transaction-data.ts +0 -283
- package/src/lib/mock-data/wire-data.ts +0 -103
- package/src/lib/mock-data.tsx +0 -180
- package/src/lib/schemas/banking-schemas.ts +0 -30
- package/src/lib/schemas/business-schemas.ts +0 -36
- package/src/lib/schemas/counterparty-schemas.ts +0 -43
- package/src/lib/schemas/index.ts +0 -5
- package/src/lib/schemas/wire-schemas.ts +0 -44
- package/src/lib/utils.ts +0 -6
- package/src/main.tsx +0 -10
- package/src/pages/Cases.tsx +0 -16
- package/src/pages/Dashboard.tsx +0 -16
- package/src/pages/NotFound.tsx +0 -27
- package/src/pages/TransactionHistory.tsx +0 -532
- package/src/pages/UIKit.tsx +0 -51
- package/src/pages/alerts/AlertDetail.tsx +0 -193
- package/src/pages/alerts/Alerts.tsx +0 -373
- package/src/pages/business/Business.tsx +0 -48
- package/src/pages/business/Create.tsx +0 -173
- package/src/pages/counterparty/Create.tsx +0 -48
- package/src/pages/counterparty/DomesticWire.tsx +0 -78
- package/src/pages/counterparty/Manage.tsx +0 -79
- package/src/pages/transactions/NewTransaction.tsx +0 -527
- package/src/pages/transactions/TransactionDetail.tsx +0 -192
- package/src/vite-env.d.ts +0 -1
- package/tailwind.config.ts +0 -124
- package/tsconfig.app.json +0 -30
- package/tsconfig.json +0 -19
- package/tsconfig.node.json +0 -22
- package/vite.config.ts +0 -22
- /package/{src/assets/braid-logo.png → dist/braid-logo-343BOQZ2.png} +0 -0
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
import { useState } from "react"
|
|
2
|
-
import { createPortal } from "react-dom"
|
|
3
|
-
import { AlertDocument } from "@/lib/mock-data/alert-data"
|
|
4
|
-
import { Button } from "@/components/ui/button"
|
|
5
|
-
import { toast } from "@/hooks/use-toast"
|
|
6
|
-
import { FileText, Upload, Download, Eye, Trash2, X } from "lucide-react"
|
|
7
|
-
import { cn } from "@/lib/utils"
|
|
8
|
-
import { EnhancedInput } from "@/components/ui/enhanced-input"
|
|
9
|
-
import { EnhancedTextarea } from "@/components/ui/enhanced-textarea"
|
|
10
|
-
import { EnhancedSelect } from "@/components/ui/enhanced-select"
|
|
11
|
-
|
|
12
|
-
interface AlertDocumentsProps {
|
|
13
|
-
alertId: string
|
|
14
|
-
documents: AlertDocument[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const AlertDocuments = ({ alertId, documents }: AlertDocumentsProps) => {
|
|
18
|
-
const [isUploading, setIsUploading] = useState(false)
|
|
19
|
-
const [showUploadDialog, setShowUploadDialog] = useState(false)
|
|
20
|
-
const [selectedFile, setSelectedFile] = useState<File | null>(null)
|
|
21
|
-
const [documentName, setDocumentName] = useState("")
|
|
22
|
-
const [description, setDescription] = useState("")
|
|
23
|
-
const [documentType, setDocumentType] = useState("")
|
|
24
|
-
|
|
25
|
-
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
26
|
-
const file = e.target.files?.[0]
|
|
27
|
-
if (!file) return
|
|
28
|
-
|
|
29
|
-
setSelectedFile(file)
|
|
30
|
-
setDocumentName(file.name)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const handleUploadSubmit = () => {
|
|
34
|
-
if (!selectedFile || !documentName || !documentType) {
|
|
35
|
-
toast({
|
|
36
|
-
title: "Missing Information",
|
|
37
|
-
description: "Please fill in all required fields",
|
|
38
|
-
variant: "destructive"
|
|
39
|
-
})
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
setIsUploading(true)
|
|
44
|
-
|
|
45
|
-
// Simulate upload
|
|
46
|
-
setTimeout(() => {
|
|
47
|
-
const newDocument: AlertDocument = {
|
|
48
|
-
id: String(Date.now()),
|
|
49
|
-
name: documentName,
|
|
50
|
-
type: documentType,
|
|
51
|
-
description: description || undefined,
|
|
52
|
-
size: `${(selectedFile.size / 1024 / 1024).toFixed(1)} MB`,
|
|
53
|
-
uploadedBy: "Current User",
|
|
54
|
-
uploadedAt: new Date().toISOString()
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
toast({
|
|
58
|
-
title: "Upload Successful",
|
|
59
|
-
description: `${documentName} uploaded successfully`
|
|
60
|
-
})
|
|
61
|
-
setIsUploading(false)
|
|
62
|
-
setShowUploadDialog(false)
|
|
63
|
-
resetForm()
|
|
64
|
-
}, 1000)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const resetForm = () => {
|
|
68
|
-
setSelectedFile(null)
|
|
69
|
-
setDocumentName("")
|
|
70
|
-
setDescription("")
|
|
71
|
-
setDocumentType("")
|
|
72
|
-
const fileInput = document.getElementById("file-upload") as HTMLInputElement
|
|
73
|
-
if (fileInput) fileInput.value = ""
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const handleCancelUpload = () => {
|
|
77
|
-
setShowUploadDialog(false)
|
|
78
|
-
resetForm()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const isImageType = (name: string) => {
|
|
82
|
-
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp']
|
|
83
|
-
return imageExtensions.some(ext => name.toLowerCase().endsWith(ext))
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const getFileIcon = (type: string) => {
|
|
87
|
-
return <FileText className="h-5 w-5" />
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const getFileTypeColor = (type: string) => {
|
|
91
|
-
switch (type.toUpperCase()) {
|
|
92
|
-
case "PDF":
|
|
93
|
-
return "text-red-500"
|
|
94
|
-
case "DOCX":
|
|
95
|
-
case "DOC":
|
|
96
|
-
return "text-blue-500"
|
|
97
|
-
case "XLSX":
|
|
98
|
-
case "XLS":
|
|
99
|
-
return "text-green-500"
|
|
100
|
-
case "JPG":
|
|
101
|
-
case "JPEG":
|
|
102
|
-
case "PNG":
|
|
103
|
-
return "text-purple-500"
|
|
104
|
-
default:
|
|
105
|
-
return "text-muted-foreground"
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const documentTypeOptions = [
|
|
110
|
-
{ value: "ID_DOCUMENT_FRONT", label: "ID Document (Front)" },
|
|
111
|
-
{ value: "ID_DOCUMENT_BACK", label: "ID Document (Back)" },
|
|
112
|
-
{ value: "PASSPORT", label: "Passport" },
|
|
113
|
-
{ value: "PROOF_OF_ADDRESS", label: "Proof of Address" },
|
|
114
|
-
{ value: "BANK_STATEMENT", label: "Bank Statement" },
|
|
115
|
-
{ value: "BUSINESS_LICENSE", label: "Business License" },
|
|
116
|
-
{ value: "TAX_DOCUMENT", label: "Tax Document" },
|
|
117
|
-
{ value: "OTHER", label: "Other" }
|
|
118
|
-
]
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
<div className="space-y-6">
|
|
122
|
-
{/* Upload Dialog - Render using portal */}
|
|
123
|
-
{showUploadDialog && createPortal(
|
|
124
|
-
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
|
125
|
-
<div
|
|
126
|
-
className="fixed inset-0 bg-background/80 backdrop-blur-sm"
|
|
127
|
-
onClick={handleCancelUpload}
|
|
128
|
-
/>
|
|
129
|
-
<div className="relative bg-card border rounded-lg shadow-lg max-w-lg w-full p-6 z-[101]">
|
|
130
|
-
<div className="flex items-center justify-between mb-6">
|
|
131
|
-
<h2 className="text-2xl font-bold">Upload Document</h2>
|
|
132
|
-
<Button
|
|
133
|
-
variant="ghost"
|
|
134
|
-
size="sm"
|
|
135
|
-
className="h-8 w-8 p-0"
|
|
136
|
-
onClick={handleCancelUpload}
|
|
137
|
-
>
|
|
138
|
-
<X className="h-4 w-4" />
|
|
139
|
-
</Button>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<div className="space-y-4">
|
|
143
|
-
{/* File Upload Area Inside Dialog */}
|
|
144
|
-
<div className="border-2 border-dashed rounded-lg p-6 text-center hover:border-primary/50 transition-colors">
|
|
145
|
-
<input
|
|
146
|
-
type="file"
|
|
147
|
-
id="file-upload-dialog"
|
|
148
|
-
className="hidden"
|
|
149
|
-
onChange={handleFileSelect}
|
|
150
|
-
disabled={isUploading}
|
|
151
|
-
/>
|
|
152
|
-
<label
|
|
153
|
-
htmlFor="file-upload-dialog"
|
|
154
|
-
className={cn(
|
|
155
|
-
"cursor-pointer flex flex-col items-center gap-2",
|
|
156
|
-
isUploading && "opacity-50 cursor-not-allowed"
|
|
157
|
-
)}
|
|
158
|
-
>
|
|
159
|
-
<Upload className="h-8 w-8 text-muted-foreground" />
|
|
160
|
-
<div>
|
|
161
|
-
<p className="text-sm font-medium text-foreground">
|
|
162
|
-
{selectedFile ? "Change file" : "Click to upload or drag and drop"}
|
|
163
|
-
</p>
|
|
164
|
-
<p className="text-xs text-muted-foreground mt-1">
|
|
165
|
-
PDF, DOC, DOCX, JPG, PNG up to 10MB
|
|
166
|
-
</p>
|
|
167
|
-
</div>
|
|
168
|
-
</label>
|
|
169
|
-
</div>
|
|
170
|
-
|
|
171
|
-
{selectedFile && (
|
|
172
|
-
<div className="p-3 bg-muted/50 rounded-lg">
|
|
173
|
-
<p className="text-sm text-muted-foreground">Selected file:</p>
|
|
174
|
-
<p className="text-sm font-medium">{selectedFile.name}</p>
|
|
175
|
-
<p className="text-xs text-muted-foreground">
|
|
176
|
-
{(selectedFile.size / 1024 / 1024).toFixed(2)} MB
|
|
177
|
-
</p>
|
|
178
|
-
</div>
|
|
179
|
-
)}
|
|
180
|
-
|
|
181
|
-
<EnhancedInput
|
|
182
|
-
label="Document name"
|
|
183
|
-
value={documentName}
|
|
184
|
-
onChange={(e) => setDocumentName(e.target.value)}
|
|
185
|
-
placeholder="Enter document name"
|
|
186
|
-
/>
|
|
187
|
-
|
|
188
|
-
<EnhancedTextarea
|
|
189
|
-
label="Description"
|
|
190
|
-
value={description}
|
|
191
|
-
onChange={(e) => setDescription(e.target.value)}
|
|
192
|
-
placeholder="Enter document description (optional)"
|
|
193
|
-
rows={3}
|
|
194
|
-
/>
|
|
195
|
-
|
|
196
|
-
<EnhancedSelect
|
|
197
|
-
label="Document type"
|
|
198
|
-
value={documentType}
|
|
199
|
-
onValueChange={setDocumentType}
|
|
200
|
-
placeholder="Select document type"
|
|
201
|
-
options={documentTypeOptions}
|
|
202
|
-
/>
|
|
203
|
-
</div>
|
|
204
|
-
|
|
205
|
-
<div className="flex gap-3 mt-6">
|
|
206
|
-
<Button
|
|
207
|
-
variant="outline"
|
|
208
|
-
onClick={handleCancelUpload}
|
|
209
|
-
disabled={isUploading}
|
|
210
|
-
className="flex-1"
|
|
211
|
-
>
|
|
212
|
-
Cancel
|
|
213
|
-
</Button>
|
|
214
|
-
<Button
|
|
215
|
-
onClick={handleUploadSubmit}
|
|
216
|
-
disabled={isUploading}
|
|
217
|
-
className="flex-1"
|
|
218
|
-
>
|
|
219
|
-
{isUploading ? "Uploading..." : "Upload"}
|
|
220
|
-
</Button>
|
|
221
|
-
</div>
|
|
222
|
-
</div>
|
|
223
|
-
</div>,
|
|
224
|
-
document.body
|
|
225
|
-
)}
|
|
226
|
-
|
|
227
|
-
{/* Documents List */}
|
|
228
|
-
<div className="space-y-3">
|
|
229
|
-
<div className="flex items-center justify-between">
|
|
230
|
-
<h3 className="text-sm font-medium text-foreground">Uploaded Documents</h3>
|
|
231
|
-
<Button
|
|
232
|
-
onClick={() => setShowUploadDialog(true)}
|
|
233
|
-
variant="ghost"
|
|
234
|
-
size="sm"
|
|
235
|
-
className="gap-2 text-primary hover:text-primary"
|
|
236
|
-
>
|
|
237
|
-
<Upload className="h-4 w-4" />
|
|
238
|
-
Upload
|
|
239
|
-
</Button>
|
|
240
|
-
</div>
|
|
241
|
-
{documents.length === 0 ? (
|
|
242
|
-
<div className="text-center py-8 text-muted-foreground">
|
|
243
|
-
<FileText className="h-8 w-8 mx-auto mb-2 opacity-50" />
|
|
244
|
-
<p>No documents uploaded yet</p>
|
|
245
|
-
</div>
|
|
246
|
-
) : (
|
|
247
|
-
<div className="space-y-2">
|
|
248
|
-
{documents.map((doc) => (
|
|
249
|
-
<div
|
|
250
|
-
key={doc.id}
|
|
251
|
-
className="border rounded-lg hover:bg-muted/30 transition-colors overflow-hidden"
|
|
252
|
-
>
|
|
253
|
-
{/* Image Preview for image types */}
|
|
254
|
-
{isImageType(doc.name) && doc.url && (
|
|
255
|
-
<div className="w-full bg-muted/50">
|
|
256
|
-
<img
|
|
257
|
-
src={doc.url}
|
|
258
|
-
alt={doc.name}
|
|
259
|
-
className="w-full h-48 object-cover"
|
|
260
|
-
/>
|
|
261
|
-
</div>
|
|
262
|
-
)}
|
|
263
|
-
|
|
264
|
-
<div className="flex items-center justify-between p-3">
|
|
265
|
-
<div className="flex items-center gap-3 flex-1 min-w-0">
|
|
266
|
-
{!isImageType(doc.name) && (
|
|
267
|
-
<div className={cn(getFileTypeColor(doc.type))}>
|
|
268
|
-
{getFileIcon(doc.type)}
|
|
269
|
-
</div>
|
|
270
|
-
)}
|
|
271
|
-
<div className="flex-1 min-w-0">
|
|
272
|
-
<div className="flex items-center gap-2">
|
|
273
|
-
<h4 className="font-medium text-sm truncate">{doc.name}</h4>
|
|
274
|
-
<span className={cn("text-xs px-2 py-0.5 rounded-full bg-muted", getFileTypeColor(doc.type))}>
|
|
275
|
-
{doc.type}
|
|
276
|
-
</span>
|
|
277
|
-
</div>
|
|
278
|
-
{doc.description && (
|
|
279
|
-
<p className="text-sm text-foreground mt-1">{doc.description}</p>
|
|
280
|
-
)}
|
|
281
|
-
<p className="text-xs text-muted-foreground mt-1">
|
|
282
|
-
{doc.size} • Uploaded by {doc.uploadedBy} • {new Date(doc.uploadedAt).toLocaleDateString()}
|
|
283
|
-
</p>
|
|
284
|
-
</div>
|
|
285
|
-
</div>
|
|
286
|
-
<div className="flex items-center gap-1">
|
|
287
|
-
<Button
|
|
288
|
-
variant="ghost"
|
|
289
|
-
size="sm"
|
|
290
|
-
className="h-8 w-8 p-0"
|
|
291
|
-
onClick={() => toast({ title: "Preview", description: `Viewing ${doc.name}` })}
|
|
292
|
-
>
|
|
293
|
-
<Eye className="h-4 w-4" />
|
|
294
|
-
</Button>
|
|
295
|
-
<Button
|
|
296
|
-
variant="ghost"
|
|
297
|
-
size="sm"
|
|
298
|
-
className="h-8 w-8 p-0"
|
|
299
|
-
onClick={() => toast({ title: "Download", description: `Downloading ${doc.name}` })}
|
|
300
|
-
>
|
|
301
|
-
<Download className="h-4 w-4" />
|
|
302
|
-
</Button>
|
|
303
|
-
<Button
|
|
304
|
-
variant="ghost"
|
|
305
|
-
size="sm"
|
|
306
|
-
className="h-8 w-8 p-0 text-muted-foreground hover:text-foreground"
|
|
307
|
-
onClick={() => toast({ title: "Delete", description: `Deleted ${doc.name}` })}
|
|
308
|
-
>
|
|
309
|
-
<Trash2 className="h-4 w-4" />
|
|
310
|
-
</Button>
|
|
311
|
-
</div>
|
|
312
|
-
</div>
|
|
313
|
-
</div>
|
|
314
|
-
))}
|
|
315
|
-
</div>
|
|
316
|
-
)}
|
|
317
|
-
</div>
|
|
318
|
-
</div>
|
|
319
|
-
)
|
|
320
|
-
}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { useState } from "react"
|
|
2
|
-
import { createPortal } from "react-dom"
|
|
3
|
-
import { AlertNote } from "@/lib/mock-data/alert-data"
|
|
4
|
-
import { Button } from "@/components/ui/button"
|
|
5
|
-
import { EnhancedTextarea } from "@/components/ui/enhanced-textarea"
|
|
6
|
-
import { EnhancedSelect } from "@/components/ui/enhanced-select"
|
|
7
|
-
import { Badge } from "@/components/ui/badge"
|
|
8
|
-
import { toast } from "@/hooks/use-toast"
|
|
9
|
-
import { MessageSquare, Plus, X, Trash2 } from "lucide-react"
|
|
10
|
-
|
|
11
|
-
const NOTE_TYPE_OPTIONS = [
|
|
12
|
-
{ value: "RFI Note", label: "RFI Note" },
|
|
13
|
-
{ value: "Internal Note", label: "Internal Note" }
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
interface AlertNotesProps {
|
|
17
|
-
alertId: string
|
|
18
|
-
notes: AlertNote[]
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const AlertNotes = ({ alertId, notes }: AlertNotesProps) => {
|
|
22
|
-
const [showNoteDialog, setShowNoteDialog] = useState(false)
|
|
23
|
-
const [newNote, setNewNote] = useState("")
|
|
24
|
-
const [noteType, setNoteType] = useState<"RFI Note" | "Internal Note">("RFI Note")
|
|
25
|
-
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
26
|
-
|
|
27
|
-
const resetForm = () => {
|
|
28
|
-
setNewNote("")
|
|
29
|
-
setNoteType("RFI Note")
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const handleCancelNote = () => {
|
|
33
|
-
setShowNoteDialog(false)
|
|
34
|
-
resetForm()
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const handleAddNote = async () => {
|
|
38
|
-
if (!newNote.trim()) {
|
|
39
|
-
toast({
|
|
40
|
-
title: "Error",
|
|
41
|
-
description: "Please enter a note before submitting",
|
|
42
|
-
variant: "destructive"
|
|
43
|
-
})
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
setIsSubmitting(true)
|
|
48
|
-
|
|
49
|
-
// Simulate API call
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
toast({
|
|
52
|
-
title: "Note Added",
|
|
53
|
-
description: "Your note has been added successfully"
|
|
54
|
-
})
|
|
55
|
-
setShowNoteDialog(false)
|
|
56
|
-
resetForm()
|
|
57
|
-
setIsSubmitting(false)
|
|
58
|
-
}, 500)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const handleDeleteNote = (noteId: string, noteContent: string) => {
|
|
62
|
-
toast({
|
|
63
|
-
title: "Note Deleted",
|
|
64
|
-
description: `Note deleted successfully`
|
|
65
|
-
})
|
|
66
|
-
// TODO: API call to delete note
|
|
67
|
-
console.log("Deleting note:", noteId)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<div className="space-y-6">
|
|
72
|
-
{/* Add Note Dialog - Render using portal */}
|
|
73
|
-
{showNoteDialog && createPortal(
|
|
74
|
-
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
|
75
|
-
<div
|
|
76
|
-
className="fixed inset-0 bg-background/80 backdrop-blur-sm"
|
|
77
|
-
onClick={handleCancelNote}
|
|
78
|
-
/>
|
|
79
|
-
<div className="relative bg-card border rounded-lg shadow-lg max-w-lg w-full p-6 z-[101]">
|
|
80
|
-
<div className="flex items-center justify-between mb-6">
|
|
81
|
-
<h2 className="text-2xl font-bold">Add Note</h2>
|
|
82
|
-
<Button
|
|
83
|
-
variant="ghost"
|
|
84
|
-
size="sm"
|
|
85
|
-
className="h-8 w-8 p-0"
|
|
86
|
-
onClick={handleCancelNote}
|
|
87
|
-
>
|
|
88
|
-
<X className="h-4 w-4" />
|
|
89
|
-
</Button>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
<div className="space-y-4">
|
|
93
|
-
<EnhancedSelect
|
|
94
|
-
label="Note Type"
|
|
95
|
-
value={noteType}
|
|
96
|
-
onValueChange={(value) => setNoteType(value as "RFI Note" | "Internal Note")}
|
|
97
|
-
options={NOTE_TYPE_OPTIONS}
|
|
98
|
-
/>
|
|
99
|
-
<EnhancedTextarea
|
|
100
|
-
label="Note"
|
|
101
|
-
placeholder="Enter your note here..."
|
|
102
|
-
value={newNote}
|
|
103
|
-
onChange={(e) => setNewNote(e.target.value)}
|
|
104
|
-
rows={6}
|
|
105
|
-
/>
|
|
106
|
-
</div>
|
|
107
|
-
|
|
108
|
-
<div className="flex gap-3 mt-6">
|
|
109
|
-
<Button
|
|
110
|
-
variant="outline"
|
|
111
|
-
onClick={handleCancelNote}
|
|
112
|
-
disabled={isSubmitting}
|
|
113
|
-
className="flex-1"
|
|
114
|
-
>
|
|
115
|
-
Cancel
|
|
116
|
-
</Button>
|
|
117
|
-
<Button
|
|
118
|
-
onClick={handleAddNote}
|
|
119
|
-
disabled={isSubmitting || !newNote.trim()}
|
|
120
|
-
className="flex-1"
|
|
121
|
-
>
|
|
122
|
-
{isSubmitting ? "Adding..." : "Add Note"}
|
|
123
|
-
</Button>
|
|
124
|
-
</div>
|
|
125
|
-
</div>
|
|
126
|
-
</div>,
|
|
127
|
-
document.body
|
|
128
|
-
)}
|
|
129
|
-
|
|
130
|
-
{/* Notes History */}
|
|
131
|
-
<div className="space-y-4">
|
|
132
|
-
<div className="flex items-center justify-between">
|
|
133
|
-
<h3 className="text-sm font-medium text-foreground">Note History</h3>
|
|
134
|
-
<Button
|
|
135
|
-
onClick={() => setShowNoteDialog(true)}
|
|
136
|
-
variant="ghost"
|
|
137
|
-
size="sm"
|
|
138
|
-
className="gap-2 text-primary hover:text-primary"
|
|
139
|
-
>
|
|
140
|
-
<Plus className="h-4 w-4" />
|
|
141
|
-
Add Note
|
|
142
|
-
</Button>
|
|
143
|
-
</div>
|
|
144
|
-
{notes.length === 0 ? (
|
|
145
|
-
<div className="text-center py-8 text-muted-foreground">
|
|
146
|
-
<MessageSquare className="h-8 w-8 mx-auto mb-2 opacity-50" />
|
|
147
|
-
<p>No notes yet</p>
|
|
148
|
-
</div>
|
|
149
|
-
) : (
|
|
150
|
-
<div className="space-y-3">
|
|
151
|
-
{notes.map((note) => (
|
|
152
|
-
<div
|
|
153
|
-
key={note.id}
|
|
154
|
-
className="border rounded-lg p-4 bg-muted/30"
|
|
155
|
-
>
|
|
156
|
-
<div className="flex items-start justify-between gap-4 mb-2">
|
|
157
|
-
<div className="flex items-center gap-2">
|
|
158
|
-
<p className="font-medium text-sm text-foreground">{note.user}</p>
|
|
159
|
-
<Badge variant={note.type === "RFI Note" ? "default" : "outline"}>
|
|
160
|
-
{note.type}
|
|
161
|
-
</Badge>
|
|
162
|
-
</div>
|
|
163
|
-
<div className="flex items-center gap-2">
|
|
164
|
-
<span className="text-xs text-muted-foreground whitespace-nowrap">
|
|
165
|
-
{note.timestamp}
|
|
166
|
-
</span>
|
|
167
|
-
<Button
|
|
168
|
-
variant="ghost"
|
|
169
|
-
size="sm"
|
|
170
|
-
className="h-8 w-8 p-0 text-muted-foreground hover:text-foreground"
|
|
171
|
-
onClick={() => handleDeleteNote(note.id, note.content)}
|
|
172
|
-
>
|
|
173
|
-
<Trash2 className="h-4 w-4" />
|
|
174
|
-
</Button>
|
|
175
|
-
</div>
|
|
176
|
-
</div>
|
|
177
|
-
<p className="text-sm text-foreground">{note.content}</p>
|
|
178
|
-
</div>
|
|
179
|
-
))}
|
|
180
|
-
</div>
|
|
181
|
-
)}
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
)
|
|
185
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { TimelineEvent } from "@/lib/mock-data/alert-data"
|
|
2
|
-
import { CheckCircle, Circle, UserPlus, Edit, XCircle } from "lucide-react"
|
|
3
|
-
import { cn } from "@/lib/utils"
|
|
4
|
-
|
|
5
|
-
interface AlertTimelineProps {
|
|
6
|
-
events: TimelineEvent[]
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const AlertTimeline = ({ events }: AlertTimelineProps) => {
|
|
10
|
-
const getIcon = (action: string) => {
|
|
11
|
-
if (action.includes("Created")) return <Circle className="h-4 w-4" />
|
|
12
|
-
if (action.includes("Assigned")) return <UserPlus className="h-4 w-4" />
|
|
13
|
-
if (action.includes("Updated") || action.includes("Modified")) return <Edit className="h-4 w-4" />
|
|
14
|
-
if (action.includes("Closed") || action.includes("Resolved")) return <CheckCircle className="h-4 w-4" />
|
|
15
|
-
if (action.includes("Rejected")) return <XCircle className="h-4 w-4" />
|
|
16
|
-
return <Circle className="h-4 w-4" />
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const getStatusColor = (status?: string) => {
|
|
20
|
-
switch (status) {
|
|
21
|
-
case "Unassigned":
|
|
22
|
-
return "text-destructive"
|
|
23
|
-
case "Closed":
|
|
24
|
-
return "text-success"
|
|
25
|
-
case "In Progress":
|
|
26
|
-
return "text-warning"
|
|
27
|
-
default:
|
|
28
|
-
return "text-muted-foreground"
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (events.length === 0) {
|
|
33
|
-
return (
|
|
34
|
-
<div className="text-center py-8 text-muted-foreground">
|
|
35
|
-
No timeline events yet
|
|
36
|
-
</div>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<div className="space-y-3">
|
|
42
|
-
{events.map((event, index) => (
|
|
43
|
-
<div key={event.id} className="relative pl-6 pb-3">
|
|
44
|
-
{/* Timeline line */}
|
|
45
|
-
{index !== events.length - 1 && (
|
|
46
|
-
<div className="absolute left-[7px] top-5 bottom-0 w-[2px] bg-border" />
|
|
47
|
-
)}
|
|
48
|
-
|
|
49
|
-
{/* Icon */}
|
|
50
|
-
<div className={cn(
|
|
51
|
-
"absolute left-0 top-0 flex-none",
|
|
52
|
-
getStatusColor(event.status)
|
|
53
|
-
)}>
|
|
54
|
-
<div className="h-4 w-4">
|
|
55
|
-
{getIcon(event.action)}
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
|
|
59
|
-
{/* Content */}
|
|
60
|
-
<div className="space-y-0.5">
|
|
61
|
-
<p className="text-xs font-medium text-foreground">{event.action}</p>
|
|
62
|
-
<p className="text-xs text-muted-foreground">by {event.user}</p>
|
|
63
|
-
{event.details && (
|
|
64
|
-
<p className="text-xs text-muted-foreground">{event.details}</p>
|
|
65
|
-
)}
|
|
66
|
-
{event.status && (
|
|
67
|
-
<p className={cn("text-xs font-medium", getStatusColor(event.status))}>
|
|
68
|
-
Status: {event.status}
|
|
69
|
-
</p>
|
|
70
|
-
)}
|
|
71
|
-
<p className="text-xs text-muted-foreground/70 pt-0.5">
|
|
72
|
-
{event.timestamp}
|
|
73
|
-
</p>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
))}
|
|
77
|
-
</div>
|
|
78
|
-
)
|
|
79
|
-
}
|