@liorian/sdk 0.28.0-alpha.56010ca

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 (362) hide show
  1. package/README.md +483 -0
  2. package/package.json +94 -0
  3. package/schemas/module.schema.json +818 -0
  4. package/src/application/index.ts +3 -0
  5. package/src/application/module-instance.ts +36 -0
  6. package/src/application/service/auth-api-service.ts +291 -0
  7. package/src/application/service/auth-user.service.ts +108 -0
  8. package/src/application/service/index.ts +12 -0
  9. package/src/application/service/module-activation-api.service.ts +105 -0
  10. package/src/application/service/notifications-api-service.ts +38 -0
  11. package/src/application/service/notifications-push.service.ts +299 -0
  12. package/src/application/service/notifications-socket-service.ts +76 -0
  13. package/src/application/service/organizations-api-service.ts +104 -0
  14. package/src/application/service/otp-api-service.ts +11 -0
  15. package/src/application/service/storage-api-service.ts +77 -0
  16. package/src/application/service/storefront-api.service.ts +72 -0
  17. package/src/application/service/user-preferences-api.service.ts +57 -0
  18. package/src/domain/config/app.config.ts +35 -0
  19. package/src/domain/config/auth.config.ts +30 -0
  20. package/src/domain/config/index.ts +4 -0
  21. package/src/domain/config/logo.config.ts +17 -0
  22. package/src/domain/entities/activities.interface.ts +18 -0
  23. package/src/domain/entities/catalog.interface.ts +96 -0
  24. package/src/domain/entities/index.ts +13 -0
  25. package/src/domain/entities/media.ts +22 -0
  26. package/src/domain/entities/module-activation.interface.ts +173 -0
  27. package/src/domain/entities/module.interface.ts +101 -0
  28. package/src/domain/entities/notification.interface.ts +23 -0
  29. package/src/domain/entities/objectable.type.ts +3 -0
  30. package/src/domain/entities/organization.interface.ts +81 -0
  31. package/src/domain/entities/user-auth.interface.ts +17 -0
  32. package/src/domain/entities/user-phone.interface.ts +11 -0
  33. package/src/domain/entities/user-profile.interface.ts +23 -0
  34. package/src/domain/entities/user.interface.ts +79 -0
  35. package/src/domain/enums/coloring.enum.ts +6 -0
  36. package/src/domain/enums/domains.enum.ts +282 -0
  37. package/src/domain/enums/index.ts +8 -0
  38. package/src/domain/enums/module-category.enum.ts +57 -0
  39. package/src/domain/enums/module.enum.ts +97 -0
  40. package/src/domain/enums/routine.enum.ts +12 -0
  41. package/src/domain/enums/user-profile.enum.ts +25 -0
  42. package/src/domain/enums/user-status.enum.ts +7 -0
  43. package/src/domain/index.ts +6 -0
  44. package/src/domain/typing/auth-caches.ts +12 -0
  45. package/src/domain/typing/auth-oauth.types.ts +172 -0
  46. package/src/domain/typing/devise.ts +2 -0
  47. package/src/domain/typing/index.ts +10 -0
  48. package/src/domain/typing/response.ts +30 -0
  49. package/src/domain/typing/routine.types.ts +113 -0
  50. package/src/domain/typing/session.interface.ts +28 -0
  51. package/src/domain/typing/statisticals.ts +11 -0
  52. package/src/domain/typing/user-media-upload.ts +9 -0
  53. package/src/domain/typing/values.ts +6 -0
  54. package/src/index.tsx +168 -0
  55. package/src/infrastructure/capabilities/cache-storage/capability.ts +129 -0
  56. package/src/infrastructure/capabilities/cache-storage/enum.ts +5 -0
  57. package/src/infrastructure/capabilities/cache-storage/index.ts +4 -0
  58. package/src/infrastructure/capabilities/cache-storage/types.ts +13 -0
  59. package/src/infrastructure/capabilities/index.ts +3 -0
  60. package/src/infrastructure/capabilities/stackable/capability.ts +55 -0
  61. package/src/infrastructure/capabilities/stackable/index.ts +3 -0
  62. package/src/infrastructure/capabilities/stackable/types.ts +24 -0
  63. package/src/infrastructure/common-classname.constant.ts +4 -0
  64. package/src/infrastructure/data/countries.ts +208 -0
  65. package/src/infrastructure/data/gender.ts +5 -0
  66. package/src/infrastructure/data/index.ts +3 -0
  67. package/src/infrastructure/dataset/index.ts +3 -0
  68. package/src/infrastructure/dataset/sign-in.dataset.ts +21 -0
  69. package/src/infrastructure/dataset/sign-up.dataset.ts +64 -0
  70. package/src/infrastructure/hooks/index.ts +10 -0
  71. package/src/infrastructure/hooks/use-activity-lock-draft.ts +69 -0
  72. package/src/infrastructure/hooks/use-auth.ts +24 -0
  73. package/src/infrastructure/hooks/use-elastic-interaction.ts +180 -0
  74. package/src/infrastructure/hooks/use-is-desktop.ts +25 -0
  75. package/src/infrastructure/hooks/use-is-tauri.ts +17 -0
  76. package/src/infrastructure/hooks/use-mobile.ts +19 -0
  77. package/src/infrastructure/hooks/use-notifications.ts +128 -0
  78. package/src/infrastructure/hooks/use-recent-colors.ts +113 -0
  79. package/src/infrastructure/hooks/use-recent-modules.ts +76 -0
  80. package/src/infrastructure/index.tsx +11 -0
  81. package/src/infrastructure/library/design-system.ts +95 -0
  82. package/src/infrastructure/library/index.tsx +5 -0
  83. package/src/infrastructure/library/motion-utils.ts +77 -0
  84. package/src/infrastructure/library/motion.tsx +31 -0
  85. package/src/infrastructure/library/scroll-progress.tsx +93 -0
  86. package/src/infrastructure/providers/auth-guard.provider.tsx +47 -0
  87. package/src/infrastructure/providers/auth.provider.tsx +168 -0
  88. package/src/infrastructure/providers/index.tsx +8 -0
  89. package/src/infrastructure/providers/module-usage.provider.tsx +95 -0
  90. package/src/infrastructure/providers/modules-guard.provider.tsx +64 -0
  91. package/src/infrastructure/providers/modules-routines.provider.tsx +33 -0
  92. package/src/infrastructure/providers/modules-switcher.provider.tsx +25 -0
  93. package/src/infrastructure/providers/query.provider.tsx +27 -0
  94. package/src/infrastructure/routines/__tests__/routine.test.ts +368 -0
  95. package/src/infrastructure/routines/index.tsx +3 -0
  96. package/src/infrastructure/routines/routine.hook.ts +121 -0
  97. package/src/infrastructure/routines/routine.ts +283 -0
  98. package/src/infrastructure/routines/routine.tsx +283 -0
  99. package/src/infrastructure/stores/activity-lock.store.ts +22 -0
  100. package/src/infrastructure/stores/auth-user-connected.store.ts +24 -0
  101. package/src/infrastructure/stores/dataset.store.ts +106 -0
  102. package/src/infrastructure/stores/index.ts +6 -0
  103. package/src/infrastructure/stores/module.store.ts +266 -0
  104. package/src/infrastructure/stores/upload.store.ts +198 -0
  105. package/src/infrastructure/utilities/access-label.util.ts +158 -0
  106. package/src/infrastructure/utilities/activities.util.tsx +54 -0
  107. package/src/infrastructure/utilities/activity-lock.service.ts +263 -0
  108. package/src/infrastructure/utilities/activity-tracker.service.ts +205 -0
  109. package/src/infrastructure/utilities/api-service.ts +237 -0
  110. package/src/infrastructure/utilities/auth-logout.util.ts +23 -0
  111. package/src/infrastructure/utilities/classname.util.ts +7 -0
  112. package/src/infrastructure/utilities/encryption.service.ts +125 -0
  113. package/src/infrastructure/utilities/form-snapshot.service.ts +304 -0
  114. package/src/infrastructure/utilities/format.util.ts +40 -0
  115. package/src/infrastructure/utilities/index.tsx +23 -0
  116. package/src/infrastructure/utilities/media-label.service.ts +47 -0
  117. package/src/infrastructure/utilities/modules.ts +11 -0
  118. package/src/infrastructure/utilities/permission.util.ts +22 -0
  119. package/src/infrastructure/utilities/push-permission.util.ts +43 -0
  120. package/src/infrastructure/utilities/route-access.ts +38 -0
  121. package/src/infrastructure/utilities/socket-service.ts +123 -0
  122. package/src/infrastructure/utilities/sso-auth.util.ts +188 -0
  123. package/src/infrastructure/utilities/stringable.util.ts +16 -0
  124. package/src/infrastructure/utilities/strings.util.ts +18 -0
  125. package/src/infrastructure/utilities/tauri.util.ts +15 -0
  126. package/src/infrastructure/utilities/utils.ts +6 -0
  127. package/src/infrastructure/utilities/values.ts +5 -0
  128. package/src/presentation/8starlabs-ui/button.tsx +94 -0
  129. package/src/presentation/8starlabs-ui/flip-clock.tsx +368 -0
  130. package/src/presentation/8starlabs-ui/heatmap.tsx +430 -0
  131. package/src/presentation/8starlabs-ui/hooks/index.tsx +2 -0
  132. package/src/presentation/8starlabs-ui/hooks/use-mobile.ts +21 -0
  133. package/src/presentation/8starlabs-ui/index.tsx +20 -0
  134. package/src/presentation/8starlabs-ui/json-viewer.tsx +972 -0
  135. package/src/presentation/8starlabs-ui/marquee.tsx +134 -0
  136. package/src/presentation/8starlabs-ui/partition-bar.tsx +198 -0
  137. package/src/presentation/8starlabs-ui/scroll-fade.tsx +158 -0
  138. package/src/presentation/8starlabs-ui/status-indicator.tsx +86 -0
  139. package/src/presentation/8starlabs-ui/system-banner.tsx +50 -0
  140. package/src/presentation/8starlabs-ui/timeline.tsx +576 -0
  141. package/src/presentation/8starlabs-ui/transport-badge.tsx +249 -0
  142. package/src/presentation/8starlabs-ui/ui/copy-button.tsx +60 -0
  143. package/src/presentation/8starlabs-ui/ui/index.tsx +2 -0
  144. package/src/presentation/analytics-section.tsx +85 -0
  145. package/src/presentation/app-sidebar.tsx +234 -0
  146. package/src/presentation/charts/area-widget.chart-skeleton.tsx +61 -0
  147. package/src/presentation/charts/area-widget.chart.tsx +128 -0
  148. package/src/presentation/charts/chart-widgets.types.ts +81 -0
  149. package/src/presentation/charts/index.tsx +16 -0
  150. package/src/presentation/charts/line-widget.chart-skeleton.tsx +64 -0
  151. package/src/presentation/charts/line-widget.chart.tsx +105 -0
  152. package/src/presentation/charts/pie-widget.chart-skeleton.tsx +56 -0
  153. package/src/presentation/charts/pie-widget.chart.tsx +168 -0
  154. package/src/presentation/charts/radar-widget.chart-skeleton.tsx +67 -0
  155. package/src/presentation/charts/radar-widget.chart.tsx +80 -0
  156. package/src/presentation/charts/radial-stacked-widget.chart-skeleton.tsx +66 -0
  157. package/src/presentation/charts/radial-stacked-widget.chart.tsx +120 -0
  158. package/src/presentation/charts/radial-widget.chart-skeleton.tsx +61 -0
  159. package/src/presentation/charts/radial-widget.chart.tsx +87 -0
  160. package/src/presentation/charts/tooltip-widget.chart-skeleton.tsx +64 -0
  161. package/src/presentation/charts/tooltip-widget.chart.tsx +89 -0
  162. package/src/presentation/components/activity-actions.tsx +20 -0
  163. package/src/presentation/components/activity-container.tsx +55 -0
  164. package/src/presentation/components/activity-content.tsx +20 -0
  165. package/src/presentation/components/activity-descriptor-parser.tsx +37 -0
  166. package/src/presentation/components/activity-header.tsx +20 -0
  167. package/src/presentation/components/activity-loader.tsx +19 -0
  168. package/src/presentation/components/activity-title.tsx +32 -0
  169. package/src/presentation/components/activity.tsx +22 -0
  170. package/src/presentation/components/auth/index.tsx +4 -0
  171. package/src/presentation/components/auth/sso-callback.view.tsx +44 -0
  172. package/src/presentation/components/auth/sso-disconnect.view.tsx +41 -0
  173. package/src/presentation/components/auth/sso-sign-in.view.tsx +29 -0
  174. package/src/presentation/components/auth-lock-screen.tsx +309 -0
  175. package/src/presentation/components/auth-session.view.tsx +17 -0
  176. package/src/presentation/components/data-table.tsx +814 -0
  177. package/src/presentation/components/dynamic-icon.tsx +16 -0
  178. package/src/presentation/components/floating-upload.tsx +291 -0
  179. package/src/presentation/components/index.tsx +40 -0
  180. package/src/presentation/components/local-time.tsx +170 -0
  181. package/src/presentation/components/markdown-parser.tsx +201 -0
  182. package/src/presentation/components/message-scroller.tsx +131 -0
  183. package/src/presentation/components/module-first-access-config.view.tsx +181 -0
  184. package/src/presentation/components/module-first-access-pending.view.tsx +38 -0
  185. package/src/presentation/components/module-guard.tsx +34 -0
  186. package/src/presentation/components/modules-first-access.guard.tsx +88 -0
  187. package/src/presentation/components/modules-guard-forbidden.tsx +46 -0
  188. package/src/presentation/components/notification-details.modal.tsx +145 -0
  189. package/src/presentation/components/notification-item.tsx +127 -0
  190. package/src/presentation/components/notifications-popover.tsx +128 -0
  191. package/src/presentation/components/push-notifications.provider.tsx +65 -0
  192. package/src/presentation/components/upload-progress-dialog.tsx +140 -0
  193. package/src/presentation/components/waiting-bar.tsx +22 -0
  194. package/src/presentation/components/waiting-section.tsx +15 -0
  195. package/src/presentation/components/waiting.tsx +14 -0
  196. package/src/presentation/data-grid/data-grid-empty.tsx +24 -0
  197. package/src/presentation/data-grid/data-grid-search-engine.tsx +32 -0
  198. package/src/presentation/data-grid/data-grid.tsx +892 -0
  199. package/src/presentation/data-grid/index.tsx +4 -0
  200. package/src/presentation/form-screen.tsx +95 -0
  201. package/src/presentation/icons/custom.tsx +20 -0
  202. package/src/presentation/icons/glyphIcons.tsx +53 -0
  203. package/src/presentation/icons/icons.enum.ts +4 -0
  204. package/src/presentation/icons/icons.util.ts +6 -0
  205. package/src/presentation/icons/index.tsx +8 -0
  206. package/src/presentation/icons/lucide.tsx +17 -0
  207. package/src/presentation/icons/remix.tsx +33 -0
  208. package/src/presentation/icons/types.ts +27 -0
  209. package/src/presentation/index.tsx +45 -0
  210. package/src/presentation/modals/components/ModalBox.tsx +74 -0
  211. package/src/presentation/modals/components/ModalPortal.tsx +31 -0
  212. package/src/presentation/modals/components/ModalStepper.tsx +319 -0
  213. package/src/presentation/modals/components/ModalWrapper.tsx +65 -0
  214. package/src/presentation/modals/components/index.tsx +5 -0
  215. package/src/presentation/modals/hooks/index.ts +2 -0
  216. package/src/presentation/modals/hooks/useModal.ts +38 -0
  217. package/src/presentation/modals/index.tsx +5 -0
  218. package/src/presentation/modals/stores/index.ts +2 -0
  219. package/src/presentation/modals/stores/useModalStore.ts +90 -0
  220. package/src/presentation/modals/types/index.ts +2 -0
  221. package/src/presentation/modals/types/modal.type.ts +33 -0
  222. package/src/presentation/module-menubar.tsx +300 -0
  223. package/src/presentation/module-widget.tsx +233 -0
  224. package/src/presentation/nav-documents.tsx +89 -0
  225. package/src/presentation/nav-main.tsx +62 -0
  226. package/src/presentation/nav-secondary.tsx +41 -0
  227. package/src/presentation/nav-user.tsx +109 -0
  228. package/src/presentation/permission-action-badge.tsx +35 -0
  229. package/src/presentation/reui/index.tsx +3 -0
  230. package/src/presentation/reui/stepper.tsx +508 -0
  231. package/src/presentation/reui/timeline.tsx +226 -0
  232. package/src/presentation/sheets/index.tsx +2 -0
  233. package/src/presentation/sheets/legacy-sheet-header.tsx +0 -0
  234. package/src/presentation/sheets/legacy-sheet.tsx +37 -0
  235. package/src/presentation/size.enum.ts +19 -0
  236. package/src/presentation/system/index.tsx +3 -0
  237. package/src/presentation/system/logo.theme.tsx +21 -0
  238. package/src/presentation/system/types.ts +10 -0
  239. package/src/presentation/theme/index.tsx +6 -0
  240. package/src/presentation/theme/prefer-color-scheme.tsx +50 -0
  241. package/src/presentation/theme/switch-color-scheme.tsx +16 -0
  242. package/src/presentation/theme/theme-switcher-button.tsx +20 -0
  243. package/src/presentation/theme/theme.enum.ts +4 -0
  244. package/src/presentation/theme/theme.store.ts +87 -0
  245. package/src/presentation/themes/index.tsx +2 -0
  246. package/src/presentation/themes/katon/dashboard-layout.tsx +1080 -0
  247. package/src/presentation/themes/katon/edge-section.tsx +19 -0
  248. package/src/presentation/themes/katon/header-menubar.tsx +270 -0
  249. package/src/presentation/themes/katon/header-modules-available.tsx +44 -0
  250. package/src/presentation/themes/katon/header-modules-recents.tsx +52 -0
  251. package/src/presentation/themes/katon/header-modules-store.tsx +25 -0
  252. package/src/presentation/themes/katon/header-options.tsx +13 -0
  253. package/src/presentation/themes/katon/header-organization-select.tsx +146 -0
  254. package/src/presentation/themes/katon/header-routines.tsx +74 -0
  255. package/src/presentation/themes/katon/header-tasks-connected-user.tsx +150 -0
  256. package/src/presentation/themes/katon/index.tsx +16 -0
  257. package/src/presentation/themes/katon/main-wrapper.tsx +34 -0
  258. package/src/presentation/themes/katon/module-item-link.tsx +32 -0
  259. package/src/presentation/themes/katon/view-frame.tsx +25 -0
  260. package/src/presentation/themes/katon/view-helmet.tsx +53 -0
  261. package/src/presentation/themes/katon/view-status.tsx +32 -0
  262. package/src/presentation/themes/katon/view-wrapper.tsx +15 -0
  263. package/src/presentation/themes/katon/view.tsx +42 -0
  264. package/src/presentation/ui/accordion-multiselect.tsx +206 -0
  265. package/src/presentation/ui/accordion.tsx +81 -0
  266. package/src/presentation/ui/alert-dialog.tsx +199 -0
  267. package/src/presentation/ui/alert.tsx +76 -0
  268. package/src/presentation/ui/aspect-ratio.tsx +11 -0
  269. package/src/presentation/ui/attachment.tsx +204 -0
  270. package/src/presentation/ui/avatar.tsx +112 -0
  271. package/src/presentation/ui/badge.tsx +49 -0
  272. package/src/presentation/ui/breadcrumb.tsx +122 -0
  273. package/src/presentation/ui/bubble.tsx +125 -0
  274. package/src/presentation/ui/button-group.tsx +83 -0
  275. package/src/presentation/ui/button.tsx +87 -0
  276. package/src/presentation/ui/calendar.tsx +222 -0
  277. package/src/presentation/ui/card.tsx +106 -0
  278. package/src/presentation/ui/carousel.tsx +242 -0
  279. package/src/presentation/ui/chart.tsx +373 -0
  280. package/src/presentation/ui/checkbox.tsx +33 -0
  281. package/src/presentation/ui/clickable.tsx +58 -0
  282. package/src/presentation/ui/collapsible.tsx +33 -0
  283. package/src/presentation/ui/color-swatch-selector.tsx +81 -0
  284. package/src/presentation/ui/combobox.tsx +299 -0
  285. package/src/presentation/ui/command.tsx +195 -0
  286. package/src/presentation/ui/context-menu.tsx +263 -0
  287. package/src/presentation/ui/dialog.tsx +168 -0
  288. package/src/presentation/ui/direction.tsx +22 -0
  289. package/src/presentation/ui/drawer.tsx +134 -0
  290. package/src/presentation/ui/dropdown-menu.tsx +269 -0
  291. package/src/presentation/ui/empty.tsx +104 -0
  292. package/src/presentation/ui/field.tsx +238 -0
  293. package/src/presentation/ui/granularity-selector.tsx +58 -0
  294. package/src/presentation/ui/hover-card.tsx +44 -0
  295. package/src/presentation/ui/index.tsx +74 -0
  296. package/src/presentation/ui/input-group.tsx +156 -0
  297. package/src/presentation/ui/input-otp.tsx +87 -0
  298. package/src/presentation/ui/input.tsx +19 -0
  299. package/src/presentation/ui/item.tsx +196 -0
  300. package/src/presentation/ui/kpi-card.tsx +203 -0
  301. package/src/presentation/ui/label-selector.tsx +100 -0
  302. package/src/presentation/ui/label.tsx +24 -0
  303. package/src/presentation/ui/legacy-birth-date-input.tsx +43 -0
  304. package/src/presentation/ui/legacy-color-picker/index.tsx +42 -0
  305. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.content.tsx +37 -0
  306. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.context.tsx +42 -0
  307. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.hex-input.tsx +97 -0
  308. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.picker.tsx +266 -0
  309. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.presets.ts +22 -0
  310. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.quick-list.tsx +49 -0
  311. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.recent.tsx +43 -0
  312. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.swatches.tsx +111 -0
  313. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.trigger.tsx +128 -0
  314. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.tsx +110 -0
  315. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.types.ts +1 -0
  316. package/src/presentation/ui/legacy-color-picker/legacy-color-picker.utils.ts +114 -0
  317. package/src/presentation/ui/legacy-country-input.tsx +171 -0
  318. package/src/presentation/ui/legacy-gender-input.tsx +22 -0
  319. package/src/presentation/ui/legacy-input.tsx +106 -0
  320. package/src/presentation/ui/legacy-phone-input.tsx +213 -0
  321. package/src/presentation/ui/legacy-select-input.tsx +114 -0
  322. package/src/presentation/ui/legacy-text-area.tsx +111 -0
  323. package/src/presentation/ui/list-items.tsx +59 -0
  324. package/src/presentation/ui/marker.tsx +69 -0
  325. package/src/presentation/ui/media-player/index.tsx +12 -0
  326. package/src/presentation/ui/media-player/media-player.context.tsx +36 -0
  327. package/src/presentation/ui/media-player/media-player.tsx +167 -0
  328. package/src/presentation/ui/media-player/player-controls.tsx +207 -0
  329. package/src/presentation/ui/media-player/players/audio-player.tsx +78 -0
  330. package/src/presentation/ui/media-player/players/index.tsx +4 -0
  331. package/src/presentation/ui/media-player/players/video-player.tsx +193 -0
  332. package/src/presentation/ui/media-player/players/voice-note-player.tsx +108 -0
  333. package/src/presentation/ui/media-player/use-media-player.hook.ts +263 -0
  334. package/src/presentation/ui/menubar.tsx +281 -0
  335. package/src/presentation/ui/message.tsx +92 -0
  336. package/src/presentation/ui/navigation-menu.tsx +172 -0
  337. package/src/presentation/ui/pagination.tsx +129 -0
  338. package/src/presentation/ui/popover.tsx +89 -0
  339. package/src/presentation/ui/progress.tsx +31 -0
  340. package/src/presentation/ui/resizable.tsx +50 -0
  341. package/src/presentation/ui/select.tsx +192 -0
  342. package/src/presentation/ui/separator.tsx +28 -0
  343. package/src/presentation/ui/sheet.tsx +147 -0
  344. package/src/presentation/ui/sidebar.tsx +702 -0
  345. package/src/presentation/ui/skeleton.tsx +13 -0
  346. package/src/presentation/ui/slide-to-confirm.tsx +129 -0
  347. package/src/presentation/ui/slider.tsx +59 -0
  348. package/src/presentation/ui/sonner.tsx +58 -0
  349. package/src/presentation/ui/switch.tsx +33 -0
  350. package/src/presentation/ui/table.tsx +116 -0
  351. package/src/presentation/ui/tabs.tsx +90 -0
  352. package/src/presentation/ui/text-gradient.tsx +84 -0
  353. package/src/presentation/ui/textarea.tsx +18 -0
  354. package/src/presentation/ui/timeline-steps.tsx +235 -0
  355. package/src/presentation/ui/toggle-group.tsx +89 -0
  356. package/src/presentation/ui/toggle.tsx +47 -0
  357. package/src/presentation/ui/tooltip.tsx +57 -0
  358. package/src/presentation/uploading/index.tsx +3 -0
  359. package/src/presentation/uploading/media-upload-field.tsx +152 -0
  360. package/src/presentation/uploading/storage-media.tsx +210 -0
  361. package/src/styles.css +403 -0
  362. package/src/themes.css +1038 -0
