@exxatdesignux/ui 0.3.0 → 0.4.1

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 (214) hide show
  1. package/CHANGELOG.md +701 -6
  2. package/README.md +138 -0
  3. package/bin/init.mjs +134 -31
  4. package/consumer-extras/cursor-rules/exxat-board-cards.mdc +1 -1
  5. package/consumer-extras/cursor-rules/exxat-centralized-list-dataset.mdc +2 -2
  6. package/consumer-extras/cursor-rules/exxat-collaboration-access.mdc +1 -1
  7. package/consumer-extras/cursor-rules/exxat-data-tables.mdc +2 -0
  8. package/consumer-extras/cursor-rules/exxat-dedicated-search-surfaces.mdc +1 -1
  9. package/consumer-extras/cursor-rules/exxat-ds-agents.mdc +3 -3
  10. package/consumer-extras/cursor-rules/exxat-library-hub-header.mdc +28 -0
  11. package/consumer-extras/cursor-rules/exxat-mono-ids.mdc +1 -1
  12. package/consumer-extras/cursor-rules/exxat-person-identity-display.mdc +1 -1
  13. package/consumer-extras/cursor-rules/exxat-primary-nav-secondary-panel.mdc +6 -6
  14. package/consumer-extras/cursor-rules/exxat-reuse-before-custom.mdc +1 -1
  15. package/consumer-extras/cursor-skills/exxat-board-cards/SKILL.md +2 -2
  16. package/consumer-extras/cursor-skills/exxat-centralized-list-dataset/SKILL.md +1 -1
  17. package/consumer-extras/cursor-skills/exxat-collaboration-access/SKILL.md +3 -3
  18. package/consumer-extras/cursor-skills/exxat-dedicated-search-surfaces/SKILL.md +2 -2
  19. package/consumer-extras/cursor-skills/exxat-ds-skill/SKILL.md +7 -7
  20. package/consumer-extras/cursor-skills/exxat-kpi-flat-band/SKILL.md +1 -1
  21. package/consumer-extras/cursor-skills/exxat-list-page-view-shells/SKILL.md +1 -1
  22. package/consumer-extras/cursor-skills/exxat-mono-ids/SKILL.md +4 -4
  23. package/consumer-extras/cursor-skills/exxat-primary-nav-secondary-panel/SKILL.md +8 -8
  24. package/consumer-extras/cursor-skills/exxat-token-economy/SKILL.md +277 -0
  25. package/consumer-extras/handbook/HANDBOOK.md +2 -0
  26. package/consumer-extras/handbook/glossary.md +2 -1
  27. package/consumer-extras/handbook/reference-implementations.md +31 -4
  28. package/consumer-extras/patterns/collaboration-access-pattern.md +7 -7
  29. package/consumer-extras/patterns/data-views-pattern.md +18 -16
  30. package/consumer-extras/patterns/kpi-flat-band-pattern.md +2 -2
  31. package/dist/components/data-table/index.js +2 -2
  32. package/dist/components/data-table/index.js.map +1 -1
  33. package/dist/components/data-table/pagination.js +3 -3
  34. package/dist/components/data-table/pagination.js.map +1 -1
  35. package/dist/components/data-table/use-table-state.d.ts +1 -1
  36. package/dist/components/data-table/use-table-state.js.map +1 -1
  37. package/dist/components/data-views/data-row-list.js.map +1 -1
  38. package/dist/components/data-views/finder-panel-view.d.ts +1 -1
  39. package/dist/components/data-views/finder-panel-view.js.map +1 -1
  40. package/dist/components/data-views/hub-table.d.ts +9 -3
  41. package/dist/components/data-views/hub-table.js +262 -40
  42. package/dist/components/data-views/hub-table.js.map +1 -1
  43. package/dist/components/data-views/index.js +262 -40
  44. package/dist/components/data-views/index.js.map +1 -1
  45. package/dist/components/data-views/list-page-split-hub-tokens.d.ts +2 -2
  46. package/dist/components/data-views/list-page-split-hub-tokens.js.map +1 -1
  47. package/dist/components/data-views/list-page-tree-column-header.d.ts +1 -1
  48. package/dist/components/data-views/list-page-tree-column-header.js.map +1 -1
  49. package/dist/components/data-views/list-page-tree-panel-shell.js.map +1 -1
  50. package/dist/components/data-views/os-folder-glyph.d.ts +1 -1
  51. package/dist/components/data-views/os-folder-glyph.js.map +1 -1
  52. package/dist/components/ui/avatar.d.ts +1 -1
  53. package/dist/components/ui/key-metrics.js.map +1 -1
  54. package/dist/index.js +136 -39
  55. package/dist/index.js.map +1 -1
  56. package/package.json +3 -2
  57. package/src/components/data-table/index.tsx +2 -2
  58. package/src/components/data-table/pagination.tsx +5 -1
  59. package/src/components/data-table/use-table-state.ts +1 -1
  60. package/src/components/data-views/data-row-list.tsx +1 -1
  61. package/src/components/data-views/finder-panel-view.tsx +2 -2
  62. package/src/components/data-views/hub-table.tsx +149 -41
  63. package/src/components/data-views/list-page-split-hub-tokens.ts +2 -2
  64. package/src/components/data-views/list-page-tree-column-header.tsx +1 -1
  65. package/src/components/data-views/os-folder-glyph.tsx +1 -1
  66. package/src/components/ui/key-metrics.tsx +1 -1
  67. package/template/.claude/skills/exxat-ds-skill/SKILL.md +8 -7
  68. package/template/.cursor/rules/exxat-accessibility.mdc +1 -1
  69. package/template/.cursor/rules/exxat-command-menu.mdc +1 -1
  70. package/template/.cursor/rules/exxat-dashboard-view-charts.mdc +6 -6
  71. package/template/.cursor/rules/exxat-data-tables.mdc +3 -3
  72. package/template/.cursor/rules/exxat-kbd-shortcuts.mdc +5 -5
  73. package/template/.cursor/rules/exxat-mono-ids.mdc +1 -1
  74. package/template/.cursor/rules/exxat-page-vs-drawer.mdc +1 -1
  75. package/template/.cursor/rules/exxat-table-properties-drawer.mdc +1 -1
  76. package/template/AGENTS.md +43 -37
  77. package/template/app/(app)/columns/page.tsx +11 -0
  78. package/template/app/(app)/library/all/page.tsx +11 -0
  79. package/template/app/(app)/library/find/page.tsx +12 -0
  80. package/template/app/(app)/{question-bank → library}/layout.tsx +16 -16
  81. package/template/app/(app)/library/list/page.tsx +12 -0
  82. package/template/app/(app)/{question-bank → library}/new/page.tsx +10 -10
  83. package/template/app/(app)/library/page.tsx +11 -0
  84. package/template/app/(app)/tokens-themes/page.tsx +11 -0
  85. package/template/components/ask-leo-composer.tsx +2 -2
  86. package/template/components/columns-client.tsx +158 -0
  87. package/template/components/columns-showcase.tsx +541 -0
  88. package/template/components/data-views/index.ts +32 -6
  89. package/template/components/data-views/{question-bank-folder-tree-branch.tsx → library-folder-tree-branch.tsx} +19 -19
  90. package/template/components/data-views/table-cells.tsx +673 -0
  91. package/template/components/folder-details-shell.tsx +11 -11
  92. package/template/components/hub-tree-panel-view.tsx +24 -24
  93. package/template/components/{question-bank-board-view.tsx → library-board-view.tsx} +44 -44
  94. package/template/components/{question-bank-client.tsx → library-client.tsx} +82 -82
  95. package/template/components/{question-bank-dashboard-charts.tsx → library-dashboard-charts.tsx} +14 -14
  96. package/template/components/{question-bank-favorite-button.tsx → library-favorite-button.tsx} +7 -7
  97. package/template/components/{question-bank-hub-client.tsx → library-hub-client.tsx} +43 -43
  98. package/template/components/{question-bank-new-folder-sheet.tsx → library-new-folder-sheet.tsx} +14 -14
  99. package/template/components/{question-bank-os-folder-view.tsx → library-os-folder-view.tsx} +31 -31
  100. package/template/components/{question-bank-page-header.tsx → library-page-header.tsx} +6 -6
  101. package/template/components/library-panel-activator.tsx +8 -0
  102. package/template/components/{question-bank-secondary-nav.tsx → library-secondary-nav.tsx} +60 -60
  103. package/template/components/{question-bank-table.tsx → library-table.tsx} +97 -97
  104. package/template/components/list-hub-status-badge.tsx +2 -2
  105. package/template/components/{new-question-composer.tsx → new-library-item-form.tsx} +37 -37
  106. package/template/components/sidebar/app-sidebar.tsx +61 -5
  107. package/template/components/sidebar/secondary-panel.tsx +109 -56
  108. package/template/components/sidebar/sidebar-auto-collapse.tsx +2 -2
  109. package/template/components/sidebar/sidebar-auto-open.tsx +2 -1
  110. package/template/components/table-properties/types.ts +1 -1
  111. package/template/components/templates/discovery-hub-template.tsx +1 -1
  112. package/template/components/templates/new-focus-template.tsx +2 -2
  113. package/template/components/templates/secondary-panel-hub-template.tsx +1 -1
  114. package/template/components/tokens-secondary-nav.tsx +192 -0
  115. package/template/components/tokens-themes-client.tsx +476 -0
  116. package/template/components/tokens-themes-section.tsx +386 -0
  117. package/template/docs/HANDBOOK.md +187 -0
  118. package/template/docs/blueprints/README.md +1 -1
  119. package/template/docs/blueprints/board-card.md +1 -1
  120. package/template/docs/blueprints/data-table.md +2 -2
  121. package/template/docs/blueprints/list-page-template.md +3 -3
  122. package/template/docs/blueprints/page-header.md +4 -4
  123. package/template/docs/collaboration-access-pattern.md +7 -7
  124. package/template/docs/component-selection-guide.md +1 -1
  125. package/template/docs/data-views-pattern.md +18 -16
  126. package/template/docs/glossary.md +58 -0
  127. package/template/docs/kpi-flat-band-pattern.md +3 -3
  128. package/template/docs/kpi-trend-pattern.md +18 -3
  129. package/template/docs/large-dataset-strategy.md +155 -0
  130. package/template/docs/library-hub-header-pattern.md +25 -0
  131. package/template/docs/migrations/_template.md +1 -1
  132. package/template/docs/reference-implementations.md +151 -0
  133. package/template/docs/token-taxonomy.md +1 -1
  134. package/template/docs/voice-and-tone.md +262 -0
  135. package/template/eslint.config.mjs +9 -39
  136. package/template/hooks/use-secondary-panel-hub-nav.ts +10 -10
  137. package/template/lib/ask-leo-route-context.ts +6 -18
  138. package/template/lib/coach-mark-registry.ts +0 -16
  139. package/template/lib/command-menu-config.ts +5 -12
  140. package/template/lib/command-menu-search-data.ts +8 -39
  141. package/template/lib/{question-bank-authoring.ts → library-authoring.ts} +89 -88
  142. package/template/lib/library-dedicated-search.ts +19 -0
  143. package/template/lib/library-hub-search.ts +90 -0
  144. package/template/lib/library-nav.ts +477 -0
  145. package/template/lib/library-recent-searches.ts +22 -0
  146. package/template/lib/{placements-supported-views.ts → library-supported-views.ts} +2 -2
  147. package/template/lib/list-status-badges.ts +16 -104
  148. package/template/lib/mock/dashboard.ts +1 -1
  149. package/template/lib/mock/{question-bank-folders.ts → library-folders.ts} +30 -30
  150. package/template/lib/mock/library-header-collaborators.ts +54 -0
  151. package/template/lib/mock/{question-bank-inspector.ts → library-inspector.ts} +29 -29
  152. package/template/lib/mock/{question-bank-kpi.ts → library-kpi.ts} +20 -20
  153. package/template/lib/mock/library.ts +249 -0
  154. package/template/lib/mock/navigation.tsx +32 -26
  155. package/template/lib/table-state-lifecycle.ts +1 -1
  156. package/template/next.config.mjs +7 -4
  157. package/template/package.json +0 -1
  158. package/tokens/hooks-index.json +2874 -0
  159. package/consumer-extras/cursor-rules/exxat-question-bank-hub-header.mdc +0 -28
  160. package/template/app/(app)/examples/page.tsx +0 -41
  161. package/template/app/(app)/question-bank/find/page.tsx +0 -12
  162. package/template/app/(app)/question-bank/library/page.tsx +0 -11
  163. package/template/app/(app)/question-bank/list/page.tsx +0 -12
  164. package/template/app/(app)/question-bank/page.tsx +0 -11
  165. package/template/components/compliance-board-view.tsx +0 -142
  166. package/template/components/compliance-client.tsx +0 -92
  167. package/template/components/compliance-page-header.tsx +0 -89
  168. package/template/components/compliance-table.tsx +0 -468
  169. package/template/components/data-view-dashboard-charts-compliance.tsx +0 -963
  170. package/template/components/data-view-dashboard-charts-team.tsx +0 -971
  171. package/template/components/data-view-dashboard-charts.tsx +0 -1503
  172. package/template/components/new-placement-back-btn.tsx +0 -28
  173. package/template/components/new-placement-form.tsx +0 -942
  174. package/template/components/placement-board-card.tsx +0 -250
  175. package/template/components/placement-detail.tsx +0 -438
  176. package/template/components/placements-board-view.tsx +0 -397
  177. package/template/components/placements-client.tsx +0 -220
  178. package/template/components/placements-list-view.tsx +0 -124
  179. package/template/components/placements-page-header.tsx +0 -166
  180. package/template/components/placements-table-cells.test.tsx +0 -22
  181. package/template/components/placements-table-cells.tsx +0 -173
  182. package/template/components/placements-table-columns.tsx +0 -210
  183. package/template/components/placements-table.tsx +0 -934
  184. package/template/components/question-bank-panel-activator.tsx +0 -8
  185. package/template/components/rotations-empty-state.tsx +0 -50
  186. package/template/components/rotations-panel-activator.tsx +0 -8
  187. package/template/components/sites-board-view.tsx +0 -67
  188. package/template/components/sites-client.tsx +0 -154
  189. package/template/components/sites-table.tsx +0 -249
  190. package/template/components/team-board-view.tsx +0 -122
  191. package/template/components/team-client.tsx +0 -100
  192. package/template/components/team-page-header.tsx +0 -92
  193. package/template/components/team-table.tsx +0 -553
  194. package/template/docs/question-bank-hub-header-pattern.md +0 -25
  195. package/template/lib/compliance-supported-views.ts +0 -10
  196. package/template/lib/data-view-dashboard-placements-layout.ts +0 -215
  197. package/template/lib/mock/compliance-kpi.ts +0 -61
  198. package/template/lib/mock/compliance.ts +0 -146
  199. package/template/lib/mock/placements-kpi.ts +0 -134
  200. package/template/lib/mock/placements.ts +0 -176
  201. package/template/lib/mock/question-bank-header-collaborators.ts +0 -54
  202. package/template/lib/mock/question-bank.ts +0 -249
  203. package/template/lib/mock/sites-directory.ts +0 -16
  204. package/template/lib/mock/sites-kpi.ts +0 -25
  205. package/template/lib/mock/team-kpi.ts +0 -60
  206. package/template/lib/mock/team.ts +0 -118
  207. package/template/lib/placement-board-card-layout.ts +0 -79
  208. package/template/lib/question-bank-dedicated-search.ts +0 -19
  209. package/template/lib/question-bank-hub-search.ts +0 -90
  210. package/template/lib/question-bank-nav.ts +0 -477
  211. package/template/lib/question-bank-recent-searches.ts +0 -22
  212. package/template/lib/question-bank-supported-views.ts +0 -12
  213. package/template/lib/sites-supported-views.ts +0 -10
  214. package/template/lib/team-supported-views.ts +0 -10
