@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,19 @@
1
+ import {cn} from "../../../infrastructure/utilities/utils";
2
+ import {CommonClassName} from "../../../infrastructure/utilities/classname.util";
3
+
4
+ export interface HeaderSectionProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ children?: React.ReactNode;
6
+ }
7
+
8
+ export function EdgeSection({children, ...props}: HeaderSectionProps) {
9
+ return (
10
+ <div {...props} className={cn(
11
+ "flex flex-row items-center",
12
+ CommonClassName.layer,
13
+ CommonClassName.glossyBorder,
14
+ props.className,
15
+ )}>
16
+ {children}
17
+ </div>
18
+ )
19
+ }
@@ -0,0 +1,270 @@
1
+ "use client"
2
+
3
+ import {useModuleStore} from "../../../infrastructure/stores/module.store"
4
+ import {MenuIcon} from "lucide-react"
5
+ import {useRouter, usePathname} from "next/navigation"
6
+ import {cn} from "../../../infrastructure/utilities/utils"
7
+ import {useState} from "react"
8
+ import {
9
+ NavigationMenu as NavigationMenuRoot,
10
+ NavigationMenuContent,
11
+ NavigationMenuItem,
12
+ NavigationMenuList,
13
+ NavigationMenuTrigger,
14
+ NavigationMenuViewport,
15
+ } from "../../ui/navigation-menu";
16
+ import {LucideIcon} from "../../icons/lucide";
17
+ import {Accordion, AccordionContent, AccordionItem, AccordionTrigger} from "../../ui/accordion";
18
+ import {Button} from "../../ui/button";
19
+ import {Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger} from "../../ui/sheet";
20
+
21
+
22
+ export type NavigationMenuSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
23
+
24
+ const sizeClasses: Record<NavigationMenuSize, { name: string; wrapper: string }> = {
25
+ xs: {name: "text-sm", wrapper: "pt-0"},
26
+ sm: {name: "text-sm", wrapper: "pt-0"},
27
+ md: {name: "text-sm", wrapper: "pt-0"},
28
+ lg: {name: "text-lg", wrapper: "pt-0"},
29
+ xl: {name: "text-xl", wrapper: "pt-0"},
30
+ xxl: {name: "text-2xl", wrapper: "pt-0"},
31
+ }
32
+
33
+ export interface NavigationMenuProps {
34
+ size?: NavigationMenuSize
35
+ }
36
+
37
+ export function NavigationMenu({size = 'md'}: NavigationMenuProps) {
38
+ const {selectedModule} = useModuleStore()
39
+ const router = useRouter()
40
+ const pathname = usePathname()
41
+ const classes = sizeClasses[size]
42
+ const [open, setOpen] = useState(false)
43
+
44
+ const sizeMap: Record<NavigationMenuSize, { trigger: string; item: string; icon: number; mobileItem: string }> = {
45
+ xs: {trigger: "text-xs h-7 px-1.5 py-0", item: "text-xs px-2 py-1", icon: 3, mobileItem: "text-xs h-8"},
46
+ sm: {trigger: "text-xs h-8 px-2 py-0", item: "text-xs px-2.5 py-1.5", icon: 3, mobileItem: "text-sm h-9"},
47
+ md: {trigger: "text-sm h-9 px-2.5 py-0", item: "text-sm px-3 py-1.5", icon: 4, mobileItem: "text-sm h-10"},
48
+ lg: {trigger: "text-sm h-10 px-3.5 py-0", item: "text-sm px-3.5 py-2", icon: 4, mobileItem: "text-base h-11"},
49
+ xl: {trigger: "text-base h-11 px-4.5 py-0", item: "text-base px-4 py-2", icon: 5, mobileItem: "text-base h-12"},
50
+ xxl: {trigger: "text-lg h-12 px-5 py-2.5", item: "text-lg px-5 py-2.5", icon: 5, mobileItem: "text-lg h-14"},
51
+ }
52
+ const s = sizeMap[size]
53
+
54
+ const activeClasses = {
55
+ desktop: "cursor-pointer",
56
+ mobileAccordion: "text-primary",
57
+ mobileButton: "secondary" as const,
58
+ }
59
+
60
+ const isItemActive = (item: any): boolean => {
61
+ if (item.url && pathname === item.url) {
62
+ return true
63
+ }
64
+ if (item.items) {
65
+ return item.items.some((subItem: any) => {
66
+ if ('separator' in subItem) return false
67
+ return isItemActive(subItem as any)
68
+ })
69
+ }
70
+ return false
71
+ }
72
+
73
+ const handleItemAction = (item: any) => {
74
+ if (item.action) {
75
+ item.action(router)
76
+ }
77
+ if (item.url) {
78
+ router.push(item.url)
79
+ }
80
+ }
81
+
82
+ const renderDesktopItems = (items: any[]) => {
83
+ return items.map((item, index) => {
84
+ if ('separator' in item) {
85
+ return <li key={`sep-${index}`} className="my-1 h-px bg-border"/>
86
+ }
87
+
88
+ const itemWithItems = item as any
89
+ const active = isItemActive(itemWithItems)
90
+ const hasChildren = itemWithItems.items && itemWithItems.items.length > 0
91
+
92
+ return (
93
+ <NavigationMenuItem key={itemWithItems.label || index}>
94
+ <NavigationMenuTrigger
95
+ hideChevron={!hasChildren}
96
+ className={cn(
97
+ "gap-2 rounded-sm",
98
+ s.trigger,
99
+ active && activeClasses.desktop,
100
+ active && 'hover:bg-transparent hover:text-foreground'
101
+ )}
102
+ onClick={() => !hasChildren && handleItemAction(itemWithItems)}
103
+ >
104
+ {itemWithItems.icon && <LucideIcon name={itemWithItems.icon} size={s.icon}/>}
105
+ <span>{itemWithItems.label}</span>
106
+ </NavigationMenuTrigger>
107
+ {hasChildren && (
108
+ <NavigationMenuContent>
109
+ <ul className="grid gap-1 p-2 w-48">
110
+ {itemWithItems.items.map((subItem: any, subIndex: number) => {
111
+ if ('separator' in subItem) {
112
+ return <li key={`sep-${subIndex}`} className="my-1 h-px bg-border"/>
113
+ }
114
+ const subActive = isItemActive(subItem)
115
+ return (
116
+ <li key={subItem.label || subIndex}>
117
+ <button
118
+ onClick={() => handleItemAction(subItem)}
119
+ className={cn(
120
+ "flex items-center gap-2 w-full rounded-md px-2 py-1.5 text-sm text-left hover:bg-accent hover:text-accent-foreground",
121
+ subActive && "bg-accent text-accent-foreground"
122
+ )}
123
+ >
124
+ {subItem.icon && <LucideIcon name={subItem.icon} size={s.icon}/>}
125
+ <span>{subItem.label}</span>
126
+ </button>
127
+ </li>
128
+ )
129
+ })}
130
+ </ul>
131
+ </NavigationMenuContent>
132
+ )}
133
+ </NavigationMenuItem>
134
+ )
135
+ })
136
+ }
137
+
138
+ const renderMobileItems = (items: any[]) => {
139
+ return items.map((item, index) => {
140
+ if ('separator' in item) {
141
+ return <div key={`sep-${index}`} className="my-2 border-b border-border/50"/>
142
+ }
143
+
144
+ const itemWithItems = item as any
145
+ const active = isItemActive(itemWithItems)
146
+
147
+ if (itemWithItems.items && itemWithItems.items.length > 0) {
148
+ return (
149
+ <AccordionItem key={itemWithItems.label} value={itemWithItems.label} className="border-none">
150
+ <AccordionTrigger className={cn(
151
+ "py-2 rounded-sm hover:no-underline",
152
+ s.mobileItem,
153
+ active && activeClasses.mobileAccordion
154
+ )}>
155
+ <div className="flex items-center gap-2">
156
+ {itemWithItems.icon && <LucideIcon name={itemWithItems.icon} size={s.icon}/>}
157
+ <span>{itemWithItems.label}</span>
158
+ </div>
159
+ </AccordionTrigger>
160
+ <AccordionContent>
161
+ <div className="pl-4 flex flex-col gap-1 border-l ml-2">
162
+ {renderMobileItems(itemWithItems.items)}
163
+ </div>
164
+ </AccordionContent>
165
+ </AccordionItem>
166
+ )
167
+ }
168
+
169
+ return (
170
+ <Button
171
+ key={itemWithItems.label}
172
+ variant={active ? activeClasses.mobileButton : "ghost"}
173
+ className={cn("w-full justify-start gap-2 px-2 font-semibold border-b", s.mobileItem)}
174
+ onClick={() => {
175
+ handleItemAction(itemWithItems)
176
+ setOpen(false)
177
+ }}
178
+ >
179
+ {itemWithItems.icon && <LucideIcon name={itemWithItems.icon} size={s.icon}/>}
180
+ <span>{itemWithItems.label}</span>
181
+ </Button>
182
+ )
183
+ })
184
+ }
185
+
186
+ const allItems = selectedModule?.menu?.items || []
187
+
188
+ return (
189
+ <>
190
+ {/* Desktop navigation */}
191
+ <div className="flex-auto items-center hidden md:flex px-1.5 gap-3 animate-slide-in-down duration-150">
192
+
193
+ {selectedModule && (
194
+ <div className="font-bold text-base">
195
+ {selectedModule.name}
196
+ </div>
197
+ )}
198
+
199
+ <NavigationMenuRoot>
200
+ <NavigationMenuList>
201
+ {renderDesktopItems(allItems)}
202
+ </NavigationMenuList>
203
+ <NavigationMenuViewport/>
204
+ </NavigationMenuRoot>
205
+ </div>
206
+
207
+ {/* Mobile sheet */}
208
+ <Sheet open={open} onOpenChange={setOpen}>
209
+ <SheetTrigger asChild>
210
+ <Button variant="ghost" size="icon-sm" className="md:hidden">
211
+ <MenuIcon/>
212
+ </Button>
213
+ </SheetTrigger>
214
+ <SheetContent side="left"
215
+ className="w-[300px]! rounded-sm m-3 h-[92dvh]! px-6 bg-background/70 backdrop-blur-lg">
216
+ <SheetHeader className="pb-4">
217
+ <SheetTitle className="flex items-center gap-2">
218
+ {selectedModule?.icon && <LucideIcon name={selectedModule?.icon} size={5}/>}
219
+ {selectedModule?.name}
220
+ </SheetTitle>
221
+ </SheetHeader>
222
+ <div className="py-4 overflow-y-auto max-h-[calc(100vh-80px)]">
223
+ <Accordion type="multiple" className="w-full">
224
+ {selectedModule?.menu?.items.map((menu, index) => {
225
+ const active = isItemActive(menu)
226
+ if (menu.items && menu.items.length > 0) {
227
+ return (
228
+ <AccordionItem key={menu.label || index} value={menu.label || `item-${index}`}
229
+ className="border-b">
230
+ <AccordionTrigger className={cn(
231
+ "font-semibold hover:no-underline",
232
+ s.mobileItem,
233
+ active && activeClasses.mobileAccordion
234
+ )}>
235
+ <div className="flex items-center gap-2">
236
+ {menu.icon && <LucideIcon name={menu.icon} size={s.icon}/>}
237
+ <span>{menu.label}</span>
238
+ </div>
239
+ </AccordionTrigger>
240
+ <AccordionContent>
241
+ <div className="flex flex-col gap-1 py-1">
242
+ {renderMobileItems(menu.items)}
243
+ </div>
244
+ </AccordionContent>
245
+ </AccordionItem>
246
+ );
247
+ }
248
+
249
+ return (
250
+ <Button
251
+ key={menu.label || index}
252
+ variant={active ? activeClasses.mobileButton : "ghost"}
253
+ className={cn("w-full justify-start gap-2 px-0 font-semibold border-b rounded-sm", s.mobileItem)}
254
+ onClick={() => {
255
+ handleItemAction(menu)
256
+ setOpen(false)
257
+ }}
258
+ >
259
+ {menu.icon && <LucideIcon name={menu.icon} size={s.icon}/>}
260
+ <span>{menu.label}</span>
261
+ </Button>
262
+ );
263
+ })}
264
+ </Accordion>
265
+ </div>
266
+ </SheetContent>
267
+ </Sheet>
268
+ </>
269
+ )
270
+ }
@@ -0,0 +1,44 @@
1
+ "use client"
2
+
3
+ import {useModuleStore} from "../../../infrastructure/stores/module.store";
4
+ import {Popover, PopoverContent, PopoverTrigger} from "../../ui/popover";
5
+ import {LayoutGrid} from "lucide-react";
6
+ import {Tooltip, TooltipContent, TooltipTrigger} from "../../ui/tooltip";
7
+ import {ModuleDeclarationInterface} from "../../../domain/entities/module.interface";
8
+ import {ModuleItemLink} from "./module-item-link";
9
+
10
+
11
+ export function HeaderModulesAvailable() {
12
+ const {modules} = useModuleStore()
13
+ const available = modules
14
+ .filter(module => !module.isDefault)
15
+ .filter(module => module.isEnabled)
16
+ .filter(module => module.identifier !== 'mod.liorian.store')
17
+
18
+ return (
19
+ <div className={"flex flex-row items-center gap-2"}>
20
+ <Popover>
21
+ <Tooltip>
22
+ <TooltipTrigger asChild>
23
+ <PopoverTrigger className={"cursor-pointer"}>
24
+ <LayoutGrid className={"size-5"}/>
25
+ </PopoverTrigger>
26
+ </TooltipTrigger>
27
+ <TooltipContent side={'bottom'} align={'start'}>
28
+ Tous les modules disponibles
29
+ </TooltipContent>
30
+ </Tooltip>
31
+ <PopoverContent
32
+ side={'bottom'}
33
+ align={'start'}
34
+ className={"mt-2 p-1! grid grid-cols-1 w-[400px] gap-0 md:w-[500px] md:grid-cols-2 lg:w-[600px]"}>
35
+ {
36
+ available.map((module: ModuleDeclarationInterface) =>
37
+ <ModuleItemLink key={module.identifier} module={module}/>
38
+ )
39
+ }
40
+ </PopoverContent>
41
+ </Popover>
42
+ </div>
43
+ )
44
+ }
@@ -0,0 +1,52 @@
1
+ "use client"
2
+
3
+ import {useModuleStore} from "../../../infrastructure/stores/module.store";
4
+ import {useRecentModules} from "../../../infrastructure/hooks/use-recent-modules";
5
+ import {Popover, PopoverContent, PopoverTrigger} from "../../ui/popover";
6
+ import {History, TimelineIcon} from "lucide-react";
7
+ import {Tooltip, TooltipContent, TooltipTrigger} from "../../ui/tooltip";
8
+ import {ModuleDeclarationInterface} from "../../../domain/entities/module.interface";
9
+ import {ModuleItemLink} from "./module-item-link";
10
+
11
+ export function HeaderModulesRecents() {
12
+ const {modules} = useModuleStore()
13
+ const recentModules = useRecentModules()
14
+ const recent = recentModules
15
+ .map(rm => modules.find(m => m.identifier === rm.id))
16
+ .filter((m): m is ModuleDeclarationInterface => !!m)
17
+ // .filter(module => !module.isDefault)
18
+ .filter(module => module.isEnabled)
19
+
20
+ return (
21
+ <div className={"flex flex-row items-center gap-2"}>
22
+ <Popover>
23
+ <Tooltip>
24
+ <TooltipTrigger asChild>
25
+ <PopoverTrigger className={"cursor-pointer text-foreground/70"}>
26
+ <TimelineIcon className={"size-5"}/>
27
+ </PopoverTrigger>
28
+ </TooltipTrigger>
29
+ <TooltipContent side={'bottom'} align={'start'}>
30
+ Modules récents
31
+ </TooltipContent>
32
+ </Tooltip>
33
+ <PopoverContent
34
+ side={'bottom'}
35
+ align={'start'}
36
+ className={"mt-2 p-1! grid grid-cols-1 w-[200px] gap-0 md:w-[250px] md:grid-cols-1 lg:w-[300px]"}>
37
+ {
38
+ recent.length === 0 ? (
39
+ <div className="p-4 text-center text-xs text-muted-foreground col-span-full">
40
+ Aucun module récent
41
+ </div>
42
+ ) : (
43
+ recent.map((module: ModuleDeclarationInterface) =>
44
+ <ModuleItemLink key={module.identifier} module={module}/>
45
+ )
46
+ )
47
+ }
48
+ </PopoverContent>
49
+ </Popover>
50
+ </div>
51
+ )
52
+ }
@@ -0,0 +1,25 @@
1
+ "use client"
2
+
3
+ import {Store} from "lucide-react";
4
+ import {Tooltip, TooltipContent, TooltipTrigger} from "../../ui/tooltip";
5
+ import Link from "next/link";
6
+
7
+ export function HeaderModulesStore() {
8
+ return (
9
+ <div className={"flex flex-row items-center gap-2"}>
10
+ <Tooltip>
11
+ <TooltipTrigger asChild>
12
+ <Link
13
+ href={"/store/explorer"}
14
+ className={"text-foreground/70 hover:text-primary transition-colors"}
15
+ >
16
+ <Store className={"size-5"}/>
17
+ </Link>
18
+ </TooltipTrigger>
19
+ <TooltipContent side={'bottom'} align={'start'}>
20
+ Store
21
+ </TooltipContent>
22
+ </Tooltip>
23
+ </div>
24
+ )
25
+ }
@@ -0,0 +1,13 @@
1
+ import {HeaderTasksConnectedUser} from "./header-tasks-connected-user";
2
+ import {NotificationsPopover} from "../../components/notifications-popover";
3
+ import {LocalTime} from "../../components/local-time";
4
+
5
+ export function HeaderOptions() {
6
+ return (
7
+ <div className="flex flex-row items-center justify-center gap-1">
8
+ <NotificationsPopover/>
9
+ <LocalTime tauriOnly/>
10
+ <HeaderTasksConnectedUser/>
11
+ </div>
12
+ )
13
+ }
@@ -0,0 +1,146 @@
1
+ "use client"
2
+
3
+ import React, {useState} from "react";
4
+ import {useRouter} from "next/navigation";
5
+ import {AuthUserService} from "../../../application/service/auth-user.service";
6
+ import {OrganizationsApiService} from "../../../application/service/organizations-api-service";
7
+ import {authUserConnectedStore} from "../../../infrastructure/stores/auth-user-connected.store";
8
+ import {OrganizationInterface} from "../../../domain/entities/organization.interface";
9
+ import {
10
+ DropdownMenu,
11
+ DropdownMenuContent,
12
+ DropdownMenuGroup,
13
+ DropdownMenuItem,
14
+ DropdownMenuLabel,
15
+ DropdownMenuSeparator,
16
+ DropdownMenuTrigger,
17
+ } from "../../ui/dropdown-menu";
18
+ import {Building2Icon, CheckIcon, ChevronsUpDown} from "lucide-react";
19
+ import {toast} from "sonner";
20
+ import {cn} from "../../../infrastructure/utilities/utils";
21
+ import {Activity} from "../../components/activity";
22
+
23
+ export function HeaderOrganizationSelect() {
24
+ const router = useRouter();
25
+ const {currentOrganization, organizations: storeOrganizations, setCurrentOrganization} = authUserConnectedStore();
26
+ const [switchingOrgId, setSwitchingOrgId] = useState<string | null>(null);
27
+
28
+ const organization = currentOrganization || AuthUserService.getCurrentOrganization();
29
+ const organizations = (storeOrganizations && storeOrganizations.length > 0)
30
+ ? storeOrganizations
31
+ : AuthUserService.getOrganizations();
32
+
33
+ const handleSelectOrganization = async (org: OrganizationInterface) => {
34
+ if (org.id === organization?.id || switchingOrgId) return;
35
+
36
+ setSwitchingOrgId(org.id);
37
+
38
+ try {
39
+ // 1. Enregistrer l'organisation courante
40
+ await AuthUserService.setCurrentOrganization(org);
41
+ setCurrentOrganization(org);
42
+
43
+ // 2. Rechercher sa clé publique d'API
44
+ try {
45
+ const response = await OrganizationsApiService.getApiAccess(org.id);
46
+ const apiKeys = response?.data?.data;
47
+ const publicKey = apiKeys?.publicKeys && apiKeys.publicKeys.length > 0 ? apiKeys.publicKeys[0] : null;
48
+
49
+ if (publicKey) {
50
+ await AuthUserService.setApiKey(publicKey);
51
+ }
52
+ } catch (apiError) {
53
+ console.warn("Could not fetch API key for organization", apiError);
54
+ }
55
+
56
+ toast.success(`Organisation ${org.name} sélectionnée`);
57
+ router.refresh();
58
+ } catch (error) {
59
+ console.error("Organization Switch Error", error);
60
+ toast.error("Erreur lors du changement d'organisation");
61
+ } finally {
62
+ setSwitchingOrgId(null);
63
+ }
64
+ };
65
+
66
+ if (!organization && organizations.length === 0) {
67
+ return null;
68
+ }
69
+
70
+ return (
71
+ <div className="hidden sm:flex flex-row items-center justify-end">
72
+ <DropdownMenu>
73
+ <DropdownMenuTrigger asChild>
74
+ <button
75
+ type="button"
76
+ className="flex items-center gap-2 px-3 py-2 rounded-sm hover:bg-primary/10 hover:text-primary transition-colors text-left cursor-pointer outline-hidden"
77
+ >
78
+ <span className="text-sm leading-3 truncate max-w-80 font-medium">
79
+ {organization?.name || "Sélectionner une organisation"}
80
+ </span>
81
+ <Building2Icon size={16} className="shrink-0 text-muted-foreground"/>
82
+ <ChevronsUpDown size={16} className="shrink-0 text-muted-foreground"/>
83
+ </button>
84
+ </DropdownMenuTrigger>
85
+ <DropdownMenuContent side="bottom" align="end" className="w-64 sm:w-72 p-1">
86
+ {/*<DropdownMenuLabel className="px-2 py-1.5 text-xs text-muted-foreground font-semibold ">*/}
87
+ {/* Organisations*/}
88
+ {/*</DropdownMenuLabel>*/}
89
+ {/*<DropdownMenuSeparator/>*/}
90
+ <DropdownMenuGroup>
91
+ {organizations.length > 0 ? (
92
+ organizations.map((org) => {
93
+ const isSelected = organization?.id === org.id;
94
+ const isSwitching = switchingOrgId === org.id;
95
+
96
+ return (
97
+ <DropdownMenuItem
98
+ key={org.id}
99
+ onClick={() => handleSelectOrganization(org)}
100
+ disabled={!!switchingOrgId}
101
+ className={cn(
102
+ "flex items-center justify-between gap-2 px-2 py-2 cursor-pointer rounded-md",
103
+ isSelected && "bg-primary/10 text-primary font-medium"
104
+ )}
105
+ >
106
+ <div className="flex items-center gap-2.5 min-w-0 flex-1">
107
+ <div
108
+ className={cn(
109
+ "flex h-7 w-7 shrink-0 items-center justify-center rounded-md border text-xs",
110
+ isSelected
111
+ ? "bg-primary text-primary-foreground border-primary"
112
+ : "bg-muted text-muted-foreground border-border"
113
+ )}
114
+ >
115
+ <Building2Icon className="size-3.5"/>
116
+ </div>
117
+ <div className="flex flex-col min-w-0 flex-1">
118
+ <span className="text-sm leading-none truncate font-medium">
119
+ {org.name}
120
+ </span>
121
+ {org.description && (
122
+ <span className="text-[11px] text-muted-foreground truncate mt-0.5">
123
+ {org.description}
124
+ </span>
125
+ )}
126
+ </div>
127
+ </div>
128
+ {isSwitching ? (
129
+ <Activity.Loader size={16}/>
130
+ ) : isSelected ? (
131
+ <CheckIcon className="size-4 shrink-0 text-primary"/>
132
+ ) : null}
133
+ </DropdownMenuItem>
134
+ );
135
+ })
136
+ ) : (
137
+ <DropdownMenuItem disabled className="text-xs text-muted-foreground">
138
+ Aucune organisation disponible
139
+ </DropdownMenuItem>
140
+ )}
141
+ </DropdownMenuGroup>
142
+ </DropdownMenuContent>
143
+ </DropdownMenu>
144
+ </div>
145
+ );
146
+ }
@@ -0,0 +1,74 @@
1
+ "use client"
2
+
3
+ import {Fragment} from "react";
4
+ import {useRoutines} from "../../../infrastructure/routines/routine.hook";
5
+ import {Tooltip, TooltipContent, TooltipTrigger} from "../../ui/tooltip";
6
+ import {LucideIcon} from "../../icons/lucide";
7
+ import {Button} from "../../ui/button";
8
+ import {Badge} from "../../ui/badge";
9
+ import {Popover, PopoverContent, PopoverTrigger} from "../../ui/popover";
10
+
11
+ export function HeaderRoutines() {
12
+ const {getEntries} = useRoutines()
13
+ const routineEntries = [...getEntries()]
14
+
15
+ return (
16
+ <Fragment>
17
+ {routineEntries.map((routine, index) => {
18
+ const key = `${routine.id}-${index}`;
19
+ const label = routine.name || routine.id;
20
+ const iconName = routine.icon || 'Cog';
21
+
22
+ // Fonctionnalité optionnelle : la routine fournit le CONTENU du
23
+ // popover ; le système fournit l'icône déclencheur + conteneur.
24
+ const Content = routine.popover?.();
25
+
26
+ if (!Content) {
27
+ // Comportement historique : icône informative + tooltip
28
+ return (
29
+ <Tooltip key={key}>
30
+ <TooltipTrigger>
31
+ <div className={'px-2'}>
32
+ <LucideIcon name={iconName} size={4}/>
33
+ </div>
34
+ </TooltipTrigger>
35
+ <TooltipContent>
36
+ {label}
37
+ </TooltipContent>
38
+ </Tooltip>
39
+ );
40
+ }
41
+
42
+ return (
43
+ <Popover key={key}>
44
+ <Tooltip>
45
+ <TooltipTrigger asChild>
46
+ <PopoverTrigger asChild>
47
+ <Button variant="ghost" className="relative size-4" aria-label={label}>
48
+ <LucideIcon name={iconName} size={4}/>
49
+ <RoutineBadge value={routine.badge?.() ?? 0}/>
50
+ </Button>
51
+ </PopoverTrigger>
52
+ </TooltipTrigger>
53
+ <TooltipContent side="bottom">
54
+ {label}
55
+ </TooltipContent>
56
+ </Tooltip>
57
+ <PopoverContent className="w-96 p-0" side="bottom" align="end" sideOffset={8}>
58
+ <Content/>
59
+ </PopoverContent>
60
+ </Popover>
61
+ );
62
+ })}
63
+ </Fragment>
64
+ )
65
+ }
66
+
67
+ function RoutineBadge({value}: { value: number }) {
68
+ if (value <= 0) return null;
69
+ return (
70
+ <Badge className="absolute -top-0.5 -right-0.5 h-4 min-w-4 px-1 text-[10px]">
71
+ {value > 9 ? "9+" : value}
72
+ </Badge>
73
+ );
74
+ }