@@ -0,0 +1,892 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ closestCenter,
6
+ DndContext,
7
+ KeyboardSensor,
8
+ MouseSensor,
9
+ TouchSensor,
10
+ useSensor,
11
+ useSensors,
12
+ type DragEndEvent,
13
+ type UniqueIdentifier,
14
+ } from "@dnd-kit/core"
15
+ import {restrictToVerticalAxis} from "@dnd-kit/modifiers"
16
+ import {
17
+ arrayMove,
18
+ SortableContext,
19
+ useSortable,
20
+ verticalListSortingStrategy,
21
+ } from "@dnd-kit/sortable"
22
+ import {CSS} from "@dnd-kit/utilities"
23
+ import {
24
+ flexRender,
25
+ getCoreRowModel,
26
+ getFacetedRowModel,
27
+ getFacetedUniqueValues,
28
+ getFilteredRowModel,
29
+ getPaginationRowModel,
30
+ getSortedRowModel,
31
+ useReactTable,
32
+ type ColumnDef,
33
+ type ColumnFiltersState,
34
+ type Row,
35
+ type SortingState,
36
+ type VisibilityState,
37
+ type Table as TanstackTable,
38
+ type OnChangeFn,
39
+ type RowSelectionState,
40
+ } from "@tanstack/react-table"
41
+ import {
42
+ GripVerticalIcon,
43
+ Columns3Icon,
44
+ ChevronDownIcon,
45
+ ChevronsLeftIcon,
46
+ ChevronLeftIcon,
47
+ ChevronRightIcon,
48
+ ChevronsRightIcon,
49
+ XIcon,
50
+ EllipsisVerticalIcon
51
+ } from "lucide-react"
52
+
53
+ import {Button} from "../ui/button"
54
+ import {Checkbox} from "../ui/checkbox"
55
+ import {
56
+ DropdownMenu,
57
+ DropdownMenuCheckboxItem,
58
+ DropdownMenuContent,
59
+ DropdownMenuItem,
60
+ DropdownMenuSeparator,
61
+ DropdownMenuTrigger,
62
+ } from "../ui/dropdown-menu"
63
+ import {Label} from "../ui/label"
64
+ import {
65
+ Select,
66
+ SelectContent,
67
+ SelectGroup,
68
+ SelectItem,
69
+ SelectTrigger,
70
+ SelectValue,
71
+ } from "../ui/select"
72
+ import {
73
+ Table,
74
+ TableBody,
75
+ TableCell,
76
+ TableHead,
77
+ TableHeader,
78
+ TableRow,
79
+ } from "../ui/table"
80
+ import {
81
+ ContextMenu,
82
+ ContextMenuContent,
83
+ ContextMenuItem,
84
+ ContextMenuTrigger,
85
+ } from "../ui/context-menu"
86
+ import {cn} from "../../infrastructure/utilities/utils"
87
+ import {DataGridEmpty} from "./data-grid-empty";
88
+
89
+ export interface BulkAction<TData> {
90
+ /**
91
+ * Unique identifier for the action
92
+ */
93
+ id: string
94
+ /**
95
+ * Display label for the action
96
+ */
97
+ label: string
98
+ /**
99
+ * Callback when action is triggered
100
+ */
101
+ onExecute: (selectedRows: TData[]) => void | Promise<void>
102
+ /**
103
+ * Optional icon for the action button
104
+ */
105
+ icon?: React.ReactNode
106
+ /**
107
+ * Variant of the button (e.g., 'destructive')
108
+ */
109
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost"
110
+ }
111
+
112
+ export interface RowAction<TData> {
113
+ /**
114
+ * Unique identifier for the action
115
+ */
116
+ id: string
117
+ /**
118
+ * Display label for the action
119
+ */
120
+ label: string
121
+ /**
122
+ * Callback when action is triggered
123
+ */
124
+ onExecute: (row: TData) => void | Promise<void>
125
+ /**
126
+ * Optional icon for the action item
127
+ */
128
+ icon?: React.ReactNode
129
+ /**
130
+ * Variant of the item (e.g., 'destructive')
131
+ */
132
+ variant?: "default" | "destructive"
133
+ /**
134
+ * Whether to show the action in the context menu. Defaults to true.
135
+ */
136
+ showInContextMenu?: boolean
137
+ }
138
+
139
+ export interface DataGridProps<TData> {
140
+ /**
141
+ * Data to display in the grid
142
+ */
143
+ data: TData[]
144
+ /**
145
+ * Column definitions
146
+ */
147
+ columns: ColumnDef<TData, any>[]
148
+ /**
149
+ * Function to get a unique ID for each row. Required for DND and selection.
150
+ */
151
+ getRowId: (row: TData) => string
152
+ /**
153
+ * Callback called when data is reordered (if DND is enabled)
154
+ */
155
+ onDataReorder?: (newData: TData[]) => void
156
+ /**
157
+ * Enable drag and drop row reordering
158
+ */
159
+ enableDnd?: boolean
160
+ /**
161
+ * Enable row selection
162
+ */
163
+ enableSelection?: boolean
164
+ /**
165
+ * Callback for row selection change
166
+ */
167
+ onRowSelectionChange?: OnChangeFn<RowSelectionState>
168
+ /**
169
+ * Initial row selection state
170
+ */
171
+ rowSelection?: RowSelectionState
172
+ /**
173
+ * Enable bulk actions bar
174
+ */
175
+ // enableBulkActions?: boolean
176
+ /**
177
+ * Bulk actions available when rows are selected
178
+ */
179
+ bulkActions?: BulkAction<TData>[]
180
+ /**
181
+ * Enable context menu on rows
182
+ */
183
+ // enableRowActions?: boolean
184
+ /**
185
+ * Actions available in the row context menu
186
+ */
187
+ actions?: (row: TData) => RowAction<TData>[]
188
+ /**
189
+ * Enable column visibility toggling
190
+ */
191
+ enableColumnVisibility?: boolean
192
+ /**
193
+ * Enable pagination
194
+ */
195
+ enablePagination?: boolean
196
+ /**
197
+ * Enable manual pagination (server-side)
198
+ */
199
+ manualPagination?: boolean
200
+ /**
201
+ * Total page count for manual pagination
202
+ */
203
+ pageCount?: number
204
+ /**
205
+ * Callback for pagination change
206
+ */
207
+ onPaginationChange?: OnChangeFn<import("@tanstack/react-table").PaginationState>
208
+ /**
209
+ * Current pagination state
210
+ */
211
+ pagination?: import("@tanstack/react-table").PaginationState
212
+ /**
213
+ * Available page size options
214
+ */
215
+ pageSizeOptions?: number[]
216
+ /**
217
+ * Initial page size
218
+ */
219
+ initialPageSize?: number
220
+ /**
221
+ * Custom toolbar content (placed above the table)
222
+ */
223
+ toolbar?: (table: TanstackTable<TData>) => React.ReactNode
224
+ /**
225
+ * Additional class name for the table wrapper
226
+ */
227
+ className?: string
228
+ /**
229
+ * Additional class name for the outer container
230
+ */
231
+ containerClassName?: string
232
+ /**
233
+ * If true, the table header will be sticky
234
+ */
235
+ stickyHeader?: boolean
236
+ }
237
+
238
+ export interface DataGridTableMeta<TData> {
239
+ /**
240
+ * Returns the row actions declared on the DataGrid for a given row.
241
+ * Accessible from cell/header renders via `table.options.meta.getRowActions(row)`.
242
+ */
243
+ getRowActions: (row: TData) => RowAction<TData>[]
244
+ }
245
+
246
+ /**
247
+ * Generic utility to retrieve, from any column cell render, the row actions
248
+ * declared on the DataGrid via the `actions` prop.
249
+ *
250
+ * @example
251
+ * cell: ({row, table}) => {
252
+ * const actions = getRowActions(table, row.original)
253
+ * const edit = actions.find(a => a.id === "edit")
254
+ * return <Button onClick={() => edit?.onExecute(row.original)}>Modifier</Button>
255
+ * }
256
+ */
257
+ export function getDataGridActions<TData>(table: TanstackTable<TData>, row: TData): RowAction<TData>[] {
258
+ const meta = table?.options?.meta as DataGridTableMeta<TData> | undefined
259
+ return meta?.getRowActions?.(row) ?? []
260
+ }
261
+
262
+ /**
263
+ * Generic utility to retrieve a single row action by its id, if it exists.
264
+ *
265
+ * @example
266
+ * cell: ({row, table}) => {
267
+ * const edit = getRowAction(table, row.original, "edit")
268
+ * return edit && <Button onClick={() => edit.onExecute(row.original)}>Modifier</Button>
269
+ * }
270
+ */
271
+ export function getDataGridAction<TData>(
272
+ table: TanstackTable<TData>,
273
+ row: TData,
274
+ actionId: string,
275
+ ): RowAction<TData> | undefined {
276
+ return getDataGridActions(table, row).find(action => action.id === actionId)
277
+ }
278
+
279
+ // Internal component for the drag handle
280
+ function DragHandle({id}: { id: UniqueIdentifier }) {
281
+ const {attributes, listeners} = useSortable({id})
282
+
283
+ return (
284
+ <Button
285
+ {...attributes}
286
+ {...listeners}
287
+ variant="ghost"
288
+ size="icon"
289
+ className="size-7 text-muted-foreground hover:bg-transparent"
290
+ >
291
+ <GripVerticalIcon className="size-3 text-muted-foreground"/>
292
+ <span className="sr-only">Drag to reorder</span>
293
+ </Button>
294
+ )
295
+ }
296
+
297
+ interface RowActionMenuProps<TData> {
298
+ children: React.ReactNode
299
+ row: Row<TData>
300
+ enableRowActions?: boolean
301
+ rowActions?: (row: TData) => RowAction<TData>[]
302
+ }
303
+
304
+ function RowActionMenu<TData>(
305
+ {
306
+ children,
307
+ row,
308
+ enableRowActions,
309
+ rowActions,
310
+ }: RowActionMenuProps<TData>) {
311
+ if (!enableRowActions || !rowActions) return <>{children}</>
312
+
313
+ const actions = rowActions(row.original).filter(action => action.showInContextMenu !== false)
314
+ if (actions.length === 0) return <>{children}</>
315
+
316
+ return (
317
+ <ContextMenu>
318
+ <ContextMenuTrigger asChild>
319
+ {children}
320
+ </ContextMenuTrigger>
321
+ <ContextMenuContent className="w-48">
322
+ {actions.map((action) => (
323
+ <ContextMenuItem
324
+ key={action.id}
325
+ onClick={() => action.onExecute(row.original)}
326
+ variant={action.variant}
327
+ >
328
+ {action.icon}
329
+ {action.label}
330
+ </ContextMenuItem>
331
+ ))}
332
+ </ContextMenuContent>
333
+ </ContextMenu>
334
+ )
335
+ }
336
+
337
+ // Internal component for draggable rows
338
+ function DraggableRow<TData>({
339
+ row,
340
+ enableRowActions,
341
+ rowActions,
342
+ }: {
343
+ row: Row<TData>
344
+ enableRowActions?: boolean
345
+ rowActions?: (row: TData) => RowAction<TData>[]
346
+ }) {
347
+ const {transform, transition, setNodeRef, isDragging} = useSortable({
348
+ id: row.id,
349
+ })
350
+
351
+ const style: React.CSSProperties = {
352
+ transform: CSS.Transform.toString(transform),
353
+ transition: transition,
354
+ }
355
+
356
+ return (
357
+ <RowActionMenu
358
+ row={row}
359
+ enableRowActions={enableRowActions}
360
+ rowActions={rowActions}
361
+ >
362
+ <TableRow
363
+ data-state={row.getIsSelected() && "selected"}
364
+ data-dragging={isDragging}
365
+ ref={setNodeRef}
366
+ className="relative z-0 data-[dragging=true]:z-1 data-[dragging=true]:opacity-80"
367
+ style={style}
368
+ >
369
+ {row.getVisibleCells().map((cell) => (
370
+ <TableCell key={cell.id}>
371
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
372
+ </TableCell>
373
+ ))}
374
+ </TableRow>
375
+ </RowActionMenu>
376
+ )
377
+ }
378
+
379
+ /**
380
+ * Shared empty fallback so an undefined `data` prop normalizes to a stable
381
+ * reference (a fresh `[]` per render would break the render-phase sync below).
382
+ */
383
+ const NO_DATA: never[] = []
384
+
385
+ /**
386
+ * DataGrid component for displaying and managing tabular data.
387
+ * Built with @tanstack/react-table and @dnd-kit.
388
+ */
389
+ export function DataGrid<TData>(
390
+ {
391
+ data: initialData,
392
+ columns: userColumns,
393
+ getRowId,
394
+ onDataReorder,
395
+ enableDnd = false,
396
+ enableSelection = false,
397
+ onRowSelectionChange,
398
+ rowSelection: initialRowSelection = {},
399
+ // enableBulkActions = false,
400
+ bulkActions = [],
401
+ // enableRowActions = false,
402
+ actions,
403
+ enableColumnVisibility = true,
404
+ enablePagination = true,
405
+ manualPagination = false,
406
+ pageCount,
407
+ onPaginationChange: onPaginationChangeProp,
408
+ pagination: paginationProp,
409
+ pageSizeOptions = [10, 20, 30, 40, 50],
410
+ initialPageSize = 10,
411
+ toolbar,
412
+ className,
413
+ containerClassName,
414
+ stickyHeader = true,
415
+ }: DataGridProps<TData>) {
416
+ // We manage internal data state to support DND reordering. When the parent
417
+ // hands us a new `initialData` reference, sync the internal copy during
418
+ // render (the "adjust state during render" pattern) instead of in an effect.
419
+ // Syncing via an effect (`setData(initialData)` in `useEffect`) can recurse
420
+ // into "Maximum update depth exceeded" when the parent re-renders.
421
+ // Normalize to an array: TanStack's getCoreRowModel reads `data.length`,
422
+ // so undefined/non-array data would crash inside `table.getRowModel()`
423
+ // (e.g. while a query is still loading). Use a module-level constant for
424
+ // the fallback so its reference stays stable across renders, otherwise the
425
+ // sync-below would call `setData` with a fresh `[]` on every pass and loop.
426
+ const safeInitialData = Array.isArray(initialData) ? initialData : NO_DATA
427
+ const [data, setData] = React.useState<TData[]>(() => safeInitialData)
428
+ const previousDataRef = React.useRef<TData[]>(safeInitialData)
429
+ if (previousDataRef.current !== safeInitialData) {
430
+ previousDataRef.current = safeInitialData
431
+ setData(safeInitialData)
432
+ }
433
+ const enableRowActions = typeof actions !== 'undefined'
434
+ const enableBulkActions = typeof bulkActions !== 'undefined'
435
+
436
+ const [rowSelection, setRowSelection] = React.useState<RowSelectionState>(initialRowSelection)
437
+ const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
438
+ const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
439
+ const [sorting, setSorting] = React.useState<SortingState>([])
440
+ const [internalPagination, setInternalPagination] = React.useState({
441
+ pageIndex: 0,
442
+ pageSize: initialPageSize,
443
+ })
444
+
445
+ const pagination = paginationProp || internalPagination
446
+ const onPaginationChange = onPaginationChangeProp || setInternalPagination
447
+ const [isExecutingAction, setIsExecutingAction] = React.useState(false)
448
+
449
+ const sensors = useSensors(
450
+ useSensor(MouseSensor, {}),
451
+ useSensor(TouchSensor, {}),
452
+ useSensor(KeyboardSensor, {})
453
+ )
454
+
455
+ const dataIds = React.useMemo<UniqueIdentifier[]>(
456
+ () => data?.map(getRowId) || [],
457
+ [data, getRowId]
458
+ )
459
+
460
+ // Merge user columns with optional feature columns (selection, dnd, actions)
461
+ const columns = React.useMemo(() => {
462
+ const cols = [...userColumns]
463
+
464
+ if (enableSelection) {
465
+ cols.unshift({
466
+ id: "select",
467
+ header: ({table}) => (
468
+ <div className="flex items-center justify-center">
469
+ <Checkbox
470
+ checked={
471
+ table.getIsAllPageRowsSelected() ||
472
+ (table.getIsSomePageRowsSelected() && "indeterminate")
473
+ }
474
+ onCheckedChange={(value) => {
475
+ table.toggleAllPageRowsSelected(!!value)
476
+ }}
477
+ aria-label="Select all"
478
+ />
479
+ </div>
480
+ ),
481
+ cell: ({row}) => (
482
+ <div className="flex items-center justify-center">
483
+ <Checkbox
484
+ checked={row.getIsSelected()}
485
+ onCheckedChange={(value) => {
486
+ row.toggleSelected(!!value)
487
+ }}
488
+ aria-label="Select row"
489
+ />
490
+ </div>
491
+ ),
492
+ enableSorting: false,
493
+ enableHiding: false,
494
+ })
495
+ }
496
+
497
+ if (enableDnd) {
498
+ cols.unshift({
499
+ id: "drag",
500
+ header: () => null,
501
+ cell: ({row}) => <DragHandle id={getRowId(row.original)}/>,
502
+ enableHiding: false,
503
+ })
504
+ }
505
+
506
+ if (enableRowActions && actions) {
507
+ const hasActionsColumn = cols.some(col => col.id === "actions")
508
+ if (!hasActionsColumn) {
509
+ cols.push({
510
+ id: "actions",
511
+ cell: ({row}) => {
512
+ const rowActions = actions(row.original)
513
+ if (rowActions.length === 0) return null
514
+
515
+ return (
516
+ <DropdownMenu>
517
+ <DropdownMenuTrigger asChild>
518
+ <Button
519
+ variant="ghost"
520
+ className="flex size-8 text-muted-foreground data-[state=open]:bg-muted ml-auto"
521
+ size="icon"
522
+ >
523
+ <EllipsisVerticalIcon className="size-4"/>
524
+ <span className="sr-only">Ouvrir le menu</span>
525
+ </Button>
526
+ </DropdownMenuTrigger>
527
+ <DropdownMenuContent align="end" className="w-48">
528
+ {rowActions.map((action, index) => (
529
+ <React.Fragment key={action.id}>
530
+ {index > 0 && action.variant === "destructive" && rowActions[index - 1].variant !== "destructive" && (
531
+ <DropdownMenuSeparator/>
532
+ )}
533
+ <DropdownMenuItem
534
+ onSelect={() => action.onExecute(row.original)}
535
+ variant={action.variant}
536
+ >
537
+ {action.icon}
538
+ {action.label}
539
+ </DropdownMenuItem>
540
+ </React.Fragment>
541
+ ))}
542
+ </DropdownMenuContent>
543
+ </DropdownMenu>
544
+ )
545
+ },
546
+ enableSorting: false,
547
+ enableHiding: false,
548
+ })
549
+ }
550
+ }
551
+
552
+ return cols
553
+ }, [userColumns, enableSelection, enableDnd, enableRowActions, actions, getRowId])
554
+
555
+ const table = useReactTable({
556
+ data,
557
+ columns,
558
+ state: {
559
+ sorting,
560
+ columnVisibility,
561
+ rowSelection,
562
+ columnFilters,
563
+ pagination,
564
+ },
565
+ getRowId: (row) => getRowId(row),
566
+ enableRowSelection: enableSelection,
567
+ onRowSelectionChange: (updater) => {
568
+ setRowSelection(updater)
569
+ onRowSelectionChange?.(updater)
570
+ },
571
+ onSortingChange: setSorting,
572
+ onColumnFiltersChange: setColumnFilters,
573
+ onColumnVisibilityChange: setColumnVisibility,
574
+ onPaginationChange,
575
+ getCoreRowModel: getCoreRowModel(),
576
+ getFilteredRowModel: getFilteredRowModel(),
577
+ getPaginationRowModel: manualPagination ? undefined : getPaginationRowModel(),
578
+ getSortedRowModel: getSortedRowModel(),
579
+ getFacetedRowModel: getFacetedRowModel(),
580
+ getFacetedUniqueValues: getFacetedUniqueValues(),
581
+ manualPagination,
582
+ pageCount,
583
+ meta: {
584
+ getRowActions: (row) => (actions ? actions(row) : []),
585
+ } satisfies DataGridTableMeta<TData>,
586
+ })
587
+
588
+ function handleDragEnd(event: DragEndEvent) {
589
+ const {active, over} = event
590
+ if (active && over && active.id !== over.id) {
591
+ const oldIndex = dataIds.indexOf(active.id)
592
+ const newIndex = dataIds.indexOf(over.id)
593
+ const newData = arrayMove(data, oldIndex, newIndex)
594
+ setData(newData)
595
+ onDataReorder?.(newData)
596
+ }
597
+ }
598
+
599
+ const sortableId = React.useId()
600
+ const model = table?.getRowModel()
601
+
602
+ const selectedRows = React.useMemo(() => {
603
+ const selectedIds = Object.keys(rowSelection).filter(key => rowSelection[key])
604
+ return model?.rows
605
+ .filter(row => selectedIds.includes(row.id))
606
+ .map(row => row.original) || []
607
+ }, [rowSelection, model?.rows])
608
+
609
+ const handleBulkAction = async (action: BulkAction<TData>) => {
610
+ setIsExecutingAction(true)
611
+ try {
612
+ await action.onExecute(selectedRows)
613
+ setRowSelection({})
614
+ } finally {
615
+ setIsExecutingAction(false)
616
+ }
617
+ }
618
+
619
+ const handleClearSelection = () => {
620
+ setRowSelection({})
621
+ }
622
+
623
+ return (
624
+ <div className={cn("flex! w-full! flex-col! gap-4!", containerClassName)}>
625
+ {(toolbar || enableColumnVisibility) && (
626
+ <div className="flex items-center justify-between ">
627
+ <div className="flex items-center gap-2">
628
+ {toolbar?.(table)}
629
+ </div>
630
+ <div className="flex items-center gap-2">
631
+ {enableColumnVisibility && (
632
+ <DropdownMenu>
633
+ <DropdownMenuTrigger asChild className={''}>
634
+ <Button variant="outline" size="lg" className="rounded-lg ">
635
+ <Columns3Icon data-icon="inline-start"/>
636
+ Colonnes
637
+ <ChevronDownIcon data-icon="inline-end"/>
638
+ </Button>
639
+ </DropdownMenuTrigger>
640
+ <DropdownMenuContent align="end" className="w-48">
641
+ {table
642
+ .getAllColumns()
643
+ .filter(
644
+ (column) =>
645
+ typeof column.accessorFn !== "undefined" &&
646
+ column.getCanHide()
647
+ )
648
+ .map((column) => {
649
+ return (
650
+ <DropdownMenuCheckboxItem
651
+ key={column.id}
652
+ // className="capitalize"
653
+ checked={column.getIsVisible()}
654
+ onCheckedChange={(value) =>
655
+ column.toggleVisibility(!!value)
656
+ }
657
+ >
658
+ {column.id}
659
+ </DropdownMenuCheckboxItem>
660
+ )
661
+ })}
662
+ </DropdownMenuContent>
663
+ </DropdownMenu>
664
+ )}
665
+ </div>
666
+ </div>
667
+ )}
668
+
669
+ {enableBulkActions && selectedRows.length > 0 && (
670
+ <div
671
+ className="flex items-center gap-3 rounded-xl p-4 bg-primary/10 border border-primary/20 backdrop-blur-2xl">
672
+ <div className="flex-1 text-sm font-medium text-foreground">
673
+ {selectedRows.length} ligne(s) sélectionnée(s)
674
+ </div>
675
+ <div className="flex items-center gap-2">
676
+ {bulkActions.map((action) => (
677
+ <Button
678
+ key={action.id}
679
+ size="sm"
680
+ variant={action.variant || "default"}
681
+ onClick={() => handleBulkAction(action)}
682
+ disabled={isExecutingAction}
683
+ >
684
+ {action.icon}
685
+ {action.label}
686
+ </Button>
687
+ ))}
688
+ <Button
689
+ size="sm"
690
+ variant="ghost"
691
+ onClick={handleClearSelection}
692
+ disabled={isExecutingAction}
693
+ >
694
+ <XIcon className="size-4"/>
695
+ <span className="sr-only">Clear selection</span>
696
+ </Button>
697
+ </div>
698
+ </div>
699
+ )}
700
+
701
+ <div className={cn("overflow-hidden rounded-lg border border-border", className)}>
702
+ {enableDnd ? (
703
+ <DndContext
704
+ collisionDetection={closestCenter}
705
+ modifiers={[restrictToVerticalAxis]}
706
+ onDragEnd={handleDragEnd}
707
+ sensors={sensors}
708
+ id={sortableId}
709
+ >
710
+ <Table>
711
+ <TableHeader className={cn(stickyHeader && "sticky top-0 z-1 bg-muted")}>
712
+ {table.getHeaderGroups().map((headerGroup) => (
713
+ <TableRow key={headerGroup.id}>
714
+ {headerGroup.headers.map((header) => (
715
+ <TableHead key={header.id} colSpan={header.colSpan}>
716
+ {header.isPlaceholder
717
+ ? null
718
+ : flexRender(
719
+ header.column.columnDef.header,
720
+ header.getContext()
721
+ )}
722
+ </TableHead>
723
+ ))}
724
+ </TableRow>
725
+ ))}
726
+ </TableHeader>
727
+ <TableBody className="**:data-[slot=table-cell]:first:w-8">
728
+ {model?.rows?.length ? (
729
+ <SortableContext
730
+ items={dataIds}
731
+ strategy={verticalListSortingStrategy}
732
+ >
733
+ {model?.rows.map((row) => (
734
+ <DraggableRow
735
+ key={row.id}
736
+ row={row}
737
+ enableRowActions={enableRowActions}
738
+ rowActions={actions}
739
+ />
740
+ ))}
741
+ </SortableContext>
742
+ ) : (
743
+ <TableRow>
744
+ <TableCell
745
+ colSpan={columns.length}
746
+ className="h-24 text-center"
747
+ >
748
+ <DataGridEmpty/>
749
+ </TableCell>
750
+ </TableRow>
751
+ )}
752
+ </TableBody>
753
+ </Table>
754
+ </DndContext>
755
+ ) : (
756
+ <Table>
757
+ <TableHeader className={cn(stickyHeader && "sticky top-0 z-1 bg-muted")}>
758
+ {table.getHeaderGroups().map((headerGroup) => (
759
+ <TableRow key={headerGroup.id}>
760
+ {headerGroup.headers.map((header) => (
761
+ <TableHead key={header.id} colSpan={header.colSpan}>
762
+ {header.isPlaceholder
763
+ ? null
764
+ : flexRender(
765
+ header.column.columnDef.header,
766
+ header.getContext()
767
+ )}
768
+ </TableHead>
769
+ ))}
770
+ </TableRow>
771
+ ))}
772
+ </TableHeader>
773
+ <TableBody>
774
+ {model?.rows?.length ? (
775
+ model?.rows.map((row) => (
776
+ <RowActionMenu
777
+ key={row.id}
778
+ row={row}
779
+ enableRowActions={enableRowActions}
780
+ rowActions={actions}
781
+ >
782
+ <TableRow
783
+ data-state={row.getIsSelected() && "selected"}
784
+ >
785
+ {row.getVisibleCells().map((cell) => (
786
+ <TableCell key={cell.id}>
787
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
788
+ </TableCell>
789
+ ))}
790
+ </TableRow>
791
+ </RowActionMenu>
792
+ ))
793
+ ) : (
794
+ <TableRow>
795
+ <TableCell
796
+ colSpan={columns.length}
797
+ className="h-24 text-center"
798
+ >
799
+ <DataGridEmpty/>
800
+ </TableCell>
801
+ </TableRow>
802
+ )}
803
+ </TableBody>
804
+ </Table>
805
+ )}
806
+ </div>
807
+
808
+ {enablePagination && (
809
+ <div className="flex items-center justify-between ">
810
+ <div className="hidden flex-1 text-sm text-muted-foreground lg:flex">
811
+ {table.getFilteredSelectedRowModel().rows.length} of{" "}
812
+ {table.getFilteredRowModel().rows.length} ligne(s) sélectionnées.
813
+ </div>
814
+ <div className="flex w-full items-center gap-8 lg:w-fit">
815
+ <div className="hidden items-center gap-2 lg:flex">
816
+ <Label htmlFor="rows-per-page" className="text-sm font-medium">
817
+ Ligne par page
818
+ </Label>
819
+ <Select
820
+ value={`${table.getState().pagination.pageSize}`}
821
+ onValueChange={(value) => {
822
+ table.setPageSize(Number(value))
823
+ }}
824
+ >
825
+ <SelectTrigger size="sm" className="w-20" id="rows-per-page">
826
+ <SelectValue
827
+ placeholder={table.getState().pagination.pageSize}
828
+ />
829
+ </SelectTrigger>
830
+ <SelectContent side="top">
831
+ <SelectGroup>
832
+ {pageSizeOptions.map((pageSize) => (
833
+ <SelectItem key={pageSize} value={`${pageSize}`}>
834
+ {pageSize}
835
+ </SelectItem>
836
+ ))}
837
+ </SelectGroup>
838
+ </SelectContent>
839
+ </Select>
840
+ </div>
841
+ <div className="flex w-fit items-center justify-center text-sm font-medium">
842
+ Page {table.getState().pagination.pageIndex + 1} sur{" "}
843
+ {table.getPageCount()}
844
+ </div>
845
+ <div className="ml-auto flex items-center gap-2 lg:ml-0">
846
+ <Button
847
+ variant="outline"
848
+ className="hidden size-8 lg:flex"
849
+ size="icon"
850
+ onClick={() => table.setPageIndex(0)}
851
+ disabled={!table.getCanPreviousPage()}
852
+ >
853
+ <span className="sr-only">Aller à la première page</span>
854
+ <ChevronsLeftIcon/>
855
+ </Button>
856
+ <Button
857
+ variant="outline"
858
+ className="size-8"
859
+ size="icon"
860
+ onClick={() => table.previousPage()}
861
+ disabled={!table.getCanPreviousPage()}
862
+ >
863
+ <span className="sr-only">Aller à la page précédente</span>
864
+ <ChevronLeftIcon/>
865
+ </Button>
866
+ <Button
867
+ variant="outline"
868
+ className="size-8"
869
+ size="icon"
870
+ onClick={() => table.nextPage()}
871
+ disabled={!table.getCanNextPage()}
872
+ >
873
+ <span className="sr-only">Aller à la page suivante</span>
874
+ <ChevronRightIcon/>
875
+ </Button>
876
+ <Button
877
+ variant="outline"
878
+ className="hidden size-8 lg:flex"
879
+ size="icon"
880
+ onClick={() => table.setPageIndex(table.getPageCount() - 1)}
881
+ disabled={!table.getCanNextPage()}
882
+ >
883
+ <span className="sr-only">Aller à la dernière page</span>
884
+ <ChevronsRightIcon/>
885
+ </Button>
886
+ </div>
887
+ </div>
888
+ </div>
889
+ )}
890
+ </div>
891
+ )
892
+ }