@handled-ai/design-system 0.8.0 → 0.9.0

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 (336) hide show
  1. package/README.md +14 -4
  2. package/dist/charts/bar-chart-component.d.ts +24 -0
  3. package/dist/charts/bar-chart-component.js +123 -0
  4. package/dist/charts/bar-chart-component.js.map +1 -0
  5. package/dist/charts/chart-tooltip.d.ts +26 -0
  6. package/dist/charts/chart-tooltip.js +69 -0
  7. package/dist/charts/chart-tooltip.js.map +1 -0
  8. package/dist/charts/chart.d.ts +64 -0
  9. package/dist/charts/chart.js +285 -0
  10. package/dist/charts/chart.js.map +1 -0
  11. package/dist/charts/donut-chart.d.ts +21 -0
  12. package/dist/charts/donut-chart.js +96 -0
  13. package/dist/charts/donut-chart.js.map +1 -0
  14. package/dist/charts/index.d.ts +11 -0
  15. package/dist/charts/index.js +10 -0
  16. package/dist/charts/index.js.map +1 -0
  17. package/dist/charts/pipeline-overview.d.ts +76 -0
  18. package/dist/charts/pipeline-overview.js +372 -0
  19. package/dist/charts/pipeline-overview.js.map +1 -0
  20. package/dist/charts/sankey-chart.d.ts +52 -0
  21. package/dist/charts/sankey-chart.js +219 -0
  22. package/dist/charts/sankey-chart.js.map +1 -0
  23. package/dist/charts/top-line-metrics.d.ts +26 -0
  24. package/dist/charts/top-line-metrics.js +224 -0
  25. package/dist/charts/top-line-metrics.js.map +1 -0
  26. package/dist/charts/trend-area-chart.d.ts +21 -0
  27. package/dist/charts/trend-area-chart.js +150 -0
  28. package/dist/charts/trend-area-chart.js.map +1 -0
  29. package/dist/charts/volume-analysis-chart.d.ts +19 -0
  30. package/dist/charts/volume-analysis-chart.js +121 -0
  31. package/dist/charts/volume-analysis-chart.js.map +1 -0
  32. package/dist/components/activity-detail.d.ts +38 -0
  33. package/dist/components/activity-detail.js +163 -0
  34. package/dist/components/activity-detail.js.map +1 -0
  35. package/dist/components/activity-log.d.ts +21 -0
  36. package/dist/components/activity-log.js +61 -0
  37. package/dist/components/activity-log.js.map +1 -0
  38. package/dist/components/agent-popover.d.ts +71 -0
  39. package/dist/components/agent-popover.js +282 -0
  40. package/dist/components/agent-popover.js.map +1 -0
  41. package/dist/components/agent-widget.d.ts +24 -0
  42. package/dist/components/agent-widget.js +117 -0
  43. package/dist/components/agent-widget.js.map +1 -0
  44. package/dist/components/avatar.d.ts +13 -0
  45. package/dist/components/avatar.js +140 -0
  46. package/dist/components/avatar.js.map +1 -0
  47. package/dist/components/badge.d.ts +12 -0
  48. package/dist/components/badge.js +75 -0
  49. package/dist/components/badge.js.map +1 -0
  50. package/dist/components/button.d.ts +13 -0
  51. package/dist/components/button.js +83 -0
  52. package/dist/components/button.js.map +1 -0
  53. package/dist/components/card.d.ts +11 -0
  54. package/dist/components/card.js +119 -0
  55. package/dist/components/card.js.map +1 -0
  56. package/dist/components/contact-list.d.ts +34 -0
  57. package/dist/components/contact-list.js +84 -0
  58. package/dist/components/contact-list.js.map +1 -0
  59. package/dist/components/dashboard-cards.d.ts +10 -0
  60. package/dist/components/dashboard-cards.js +164 -0
  61. package/dist/components/dashboard-cards.js.map +1 -0
  62. package/dist/components/data-table-display.d.ts +19 -0
  63. package/dist/components/data-table-display.js +109 -0
  64. package/dist/components/data-table-display.js.map +1 -0
  65. package/dist/components/data-table-filter.d.ts +18 -0
  66. package/dist/components/data-table-filter.js +107 -0
  67. package/dist/components/data-table-filter.js.map +1 -0
  68. package/dist/components/data-table-quick-views.d.ts +13 -0
  69. package/dist/components/data-table-quick-views.js +90 -0
  70. package/dist/components/data-table-quick-views.js.map +1 -0
  71. package/dist/components/data-table-toolbar.d.ts +18 -0
  72. package/dist/components/data-table-toolbar.js +45 -0
  73. package/dist/components/data-table-toolbar.js.map +1 -0
  74. package/dist/components/data-table.d.ts +39 -0
  75. package/dist/components/data-table.js +821 -0
  76. package/dist/components/data-table.js.map +1 -0
  77. package/dist/components/detail-view.d.ts +44 -0
  78. package/dist/components/detail-view.js +165 -0
  79. package/dist/components/detail-view.js.map +1 -0
  80. package/dist/components/dialog.d.ts +19 -0
  81. package/dist/components/dialog.js +188 -0
  82. package/dist/components/dialog.js.map +1 -0
  83. package/dist/components/dropdown-menu.d.ts +27 -0
  84. package/dist/components/dropdown-menu.js +279 -0
  85. package/dist/components/dropdown-menu.js.map +1 -0
  86. package/dist/components/entity-panel.d.ts +69 -0
  87. package/dist/components/entity-panel.js +584 -0
  88. package/dist/components/entity-panel.js.map +1 -0
  89. package/dist/components/inbox-row.d.ts +27 -0
  90. package/dist/components/inbox-row.js +139 -0
  91. package/dist/components/inbox-row.js.map +1 -0
  92. package/dist/components/inbox-toolbar.d.ts +21 -0
  93. package/dist/components/inbox-toolbar.js +203 -0
  94. package/dist/components/inbox-toolbar.js.map +1 -0
  95. package/dist/components/input.d.ts +5 -0
  96. package/dist/components/input.js +50 -0
  97. package/dist/components/input.js.map +1 -0
  98. package/dist/components/insights-filter-bar.d.ts +21 -0
  99. package/dist/components/insights-filter-bar.js +99 -0
  100. package/dist/components/insights-filter-bar.js.map +1 -0
  101. package/dist/components/item-list-display.d.ts +22 -0
  102. package/dist/components/item-list-display.js +240 -0
  103. package/dist/components/item-list-display.js.map +1 -0
  104. package/dist/components/item-list-filter.d.ts +16 -0
  105. package/dist/components/item-list-filter.js +87 -0
  106. package/dist/components/item-list-filter.js.map +1 -0
  107. package/dist/components/item-list-toolbar.d.ts +25 -0
  108. package/dist/components/item-list-toolbar.js +79 -0
  109. package/dist/components/item-list-toolbar.js.map +1 -0
  110. package/dist/components/item-list.d.ts +20 -0
  111. package/dist/components/item-list.js +702 -0
  112. package/dist/components/item-list.js.map +1 -0
  113. package/dist/components/label.d.ts +6 -0
  114. package/dist/components/label.js +55 -0
  115. package/dist/components/label.js.map +1 -0
  116. package/dist/components/message.d.ts +23 -0
  117. package/dist/components/message.js +117 -0
  118. package/dist/components/message.js.map +1 -0
  119. package/dist/components/metric-card.d.ts +25 -0
  120. package/dist/components/metric-card.js +107 -0
  121. package/dist/components/metric-card.js.map +1 -0
  122. package/dist/components/performance-metrics-table.d.ts +38 -0
  123. package/dist/components/performance-metrics-table.js +342 -0
  124. package/dist/components/performance-metrics-table.js.map +1 -0
  125. package/dist/components/preview-list.d.ts +14 -0
  126. package/dist/components/preview-list.js +83 -0
  127. package/dist/components/preview-list.js.map +1 -0
  128. package/dist/components/progress.d.ts +6 -0
  129. package/dist/components/progress.js +69 -0
  130. package/dist/components/progress.js.map +1 -0
  131. package/dist/components/quick-action-chat-area.d.ts +24 -0
  132. package/dist/components/quick-action-chat-area.js +178 -0
  133. package/dist/components/quick-action-chat-area.js.map +1 -0
  134. package/dist/components/quick-action-modal.d.ts +30 -0
  135. package/dist/components/quick-action-modal.js +288 -0
  136. package/dist/components/quick-action-modal.js.map +1 -0
  137. package/dist/components/quick-action-sidebar-nav.d.ts +51 -0
  138. package/dist/components/quick-action-sidebar-nav.js +528 -0
  139. package/dist/components/quick-action-sidebar-nav.js.map +1 -0
  140. package/dist/components/recommended-actions-section.d.ts +23 -0
  141. package/dist/components/recommended-actions-section.js +215 -0
  142. package/dist/components/recommended-actions-section.js.map +1 -0
  143. package/dist/components/report-card.d.ts +26 -0
  144. package/dist/components/report-card.js +69 -0
  145. package/dist/components/report-card.js.map +1 -0
  146. package/dist/components/score-analysis-modal.d.ts +26 -0
  147. package/dist/components/score-analysis-modal.js +141 -0
  148. package/dist/components/score-analysis-modal.js.map +1 -0
  149. package/dist/components/score-breakdown.d.ts +17 -0
  150. package/dist/components/score-breakdown.js +162 -0
  151. package/dist/components/score-breakdown.js.map +1 -0
  152. package/dist/components/score-feedback.d.ts +40 -0
  153. package/dist/components/score-feedback.js +209 -0
  154. package/dist/components/score-feedback.js.map +1 -0
  155. package/dist/components/score-ring.d.ts +14 -0
  156. package/dist/components/score-ring.js +79 -0
  157. package/dist/components/score-ring.js.map +1 -0
  158. package/dist/components/scroll-area.d.ts +7 -0
  159. package/dist/components/scroll-area.js +101 -0
  160. package/dist/components/scroll-area.js.map +1 -0
  161. package/dist/components/select.d.ts +17 -0
  162. package/dist/components/select.js +228 -0
  163. package/dist/components/select.js.map +1 -0
  164. package/dist/components/separator.d.ts +6 -0
  165. package/dist/components/separator.js +61 -0
  166. package/dist/components/separator.js.map +1 -0
  167. package/dist/components/sheet.d.ts +16 -0
  168. package/dist/components/sheet.js +168 -0
  169. package/dist/components/sheet.js.map +1 -0
  170. package/dist/components/sidebar.d.ts +73 -0
  171. package/dist/components/sidebar.js +723 -0
  172. package/dist/components/sidebar.js.map +1 -0
  173. package/dist/components/signal-feedback-inline.d.ts +51 -0
  174. package/dist/components/signal-feedback-inline.js +548 -0
  175. package/dist/components/signal-feedback-inline.js.map +1 -0
  176. package/dist/components/simple-data-table.d.ts +15 -0
  177. package/dist/components/simple-data-table.js +91 -0
  178. package/dist/components/simple-data-table.js.map +1 -0
  179. package/dist/components/skeleton.d.ts +5 -0
  180. package/dist/components/skeleton.js +44 -0
  181. package/dist/components/skeleton.js.map +1 -0
  182. package/dist/components/status-badge.d.ts +10 -0
  183. package/dist/components/status-badge.js +82 -0
  184. package/dist/components/status-badge.js.map +1 -0
  185. package/dist/components/styled-bar-list.d.ts +20 -0
  186. package/dist/components/styled-bar-list.js +59 -0
  187. package/dist/components/styled-bar-list.js.map +1 -0
  188. package/dist/components/suggested-actions.d.ts +110 -0
  189. package/dist/components/suggested-actions.js +1538 -0
  190. package/dist/components/suggested-actions.js.map +1 -0
  191. package/dist/components/table.d.ts +12 -0
  192. package/dist/components/table.js +147 -0
  193. package/dist/components/table.js.map +1 -0
  194. package/dist/components/tabs.d.ts +14 -0
  195. package/dist/components/tabs.js +129 -0
  196. package/dist/components/tabs.js.map +1 -0
  197. package/dist/components/textarea.d.ts +5 -0
  198. package/dist/components/textarea.js +47 -0
  199. package/dist/components/textarea.js.map +1 -0
  200. package/dist/components/timeline-activity.d.ts +34 -0
  201. package/dist/components/timeline-activity.js +181 -0
  202. package/dist/components/timeline-activity.js.map +1 -0
  203. package/dist/components/tooltip.d.ts +9 -0
  204. package/dist/components/tooltip.js +93 -0
  205. package/dist/components/tooltip.js.map +1 -0
  206. package/dist/components/view-mode-toggle.d.ts +16 -0
  207. package/dist/components/view-mode-toggle.js +24 -0
  208. package/dist/components/view-mode-toggle.js.map +1 -0
  209. package/dist/hooks/use-mobile.d.ts +3 -0
  210. package/dist/hooks/use-mobile.js +21 -0
  211. package/dist/hooks/use-mobile.js.map +1 -0
  212. package/dist/index.d.ts +68 -1878
  213. package/dist/index.js +69 -10918
  214. package/dist/index.js.map +1 -1
  215. package/dist/lib/icons.d.ts +18 -0
  216. package/dist/lib/icons.js +21 -0
  217. package/dist/lib/icons.js.map +1 -0
  218. package/dist/lib/utils.d.ts +5 -0
  219. package/dist/lib/utils.js +9 -0
  220. package/dist/lib/utils.js.map +1 -0
  221. package/dist/prototype/index.d.ts +20 -0
  222. package/dist/prototype/index.js +8 -0
  223. package/dist/prototype/index.js.map +1 -0
  224. package/dist/prototype/prototype-accounts-view.d.ts +22 -0
  225. package/dist/prototype/prototype-accounts-view.js +70 -0
  226. package/dist/prototype/prototype-accounts-view.js.map +1 -0
  227. package/dist/prototype/prototype-admin-view.d.ts +21 -0
  228. package/dist/prototype/prototype-admin-view.js +53 -0
  229. package/dist/prototype/prototype-admin-view.js.map +1 -0
  230. package/dist/prototype/prototype-config.d.ts +226 -0
  231. package/dist/prototype/prototype-config.js +1 -0
  232. package/dist/prototype/prototype-config.js.map +1 -0
  233. package/dist/prototype/prototype-inbox-view.d.ts +48 -0
  234. package/dist/prototype/prototype-inbox-view.js +701 -0
  235. package/dist/prototype/prototype-inbox-view.js.map +1 -0
  236. package/dist/prototype/prototype-insights-view.d.ts +23 -0
  237. package/dist/prototype/prototype-insights-view.js +335 -0
  238. package/dist/prototype/prototype-insights-view.js.map +1 -0
  239. package/dist/prototype/prototype-shell.d.ts +40 -0
  240. package/dist/prototype/prototype-shell.js +190 -0
  241. package/dist/prototype/prototype-shell.js.map +1 -0
  242. package/dist/prototype/prototype-work-queue-view.d.ts +8 -0
  243. package/dist/prototype/prototype-work-queue-view.js +17 -0
  244. package/dist/prototype/prototype-work-queue-view.js.map +1 -0
  245. package/dist/three/agent-orb.d.ts +39 -0
  246. package/dist/three/agent-orb.js +500 -0
  247. package/dist/three/agent-orb.js.map +1 -0
  248. package/dist/three/index.d.ts +2 -0
  249. package/dist/three/index.js +2 -0
  250. package/dist/three/index.js.map +1 -0
  251. package/package.json +98 -17
  252. package/src/charts/bar-chart-component.tsx +150 -0
  253. package/src/charts/chart-tooltip.tsx +86 -0
  254. package/src/charts/chart.tsx +371 -0
  255. package/src/charts/donut-chart.tsx +112 -0
  256. package/src/charts/index.ts +13 -0
  257. package/src/charts/pipeline-overview.tsx +476 -0
  258. package/src/charts/sankey-chart.tsx +290 -0
  259. package/src/charts/top-line-metrics.tsx +261 -0
  260. package/src/charts/trend-area-chart.tsx +150 -0
  261. package/src/charts/volume-analysis-chart.tsx +124 -0
  262. package/src/components/activity-detail.tsx +233 -0
  263. package/src/components/activity-log.tsx +89 -0
  264. package/src/components/agent-popover.tsx +373 -0
  265. package/src/components/agent-widget.tsx +163 -0
  266. package/src/components/avatar.tsx +109 -0
  267. package/src/components/badge.tsx +48 -0
  268. package/src/components/button.tsx +59 -0
  269. package/src/components/card.tsx +92 -0
  270. package/src/components/contact-list.tsx +121 -0
  271. package/src/components/dashboard-cards.tsx +170 -0
  272. package/src/components/data-table-display.tsx +139 -0
  273. package/src/components/data-table-filter.tsx +138 -0
  274. package/src/components/data-table-quick-views.tsx +103 -0
  275. package/src/components/data-table-toolbar.tsx +56 -0
  276. package/src/components/data-table.tsx +915 -0
  277. package/src/components/detail-view.tsx +237 -0
  278. package/src/components/dialog.tsx +158 -0
  279. package/src/components/dropdown-menu.tsx +257 -0
  280. package/src/components/entity-panel.tsx +767 -0
  281. package/src/components/inbox-row.tsx +132 -0
  282. package/src/components/inbox-toolbar.tsx +213 -0
  283. package/src/components/input.tsx +21 -0
  284. package/src/components/insights-filter-bar.tsx +132 -0
  285. package/src/components/item-list-display.tsx +278 -0
  286. package/src/components/item-list-filter.tsx +118 -0
  287. package/src/components/item-list-toolbar.tsx +97 -0
  288. package/src/components/item-list.tsx +843 -0
  289. package/src/components/label.tsx +24 -0
  290. package/src/components/message.tsx +83 -0
  291. package/src/components/metric-card.tsx +178 -0
  292. package/src/components/performance-metrics-table.tsx +442 -0
  293. package/src/components/preview-list.tsx +62 -0
  294. package/src/components/progress.tsx +31 -0
  295. package/src/components/quick-action-chat-area.tsx +156 -0
  296. package/src/components/quick-action-modal.tsx +331 -0
  297. package/src/components/quick-action-sidebar-nav.tsx +592 -0
  298. package/src/components/recommended-actions-section.tsx +258 -0
  299. package/src/components/report-card.tsx +106 -0
  300. package/src/components/score-analysis-modal.tsx +172 -0
  301. package/src/components/score-breakdown.tsx +179 -0
  302. package/src/components/score-feedback.tsx +288 -0
  303. package/src/components/score-ring.tsx +87 -0
  304. package/src/components/scroll-area.tsx +58 -0
  305. package/src/components/select.tsx +190 -0
  306. package/src/components/separator.tsx +28 -0
  307. package/src/components/sheet.tsx +143 -0
  308. package/src/components/sidebar.tsx +726 -0
  309. package/src/components/signal-feedback-inline.tsx +591 -0
  310. package/src/components/simple-data-table.tsx +124 -0
  311. package/src/components/skeleton.tsx +15 -0
  312. package/src/components/status-badge.tsx +63 -0
  313. package/src/components/styled-bar-list.tsx +70 -0
  314. package/src/components/suggested-actions.tsx +1985 -0
  315. package/src/components/table.tsx +116 -0
  316. package/src/components/tabs.tsx +91 -0
  317. package/src/components/textarea.tsx +18 -0
  318. package/src/components/timeline-activity.tsx +234 -0
  319. package/src/components/tooltip.tsx +57 -0
  320. package/src/components/view-mode-toggle.tsx +39 -0
  321. package/src/hooks/use-mobile.ts +21 -0
  322. package/src/index.ts +77 -0
  323. package/src/lib/icons.ts +18 -0
  324. package/src/lib/utils.ts +6 -0
  325. package/src/prototype/index.ts +11 -0
  326. package/src/prototype/prototype-accounts-view.tsx +112 -0
  327. package/src/prototype/prototype-admin-view.tsx +67 -0
  328. package/src/prototype/prototype-config.ts +243 -0
  329. package/src/prototype/prototype-inbox-view.tsx +810 -0
  330. package/src/prototype/prototype-insights-view.tsx +379 -0
  331. package/src/prototype/prototype-shell.tsx +219 -0
  332. package/src/prototype/prototype-work-queue-view.tsx +30 -0
  333. package/src/styles/globals.css +299 -0
  334. package/src/three/agent-orb.tsx +557 -0
  335. package/src/three/index.ts +5 -0
  336. package/src/types/r3f.d.ts +8 -0