@@ -1,215 +0,0 @@
1
- /**
2
- * Placements **Data** view dashboard — card ids, defaults, and persistence.
3
- * Split from `data-view-dashboard-charts.tsx` so list-hub code can import layout
4
- * without pulling Recharts / chart canvas into the main chunk.
5
- */
6
-
7
- import {
8
- KEY_METRICS_KPI_COUNT_DEFAULT,
9
- mergeDashboardLayoutGeneric,
10
- } from "@/lib/dashboard-layout-merge"
11
- import {
12
- loadDataViewLayout as loadStoredDataViewLayout,
13
- saveDataViewLayout as saveStoredDataViewLayout,
14
- } from "@/lib/data-view-dashboard-storage"
15
-
16
- export type ChartType =
17
- | "bar"
18
- | "horizontal-bar"
19
- | "pie"
20
- | "area"
21
- | "line"
22
- | "radial"
23
- | "stacked-bar"
24
-
25
- export interface ChartTypeOption {
26
- type: ChartType
27
- label: string
28
- icon: string
29
- }
30
-
31
- export interface DashboardCardDef {
32
- id: string
33
- title: string
34
- description: string
35
- defaultSpan: 1 | 2
36
- defaultChartType: ChartType
37
- chartTypes: ChartTypeOption[]
38
- }
39
-
40
- /** Virtual “card” for the KPI strip — reorderable with charts in edit mode */
41
- export const KEY_METRICS_CARD_ID = "key-metrics"
42
-
43
- export const ALL_DASHBOARD_CARDS: DashboardCardDef[] = [
44
- {
45
- id: KEY_METRICS_CARD_ID,
46
- title: "Key metrics",
47
- description: "Summary KPIs for filtered placements",
48
- defaultSpan: 1,
49
- defaultChartType: "bar",
50
- chartTypes: [],
51
- },
52
- {
53
- id: "status-pipeline",
54
- title: "Status Pipeline",
55
- description: "Where placements are in the workflow",
56
- defaultSpan: 1,
57
- defaultChartType: "bar",
58
- chartTypes: [
59
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
60
- { type: "horizontal-bar", label: "Horizontal Bar", icon: "fa-light fa-chart-bar fa-rotate-90" },
61
- { type: "pie", label: "Donut", icon: "fa-light fa-chart-pie" },
62
- ],
63
- },
64
- {
65
- id: "program-mix",
66
- title: "Placements by Program",
67
- description: "Distribution across active programs",
68
- defaultSpan: 1,
69
- defaultChartType: "pie",
70
- chartTypes: [
71
- { type: "pie", label: "Donut", icon: "fa-light fa-chart-pie" },
72
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
73
- { type: "horizontal-bar", label: "Horizontal Bar", icon: "fa-light fa-chart-bar fa-rotate-90" },
74
- ],
75
- },
76
- {
77
- id: "compliance-status",
78
- title: "Compliance Status",
79
- description: "Document readiness for upcoming placements",
80
- defaultSpan: 1,
81
- defaultChartType: "horizontal-bar",
82
- chartTypes: [
83
- { type: "horizontal-bar", label: "Horizontal Bar", icon: "fa-light fa-chart-bar fa-rotate-90" },
84
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
85
- { type: "pie", label: "Donut", icon: "fa-light fa-chart-pie" },
86
- ],
87
- },
88
- {
89
- id: "readiness-overview",
90
- title: "Student Readiness",
91
- description: "How prepared students are for their placements",
92
- defaultSpan: 1,
93
- defaultChartType: "bar",
94
- chartTypes: [
95
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
96
- { type: "horizontal-bar", label: "Horizontal Bar", icon: "fa-light fa-chart-bar fa-rotate-90" },
97
- { type: "pie", label: "Donut", icon: "fa-light fa-chart-pie" },
98
- ],
99
- },
100
- {
101
- id: "progress-tracker",
102
- title: "Ongoing Progress",
103
- description: "How far along each ongoing placement is",
104
- defaultSpan: 2,
105
- defaultChartType: "stacked-bar",
106
- chartTypes: [
107
- { type: "stacked-bar", label: "Stacked Bar", icon: "fa-light fa-layer-group" },
108
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
109
- ],
110
- },
111
- {
112
- id: "site-utilisation",
113
- title: "Site Utilisation",
114
- description: "Which clinical sites have the most placements",
115
- defaultSpan: 1,
116
- defaultChartType: "horizontal-bar",
117
- chartTypes: [
118
- { type: "horizontal-bar", label: "Horizontal Bar", icon: "fa-light fa-chart-bar fa-rotate-90" },
119
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
120
- { type: "pie", label: "Donut", icon: "fa-light fa-chart-pie" },
121
- ],
122
- },
123
- {
124
- id: "completion-outcomes",
125
- title: "Completion Outcomes",
126
- description: "Pass rate and average ratings for completed placements",
127
- defaultSpan: 1,
128
- defaultChartType: "radial",
129
- chartTypes: [
130
- { type: "radial", label: "Radial", icon: "fa-light fa-circle-notch" },
131
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
132
- ],
133
- },
134
- {
135
- id: "upcoming-timeline",
136
- title: "Upcoming Start Dates",
137
- description: "New placements starting in the next 8 weeks",
138
- defaultSpan: 2,
139
- defaultChartType: "area",
140
- chartTypes: [
141
- { type: "area", label: "Area", icon: "fa-light fa-chart-area" },
142
- { type: "line", label: "Line", icon: "fa-light fa-chart-line" },
143
- { type: "bar", label: "Bar", icon: "fa-light fa-chart-bar" },
144
- ],
145
- },
146
- ]
147
-
148
- export const DEFAULT_VISIBLE_CARDS = ALL_DASHBOARD_CARDS.map(c => c.id)
149
- export const DEFAULT_SPANS: Record<string, 1 | 2> = Object.fromEntries(
150
- ALL_DASHBOARD_CARDS.map(c => [c.id, c.defaultSpan]),
151
- )
152
- export const DEFAULT_CHART_TYPES: Record<string, ChartType> = Object.fromEntries(
153
- ALL_DASHBOARD_CARDS.map(c => [c.id, c.defaultChartType]),
154
- )
155
-
156
- export interface DashboardLayout {
157
- visible: string[]
158
- order: string[]
159
- spans?: Record<string, 1 | 2>
160
- chartTypes?: Record<string, ChartType>
161
- keyMetricsKpiCount?: number
162
- }
163
-
164
- export function loadDashboardLayout(): DashboardLayout | null {
165
- const v = loadStoredDataViewLayout("placements")
166
- if (!v) return null
167
- return {
168
- visible: v.visible,
169
- order: v.order,
170
- spans: v.spans,
171
- chartTypes: v.chartTypes as Record<string, ChartType> | undefined,
172
- keyMetricsKpiCount: v.keyMetricsKpiCount,
173
- }
174
- }
175
-
176
- export function mergeDashboardLayout(saved: DashboardLayout | null): DashboardLayout {
177
- const defaults = {
178
- visible: [...DEFAULT_VISIBLE_CARDS],
179
- order: ALL_DASHBOARD_CARDS.map(c => c.id),
180
- spans: { ...DEFAULT_SPANS },
181
- chartTypes: { ...DEFAULT_CHART_TYPES } as Record<string, string>,
182
- keyMetricsKpiCount: KEY_METRICS_KPI_COUNT_DEFAULT,
183
- }
184
- const ids = ALL_DASHBOARD_CARDS.map(c => c.id)
185
- const m = mergeDashboardLayoutGeneric(saved, defaults, ids)
186
- return {
187
- visible: m.visible,
188
- order: m.order,
189
- spans: m.spans as Record<string, 1 | 2>,
190
- chartTypes: m.chartTypes as Record<string, ChartType>,
191
- keyMetricsKpiCount: m.keyMetricsKpiCount,
192
- }
193
- }
194
-
195
- export function saveDashboardLayout(layout: DashboardLayout) {
196
- saveStoredDataViewLayout("placements", {
197
- visible: layout.visible,
198
- order: layout.order,
199
- spans: layout.spans,
200
- chartTypes: layout.chartTypes as Record<string, string> | undefined,
201
- keyMetricsKpiCount: layout.keyMetricsKpiCount,
202
- })
203
- }
204
-
205
- export function applyVisibleReorder(
206
- fullOrder: string[],
207
- visible: Set<string>,
208
- newVisibleOrder: string[],
209
- ): string[] {
210
- let vi = 0
211
- return fullOrder.map(id => {
212
- if (!visible.has(id)) return id
213
- return newVisibleOrder[vi++]!
214
- })
215
- }
@@ -1,61 +0,0 @@
1
- import type { MetricInsight, MetricItem } from "@/components/key-metrics"
2
- import type { ComplianceItem } from "@/lib/mock/compliance"
3
-
4
- export function complianceKpiMetrics(rows: ComplianceItem[]): MetricItem[] {
5
- const compliant = rows.filter(r => r.status === "compliant").length
6
- const dueSoon = rows.filter(r => r.status === "due_soon").length
7
- const overdue = rows.filter(r => r.status === "overdue").length
8
- const pending = rows.filter(r => r.status === "pending").length
9
-
10
- return [
11
- {
12
- id: "total",
13
- label: "Total items",
14
- value: rows.length,
15
- delta: "—",
16
- trend: "neutral",
17
- href: "#",
18
- metricVariant: "hero",
19
- },
20
- {
21
- id: "compliant",
22
- label: "Compliant",
23
- value: compliant,
24
- delta: "—",
25
- trend: "neutral",
26
- href: "#",
27
- },
28
- {
29
- id: "attention",
30
- label: "Due soon",
31
- value: dueSoon,
32
- delta: dueSoon > 0 ? "!" : "—",
33
- trend: dueSoon > 0 ? "up" : "neutral",
34
- href: "#",
35
- },
36
- {
37
- id: "risk",
38
- label: "Overdue / pending",
39
- value: overdue + pending,
40
- delta: "—",
41
- trend: overdue + pending > 0 ? "up" : "neutral",
42
- href: "#",
43
- },
44
- ]
45
- }
46
-
47
- export function complianceKpiInsight(rows: ComplianceItem[]): MetricInsight {
48
- const overdue = rows.filter(r => r.status === "overdue").length
49
- const dueSoon = rows.filter(r => r.status === "due_soon").length
50
- return {
51
- title: "Compliance queue",
52
- description:
53
- overdue > 0
54
- ? `${overdue} item(s) overdue. ${dueSoon} due within 30 days.`
55
- : dueSoon > 0
56
- ? `${dueSoon} item(s) due soon — review owners and dates.`
57
- : "No overdue items in this view.",
58
- severity: overdue > 0 ? "warning" : dueSoon > 0 ? "warning" : "info",
59
- actionLabel: "Ask Leo",
60
- }
61
- }
@@ -1,146 +0,0 @@
1
- /**
2
- * Mock compliance obligations — replace with API data in production.
3
- */
4
-
5
- export type ComplianceStatus = "compliant" | "due_soon" | "overdue" | "pending"
6
-
7
- export interface ComplianceItem extends Record<string, unknown> {
8
- id: string
9
- title: string
10
- category: string
11
- status: ComplianceStatus
12
- /** MM/DD/YYYY */
13
- dueDate: string
14
- owner: string
15
- /** MM/DD/YYYY */
16
- lastReviewed: string
17
- }
18
-
19
- export const COMPLIANCE_ITEMS: ComplianceItem[] = [
20
- {
21
- id: "1",
22
- title: "Annual HIPAA training attestation",
23
- category: "HIPAA",
24
- status: "compliant",
25
- dueDate: "12/31/2026",
26
- owner: "Alex Rivera",
27
- lastReviewed: "03/01/2026",
28
- },
29
- {
30
- id: "2",
31
- title: "OSHA bloodborne pathogen review",
32
- category: "OSHA",
33
- status: "due_soon",
34
- dueDate: "04/10/2026",
35
- owner: "Jordan Chen",
36
- lastReviewed: "10/15/2025",
37
- },
38
- {
39
- id: "3",
40
- title: "Clinical site affiliation agreements",
41
- category: "Clinical",
42
- status: "pending",
43
- dueDate: "05/01/2026",
44
- owner: "Sam Patel",
45
- lastReviewed: "—",
46
- },
47
- {
48
- id: "4",
49
- title: "FERPA student records policy",
50
- category: "Privacy",
51
- status: "compliant",
52
- dueDate: "09/30/2026",
53
- owner: "Taylor Brooks",
54
- lastReviewed: "02/20/2026",
55
- },
56
- {
57
- id: "5",
58
- title: "Background check re-verification",
59
- category: "Clinical",
60
- status: "overdue",
61
- dueDate: "03/01/2026",
62
- owner: "Jordan Chen",
63
- lastReviewed: "03/01/2025",
64
- },
65
- {
66
- id: "6",
67
- title: "Accreditation self-study draft",
68
- category: "Accreditation",
69
- status: "due_soon",
70
- dueDate: "04/22/2026",
71
- owner: "Alex Rivera",
72
- lastReviewed: "01/10/2026",
73
- },
74
- {
75
- id: "7",
76
- title: "Incident response tabletop exercise",
77
- category: "HIPAA",
78
- status: "pending",
79
- dueDate: "06/15/2026",
80
- owner: "Sam Patel",
81
- lastReviewed: "—",
82
- },
83
- {
84
- id: "8",
85
- title: "Emergency preparedness plan",
86
- category: "OSHA",
87
- status: "compliant",
88
- dueDate: "11/01/2026",
89
- owner: "Taylor Brooks",
90
- lastReviewed: "02/28/2026",
91
- },
92
- {
93
- id: "9",
94
- title: "Medication safety competency checklist",
95
- category: "Clinical",
96
- status: "compliant",
97
- dueDate: "08/01/2026",
98
- owner: "Alex Rivera",
99
- lastReviewed: "03/15/2026",
100
- },
101
- {
102
- id: "10",
103
- title: "Data breach notification procedure",
104
- category: "Privacy",
105
- status: "due_soon",
106
- dueDate: "04/05/2026",
107
- owner: "Jordan Chen",
108
- lastReviewed: "10/01/2025",
109
- },
110
- {
111
- id: "11",
112
- title: "LCME / programmatic review evidence",
113
- category: "Accreditation",
114
- status: "pending",
115
- dueDate: "07/30/2026",
116
- owner: "Sam Patel",
117
- lastReviewed: "—",
118
- },
119
- {
120
- id: "12",
121
- title: "Sharps injury log audit",
122
- category: "OSHA",
123
- status: "overdue",
124
- dueDate: "02/20/2026",
125
- owner: "Taylor Brooks",
126
- lastReviewed: "02/20/2025",
127
- },
128
- {
129
- id: "13",
130
- title: "Business associate agreement inventory",
131
- category: "HIPAA",
132
- status: "compliant",
133
- dueDate: "10/15/2026",
134
- owner: "Alex Rivera",
135
- lastReviewed: "03/01/2026",
136
- },
137
- {
138
- id: "14",
139
- title: "Student immunization tracking",
140
- category: "Clinical",
141
- status: "due_soon",
142
- dueDate: "04/18/2026",
143
- owner: "Jordan Chen",
144
- lastReviewed: "09/01/2025",
145
- },
146
- ]
@@ -1,134 +0,0 @@
1
- // ─────────────────────────────────────────────────────────────────────────────
2
- // List hub — KPI strip + insight (data-list; dashboard view uses row-driven helpers)
3
- // ─────────────────────────────────────────────────────────────────────────────
4
-
5
- import type { MetricInsight, MetricItem } from "@/components/key-metrics"
6
- import { ALL_PLACEMENTS, type Placement, type Status } from "./placements"
7
-
8
- function statusCount(status: Status): number {
9
- return ALL_PLACEMENTS.filter((p) => p.status === status).length
10
- }
11
-
12
- /**
13
- * KPIs from the current filtered row set (table/list/board/dashboard shared state).
14
- * Use for the dashboard view tab; optional for the template metrics strip when you want parity.
15
- */
16
- export function placementKpiMetricsFromRows(rows: Placement[]): MetricItem[] {
17
- const total = rows.length
18
- const startingWeek = rows.filter(p => p.daysUntilStart >= 0 && p.daysUntilStart <= 7).length
19
- const alerts = rows.filter(p => {
20
- const r = p.readiness.toLowerCase()
21
- return r.includes("risk") || r.includes("blocked")
22
- }).length
23
- const complete = rows.filter(p => p.compliance === "Complete").length
24
- const avgPct = total > 0 ? Math.round((complete / total) * 100) : 0
25
-
26
- return [
27
- {
28
- id: "total-placements",
29
- label: "Total rows",
30
- value: total,
31
- delta: "—",
32
- trend: "neutral",
33
- href: "#",
34
- metricVariant: "hero",
35
- },
36
- {
37
- id: "starting-week",
38
- label: "Due this week",
39
- value: startingWeek,
40
- delta: "—",
41
- trend: startingWeek > 0 ? "up" : "neutral",
42
- href: "#",
43
- },
44
- {
45
- id: "compliance-alerts",
46
- label: "Attention flags",
47
- value: alerts,
48
- delta: "—",
49
- trend: alerts > 0 ? "up" : "neutral",
50
- href: "#",
51
- },
52
- {
53
- id: "avg-compliance",
54
- label: "Completeness",
55
- value: `${avgPct}%`,
56
- delta: "—",
57
- trend: "neutral",
58
- href: "#",
59
- },
60
- ]
61
- }
62
-
63
- export function placementKpiInsightFromRows(rows: Placement[]): MetricInsight {
64
- const pending = rows.filter(p => p.status === "pending").length
65
- const inReview = rows.filter(p => p.status === "under-review").length
66
- const n = rows.length
67
- return {
68
- title: "Queue snapshot",
69
- description:
70
- n > 0
71
- ? `${pending} pending, ${inReview} in review in this view. Clear the queue to keep work moving.`
72
- : "No rows match the current filters.",
73
- href: "/data-list",
74
- severity: pending + inReview > 0 ? "warning" : "info",
75
- actionLabel: "Ask Leo",
76
- }
77
- }
78
-
79
- /**
80
- * KPI row for the list hub metrics strip (demo numbers).
81
- */
82
- export const PLACEMENT_KPI_METRICS: MetricItem[] = [
83
- {
84
- id: "total-placements",
85
- label: "Total rows",
86
- value: 50,
87
- delta: "+12",
88
- trend: "up",
89
- href: "#all",
90
- metricVariant: "hero",
91
- },
92
- {
93
- id: "starting-week",
94
- label: "Due this week",
95
- value: 0,
96
- delta: "-5",
97
- trend: "down",
98
- href: "#starting",
99
- },
100
- {
101
- id: "compliance-alerts",
102
- label: "Attention flags",
103
- value: 23,
104
- delta: "+13",
105
- trend: "up",
106
- href: "#alerts",
107
- },
108
- {
109
- id: "avg-compliance",
110
- label: "Completeness",
111
- value: "87%",
112
- delta: "+3",
113
- trend: "up",
114
- href: "#compliance",
115
- },
116
- ]
117
-
118
- /**
119
- * Insight copy derived from demo row status counts.
120
- */
121
- export function getPlacementInsight(): MetricInsight {
122
- const pending = statusCount("pending")
123
- const inReview = statusCount("under-review")
124
-
125
- return {
126
- title: "Queue snapshot",
127
- description: `${pending} pending, ${inReview} in review. Clear the queue to keep work moving.`,
128
- href: "/data-list",
129
- severity: "warning",
130
- actionLabel: "Ask Leo",
131
- }
132
- }
133
-
134
- export const PLACEMENT_KPI_INSIGHT = getPlacementInsight()