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.
Files changed (145) hide show
  1. package/README.md +327 -44
  2. package/dist/css/braid-ui-variables.css +88 -0
  3. package/dist/css/braid-ui.css +4702 -0
  4. package/dist/css/braid-ui.min.css +1 -0
  5. package/dist/index.cjs +4 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +2027 -0
  8. package/dist/index.d.ts +2027 -0
  9. package/dist/index.js +4 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +115 -55
  12. package/src/styles-only.css +121 -0
  13. package/src/{index.css → styles.css} +4 -10
  14. package/components.json +0 -20
  15. package/eslint.config.js +0 -29
  16. package/index.html +0 -24
  17. package/postcss.config.js +0 -6
  18. package/public/favicon.ico +0 -0
  19. package/public/placeholder.svg +0 -1
  20. package/public/robots.txt +0 -14
  21. package/src/App.css +0 -42
  22. package/src/App.tsx +0 -94
  23. package/src/components/MainLayout.tsx +0 -15
  24. package/src/components/alerts/AlertDocuments.tsx +0 -320
  25. package/src/components/alerts/AlertNotes.tsx +0 -185
  26. package/src/components/alerts/AlertTimeline.tsx +0 -79
  27. package/src/components/alerts/ContextSection.tsx +0 -155
  28. package/src/components/app-sidebar.tsx +0 -341
  29. package/src/components/form-sections/ACHBankCard.tsx +0 -78
  30. package/src/components/form-sections/ACHBasicInfoCard.tsx +0 -100
  31. package/src/components/form-sections/ACHTransferSection.tsx +0 -64
  32. package/src/components/form-sections/AddressForm.tsx +0 -94
  33. package/src/components/form-sections/BankAddressCard.tsx +0 -95
  34. package/src/components/form-sections/BankingDetailsCard.tsx +0 -46
  35. package/src/components/form-sections/BasicInfoCard.tsx +0 -103
  36. package/src/components/form-sections/BasicInfoSection.tsx +0 -34
  37. package/src/components/form-sections/BeneficiaryAddress.tsx +0 -19
  38. package/src/components/form-sections/BeneficiaryCard.tsx +0 -41
  39. package/src/components/form-sections/BeneficiaryDomesticWire.tsx +0 -23
  40. package/src/components/form-sections/BusinessProfileCard.tsx +0 -131
  41. package/src/components/form-sections/BusinessStatusCard.tsx +0 -53
  42. package/src/components/form-sections/ContactInfoCard.tsx +0 -63
  43. package/src/components/form-sections/CounterpartyBasicInfo.tsx +0 -101
  44. package/src/components/form-sections/CounterpartyProfileCard.tsx +0 -104
  45. package/src/components/form-sections/CounterpartyRecordsCard.tsx +0 -41
  46. package/src/components/form-sections/IntermediaryCard.tsx +0 -77
  47. package/src/components/form-sections/IntermediaryFI.tsx +0 -41
  48. package/src/components/form-sections/IntermediaryFIAddress.tsx +0 -14
  49. package/src/components/form-sections/OriginatorCard.tsx +0 -49
  50. package/src/components/form-sections/OriginatorFI.tsx +0 -42
  51. package/src/components/form-sections/OriginatorFIAddress.tsx +0 -14
  52. package/src/components/form-sections/PaymentInformationSection.tsx +0 -163
  53. package/src/components/form-sections/ReceiverCard.tsx +0 -94
  54. package/src/components/form-sections/WireTransferSection.tsx +0 -75
  55. package/src/components/layouts/list-page.tsx +0 -103
  56. package/src/components/transaction/ACHDetailsSection.tsx +0 -95
  57. package/src/components/transaction/WireDetailsSection.tsx +0 -112
  58. package/src/components/ui/account-card.tsx +0 -94
  59. package/src/components/ui/badge.tsx +0 -75
  60. package/src/components/ui/breadcrumb.tsx +0 -78
  61. package/src/components/ui/business-type-badge.tsx +0 -42
  62. package/src/components/ui/button.tsx +0 -56
  63. package/src/components/ui/calendar.tsx +0 -49
  64. package/src/components/ui/card.tsx +0 -223
  65. package/src/components/ui/container.tsx +0 -45
  66. package/src/components/ui/counterparty-type-badge.tsx +0 -53
  67. package/src/components/ui/data-grid.tsx +0 -99
  68. package/src/components/ui/data-table.tsx +0 -152
  69. package/src/components/ui/detail-page-layout.tsx +0 -83
  70. package/src/components/ui/dialog.tsx +0 -120
  71. package/src/components/ui/dropdown-menu.tsx +0 -82
  72. package/src/components/ui/editable-form-card.tsx +0 -106
  73. package/src/components/ui/editable-info-field.tsx +0 -67
  74. package/src/components/ui/enhanced-input.tsx +0 -78
  75. package/src/components/ui/enhanced-select.tsx +0 -101
  76. package/src/components/ui/enhanced-textarea.tsx +0 -64
  77. package/src/components/ui/entity-card.tsx +0 -140
  78. package/src/components/ui/form-card.tsx +0 -40
  79. package/src/components/ui/form-field.tsx +0 -50
  80. package/src/components/ui/form-input.tsx +0 -29
  81. package/src/components/ui/form-provider.tsx +0 -18
  82. package/src/components/ui/form-section.tsx +0 -66
  83. package/src/components/ui/form-select.tsx +0 -35
  84. package/src/components/ui/info-field.tsx +0 -36
  85. package/src/components/ui/json-viewer.tsx +0 -146
  86. package/src/components/ui/label.tsx +0 -24
  87. package/src/components/ui/metric-card.tsx +0 -80
  88. package/src/components/ui/page-layout.tsx +0 -183
  89. package/src/components/ui/popover.tsx +0 -29
  90. package/src/components/ui/responsive-grid.tsx +0 -46
  91. package/src/components/ui/separator.tsx +0 -31
  92. package/src/components/ui/sheet.tsx +0 -140
  93. package/src/components/ui/sidebar.tsx +0 -775
  94. package/src/components/ui/sonner.tsx +0 -29
  95. package/src/components/ui/stack.tsx +0 -77
  96. package/src/components/ui/status-badge.tsx +0 -68
  97. package/src/components/ui/tabs.tsx +0 -52
  98. package/src/components/ui/toast.tsx +0 -127
  99. package/src/components/ui/toaster.tsx +0 -33
  100. package/src/components/ui/tooltip.tsx +0 -28
  101. package/src/components/ui/use-toast.ts +0 -3
  102. package/src/components/ui-kit/dashboard-demo.tsx +0 -156
  103. package/src/components/ui-kit/pattern-library.tsx +0 -248
  104. package/src/components/ui-kit/showcase.tsx +0 -211
  105. package/src/hooks/use-mobile.tsx +0 -19
  106. package/src/hooks/use-toast.ts +0 -191
  107. package/src/hooks/useEditState.ts +0 -70
  108. package/src/hooks/useFormWithEditState.ts +0 -115
  109. package/src/lib/constants.ts +0 -25
  110. package/src/lib/mock-data/alert-data.ts +0 -275
  111. package/src/lib/mock-data/banking-data.ts +0 -72
  112. package/src/lib/mock-data/business-data.ts +0 -71
  113. package/src/lib/mock-data/counterparty-data.ts +0 -70
  114. package/src/lib/mock-data/index.ts +0 -5
  115. package/src/lib/mock-data/transaction-data.ts +0 -283
  116. package/src/lib/mock-data/wire-data.ts +0 -103
  117. package/src/lib/mock-data.tsx +0 -180
  118. package/src/lib/schemas/banking-schemas.ts +0 -30
  119. package/src/lib/schemas/business-schemas.ts +0 -36
  120. package/src/lib/schemas/counterparty-schemas.ts +0 -43
  121. package/src/lib/schemas/index.ts +0 -5
  122. package/src/lib/schemas/wire-schemas.ts +0 -44
  123. package/src/lib/utils.ts +0 -6
  124. package/src/main.tsx +0 -10
  125. package/src/pages/Cases.tsx +0 -16
  126. package/src/pages/Dashboard.tsx +0 -16
  127. package/src/pages/NotFound.tsx +0 -27
  128. package/src/pages/TransactionHistory.tsx +0 -532
  129. package/src/pages/UIKit.tsx +0 -51
  130. package/src/pages/alerts/AlertDetail.tsx +0 -193
  131. package/src/pages/alerts/Alerts.tsx +0 -373
  132. package/src/pages/business/Business.tsx +0 -48
  133. package/src/pages/business/Create.tsx +0 -173
  134. package/src/pages/counterparty/Create.tsx +0 -48
  135. package/src/pages/counterparty/DomesticWire.tsx +0 -78
  136. package/src/pages/counterparty/Manage.tsx +0 -79
  137. package/src/pages/transactions/NewTransaction.tsx +0 -527
  138. package/src/pages/transactions/TransactionDetail.tsx +0 -192
  139. package/src/vite-env.d.ts +0 -1
  140. package/tailwind.config.ts +0 -124
  141. package/tsconfig.app.json +0 -30
  142. package/tsconfig.json +0 -19
  143. package/tsconfig.node.json +0 -22
  144. package/vite.config.ts +0 -22
  145. /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
- }