@@ -0,0 +1,132 @@
1
+ import * as React from "react"
2
+ import { Phone, Mail, MessageSquare, AlertCircle, ChevronDown } from "lucide-react"
3
+ import { cn } from "../lib/utils"
4
+
5
+ export interface InboxRowProps extends React.HTMLAttributes<HTMLDivElement> {
6
+ itemId: string
7
+ statusColor: "red" | "orange" | "gray"
8
+ primaryText: string
9
+ secondaryText: string
10
+ tertiaryText: string
11
+ isAtRisk?: boolean
12
+ isSelected?: boolean
13
+ contactMethods?: { phone?: boolean; email?: boolean; message?: boolean }
14
+ interactionCount: number | string
15
+ assignee: string
16
+ status: string
17
+ time: string
18
+ }
19
+
20
+ export const InboxRow = React.forwardRef<HTMLDivElement, InboxRowProps>(
21
+ (
22
+ {
23
+ className,
24
+ itemId,
25
+ statusColor,
26
+ primaryText,
27
+ secondaryText,
28
+ tertiaryText,
29
+ isAtRisk = false,
30
+ isSelected = false,
31
+ contactMethods = { phone: true, email: true, message: true },
32
+ interactionCount,
33
+ assignee,
34
+ status,
35
+ time,
36
+ ...props
37
+ },
38
+ ref
39
+ ) => {
40
+ return (
41
+ <div
42
+ ref={ref}
43
+ className={cn(
44
+ "group flex items-center gap-4 py-2.5 px-4 border-b border-border cursor-pointer transition-colors text-[13px] border-l-2",
45
+ isSelected
46
+ ? "bg-muted/30 border-l-brand-purple"
47
+ : "bg-background hover:bg-muted/50 border-l-transparent",
48
+ className
49
+ )}
50
+ {...props}
51
+ >
52
+ <div className="w-[100px] shrink-0 text-muted-foreground font-mono text-xs">
53
+ {itemId}
54
+ </div>
55
+
56
+ <div className="flex-1 min-w-0 flex items-center gap-3">
57
+ <div
58
+ className={cn("w-2 h-2 rounded-full shrink-0", {
59
+ "bg-red-500": statusColor === "red",
60
+ "bg-orange-500": statusColor === "orange",
61
+ "bg-gray-300": statusColor === "gray",
62
+ })}
63
+ />
64
+ <div className="flex items-center gap-1.5 truncate">
65
+ <span className="font-semibold text-foreground text-sm">{primaryText}</span>
66
+ <span className="text-muted-foreground text-xs">via {secondaryText}</span>
67
+ <span className="text-muted-foreground text-xs">&rarr;</span>
68
+ <span className="text-muted-foreground text-xs">{tertiaryText}</span>
69
+ </div>
70
+ </div>
71
+
72
+ <div className="w-24 shrink-0 flex items-center justify-end px-2">
73
+ {isAtRisk && (
74
+ <div className="flex items-center gap-1 text-red-600 bg-red-50 px-1.5 py-0.5 rounded-md text-[10px] font-semibold border border-red-100">
75
+ <AlertCircle className="w-3 h-3" />
76
+ At Risk
77
+ </div>
78
+ )}
79
+ </div>
80
+
81
+ <div className="flex items-center gap-2 text-muted-foreground/40 shrink-0 w-20 justify-center">
82
+ <Phone className={cn("w-3.5 h-3.5", contactMethods.phone && "text-muted-foreground/80")} />
83
+ <Mail className={cn("w-3.5 h-3.5", contactMethods.email && "text-muted-foreground/80")} />
84
+ <MessageSquare className={cn("w-3.5 h-3.5", contactMethods.message && "text-muted-foreground/80")} />
85
+ </div>
86
+
87
+ <div className="w-12 shrink-0 flex items-center justify-center">
88
+ <div
89
+ className={cn(
90
+ "text-[10px] font-semibold px-1.5 py-0.5 rounded border",
91
+ typeof interactionCount === "string" && interactionCount.includes("+")
92
+ ? "bg-red-50 border-red-200 text-red-700"
93
+ : Number(interactionCount) > 2
94
+ ? "bg-yellow-50 border-yellow-200 text-yellow-700"
95
+ : "bg-muted border-border text-foreground"
96
+ )}
97
+ >
98
+ {interactionCount}
99
+ </div>
100
+ </div>
101
+
102
+ <div className="w-32 shrink-0 text-xs font-medium text-foreground truncate">
103
+ {assignee}
104
+ </div>
105
+
106
+ <div className="w-28 shrink-0">
107
+ <div className="inline-flex items-center bg-muted/80 px-2 py-0.5 rounded text-[10px] font-medium text-muted-foreground">
108
+ {status}
109
+ </div>
110
+ </div>
111
+
112
+ <div className="w-24 shrink-0 text-right text-xs text-muted-foreground">
113
+ {time}
114
+ </div>
115
+ </div>
116
+ )
117
+ }
118
+ )
119
+
120
+ InboxRow.displayName = "InboxRow"
121
+
122
+ export function InboxGroupHeader({ title, count }: { title: string; count: number }) {
123
+ return (
124
+ <div className="flex items-center gap-2 py-2 px-4 bg-muted/30 border-b border-border text-[11px] font-bold text-muted-foreground uppercase tracking-wider">
125
+ <ChevronDown className="w-3.5 h-3.5" />
126
+ {title}
127
+ <span className="bg-background border border-border px-1.5 py-0.5 rounded text-[10px]">
128
+ {count}
129
+ </span>
130
+ </div>
131
+ )
132
+ }
@@ -0,0 +1,213 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ User,
6
+ Users,
7
+ List,
8
+ Filter,
9
+ ChevronDown,
10
+ X,
11
+ } from "lucide-react"
12
+ import { cn } from "../lib/utils"
13
+ import { Button } from "./button"
14
+ import { Badge } from "./badge"
15
+ import {
16
+ DropdownMenu,
17
+ DropdownMenuContent,
18
+ DropdownMenuLabel,
19
+ DropdownMenuRadioGroup,
20
+ DropdownMenuRadioItem,
21
+ DropdownMenuSeparator,
22
+ DropdownMenuSub,
23
+ DropdownMenuSubContent,
24
+ DropdownMenuSubTrigger,
25
+ DropdownMenuTrigger,
26
+ } from "./dropdown-menu"
27
+
28
+ export type AssigneeFilter = "me" | "team" | "all"
29
+
30
+ export interface InboxFilterCategory {
31
+ id: string
32
+ label: string
33
+ icon: React.ReactNode
34
+ options: string[]
35
+ }
36
+
37
+ export interface InboxToolbarProps {
38
+ assignee: AssigneeFilter
39
+ onAssigneeChange: (value: AssigneeFilter) => void
40
+ filterCategories: InboxFilterCategory[]
41
+ selectedFilters: Record<string, string>
42
+ onFilterChange: (categoryId: string, value: string) => void
43
+ onClearFilters: () => void
44
+ className?: string
45
+ }
46
+
47
+ const FILTER_PILL_COLORS: Record<string, string> = {
48
+ status: "bg-muted text-foreground border-border hover:bg-muted/80",
49
+ category: "bg-blue-50 text-blue-700 border-blue-100 hover:bg-blue-100",
50
+ account: "bg-indigo-50 text-indigo-700 border-indigo-100 hover:bg-indigo-100",
51
+ company: "bg-purple-50 text-purple-700 border-purple-100 hover:bg-purple-100",
52
+ }
53
+
54
+ function getFilterPillColor(categoryId: string) {
55
+ return FILTER_PILL_COLORS[categoryId] ?? FILTER_PILL_COLORS.status
56
+ }
57
+
58
+ export function InboxToolbar({
59
+ assignee,
60
+ onAssigneeChange,
61
+ filterCategories,
62
+ selectedFilters,
63
+ onFilterChange,
64
+ onClearFilters,
65
+ className,
66
+ }: InboxToolbarProps) {
67
+ const hasActiveFilters = Object.values(selectedFilters).some(
68
+ (v) => v !== "all"
69
+ )
70
+
71
+ return (
72
+ <div
73
+ className={cn(
74
+ "flex items-center gap-2 overflow-x-auto px-4 py-2 border-b border-border",
75
+ className
76
+ )}
77
+ >
78
+ <DropdownMenu>
79
+ <DropdownMenuTrigger asChild>
80
+ <Button
81
+ variant="outline"
82
+ size="sm"
83
+ className="h-7 shrink-0 gap-1.5 border-border bg-background text-xs font-medium shadow-sm"
84
+ >
85
+ {assignee === "me" && (
86
+ <User className="h-3.5 w-3.5 text-brand-purple" />
87
+ )}
88
+ {assignee === "team" && (
89
+ <Users className="h-3.5 w-3.5 text-blue-600" />
90
+ )}
91
+ {assignee === "all" && (
92
+ <List className="h-3.5 w-3.5 text-muted-foreground" />
93
+ )}
94
+ <span>
95
+ {assignee === "me" && "Assigned to me"}
96
+ {assignee === "team" && "My Team"}
97
+ {assignee === "all" && "All Cases"}
98
+ </span>
99
+ <ChevronDown className="h-3 w-3 opacity-50" />
100
+ </Button>
101
+ </DropdownMenuTrigger>
102
+ <DropdownMenuContent align="start" className="w-[180px]">
103
+ <DropdownMenuLabel>Assignee</DropdownMenuLabel>
104
+ <DropdownMenuSeparator />
105
+ <DropdownMenuRadioGroup
106
+ value={assignee}
107
+ onValueChange={(v) => onAssigneeChange(v as AssigneeFilter)}
108
+ >
109
+ <DropdownMenuRadioItem value="me" className="gap-2 text-xs">
110
+ <User className="h-3.5 w-3.5 text-brand-purple" />
111
+ Assigned to me
112
+ </DropdownMenuRadioItem>
113
+ <DropdownMenuRadioItem value="team" className="gap-2 text-xs">
114
+ <Users className="h-3.5 w-3.5 text-blue-600" />
115
+ My Team
116
+ </DropdownMenuRadioItem>
117
+ <DropdownMenuRadioItem value="all" className="gap-2 text-xs">
118
+ <List className="h-3.5 w-3.5 text-muted-foreground" />
119
+ All Cases
120
+ </DropdownMenuRadioItem>
121
+ </DropdownMenuRadioGroup>
122
+ </DropdownMenuContent>
123
+ </DropdownMenu>
124
+
125
+ <div className="mx-1 h-4 w-px shrink-0 bg-border" />
126
+
127
+ <DropdownMenu>
128
+ <DropdownMenuTrigger asChild>
129
+ <Button
130
+ variant="outline"
131
+ size="sm"
132
+ className="h-7 shrink-0 gap-1.5 border-dashed border-border bg-transparent text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground"
133
+ >
134
+ <Filter className="h-3.5 w-3.5" />
135
+ Filter
136
+ </Button>
137
+ </DropdownMenuTrigger>
138
+ <DropdownMenuContent align="start" className="w-[220px]">
139
+ <DropdownMenuLabel>Add Filter</DropdownMenuLabel>
140
+ <DropdownMenuSeparator />
141
+ {filterCategories.map((category) => (
142
+ <DropdownMenuSub key={category.id}>
143
+ <DropdownMenuSubTrigger className="gap-2 text-xs">
144
+ {category.icon}
145
+ {category.label}
146
+ </DropdownMenuSubTrigger>
147
+ <DropdownMenuSubContent className="max-h-[300px] w-[180px] overflow-y-auto">
148
+ <DropdownMenuRadioGroup
149
+ value={selectedFilters[category.id] ?? "all"}
150
+ onValueChange={(v) => onFilterChange(category.id, v)}
151
+ >
152
+ <DropdownMenuRadioItem value="all" className="text-xs">
153
+ All
154
+ </DropdownMenuRadioItem>
155
+ {category.options.map((option) => (
156
+ <DropdownMenuRadioItem
157
+ key={option}
158
+ value={option}
159
+ className="text-xs"
160
+ >
161
+ {option}
162
+ </DropdownMenuRadioItem>
163
+ ))}
164
+ </DropdownMenuRadioGroup>
165
+ </DropdownMenuSubContent>
166
+ </DropdownMenuSub>
167
+ ))}
168
+ </DropdownMenuContent>
169
+ </DropdownMenu>
170
+
171
+ {Object.entries(selectedFilters).map(([categoryId, value]) => {
172
+ if (value === "all") return null
173
+ const category = filterCategories.find((c) => c.id === categoryId)
174
+ if (!category) return null
175
+
176
+ return (
177
+ <Badge
178
+ key={categoryId}
179
+ variant="secondary"
180
+ className={cn(
181
+ "h-7 shrink-0 gap-1 border pl-2 pr-1 font-normal transition-colors",
182
+ getFilterPillColor(categoryId)
183
+ )}
184
+ >
185
+ <span className="text-[10px] opacity-60">{category.label}:</span>
186
+ <span className="max-w-[120px] truncate text-[10px] font-medium">
187
+ {value}
188
+ </span>
189
+ <button
190
+ type="button"
191
+ onClick={() => onFilterChange(categoryId, "all")}
192
+ className="ml-0.5 rounded-sm p-0.5 hover:bg-foreground/10"
193
+ >
194
+ <X className="h-2.5 w-2.5" />
195
+ <span className="sr-only">Remove</span>
196
+ </button>
197
+ </Badge>
198
+ )
199
+ })}
200
+
201
+ {hasActiveFilters && (
202
+ <Button
203
+ variant="ghost"
204
+ size="sm"
205
+ className="ml-auto h-7 shrink-0 px-2 text-xs text-muted-foreground hover:text-foreground"
206
+ onClick={onClearFilters}
207
+ >
208
+ Clear All
209
+ </Button>
210
+ )}
211
+ </div>
212
+ )
213
+ }
@@ -0,0 +1,21 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "../lib/utils"
4
+
5
+ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6
+ return (
7
+ <input
8
+ type={type}
9
+ data-slot="input"
10
+ className={cn(
11
+ "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
12
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
13
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
14
+ className
15
+ )}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ export { Input }
@@ -0,0 +1,132 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { CalendarIcon, ChevronDownIcon, FilterIcon } from "lucide-react"
5
+
6
+ import { cn } from "../lib/utils"
7
+ import { Button } from "./button"
8
+ import {
9
+ DropdownMenu,
10
+ DropdownMenuCheckboxItem,
11
+ DropdownMenuContent,
12
+ DropdownMenuItem,
13
+ DropdownMenuTrigger,
14
+ } from "./dropdown-menu"
15
+
16
+ export interface FilterDefinition {
17
+ id: string
18
+ label: string
19
+ options: string[]
20
+ defaultValue?: string
21
+ icon?: "calendar" | React.ComponentType<{ className?: string }>
22
+ }
23
+
24
+ export interface InsightsFilterBarProps {
25
+ filters: FilterDefinition[]
26
+ values: Record<string, string>
27
+ onChange: (filterId: string, value: string) => void
28
+ onClearAll?: () => void
29
+ className?: string
30
+ }
31
+
32
+ function hasNonDefaultValue(
33
+ filters: FilterDefinition[],
34
+ values: Record<string, string>
35
+ ) {
36
+ return filters.some((filter) => {
37
+ const defaultVal = filter.defaultValue ?? filter.options[0] ?? "All"
38
+ return values[filter.id] !== undefined && values[filter.id] !== defaultVal
39
+ })
40
+ }
41
+
42
+ function InsightsFilterBar({
43
+ filters,
44
+ values,
45
+ onChange,
46
+ onClearAll,
47
+ className,
48
+ }: InsightsFilterBarProps) {
49
+ const showClearAll = onClearAll && hasNonDefaultValue(filters, values)
50
+
51
+ return (
52
+ <div
53
+ data-slot="insights-filter-bar"
54
+ className={cn(
55
+ "flex flex-wrap items-center gap-3 rounded-md border border-border bg-card p-4 shadow-sm",
56
+ className
57
+ )}
58
+ >
59
+ <div className="flex items-center gap-2">
60
+ <FilterIcon className="h-4 w-4 text-muted-foreground" />
61
+ <span className="text-sm font-medium text-muted-foreground">
62
+ Filters:
63
+ </span>
64
+ </div>
65
+
66
+ {filters.map((filter) => {
67
+ const current = values[filter.id] ?? filter.defaultValue ?? "All"
68
+ const isCheckbox = filter.options.length > 0
69
+
70
+ const IconComp =
71
+ filter.icon === "calendar"
72
+ ? CalendarIcon
73
+ : typeof filter.icon === "function"
74
+ ? filter.icon
75
+ : null
76
+
77
+ return (
78
+ <DropdownMenu key={filter.id}>
79
+ <DropdownMenuTrigger asChild>
80
+ <Button
81
+ variant="outline"
82
+ size="sm"
83
+ className="h-8 gap-1.5 text-xs font-normal shadow-none"
84
+ >
85
+ {IconComp ? (
86
+ <IconComp className="h-3.5 w-3.5 text-muted-foreground" />
87
+ ) : null}
88
+ {filter.label}: {current}
89
+ <ChevronDownIcon className="h-3.5 w-3.5 opacity-50" />
90
+ </Button>
91
+ </DropdownMenuTrigger>
92
+ <DropdownMenuContent align="start">
93
+ {isCheckbox
94
+ ? filter.options.map((option) => (
95
+ <DropdownMenuCheckboxItem
96
+ key={option}
97
+ checked={current === option}
98
+ onCheckedChange={() => onChange(filter.id, option)}
99
+ >
100
+ {option}
101
+ </DropdownMenuCheckboxItem>
102
+ ))
103
+ : filter.options.map((option) => (
104
+ <DropdownMenuItem
105
+ key={option}
106
+ onSelect={() => onChange(filter.id, option)}
107
+ >
108
+ {option}
109
+ </DropdownMenuItem>
110
+ ))}
111
+ </DropdownMenuContent>
112
+ </DropdownMenu>
113
+ )
114
+ })}
115
+
116
+ {showClearAll ? (
117
+ <div className="ml-auto">
118
+ <Button
119
+ variant="ghost"
120
+ size="sm"
121
+ className="h-8 text-xs text-destructive hover:text-destructive"
122
+ onClick={onClearAll}
123
+ >
124
+ Clear All
125
+ </Button>
126
+ </div>
127
+ ) : null}
128
+ </div>
129
+ )
130
+ }
131
+
132
+ export { InsightsFilterBar }