@tuturuuu/ui 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1208) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -2
  3. package/biome.json +5 -0
  4. package/components.json +1 -1
  5. package/jsr.json +9 -9
  6. package/package.json +422 -92
  7. package/postcss.config.mjs +1 -1
  8. package/src/components/ui/__tests__/avatar.test.tsx +53 -0
  9. package/src/components/ui/accordion.tsx +4 -4
  10. package/src/components/ui/alert-dialog.tsx +8 -6
  11. package/src/components/ui/alert.tsx +2 -2
  12. package/src/components/ui/avatar.tsx +6 -3
  13. package/src/components/ui/badge.tsx +6 -4
  14. package/src/components/ui/breadcrumb.tsx +3 -4
  15. package/src/components/ui/button.tsx +3 -3
  16. package/src/components/ui/calendar-app/calendar-client-page.tsx +69 -0
  17. package/src/components/ui/calendar-app/calendar-page-shell.tsx +59 -0
  18. package/src/components/ui/calendar-app/components/actions-dropdown.tsx +269 -0
  19. package/src/components/ui/calendar-app/components/auto-schedule-comprehensive-dialog.tsx +220 -0
  20. package/src/components/ui/calendar-app/components/calendar-connections-manager.tsx +2 -0
  21. package/src/components/ui/calendar-app/components/calendar-connections-unified.tsx +1433 -0
  22. package/src/components/ui/calendar-app/components/calendar-connections.tsx +843 -0
  23. package/src/components/ui/calendar-app/components/calendar-header-actions.tsx +67 -0
  24. package/src/components/ui/calendar-app/components/calendar-types.ts +46 -0
  25. package/src/components/ui/calendar-app/components/connected-accounts-dialog.tsx +353 -0
  26. package/src/components/ui/calendar-app/components/e2ee-status-badge.tsx +237 -0
  27. package/src/components/ui/calendar-app/components/experimental-feature-dialog.tsx +56 -0
  28. package/src/components/ui/calendar-app/components/habits-panel.tsx +332 -0
  29. package/src/components/ui/calendar-app/components/priority-dropdown.tsx +113 -0
  30. package/src/components/ui/calendar-app/components/priority-view.tsx +939 -0
  31. package/src/components/ui/calendar-app/components/quick-calendar-toggle.tsx +1 -0
  32. package/src/components/ui/calendar-app/components/quick-task-dialog.tsx +335 -0
  33. package/src/components/ui/calendar-app/components/quick-task-timer.tsx +112 -0
  34. package/src/components/ui/calendar-app/components/require-workspace-timezone-dialog.tsx +415 -0
  35. package/src/components/ui/calendar-app/components/scheduling-dialog.tsx +660 -0
  36. package/src/components/ui/calendar-app/components/sidebar/calendar-sidebar.tsx +128 -0
  37. package/src/components/ui/calendar-app/components/sidebar/index.tsx +1 -0
  38. package/src/components/ui/calendar-app/components/smart-schedule-button.tsx +117 -0
  39. package/src/components/ui/calendar-app/components/smart-schedule-preview-dialog.tsx +845 -0
  40. package/src/components/ui/calendar-app/components/smart-schedule-preview-panel.tsx +941 -0
  41. package/src/components/ui/calendar-app/components/sync-debug-panel.tsx +708 -0
  42. package/src/components/ui/calendar-app/components/task-fetcher.ts +51 -0
  43. package/src/components/ui/calendar-app/components/task-form.tsx +132 -0
  44. package/src/components/ui/calendar-app/components/task-list-form.tsx +84 -0
  45. package/src/components/ui/calendar-app/components/task-scheduler-panel.tsx +490 -0
  46. package/src/components/ui/calendar-app/components/tasks-sidebar-content.tsx +232 -0
  47. package/src/components/ui/calendar-app/components/tasks-sidebar.tsx +143 -0
  48. package/src/components/ui/calendar-app/components/test-event-generator-button.tsx +94 -0
  49. package/src/components/ui/calendar-app/components/time-tracker/components/active-session-card.tsx +113 -0
  50. package/src/components/ui/calendar-app/components/time-tracker/components/index.ts +3 -0
  51. package/src/components/ui/calendar-app/components/time-tracker/components/session-card.tsx +153 -0
  52. package/src/components/ui/calendar-app/components/time-tracker/components/stats-cards.tsx +58 -0
  53. package/src/components/ui/calendar-app/components/time-tracker/dialogs/create-task-dialog.tsx +190 -0
  54. package/src/components/ui/calendar-app/components/time-tracker/dialogs/delete-session-dialog.tsx +52 -0
  55. package/src/components/ui/calendar-app/components/time-tracker/dialogs/edit-session-dialog.tsx +173 -0
  56. package/src/components/ui/calendar-app/components/time-tracker/dialogs/index.ts +3 -0
  57. package/src/components/ui/calendar-app/components/time-tracker/hooks/index.ts +2 -0
  58. package/src/components/ui/calendar-app/components/time-tracker/hooks/use-sessions.ts +191 -0
  59. package/src/components/ui/calendar-app/components/time-tracker/hooks/use-time-tracker.ts +408 -0
  60. package/src/components/ui/calendar-app/components/time-tracker/index.tsx +902 -0
  61. package/src/components/ui/calendar-app/components/time-tracker/tabs/history-tab.tsx +28 -0
  62. package/src/components/ui/calendar-app/components/time-tracker/tabs/index.ts +2 -0
  63. package/src/components/ui/calendar-app/components/time-tracker/tabs/recent-sessions-tab.tsx +173 -0
  64. package/src/components/ui/calendar-app/components/time-tracker/time-tracker-trigger.tsx +50 -0
  65. package/src/components/ui/calendar-app/components/time-tracker/utils/category-colors.ts +38 -0
  66. package/src/components/ui/calendar-app/components/time-tracker/utils/format-time.ts +26 -0
  67. package/src/components/ui/calendar-app/components/time-tracker/utils/index.ts +2 -0
  68. package/src/components/ui/calendar-app/components/time-tracker.tsx +2040 -0
  69. package/src/components/ui/calendar-app/hooks/index.ts +9 -0
  70. package/src/components/ui/calendar-app/hooks/use-calendar-settings.ts +130 -0
  71. package/src/components/ui/calendar-app/hooks/use-e2ee.ts +283 -0
  72. package/src/components/ui/calendar.tsx +212 -64
  73. package/src/components/ui/card.tsx +3 -3
  74. package/src/components/ui/carousel.tsx +6 -5
  75. package/src/components/ui/chart.tsx +76 -24
  76. package/src/components/ui/chat/ai-message-markdown.tsx +59 -0
  77. package/src/components/ui/chat/ai-message-parts.tsx +176 -0
  78. package/src/components/ui/chat/ai-message-render-registry.tsx +203 -0
  79. package/src/components/ui/chat/ai-message-render-utils.ts +220 -0
  80. package/src/components/ui/chat/ai-message-tool-part.tsx +433 -0
  81. package/src/components/ui/chat/ai-message-tool-utils.ts +138 -0
  82. package/src/components/ui/chat/chat-agent-details-external-thread-panel.test.tsx +134 -0
  83. package/src/components/ui/chat/chat-agent-details-external-thread-panel.tsx +204 -0
  84. package/src/components/ui/chat/chat-agent-details-operations-panel.tsx +187 -0
  85. package/src/components/ui/chat/chat-agent-details-setup-panel.tsx +297 -0
  86. package/src/components/ui/chat/chat-agent-details-sidebar.test.tsx +136 -0
  87. package/src/components/ui/chat/chat-agent-details-sidebar.tsx +327 -0
  88. package/src/components/ui/chat/chat-agent-details-utils.test.ts +161 -0
  89. package/src/components/ui/chat/chat-agent-details-utils.tsx +280 -0
  90. package/src/components/ui/chat/chat-ai-credit-source-picker.tsx +210 -0
  91. package/src/components/ui/chat/chat-ai-details-panels.tsx +421 -0
  92. package/src/components/ui/chat/chat-ai-details-sidebar.tsx +206 -0
  93. package/src/components/ui/chat/chat-ai-models.test.ts +37 -0
  94. package/src/components/ui/chat/chat-ai-models.ts +23 -0
  95. package/src/components/ui/chat/chat-shared-content-sidebar.tsx +209 -0
  96. package/src/components/ui/chat/chat-sidebar-groups.test.ts +64 -0
  97. package/src/components/ui/chat/chat-sidebar-items.tsx +195 -0
  98. package/src/components/ui/chat/chat-sidebar-panel.tsx +183 -0
  99. package/src/components/ui/chat/chat-sidebar.tsx +505 -0
  100. package/src/components/ui/chat/chat-utils.test.ts +280 -0
  101. package/src/components/ui/chat/chat-workspace-header.tsx +429 -0
  102. package/src/components/ui/chat/chat-workspace.tsx +575 -0
  103. package/src/components/ui/chat/conversation-type-selector.tsx +51 -0
  104. package/src/components/ui/chat/create-conversation-dialog.test.tsx +89 -0
  105. package/src/components/ui/chat/create-conversation-dialog.tsx +377 -0
  106. package/src/components/ui/chat/directory-user-picker.tsx +160 -0
  107. package/src/components/ui/chat/friend-request-items.tsx +124 -0
  108. package/src/components/ui/chat/friend-requests-button.tsx +243 -0
  109. package/src/components/ui/chat/friend-requests-panel.tsx +116 -0
  110. package/src/components/ui/chat/hooks-ai.ts +73 -0
  111. package/src/components/ui/chat/hooks-attachments.ts +83 -0
  112. package/src/components/ui/chat/hooks-conversations.ts +205 -0
  113. package/src/components/ui/chat/hooks-directory.ts +45 -0
  114. package/src/components/ui/chat/hooks-friends.ts +74 -0
  115. package/src/components/ui/chat/hooks-messages.test.tsx +67 -0
  116. package/src/components/ui/chat/hooks-messages.ts +707 -0
  117. package/src/components/ui/chat/hooks-realtime.ts +157 -0
  118. package/src/components/ui/chat/hooks-shared-content.ts +56 -0
  119. package/src/components/ui/chat/hooks.ts +9 -0
  120. package/src/components/ui/chat/message-attachment-button.tsx +188 -0
  121. package/src/components/ui/chat/message-attachment-preview-dialog.tsx +141 -0
  122. package/src/components/ui/chat/message-bubble.tsx +372 -0
  123. package/src/components/ui/chat/message-composer.tsx +213 -0
  124. package/src/components/ui/chat/message-links.tsx +193 -0
  125. package/src/components/ui/chat/message-list.tsx +318 -0
  126. package/src/components/ui/chat/message-markdown.tsx +112 -0
  127. package/src/components/ui/chat/message-youtube.ts +48 -0
  128. package/src/components/ui/chat/query-keys.ts +48 -0
  129. package/src/components/ui/chat/utils.ts +284 -0
  130. package/src/components/ui/checkbox.tsx +24 -8
  131. package/src/components/ui/codeblock.tsx +7 -7
  132. package/src/components/ui/color-picker.tsx +9 -8
  133. package/src/components/ui/command.tsx +19 -11
  134. package/src/components/ui/context-menu.tsx +10 -10
  135. package/src/components/ui/currency-input.tsx +464 -0
  136. package/src/components/ui/custom/__tests__/facebook-mockup.test.tsx +291 -0
  137. package/src/components/ui/custom/__tests__/report-preview-pagination.test.ts +189 -0
  138. package/src/components/ui/custom/__tests__/report-preview.test.tsx +201 -0
  139. package/src/components/ui/custom/__tests__/settings-dialog-shell.test.tsx +144 -0
  140. package/src/components/ui/custom/__tests__/tuturuuu-logo.test.ts +10 -0
  141. package/src/components/ui/custom/autosize-textarea.tsx +3 -2
  142. package/src/components/ui/custom/calendar/core.tsx +11 -3
  143. package/src/components/ui/custom/calendar/day-cell.tsx +58 -44
  144. package/src/components/ui/custom/calendar/month-header.tsx +5 -7
  145. package/src/components/ui/custom/calendar/month-view.tsx +21 -9
  146. package/src/components/ui/custom/calendar/year-calendar.tsx +51 -10
  147. package/src/components/ui/custom/calendar/year-view.tsx +9 -5
  148. package/src/components/ui/custom/combobox.tsx +357 -89
  149. package/src/components/ui/custom/common-footer.tsx +89 -39
  150. package/src/components/ui/custom/compared-date-range-picker.tsx +478 -261
  151. package/src/components/ui/custom/data-pagination.tsx +446 -0
  152. package/src/components/ui/custom/date-input.tsx +4 -7
  153. package/src/components/ui/custom/education/certificates/certificate-viewer.tsx +98 -0
  154. package/src/components/ui/custom/education/certificates/download-button-pdf.tsx +82 -0
  155. package/src/components/ui/custom/education/certificates/types.ts +25 -0
  156. package/src/components/ui/custom/education/courses/course-card-view.tsx +252 -0
  157. package/src/components/ui/custom/education/courses/course-form.tsx +248 -0
  158. package/src/components/ui/custom/education/courses/course-header.tsx +38 -0
  159. package/src/components/ui/custom/education/courses/course-pagination.tsx +62 -0
  160. package/src/components/ui/custom/education/courses/course-row-actions.tsx +130 -0
  161. package/src/components/ui/custom/education/modules/content-section.tsx +73 -0
  162. package/src/components/ui/custom/education/modules/course-module-form.tsx +234 -0
  163. package/src/components/ui/custom/education/modules/course-module-row-actions.tsx +126 -0
  164. package/src/components/ui/custom/education/modules/link-button.tsx +66 -0
  165. package/src/components/ui/custom/education/modules/module-toggle.tsx +115 -0
  166. package/src/components/ui/custom/education/modules/resources/delete-resource.tsx +46 -0
  167. package/src/components/ui/custom/education/modules/resources/file-display.tsx +84 -0
  168. package/src/components/ui/custom/education/modules/resources/file-upload-form.tsx +544 -0
  169. package/src/components/ui/custom/education/modules/resources/pdf-viewer.tsx +119 -0
  170. package/src/components/ui/custom/education/modules/youtube/delete-link-button.tsx +62 -0
  171. package/src/components/ui/custom/education/modules/youtube/embed.tsx +20 -0
  172. package/src/components/ui/custom/education/modules/youtube/form.tsx +112 -0
  173. package/src/components/ui/custom/education/shell/education-content-surface.tsx +31 -0
  174. package/src/components/ui/custom/education/shell/education-kpi-strip.tsx +48 -0
  175. package/src/components/ui/custom/education/shell/education-page-header.tsx +56 -0
  176. package/src/components/ui/custom/empty-card.tsx +2 -2
  177. package/src/components/ui/custom/facebook-mockup/defaults.ts +81 -0
  178. package/src/components/ui/custom/facebook-mockup/facebook-mockup.tsx +313 -0
  179. package/src/components/ui/custom/facebook-mockup/form.tsx +629 -0
  180. package/src/components/ui/custom/facebook-mockup/image-upload-field.tsx +111 -0
  181. package/src/components/ui/custom/facebook-mockup/preview.tsx +760 -0
  182. package/src/components/ui/custom/facebook-mockup/types.ts +44 -0
  183. package/src/components/ui/custom/feature-summary.tsx +61 -7
  184. package/src/components/ui/custom/file-uploader.tsx +18 -15
  185. package/src/components/ui/custom/get-started-button.tsx +33 -0
  186. package/src/components/ui/custom/get-started-gradient-button.tsx +23 -0
  187. package/src/components/ui/custom/gradient-headline.tsx +25 -0
  188. package/src/components/ui/custom/icon-picker/icon-options.ts +24240 -0
  189. package/src/components/ui/custom/icon-picker/icon-picker.tsx +608 -0
  190. package/src/components/ui/custom/icon-picker/index.ts +45 -0
  191. package/src/components/ui/custom/icon-picker/types.ts +133 -0
  192. package/src/components/ui/custom/input-field.tsx +3 -1
  193. package/src/components/ui/custom/language-dropdown-item.tsx +55 -0
  194. package/src/components/ui/custom/language-dropdown-wrapper.tsx +34 -0
  195. package/src/components/ui/custom/language-toggle.tsx +43 -0
  196. package/src/components/ui/custom/language-wrapper.tsx +23 -0
  197. package/src/components/ui/custom/lead-generation-preview.tsx +310 -0
  198. package/src/components/ui/custom/loading-indicator.tsx +3 -0
  199. package/src/components/ui/custom/loading.tsx +8 -0
  200. package/src/components/ui/custom/logo-title.tsx +20 -0
  201. package/src/components/ui/custom/missed-entry/image-upload-section.tsx +192 -0
  202. package/src/components/ui/custom/modifiable-dialog-trigger.tsx +13 -7
  203. package/src/components/ui/custom/month-picker.tsx +8 -8
  204. package/src/components/ui/custom/nav-link.tsx +474 -0
  205. package/src/components/ui/custom/nav.tsx +86 -0
  206. package/src/components/ui/custom/navigation.tsx +192 -0
  207. package/src/components/ui/custom/notification-popover-client.tsx +758 -0
  208. package/src/components/ui/custom/production-indicator.tsx +22 -0
  209. package/src/components/ui/custom/qr/color.tsx +36 -0
  210. package/src/components/ui/custom/qr/display.tsx +82 -0
  211. package/src/components/ui/custom/qr/formats.tsx +52 -0
  212. package/src/components/ui/custom/qr/image-upload.tsx +440 -0
  213. package/src/components/ui/custom/qr/qr.tsx +170 -0
  214. package/src/components/ui/custom/qr/styles.tsx +133 -0
  215. package/src/components/ui/custom/qr/workspace-title.tsx +47 -0
  216. package/src/components/ui/custom/report-preview-pagination.ts +579 -0
  217. package/src/components/ui/custom/report-preview.tsx +745 -126
  218. package/src/components/ui/custom/search-bar.tsx +8 -12
  219. package/src/components/ui/custom/select-field.tsx +5 -3
  220. package/src/components/ui/custom/settings/appearance-settings.tsx +129 -0
  221. package/src/components/ui/custom/settings/lunar-calendar-settings.tsx +36 -0
  222. package/src/components/ui/custom/settings/sidebar-settings.tsx +135 -0
  223. package/src/components/ui/custom/settings/task-settings.tsx +236 -0
  224. package/src/components/ui/custom/settings-dialog-shell.tsx +481 -0
  225. package/src/components/ui/custom/settings-item-tab.tsx +29 -0
  226. package/src/components/ui/custom/sidebar-context.tsx +148 -0
  227. package/src/components/ui/custom/sidebar-footer-actions.tsx +337 -0
  228. package/src/components/ui/custom/staff-toolbar.tsx +16 -0
  229. package/src/components/ui/custom/structure.tsx +213 -0
  230. package/src/components/ui/custom/system-language-dropdown-item.tsx +46 -0
  231. package/src/components/ui/custom/system-language-wrapper.tsx +15 -0
  232. package/src/components/ui/custom/tables/custom-data-table.tsx +130 -0
  233. package/src/components/ui/custom/tables/data-table-column-header.tsx +9 -7
  234. package/src/components/ui/custom/tables/data-table-create-button.tsx +2 -2
  235. package/src/components/ui/custom/tables/data-table-faceted-filter.tsx +5 -5
  236. package/src/components/ui/custom/tables/data-table-pagination.tsx +69 -91
  237. package/src/components/ui/custom/tables/data-table-refresh-button.tsx +2 -2
  238. package/src/components/ui/custom/tables/data-table-toolbar.tsx +42 -19
  239. package/src/components/ui/custom/tables/data-table-view-options.tsx +27 -15
  240. package/src/components/ui/custom/tables/data-table.tsx +150 -56
  241. package/src/components/ui/custom/tailwind-indicator.tsx +14 -0
  242. package/src/components/ui/custom/theme-dropdown-items.tsx +90 -0
  243. package/src/components/ui/custom/theme-toggle.tsx +35 -0
  244. package/src/components/ui/custom/tuturuuu-logo.tsx +16 -0
  245. package/src/components/ui/custom/uploaded-files-card.tsx +1 -0
  246. package/src/components/ui/custom/user-filters.tsx +487 -0
  247. package/src/components/ui/custom/version-badge.test.tsx +102 -0
  248. package/src/components/ui/custom/version-badge.tsx +169 -0
  249. package/src/components/ui/custom/view-toggle.tsx +63 -0
  250. package/src/components/ui/custom/workspace-access/adapters.test.ts +31 -0
  251. package/src/components/ui/custom/workspace-access/adapters.ts +169 -0
  252. package/src/components/ui/custom/workspace-access/index.ts +32 -0
  253. package/src/components/ui/custom/workspace-access/member-filter-utils.test.ts +175 -0
  254. package/src/components/ui/custom/workspace-access/member-filter-utils.ts +190 -0
  255. package/src/components/ui/custom/workspace-access/types.ts +150 -0
  256. package/src/components/ui/custom/workspace-access/workspace-access-client-pages.tsx +26 -0
  257. package/src/components/ui/custom/workspace-access/workspace-access-default-role-card.tsx +92 -0
  258. package/src/components/ui/custom/workspace-access/workspace-access-invite-dialog.tsx +102 -0
  259. package/src/components/ui/custom/workspace-access/workspace-access-labels.ts +53 -0
  260. package/src/components/ui/custom/workspace-access/workspace-access-member-row.tsx +249 -0
  261. package/src/components/ui/custom/workspace-access/workspace-access-members.tsx +84 -0
  262. package/src/components/ui/custom/workspace-access/workspace-access-page-header.tsx +72 -0
  263. package/src/components/ui/custom/workspace-access/workspace-access-page.tsx +388 -0
  264. package/src/components/ui/custom/workspace-access/workspace-access-people-filters.tsx +200 -0
  265. package/src/components/ui/custom/workspace-access/workspace-access-permission-checklist.tsx +87 -0
  266. package/src/components/ui/custom/workspace-access/workspace-access-permission-preview.tsx +35 -0
  267. package/src/components/ui/custom/workspace-access/workspace-access-role-editor-dialog.tsx +180 -0
  268. package/src/components/ui/custom/workspace-access/workspace-access-role-editor-labels.ts +33 -0
  269. package/src/components/ui/custom/workspace-access/workspace-access-roles.tsx +171 -0
  270. package/src/components/ui/custom/workspace-access/workspace-access-tabs-toolbar.tsx +71 -0
  271. package/src/components/ui/custom/workspace-select.tsx +849 -0
  272. package/src/components/ui/custom/workspace-wrapper.tsx +142 -0
  273. package/src/components/ui/date-time-picker.tsx +706 -0
  274. package/src/components/ui/dialog.tsx +23 -14
  275. package/src/components/ui/diff-viewer.tsx +921 -0
  276. package/src/components/ui/drawer.tsx +5 -5
  277. package/src/components/ui/dropdown-menu.tsx +18 -10
  278. package/src/components/ui/finance/analytics/analytics-date-controls.tsx +173 -0
  279. package/src/components/ui/finance/analytics/analytics-page.test.tsx +182 -0
  280. package/src/components/ui/finance/analytics/analytics-page.tsx +296 -0
  281. package/src/components/ui/finance/analytics/balance-trend-chart.tsx +288 -0
  282. package/src/components/ui/finance/analytics/category-spending-chart.test.tsx +75 -0
  283. package/src/components/ui/finance/analytics/category-spending-chart.tsx +213 -0
  284. package/src/components/ui/finance/analytics/income-expense-chart-utils.ts +52 -0
  285. package/src/components/ui/finance/analytics/income-expense-chart.tsx +242 -0
  286. package/src/components/ui/finance/analytics/income-expense-view-mode-control.tsx +37 -0
  287. package/src/components/ui/finance/analytics/spending-trends-chart.tsx +156 -0
  288. package/src/components/ui/finance/budgets/budget-alerts.test.tsx +133 -0
  289. package/src/components/ui/finance/budgets/budget-alerts.tsx +111 -0
  290. package/src/components/ui/finance/budgets/budget-card.test.tsx +72 -0
  291. package/src/components/ui/finance/budgets/budget-card.tsx +233 -0
  292. package/src/components/ui/finance/budgets/budgets-page.test.tsx +56 -0
  293. package/src/components/ui/finance/budgets/budgets-page.tsx +179 -0
  294. package/src/components/ui/finance/budgets/form-fields.tsx +304 -0
  295. package/src/components/ui/finance/budgets/form-schema.ts +39 -0
  296. package/src/components/ui/finance/budgets/form.tsx +141 -0
  297. package/src/components/ui/finance/categories-tags-tabs.tsx +80 -0
  298. package/src/components/ui/finance/debts/debt-loan-card.test.tsx +75 -0
  299. package/src/components/ui/finance/debts/debt-loan-card.tsx +212 -0
  300. package/src/components/ui/finance/debts/debt-loan-detail-cards.test.tsx +89 -0
  301. package/src/components/ui/finance/debts/debt-loan-detail-cards.tsx +207 -0
  302. package/src/components/ui/finance/debts/debt-loan-detail-page.tsx +301 -0
  303. package/src/components/ui/finance/debts/debt-loan-form-schema.ts +30 -0
  304. package/src/components/ui/finance/debts/debt-loan-form.tsx +394 -0
  305. package/src/components/ui/finance/debts/debt-loan-list.tsx +58 -0
  306. package/src/components/ui/finance/debts/debt-loan-summary.tsx +94 -0
  307. package/src/components/ui/finance/debts/debts-page.test.tsx +97 -0
  308. package/src/components/ui/finance/debts/debts-page.tsx +230 -0
  309. package/src/components/ui/finance/debts/index.ts +6 -0
  310. package/src/components/ui/finance/debts/query-invalidation.test.ts +62 -0
  311. package/src/components/ui/finance/debts/query-invalidation.ts +44 -0
  312. package/src/components/ui/finance/finance-layout.tsx +98 -0
  313. package/src/components/ui/finance/finance-overview-metrics.tsx +120 -0
  314. package/src/components/ui/finance/finance-page.tsx +169 -0
  315. package/src/components/ui/finance/finance-route-context.tsx +50 -0
  316. package/src/components/ui/finance/invoices/attendance-calendar.tsx +247 -0
  317. package/src/components/ui/finance/invoices/charts/invoice-totals-chart.test.tsx +67 -0
  318. package/src/components/ui/finance/invoices/charts/invoice-totals-chart.tsx +868 -0
  319. package/src/components/ui/finance/invoices/columns.test.tsx +66 -0
  320. package/src/components/ui/finance/invoices/columns.tsx +365 -0
  321. package/src/components/ui/finance/invoices/components/invoice-blocked-state.tsx +30 -0
  322. package/src/components/ui/finance/invoices/components/invoice-checkout-summary.tsx +120 -0
  323. package/src/components/ui/finance/invoices/components/invoice-content-editor.tsx +71 -0
  324. package/src/components/ui/finance/invoices/components/invoice-customer-select-card.tsx +342 -0
  325. package/src/components/ui/finance/invoices/components/invoice-payment-settings.tsx +216 -0
  326. package/src/components/ui/finance/invoices/components/invoice-user-history-accordion.tsx +219 -0
  327. package/src/components/ui/finance/invoices/components/subscription-attendance-summary.tsx +272 -0
  328. package/src/components/ui/finance/invoices/components/subscription-group-selector.tsx +346 -0
  329. package/src/components/ui/finance/invoices/create-promotion-dialog.tsx +67 -0
  330. package/src/components/ui/finance/invoices/export-dialog-content.tsx +492 -0
  331. package/src/components/ui/finance/invoices/hooks/use-best-promotion-selection.ts +119 -0
  332. package/src/components/ui/finance/invoices/hooks/use-invoice-analytics.ts +79 -0
  333. package/src/components/ui/finance/invoices/hooks/use-invoice-rounding.ts +33 -0
  334. package/src/components/ui/finance/invoices/hooks/use-invoice-subtotal.ts +13 -0
  335. package/src/components/ui/finance/invoices/hooks/use-subscription-auto-selection.ts +412 -0
  336. package/src/components/ui/finance/invoices/hooks/use-subscription-invoice-content.ts +191 -0
  337. package/src/components/ui/finance/invoices/hooks.ts +878 -0
  338. package/src/components/ui/finance/invoices/internal-api.ts +466 -0
  339. package/src/components/ui/finance/invoices/invoice-analytics.tsx +167 -0
  340. package/src/components/ui/finance/invoices/invoice-page.tsx +468 -0
  341. package/src/components/ui/finance/invoices/invoice-visibility-format.test.ts +90 -0
  342. package/src/components/ui/finance/invoices/invoice-visibility-format.ts +67 -0
  343. package/src/components/ui/finance/invoices/invoiceId/compact-invoice-template.tsx +172 -0
  344. package/src/components/ui/finance/invoices/invoiceId/full-invoice-template.tsx +349 -0
  345. package/src/components/ui/finance/invoices/invoiceId/invoice-card.tsx +360 -0
  346. package/src/components/ui/finance/invoices/invoiceId/invoice-details-page.test.tsx +227 -0
  347. package/src/components/ui/finance/invoices/invoiceId/invoice-details-page.tsx +409 -0
  348. package/src/components/ui/finance/invoices/invoiceId/invoice-edit-form.tsx +161 -0
  349. package/src/components/ui/finance/invoices/invoiceId/product-card.tsx +90 -0
  350. package/src/components/ui/finance/invoices/invoiceId/promotion-card.tsx +76 -0
  351. package/src/components/ui/finance/invoices/invoices-table.tsx +284 -0
  352. package/src/components/ui/finance/invoices/new-invoice-page.tsx +215 -0
  353. package/src/components/ui/finance/invoices/pending-columns.tsx +308 -0
  354. package/src/components/ui/finance/invoices/pending-invoices-tab.tsx +43 -0
  355. package/src/components/ui/finance/invoices/pending-invoices-table.tsx +258 -0
  356. package/src/components/ui/finance/invoices/product-selection.test.tsx +78 -0
  357. package/src/components/ui/finance/invoices/product-selection.tsx +345 -0
  358. package/src/components/ui/finance/invoices/promotion-form.tsx +352 -0
  359. package/src/components/ui/finance/invoices/query-invalidation.ts +65 -0
  360. package/src/components/ui/finance/invoices/row-actions.tsx +148 -0
  361. package/src/components/ui/finance/invoices/standard-invoice.tsx +595 -0
  362. package/src/components/ui/finance/invoices/subscription-invoice.tsx +1009 -0
  363. package/src/components/ui/finance/invoices/types.ts +93 -0
  364. package/src/components/ui/finance/invoices/user-filter-wrapper.tsx +59 -0
  365. package/src/components/ui/finance/invoices/utils.test.ts +165 -0
  366. package/src/components/ui/finance/invoices/utils.ts +484 -0
  367. package/src/components/ui/finance/invoices/wallet-filter-wrapper.tsx +47 -0
  368. package/src/components/ui/finance/recurring/form-fields.tsx +142 -0
  369. package/src/components/ui/finance/recurring/form-schedule-fields.tsx +112 -0
  370. package/src/components/ui/finance/recurring/form-schema.ts +32 -0
  371. package/src/components/ui/finance/recurring/form.tsx +130 -0
  372. package/src/components/ui/finance/recurring/recurring-sections.tsx +141 -0
  373. package/src/components/ui/finance/recurring/recurring-transaction-card.tsx +152 -0
  374. package/src/components/ui/finance/recurring/recurring-transactions-page.test.tsx +87 -0
  375. package/src/components/ui/finance/recurring/recurring-transactions-page.tsx +154 -0
  376. package/src/components/ui/finance/recurring/upcoming-transaction-card.tsx +84 -0
  377. package/src/components/ui/finance/shared/charts/category-breakdown-chart-body.tsx +118 -0
  378. package/src/components/ui/finance/shared/charts/category-breakdown-chart-controls.tsx +146 -0
  379. package/src/components/ui/finance/shared/charts/category-breakdown-chart-legend.tsx +49 -0
  380. package/src/components/ui/finance/shared/charts/category-breakdown-chart-tooltip.tsx +109 -0
  381. package/src/components/ui/finance/shared/charts/category-breakdown-chart-types.ts +24 -0
  382. package/src/components/ui/finance/shared/charts/category-breakdown-chart-utils.ts +207 -0
  383. package/src/components/ui/finance/shared/charts/category-breakdown-chart.tsx +263 -0
  384. package/src/components/ui/finance/shared/charts/daily-total-chart-client.tsx +384 -0
  385. package/src/components/ui/finance/shared/charts/daily-total-chart.tsx +299 -0
  386. package/src/components/ui/finance/shared/charts/monthly-total-chart-client.tsx +391 -0
  387. package/src/components/ui/finance/shared/charts/monthly-total-chart.tsx +296 -0
  388. package/src/components/ui/finance/shared/charts/use-finance-confidential-visibility.ts +5 -0
  389. package/src/components/ui/finance/shared/confidential-toggle.tsx +78 -0
  390. package/src/components/ui/finance/shared/create-dialog-feature-summary.tsx +23 -0
  391. package/src/components/ui/finance/shared/dashboard-header.tsx +19 -0
  392. package/src/components/ui/finance/shared/date-picker.tsx +74 -0
  393. package/src/components/ui/finance/shared/date-range-filter-wrapper.tsx +86 -0
  394. package/src/components/ui/finance/shared/date-range-picker.tsx +42 -0
  395. package/src/components/ui/finance/shared/empty-state.tsx +41 -0
  396. package/src/components/ui/finance/shared/filter.tsx +267 -0
  397. package/src/components/ui/finance/shared/finance-display-amount.tsx +25 -0
  398. package/src/components/ui/finance/shared/loaders/statistics.tsx +18 -0
  399. package/src/components/ui/finance/shared/loaders/table-skeleton.tsx +5 -0
  400. package/src/components/ui/finance/shared/metrics.tsx +69 -0
  401. package/src/components/ui/finance/shared/month-picker.tsx +177 -0
  402. package/src/components/ui/finance/shared/month-range-picker.tsx +50 -0
  403. package/src/components/ui/finance/shared/next-charts.tsx +77 -0
  404. package/src/components/ui/finance/shared/numbers-visibility-toggle.test.tsx +38 -0
  405. package/src/components/ui/finance/shared/numbers-visibility-toggle.tsx +43 -0
  406. package/src/components/ui/finance/shared/quick-actions.tsx +143 -0
  407. package/src/components/ui/finance/shared/use-finance-confidential-visibility.ts +68 -0
  408. package/src/components/ui/finance/shared/year-picker.tsx +178 -0
  409. package/src/components/ui/finance/shared/year-range-picker.tsx +50 -0
  410. package/src/components/ui/finance/statistics/card.tsx +195 -0
  411. package/src/components/ui/finance/statistics/expense.tsx +63 -0
  412. package/src/components/ui/finance/statistics/income.tsx +63 -0
  413. package/src/components/ui/finance/statistics/invoices.tsx +77 -0
  414. package/src/components/ui/finance/statistics/monthly-expense.tsx +63 -0
  415. package/src/components/ui/finance/statistics/monthly-income.tsx +63 -0
  416. package/src/components/ui/finance/statistics/total-balance.test.tsx +79 -0
  417. package/src/components/ui/finance/statistics/total-balance.tsx +64 -0
  418. package/src/components/ui/finance/statistics/transaction-categories.tsx +59 -0
  419. package/src/components/ui/finance/statistics/transactions.tsx +90 -0
  420. package/src/components/ui/finance/statistics/wallets.tsx +55 -0
  421. package/src/components/ui/finance/tags/tag-badge.tsx +36 -0
  422. package/src/components/ui/finance/tags/tag-manager.test.tsx +128 -0
  423. package/src/components/ui/finance/tags/tag-manager.tsx +646 -0
  424. package/src/components/ui/finance/transactions/TRANSACTIONS_UI_REVAMP.md +328 -0
  425. package/src/components/ui/finance/transactions/UI_IMPROVEMENTS.md +444 -0
  426. package/src/components/ui/finance/transactions/__tests__/export-utils.test.ts +167 -0
  427. package/src/components/ui/finance/transactions/categories/amount-filter-wrapper.tsx +55 -0
  428. package/src/components/ui/finance/transactions/categories/amount-filter.tsx +135 -0
  429. package/src/components/ui/finance/transactions/categories/categories-data-table.tsx +274 -0
  430. package/src/components/ui/finance/transactions/categories/columns.test.tsx +113 -0
  431. package/src/components/ui/finance/transactions/categories/columns.tsx +253 -0
  432. package/src/components/ui/finance/transactions/categories/form.tsx +388 -0
  433. package/src/components/ui/finance/transactions/categories/hooks.test.tsx +72 -0
  434. package/src/components/ui/finance/transactions/categories/hooks.ts +95 -0
  435. package/src/components/ui/finance/transactions/categories/row-actions.tsx +132 -0
  436. package/src/components/ui/finance/transactions/categories/transactions-categories-page.tsx +96 -0
  437. package/src/components/ui/finance/transactions/categories/type-filter-wrapper.tsx +39 -0
  438. package/src/components/ui/finance/transactions/categories/type-filter.tsx +148 -0
  439. package/src/components/ui/finance/transactions/category-filter-wrapper.tsx +41 -0
  440. package/src/components/ui/finance/transactions/category-filter.tsx +252 -0
  441. package/src/components/ui/finance/transactions/columns.test.tsx +119 -0
  442. package/src/components/ui/finance/transactions/columns.tsx +313 -0
  443. package/src/components/ui/finance/transactions/confidential-field.test.tsx +32 -0
  444. package/src/components/ui/finance/transactions/confidential-field.tsx +289 -0
  445. package/src/components/ui/finance/transactions/export-dialog-content.tsx +393 -0
  446. package/src/components/ui/finance/transactions/export-utils.ts +99 -0
  447. package/src/components/ui/finance/transactions/form-basic-tab.tsx +360 -0
  448. package/src/components/ui/finance/transactions/form-content-dialog.tsx +163 -0
  449. package/src/components/ui/finance/transactions/form-more-tab.tsx +203 -0
  450. package/src/components/ui/finance/transactions/form-schema.ts +52 -0
  451. package/src/components/ui/finance/transactions/form-types.ts +39 -0
  452. package/src/components/ui/finance/transactions/form-utils.tsx +60 -0
  453. package/src/components/ui/finance/transactions/form.test.tsx +151 -0
  454. package/src/components/ui/finance/transactions/form.tsx +942 -0
  455. package/src/components/ui/finance/transactions/hooks/use-filter-reset.ts +27 -0
  456. package/src/components/ui/finance/transactions/infinite-transactions-list.tsx +1127 -0
  457. package/src/components/ui/finance/transactions/internal-api.ts +148 -0
  458. package/src/components/ui/finance/transactions/money-lover-import-dialog-utils.test.ts +16 -0
  459. package/src/components/ui/finance/transactions/money-lover-import-dialog-utils.ts +17 -0
  460. package/src/components/ui/finance/transactions/money-lover-import-dialog.tsx +908 -0
  461. package/src/components/ui/finance/transactions/period-charts/activity-distribution-chart.tsx +315 -0
  462. package/src/components/ui/finance/transactions/period-charts/category-breakdown-dialog.tsx +820 -0
  463. package/src/components/ui/finance/transactions/period-charts/category-donut-chart.tsx +609 -0
  464. package/src/components/ui/finance/transactions/period-charts/index.ts +4 -0
  465. package/src/components/ui/finance/transactions/period-charts/period-breakdown-panel.tsx +492 -0
  466. package/src/components/ui/finance/transactions/query-invalidation.test.ts +91 -0
  467. package/src/components/ui/finance/transactions/query-invalidation.ts +116 -0
  468. package/src/components/ui/finance/transactions/row-actions.tsx +145 -0
  469. package/src/components/ui/finance/transactions/tag-filter-wrapper.tsx +40 -0
  470. package/src/components/ui/finance/transactions/tag-filter.test.tsx +49 -0
  471. package/src/components/ui/finance/transactions/tag-filter.tsx +171 -0
  472. package/src/components/ui/finance/transactions/transaction-attachments-field.tsx +787 -0
  473. package/src/components/ui/finance/transactions/transaction-card.tsx +576 -0
  474. package/src/components/ui/finance/transactions/transaction-edit-dialog.test.tsx +101 -0
  475. package/src/components/ui/finance/transactions/transaction-edit-dialog.tsx +947 -0
  476. package/src/components/ui/finance/transactions/transaction-statistics.test.tsx +58 -0
  477. package/src/components/ui/finance/transactions/transaction-statistics.tsx +280 -0
  478. package/src/components/ui/finance/transactions/transaction-type-filter-wrapper.tsx +40 -0
  479. package/src/components/ui/finance/transactions/transaction-type-filter.tsx +95 -0
  480. package/src/components/ui/finance/transactions/transactionId/bill.tsx +307 -0
  481. package/src/components/ui/finance/transactions/transactionId/objects.tsx +149 -0
  482. package/src/components/ui/finance/transactions/transactionId/row-actions.tsx +263 -0
  483. package/src/components/ui/finance/transactions/transactionId/transaction-details-client-page.tsx +334 -0
  484. package/src/components/ui/finance/transactions/transactionId/transaction-details-page.tsx +76 -0
  485. package/src/components/ui/finance/transactions/transactions-create-summary.tsx +56 -0
  486. package/src/components/ui/finance/transactions/transactions-infinite-page.tsx +213 -0
  487. package/src/components/ui/finance/transactions/transactions-page.tsx +116 -0
  488. package/src/components/ui/finance/transactions/transfer-fields.tsx +194 -0
  489. package/src/components/ui/finance/transactions/user-filter-wrapper.tsx +42 -0
  490. package/src/components/ui/finance/transactions/user-filter.test.tsx +66 -0
  491. package/src/components/ui/finance/transactions/user-filter.tsx +282 -0
  492. package/src/components/ui/finance/transactions/view-mode-toggle.tsx +124 -0
  493. package/src/components/ui/finance/transactions/wallet-filter-wrapper.tsx +41 -0
  494. package/src/components/ui/finance/transactions/wallet-filter.test.tsx +52 -0
  495. package/src/components/ui/finance/transactions/wallet-filter.tsx +204 -0
  496. package/src/components/ui/finance/wallets/columns.tsx +324 -0
  497. package/src/components/ui/finance/wallets/form.test.tsx +78 -0
  498. package/src/components/ui/finance/wallets/form.tsx +491 -0
  499. package/src/components/ui/finance/wallets/query-invalidation.ts +58 -0
  500. package/src/components/ui/finance/wallets/row-actions.tsx +166 -0
  501. package/src/components/ui/finance/wallets/wallet-form-schema.ts +63 -0
  502. package/src/components/ui/finance/wallets/wallet-icon-display.tsx +71 -0
  503. package/src/components/ui/finance/wallets/wallet-icon-image-picker.tsx +369 -0
  504. package/src/components/ui/finance/wallets/wallet-images.ts +180 -0
  505. package/src/components/ui/finance/wallets/walletId/credit-wallet-summary.tsx +265 -0
  506. package/src/components/ui/finance/wallets/walletId/interest/index.ts +18 -0
  507. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-chart.tsx +296 -0
  508. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-detection-banner.tsx +77 -0
  509. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-disable-dialog.tsx +55 -0
  510. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-hero.tsx +149 -0
  511. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-pending-deposits.tsx +185 -0
  512. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-projections.tsx +259 -0
  513. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-rate-dialog.tsx +89 -0
  514. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-rate-history.tsx +116 -0
  515. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-section.tsx +260 -0
  516. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-settings.tsx +427 -0
  517. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-setup-dialog.tsx +206 -0
  518. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-summary.tsx +244 -0
  519. package/src/components/ui/finance/wallets/walletId/interest/wallet-interest-transparency.tsx +176 -0
  520. package/src/components/ui/finance/wallets/walletId/wallet-delete-button.test.tsx +78 -0
  521. package/src/components/ui/finance/wallets/walletId/wallet-delete-button.tsx +99 -0
  522. package/src/components/ui/finance/wallets/walletId/wallet-details-actions.tsx +119 -0
  523. package/src/components/ui/finance/wallets/walletId/wallet-details-amount.tsx +36 -0
  524. package/src/components/ui/finance/wallets/walletId/wallet-details-page.test.tsx +161 -0
  525. package/src/components/ui/finance/wallets/walletId/wallet-details-page.tsx +365 -0
  526. package/src/components/ui/finance/wallets/walletId/wallet-role-access-dialog.tsx +45 -0
  527. package/src/components/ui/finance/wallets/walletId/wallet-role-access.tsx +538 -0
  528. package/src/components/ui/finance/wallets/wallets-data-table.tsx +137 -0
  529. package/src/components/ui/finance/wallets/wallets-page.test.tsx +107 -0
  530. package/src/components/ui/finance/wallets/wallets-page.tsx +136 -0
  531. package/src/components/ui/form-required-indicator.tsx +31 -0
  532. package/src/components/ui/form.tsx +36 -13
  533. package/src/components/ui/hover-card.tsx +2 -2
  534. package/src/components/ui/input-otp.tsx +4 -4
  535. package/src/components/ui/input.tsx +2 -2
  536. package/src/components/ui/kbd.tsx +28 -0
  537. package/src/components/ui/label.tsx +2 -2
  538. package/src/components/ui/legacy/calendar/__tests__/event-utils.test.ts +247 -0
  539. package/src/components/ui/legacy/calendar/agenda-view.tsx +398 -0
  540. package/src/components/ui/legacy/calendar/all-day-event-bar.tsx +1033 -0
  541. package/src/components/ui/legacy/calendar/calendar-cell.tsx +1018 -0
  542. package/src/components/ui/legacy/calendar/calendar-column.tsx +31 -0
  543. package/src/components/ui/legacy/calendar/calendar-content.tsx +670 -0
  544. package/src/components/ui/legacy/calendar/calendar-header.tsx +195 -0
  545. package/src/components/ui/legacy/calendar/calendar-matrix.tsx +328 -0
  546. package/src/components/ui/legacy/calendar/calendar-settings-dialog.tsx +340 -0
  547. package/src/components/ui/legacy/calendar/calendar-view-with-trail.tsx +48 -0
  548. package/src/components/ui/legacy/calendar/calendar-view.tsx +28 -0
  549. package/src/components/ui/legacy/calendar/color-highlights.ts +55 -0
  550. package/src/components/ui/legacy/calendar/config.ts +8 -0
  551. package/src/components/ui/legacy/calendar/create-event-button.tsx +155 -0
  552. package/src/components/ui/legacy/calendar/day-title.tsx +68 -0
  553. package/src/components/ui/legacy/calendar/dynamic-island.tsx +245 -0
  554. package/src/components/ui/legacy/calendar/event-card.tsx +1430 -0
  555. package/src/components/ui/legacy/calendar/event-form-components.tsx +593 -0
  556. package/src/components/ui/legacy/calendar/event-modal.tsx +1544 -0
  557. package/src/components/ui/legacy/calendar/event-utils.ts +149 -0
  558. package/src/components/ui/legacy/calendar/location-timeline.tsx +1482 -0
  559. package/src/components/ui/legacy/calendar/month-calendar.tsx +986 -0
  560. package/src/components/ui/legacy/calendar/month-cell.tsx +33 -0
  561. package/src/components/ui/legacy/calendar/month-grid.tsx +105 -0
  562. package/src/components/ui/legacy/calendar/settings/analytics-charts.tsx +414 -0
  563. package/src/components/ui/legacy/calendar/settings/appearance-settings.tsx +218 -0
  564. package/src/components/ui/legacy/calendar/settings/calendar-sync-dashboard.tsx +217 -0
  565. package/src/components/ui/legacy/calendar/settings/category-color-settings.tsx +475 -0
  566. package/src/components/ui/legacy/calendar/settings/color-picker.tsx +177 -0
  567. package/src/components/ui/legacy/calendar/settings/google-calendar-settings.tsx +562 -0
  568. package/src/components/ui/legacy/calendar/settings/hour-settings.tsx +292 -0
  569. package/src/components/ui/legacy/calendar/settings/notification-settings.tsx +254 -0
  570. package/src/components/ui/legacy/calendar/settings/settings-context.tsx +257 -0
  571. package/src/components/ui/legacy/calendar/settings/smart-scheduling-settings.tsx +325 -0
  572. package/src/components/ui/legacy/calendar/settings/summary-cards.tsx +93 -0
  573. package/src/components/ui/legacy/calendar/settings/sync-logs-table.tsx +392 -0
  574. package/src/components/ui/legacy/calendar/settings/task-settings.tsx +330 -0
  575. package/src/components/ui/legacy/calendar/settings/time-range-picker.tsx +666 -0
  576. package/src/components/ui/legacy/calendar/settings/timezone-settings.tsx +580 -0
  577. package/src/components/ui/legacy/calendar/settings/types.ts +119 -0
  578. package/src/components/ui/legacy/calendar/settings-button.tsx +41 -0
  579. package/src/components/ui/legacy/calendar/smart-calendar.tsx +82 -0
  580. package/src/components/ui/legacy/calendar/time-indicator-line.tsx +61 -0
  581. package/src/components/ui/legacy/calendar/time-indicator-text.tsx +61 -0
  582. package/src/components/ui/legacy/calendar/time-indicator.tsx +19 -0
  583. package/src/components/ui/legacy/calendar/time-trail.tsx +52 -0
  584. package/src/components/ui/legacy/calendar/weekday-bar.tsx +78 -0
  585. package/src/components/ui/legacy/calendar/year-calendar.tsx +345 -0
  586. package/src/components/ui/legacy/meet/client-wrapper.tsx +74 -0
  587. package/src/components/ui/legacy/meet/create-plan-dialog.tsx +404 -0
  588. package/src/components/ui/legacy/meet/date-selector.tsx +46 -0
  589. package/src/components/ui/legacy/meet/edit-plan-dialog.tsx +501 -0
  590. package/src/components/ui/legacy/meet/experimental-notice.tsx +39 -0
  591. package/src/components/ui/legacy/meet/form.tsx +94 -0
  592. package/src/components/ui/legacy/meet/multiple-choice-vote.tsx +556 -0
  593. package/src/components/ui/legacy/meet/page.tsx +331 -0
  594. package/src/components/ui/legacy/meet/pagination.tsx +87 -0
  595. package/src/components/ui/legacy/meet/planId/account-badge.tsx +21 -0
  596. package/src/components/ui/legacy/meet/planId/agenda-details.tsx +131 -0
  597. package/src/components/ui/legacy/meet/planId/all-availabilities.tsx +105 -0
  598. package/src/components/ui/legacy/meet/planId/availability-planner.tsx +51 -0
  599. package/src/components/ui/legacy/meet/planId/confirm-button.tsx +53 -0
  600. package/src/components/ui/legacy/meet/planId/copy-link-button.tsx +218 -0
  601. package/src/components/ui/legacy/meet/planId/date-planner.tsx +243 -0
  602. package/src/components/ui/legacy/meet/planId/day-planner.tsx +78 -0
  603. package/src/components/ui/legacy/meet/planId/day-planners.tsx +151 -0
  604. package/src/components/ui/legacy/meet/planId/day-time.tsx +32 -0
  605. package/src/components/ui/legacy/meet/planId/download-as-png.tsx +16 -0
  606. package/src/components/ui/legacy/meet/planId/email-button.tsx +32 -0
  607. package/src/components/ui/legacy/meet/planId/logged-in-as-button.tsx +56 -0
  608. package/src/components/ui/legacy/meet/planId/page.tsx +236 -0
  609. package/src/components/ui/legacy/meet/planId/plan-details-client.tsx +205 -0
  610. package/src/components/ui/legacy/meet/planId/plan-login.tsx +342 -0
  611. package/src/components/ui/legacy/meet/planId/plan-user-filter-accordion.tsx +227 -0
  612. package/src/components/ui/legacy/meet/planId/plan-user-filter.tsx +68 -0
  613. package/src/components/ui/legacy/meet/planId/preview-day-time.tsx +303 -0
  614. package/src/components/ui/legacy/meet/planId/selectable-day-time.tsx +247 -0
  615. package/src/components/ui/legacy/meet/planId/show-qr-button.tsx +53 -0
  616. package/src/components/ui/legacy/meet/planId/sidebar-display.tsx +68 -0
  617. package/src/components/ui/legacy/meet/planId/sticky-bottom-indicator.tsx +28 -0
  618. package/src/components/ui/legacy/meet/planId/time-column.tsx +57 -0
  619. package/src/components/ui/legacy/meet/planId/unified-availability.tsx +93 -0
  620. package/src/components/ui/legacy/meet/planId/utility-buttons.tsx +54 -0
  621. package/src/components/ui/legacy/meet/plans-grid.tsx +192 -0
  622. package/src/components/ui/legacy/meet/plans-list-view.tsx +148 -0
  623. package/src/components/ui/legacy/meet/plans-loading-skeleton.tsx +61 -0
  624. package/src/components/ui/legacy/meet/time-selector.tsx +67 -0
  625. package/src/components/ui/legacy/meet/timezone-selector.tsx +72 -0
  626. package/src/components/ui/legacy/meet/user-time.tsx +7 -0
  627. package/src/components/ui/legacy/meet/view-toggle.tsx +44 -0
  628. package/src/components/ui/legacy/polls/poll-display.tsx +388 -0
  629. package/src/components/ui/legacy/polls/where-tu-meet.tsx +80 -0
  630. package/src/components/ui/markdown.tsx +2 -2
  631. package/src/components/ui/menubar.tsx +11 -11
  632. package/src/components/ui/navbar.tsx +150 -0
  633. package/src/components/ui/navigation-menu.tsx +9 -9
  634. package/src/components/ui/pagination.tsx +4 -5
  635. package/src/components/ui/popover.tsx +2 -2
  636. package/src/components/ui/progress.tsx +15 -4
  637. package/src/components/ui/radio-group.tsx +3 -3
  638. package/src/components/ui/report-problem-dialog.tsx +980 -0
  639. package/src/components/ui/resizable.tsx +35 -13
  640. package/src/components/ui/scroll-area.tsx +3 -3
  641. package/src/components/ui/select.tsx +9 -8
  642. package/src/components/ui/separator.tsx +2 -2
  643. package/src/components/ui/sheet.tsx +13 -11
  644. package/src/components/ui/sidebar.tsx +18 -17
  645. package/src/components/ui/slider.tsx +3 -3
  646. package/src/components/ui/sonner.tsx +2 -2
  647. package/src/components/ui/sticky-bottom-bar.tsx +51 -0
  648. package/src/components/ui/switch.tsx +2 -2
  649. package/src/components/ui/table.tsx +2 -2
  650. package/src/components/ui/tabs.tsx +3 -3
  651. package/src/components/ui/text-editor/__tests__/content-migration.test.ts +757 -0
  652. package/src/components/ui/text-editor/__tests__/extensions-integration.test.ts +131 -0
  653. package/src/components/ui/text-editor/__tests__/extensions.test.ts +69 -0
  654. package/src/components/ui/text-editor/__tests__/image-extension.test.ts +799 -0
  655. package/src/components/ui/text-editor/__tests__/inline-task-conversion.test.tsx +46 -0
  656. package/src/components/ui/text-editor/__tests__/keyboard.test.ts +176 -0
  657. package/src/components/ui/text-editor/__tests__/list-converter-extension.test.ts +51 -0
  658. package/src/components/ui/text-editor/__tests__/markdown-paste-extension.test.ts +266 -0
  659. package/src/components/ui/text-editor/__tests__/media-utils.test.ts +425 -0
  660. package/src/components/ui/text-editor/__tests__/task-mention-checkbox.test.ts +251 -0
  661. package/src/components/ui/text-editor/__tests__/task-mention-chip.test.tsx +279 -0
  662. package/src/components/ui/text-editor/__tests__/text-replacements.test.ts +39 -0
  663. package/src/components/ui/text-editor/__tests__/upload-placeholder.test.ts +279 -0
  664. package/src/components/ui/text-editor/__tests__/video-extension.test.ts +711 -0
  665. package/src/components/ui/text-editor/content-migration.ts +199 -0
  666. package/src/components/ui/text-editor/draggable-node-container.tsx +164 -0
  667. package/src/components/ui/text-editor/editor.tsx +707 -0
  668. package/src/components/ui/text-editor/extensions.ts +232 -0
  669. package/src/components/ui/text-editor/image-extension.ts +907 -0
  670. package/src/components/ui/text-editor/keyboard.ts +58 -0
  671. package/src/components/ui/text-editor/list-converter-extension.ts +55 -0
  672. package/src/components/ui/text-editor/list-item-extension.ts +13 -0
  673. package/src/components/ui/text-editor/list-item-view.tsx +17 -0
  674. package/src/components/ui/text-editor/markdown-paste-extension.ts +610 -0
  675. package/src/components/ui/text-editor/media-utils.ts +198 -0
  676. package/src/components/ui/text-editor/mention-extension.tsx +604 -0
  677. package/src/components/ui/text-editor/node-drag-extension.ts +300 -0
  678. package/src/components/ui/text-editor/task-item-checkbox-extension.ts +32 -0
  679. package/src/components/ui/text-editor/task-item-checkbox-view.tsx +227 -0
  680. package/src/components/ui/text-editor/task-item-checkbox.ts +100 -0
  681. package/src/components/ui/text-editor/task-mention-chip.tsx +1375 -0
  682. package/src/components/ui/text-editor/task-mention-resolution.ts +235 -0
  683. package/src/components/ui/text-editor/task-summary-popover.tsx +360 -0
  684. package/src/components/ui/text-editor/text-replacements.ts +65 -0
  685. package/src/components/ui/text-editor/text-shortcuts-extension.ts +60 -0
  686. package/src/components/ui/text-editor/tool-bar.tsx +1294 -0
  687. package/src/components/ui/text-editor/types.ts +1 -0
  688. package/src/components/ui/text-editor/upload-errors.ts +93 -0
  689. package/src/components/ui/text-editor/upload-placeholder.ts +124 -0
  690. package/src/components/ui/text-editor/video-extension.ts +435 -0
  691. package/src/components/ui/textarea.tsx +2 -2
  692. package/src/components/ui/time-picker-input.tsx +6 -6
  693. package/src/components/ui/time-picker-utils.tsx +2 -2
  694. package/src/components/ui/time-tracker/types.ts +112 -0
  695. package/src/components/ui/toast.tsx +9 -9
  696. package/src/components/ui/toaster.tsx +10 -14
  697. package/src/components/ui/toggle-group.tsx +2 -2
  698. package/src/components/ui/toggle.tsx +2 -2
  699. package/src/components/ui/tooltip.tsx +3 -3
  700. package/src/components/ui/tu-do/boards/__tests__/quick-create-board-dialog.test.tsx +52 -0
  701. package/src/components/ui/tu-do/boards/__tests__/task-board-form.test.tsx +130 -0
  702. package/src/components/ui/tu-do/boards/__tests__/workspace-projects-client-page.test.tsx +100 -0
  703. package/src/components/ui/tu-do/boards/analytics/GanttChart.tsx +419 -0
  704. package/src/components/ui/tu-do/boards/analytics/GanttControls.tsx +123 -0
  705. package/src/components/ui/tu-do/boards/analytics/GanttHeader.tsx +48 -0
  706. package/src/components/ui/tu-do/boards/analytics/GanttTimeline.tsx +355 -0
  707. package/src/components/ui/tu-do/boards/analytics/StatusDistribution.tsx +130 -0
  708. package/src/components/ui/tu-do/boards/analytics/TaskCreationAnalytics.tsx +285 -0
  709. package/src/components/ui/tu-do/boards/analytics/TaskDetailCard.tsx +270 -0
  710. package/src/components/ui/tu-do/boards/analytics/TaskGroup.tsx +282 -0
  711. package/src/components/ui/tu-do/boards/analytics/TaskWorkflowAnalytics.tsx +280 -0
  712. package/src/components/ui/tu-do/boards/board-selector.tsx +301 -0
  713. package/src/components/ui/tu-do/boards/board-share-dialog.tsx +280 -0
  714. package/src/components/ui/tu-do/boards/boardId/__tests__/list-actions.test.tsx +199 -0
  715. package/src/components/ui/tu-do/boards/boardId/board-column-initial-load.test.ts +38 -0
  716. package/src/components/ui/tu-do/boards/boardId/board-column.tsx +755 -0
  717. package/src/components/ui/tu-do/boards/boardId/board-text-utils.test.ts +24 -0
  718. package/src/components/ui/tu-do/boards/boardId/board-text-utils.ts +11 -0
  719. package/src/components/ui/tu-do/boards/boardId/enhanced-task-list.tsx +536 -0
  720. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/__tests__/bulk-mutations-move.test.tsx +176 -0
  721. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-actions-bar.tsx +94 -0
  722. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-actions-menu.tsx +689 -0
  723. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-custom-date-dialog.tsx +82 -0
  724. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-delete-dialog.tsx +58 -0
  725. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-clear-delete.ts +471 -0
  726. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-move.ts +657 -0
  727. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-relations-assignees.ts +429 -0
  728. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-relations-labels.ts +294 -0
  729. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-relations-projects.ts +316 -0
  730. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-relations.ts +12 -0
  731. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-updates.ts +499 -0
  732. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-operation-i18n.ts +524 -0
  733. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-operation-types.ts +34 -0
  734. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-operation-utils.ts +60 -0
  735. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-operations.ts +312 -0
  736. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-personal-external-move.ts +132 -0
  737. package/src/components/ui/tu-do/boards/boardId/kanban/data/kanban-deadline-query.ts +42 -0
  738. package/src/components/ui/tu-do/boards/boardId/kanban/data/use-applied-sets.ts +79 -0
  739. package/src/components/ui/tu-do/boards/boardId/kanban/data/use-bulk-resources.ts +58 -0
  740. package/src/components/ui/tu-do/boards/boardId/kanban/data/use-filtered-resources.ts +54 -0
  741. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/__tests__/column-reorder.test.ts +63 -0
  742. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/auto-scroll.ts +86 -0
  743. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/column-reorder.ts +62 -0
  744. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/drag-preview.tsx +98 -0
  745. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/kanban-sort-helpers.ts +76 -0
  746. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-cache.ts +325 -0
  747. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-geometry.test.ts +67 -0
  748. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-geometry.ts +94 -0
  749. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-order.ts +156 -0
  750. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-pending.test.ts +37 -0
  751. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-pending.ts +42 -0
  752. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-preview.test.ts +318 -0
  753. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-preview.ts +260 -0
  754. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-types.ts +39 -0
  755. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.test.ts +686 -0
  756. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.ts +1503 -0
  757. package/src/components/ui/tu-do/boards/boardId/kanban/kanban-constants.ts +43 -0
  758. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-column-width.ts +30 -0
  759. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.test.tsx +383 -0
  760. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.tsx +228 -0
  761. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-deadline-panels.tsx +221 -0
  762. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-deadline-tasks.test.ts +267 -0
  763. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-deadline-tasks.ts +112 -0
  764. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-skeleton.tsx +45 -0
  765. package/src/components/ui/tu-do/boards/boardId/kanban/selection/use-keyboard-shortcuts.ts +137 -0
  766. package/src/components/ui/tu-do/boards/boardId/kanban/selection/use-multi-select.ts +119 -0
  767. package/src/components/ui/tu-do/boards/boardId/kanban.tsx +495 -0
  768. package/src/components/ui/tu-do/boards/boardId/list-actions.tsx +522 -0
  769. package/src/components/ui/tu-do/boards/boardId/menus/__tests__/task-estimation-menu.test.tsx +261 -0
  770. package/src/components/ui/tu-do/boards/boardId/menus/__tests__/task-menus.test.tsx +491 -0
  771. package/src/components/ui/tu-do/boards/boardId/menus/index.ts +11 -0
  772. package/src/components/ui/tu-do/boards/boardId/menus/task-assignees-menu.tsx +176 -0
  773. package/src/components/ui/tu-do/boards/boardId/menus/task-blocking-menu.tsx +304 -0
  774. package/src/components/ui/tu-do/boards/boardId/menus/task-due-date-menu.tsx +180 -0
  775. package/src/components/ui/tu-do/boards/boardId/menus/task-estimation-menu.tsx +103 -0
  776. package/src/components/ui/tu-do/boards/boardId/menus/task-labels-menu.tsx +134 -0
  777. package/src/components/ui/tu-do/boards/boardId/menus/task-move-menu.tsx +66 -0
  778. package/src/components/ui/tu-do/boards/boardId/menus/task-parent-menu.tsx +228 -0
  779. package/src/components/ui/tu-do/boards/boardId/menus/task-picker-popover.tsx +300 -0
  780. package/src/components/ui/tu-do/boards/boardId/menus/task-priority-menu.tsx +176 -0
  781. package/src/components/ui/tu-do/boards/boardId/menus/task-projects-menu.tsx +143 -0
  782. package/src/components/ui/tu-do/boards/boardId/menus/task-related-menu.tsx +242 -0
  783. package/src/components/ui/tu-do/boards/boardId/status-grouped-board.tsx +533 -0
  784. package/src/components/ui/tu-do/boards/boardId/status-section.tsx +274 -0
  785. package/src/components/ui/tu-do/boards/boardId/task-actions.tsx +675 -0
  786. package/src/components/ui/tu-do/boards/boardId/task-board-server-page.tsx +41 -0
  787. package/src/components/ui/tu-do/boards/boardId/task-card/TaskCardCheckbox.tsx +47 -0
  788. package/src/components/ui/tu-do/boards/boardId/task-card/TaskCardDates.tsx +106 -0
  789. package/src/components/ui/tu-do/boards/boardId/task-card/TaskCardHeader.tsx +97 -0
  790. package/src/components/ui/tu-do/boards/boardId/task-card/TaskCardMetadata.tsx +152 -0
  791. package/src/components/ui/tu-do/boards/boardId/task-card/measured-task-card.tsx +109 -0
  792. package/src/components/ui/tu-do/boards/boardId/task-card/task-card-comparator.test.ts +61 -0
  793. package/src/components/ui/tu-do/boards/boardId/task-card/task-card-comparator.ts +87 -0
  794. package/src/components/ui/tu-do/boards/boardId/task-card/task-card-label-options.ts +24 -0
  795. package/src/components/ui/tu-do/boards/boardId/task-card/task-card-visibility.test.ts +41 -0
  796. package/src/components/ui/tu-do/boards/boardId/task-card/task-card-visibility.ts +14 -0
  797. package/src/components/ui/tu-do/boards/boardId/task-card/task-card.tsx +2543 -0
  798. package/src/components/ui/tu-do/boards/boardId/task-dialogs/BoardEstimationConfigDialog.tsx +499 -0
  799. package/src/components/ui/tu-do/boards/boardId/task-dialogs/TaskCustomDateDialog.tsx +109 -0
  800. package/src/components/ui/tu-do/boards/boardId/task-dialogs/TaskDeleteDialog.tsx +96 -0
  801. package/src/components/ui/tu-do/boards/boardId/task-dialogs/TaskNewLabelDialog.tsx +178 -0
  802. package/src/components/ui/tu-do/boards/boardId/task-dialogs/TaskNewProjectDialog.tsx +127 -0
  803. package/src/components/ui/tu-do/boards/boardId/task-filter.tsx +986 -0
  804. package/src/components/ui/tu-do/boards/boardId/task-form.tsx +498 -0
  805. package/src/components/ui/tu-do/boards/boardId/task-list-drag-preview.test.ts +101 -0
  806. package/src/components/ui/tu-do/boards/boardId/task-list-form.tsx +91 -0
  807. package/src/components/ui/tu-do/boards/boardId/task-list.tsx +513 -0
  808. package/src/components/ui/tu-do/boards/boardId/task-parent-badge-state.test.ts +64 -0
  809. package/src/components/ui/tu-do/boards/boardId/task-parent-badge-state.ts +31 -0
  810. package/src/components/ui/tu-do/boards/boardId/task.tsx +2 -0
  811. package/src/components/ui/tu-do/boards/boardId/timeline/task-edit-dialog.tsx +109 -0
  812. package/src/components/ui/tu-do/boards/boardId/timeline/timeline-display.ts +94 -0
  813. package/src/components/ui/tu-do/boards/boardId/timeline/timeline-grid.tsx +380 -0
  814. package/src/components/ui/tu-do/boards/boardId/timeline/timeline-task-row.tsx +350 -0
  815. package/src/components/ui/tu-do/boards/boardId/timeline/timeline-toolbar.tsx +347 -0
  816. package/src/components/ui/tu-do/boards/boardId/timeline/timeline-utils.test.ts +134 -0
  817. package/src/components/ui/tu-do/boards/boardId/timeline/timeline-utils.ts +468 -0
  818. package/src/components/ui/tu-do/boards/boardId/timeline-board.test.tsx +217 -0
  819. package/src/components/ui/tu-do/boards/boardId/timeline-board.tsx +793 -0
  820. package/src/components/ui/tu-do/boards/boards-list-skeleton.tsx +62 -0
  821. package/src/components/ui/tu-do/boards/columns.tsx +159 -0
  822. package/src/components/ui/tu-do/boards/copy-board-dialog.tsx +156 -0
  823. package/src/components/ui/tu-do/boards/enhanced-boards-view.tsx +347 -0
  824. package/src/components/ui/tu-do/boards/form.tsx +264 -0
  825. package/src/components/ui/tu-do/boards/quick-create-board-dialog.tsx +75 -0
  826. package/src/components/ui/tu-do/boards/row-actions.tsx +397 -0
  827. package/src/components/ui/tu-do/boards/workspace-projects-client-page.tsx +182 -0
  828. package/src/components/ui/tu-do/boards/workspace-projects-page.tsx +155 -0
  829. package/src/components/ui/tu-do/cycles/task-cycles-client.tsx +744 -0
  830. package/src/components/ui/tu-do/cycles/task-cycles-page.tsx +103 -0
  831. package/src/components/ui/tu-do/drafts/draft-card.tsx +204 -0
  832. package/src/components/ui/tu-do/drafts/draft-convert-dialog.tsx +197 -0
  833. package/src/components/ui/tu-do/drafts/drafts-page.tsx +105 -0
  834. package/src/components/ui/tu-do/drafts/task-drafts-page.tsx +90 -0
  835. package/src/components/ui/tu-do/estimates/client.tsx +292 -0
  836. package/src/components/ui/tu-do/estimates/edit-estimation-dialog.tsx +374 -0
  837. package/src/components/ui/tu-do/estimates/task-estimates-page.tsx +57 -0
  838. package/src/components/ui/tu-do/estimates/use-task-estimates.ts +319 -0
  839. package/src/components/ui/tu-do/habits/client.tsx +260 -0
  840. package/src/components/ui/tu-do/habits/habit-card.tsx +183 -0
  841. package/src/components/ui/tu-do/habits/habit-form-dialog.tsx +701 -0
  842. package/src/components/ui/tu-do/habits/habits-page.tsx +27 -0
  843. package/src/components/ui/tu-do/hooks/__tests__/useDraftPersistence.test.ts +494 -0
  844. package/src/components/ui/tu-do/hooks/__tests__/useTaskDialog.test.tsx +127 -0
  845. package/src/components/ui/tu-do/hooks/__tests__/useTaskDialogState.test.ts +217 -0
  846. package/src/components/ui/tu-do/hooks/__tests__/useTaskLabelManagement.test.tsx +524 -0
  847. package/src/components/ui/tu-do/hooks/useDraftPersistence.ts +199 -0
  848. package/src/components/ui/tu-do/hooks/useTaskCardRelationships.ts +340 -0
  849. package/src/components/ui/tu-do/hooks/useTaskDialog.ts +101 -0
  850. package/src/components/ui/tu-do/hooks/useTaskDialogState.ts +145 -0
  851. package/src/components/ui/tu-do/hooks/useTaskFormState.ts +206 -0
  852. package/src/components/ui/tu-do/hooks/useTaskKeyboardShortcuts.ts +58 -0
  853. package/src/components/ui/tu-do/hooks/useTaskLabelManagement.ts +416 -0
  854. package/src/components/ui/tu-do/hooks/useTaskProjectManagement.ts +461 -0
  855. package/src/components/ui/tu-do/initiatives/task-initiatives-client.tsx +921 -0
  856. package/src/components/ui/tu-do/initiatives/task-initiatives-page.tsx +116 -0
  857. package/src/components/ui/tu-do/labels/client.tsx +201 -0
  858. package/src/components/ui/tu-do/labels/components/delete-label-dialog.tsx +57 -0
  859. package/src/components/ui/tu-do/labels/components/label-card.tsx +86 -0
  860. package/src/components/ui/tu-do/labels/components/label-dialog.tsx +259 -0
  861. package/src/components/ui/tu-do/labels/components/label-list.tsx +83 -0
  862. package/src/components/ui/tu-do/labels/hooks/use-task-labels.ts +170 -0
  863. package/src/components/ui/tu-do/labels/task-labels-page.tsx +53 -0
  864. package/src/components/ui/tu-do/labels/types.ts +6 -0
  865. package/src/components/ui/tu-do/logs/columns.tsx +755 -0
  866. package/src/components/ui/tu-do/logs/logs-client.tsx +1006 -0
  867. package/src/components/ui/tu-do/logs/logs-timeline.tsx +2483 -0
  868. package/src/components/ui/tu-do/logs/task-logs-page.tsx +59 -0
  869. package/src/components/ui/tu-do/my-tasks/__tests__/my-tasks-content.test.tsx +408 -0
  870. package/src/components/ui/tu-do/my-tasks/__tests__/use-my-tasks-query.test.ts +469 -0
  871. package/src/components/ui/tu-do/my-tasks/__tests__/use-my-tasks-state.test.ts +1017 -0
  872. package/src/components/ui/tu-do/my-tasks/__tests__/use-task-context-actions.test.ts +516 -0
  873. package/src/components/ui/tu-do/my-tasks/ai-credit-indicator.tsx +143 -0
  874. package/src/components/ui/tu-do/my-tasks/board-selector-dialog.tsx +239 -0
  875. package/src/components/ui/tu-do/my-tasks/command-bar.tsx +1351 -0
  876. package/src/components/ui/tu-do/my-tasks/label-project-filter.tsx +194 -0
  877. package/src/components/ui/tu-do/my-tasks/my-task-context-menu.tsx +356 -0
  878. package/src/components/ui/tu-do/my-tasks/my-tasks-content.tsx +304 -0
  879. package/src/components/ui/tu-do/my-tasks/my-tasks-data-loader.tsx +17 -0
  880. package/src/components/ui/tu-do/my-tasks/my-tasks-filters.tsx +258 -0
  881. package/src/components/ui/tu-do/my-tasks/my-tasks-header.tsx +121 -0
  882. package/src/components/ui/tu-do/my-tasks/my-tasks-page.tsx +40 -0
  883. package/src/components/ui/tu-do/my-tasks/personal-placement-dialog.tsx +188 -0
  884. package/src/components/ui/tu-do/my-tasks/task-filter.tsx +235 -0
  885. package/src/components/ui/tu-do/my-tasks/task-list-with-completion.tsx +782 -0
  886. package/src/components/ui/tu-do/my-tasks/task-list.tsx +258 -0
  887. package/src/components/ui/tu-do/my-tasks/task-preview-dialog.tsx +1597 -0
  888. package/src/components/ui/tu-do/my-tasks/task-section.tsx +261 -0
  889. package/src/components/ui/tu-do/my-tasks/use-my-tasks-query.ts +140 -0
  890. package/src/components/ui/tu-do/my-tasks/use-my-tasks-state.ts +983 -0
  891. package/src/components/ui/tu-do/my-tasks/use-task-context-actions.ts +332 -0
  892. package/src/components/ui/tu-do/notes/note-edit-dialog.tsx +121 -0
  893. package/src/components/ui/tu-do/notes/note-list.tsx +799 -0
  894. package/src/components/ui/tu-do/notes/notes-content.tsx +178 -0
  895. package/src/components/ui/tu-do/notes/notes-page.tsx +27 -0
  896. package/src/components/ui/tu-do/projects/components/index.ts +11 -0
  897. package/src/components/ui/tu-do/projects/components/project-actions-menu.tsx +66 -0
  898. package/src/components/ui/tu-do/projects/components/project-badges.tsx +84 -0
  899. package/src/components/ui/tu-do/projects/components/project-filter-menu.tsx +170 -0
  900. package/src/components/ui/tu-do/projects/components/project-grid-card.tsx +182 -0
  901. package/src/components/ui/tu-do/projects/components/project-list-item.tsx +179 -0
  902. package/src/components/ui/tu-do/projects/components/project-metrics.tsx +87 -0
  903. package/src/components/ui/tu-do/projects/components/project-progress-meter.tsx +33 -0
  904. package/src/components/ui/tu-do/projects/components/project-sort-menu.tsx +71 -0
  905. package/src/components/ui/tu-do/projects/components/projects-empty-state.tsx +38 -0
  906. package/src/components/ui/tu-do/projects/components/projects-loading-state.tsx +26 -0
  907. package/src/components/ui/tu-do/projects/components/projects-toolbar.tsx +179 -0
  908. package/src/components/ui/tu-do/projects/dialogs/create-project-dialog.tsx +117 -0
  909. package/src/components/ui/tu-do/projects/dialogs/edit-project-dialog.tsx +125 -0
  910. package/src/components/ui/tu-do/projects/dialogs/index.ts +3 -0
  911. package/src/components/ui/tu-do/projects/dialogs/manage-tasks-dialog.tsx +205 -0
  912. package/src/components/ui/tu-do/projects/hooks/index.ts +2 -0
  913. package/src/components/ui/tu-do/projects/hooks/use-project-filters.ts +248 -0
  914. package/src/components/ui/tu-do/projects/hooks/use-task-projects.ts +238 -0
  915. package/src/components/ui/tu-do/projects/projectId/components/__tests__/tasks-tab-layout.test.tsx +163 -0
  916. package/src/components/ui/tu-do/projects/projectId/components/documents-tab.tsx +90 -0
  917. package/src/components/ui/tu-do/projects/projectId/components/index.ts +9 -0
  918. package/src/components/ui/tu-do/projects/projectId/components/overview/description-card.tsx +77 -0
  919. package/src/components/ui/tu-do/projects/projectId/components/overview/linked-documents-card.tsx +81 -0
  920. package/src/components/ui/tu-do/projects/projectId/components/overview/linked-tasks-card.tsx +85 -0
  921. package/src/components/ui/tu-do/projects/projectId/components/overview/updates-card.tsx +85 -0
  922. package/src/components/ui/tu-do/projects/projectId/components/overview-tab.tsx +35 -0
  923. package/src/components/ui/tu-do/projects/projectId/components/project-configuration.tsx +229 -0
  924. package/src/components/ui/tu-do/projects/projectId/components/project-header.tsx +115 -0
  925. package/src/components/ui/tu-do/projects/projectId/components/project-lead-selector.tsx +55 -0
  926. package/src/components/ui/tu-do/projects/projectId/components/project-overview-context.tsx +82 -0
  927. package/src/components/ui/tu-do/projects/projectId/components/project-sidebar.tsx +246 -0
  928. package/src/components/ui/tu-do/projects/projectId/components/tasks-tab.tsx +264 -0
  929. package/src/components/ui/tu-do/projects/projectId/components/update-card.tsx +162 -0
  930. package/src/components/ui/tu-do/projects/projectId/components/updates-tab.tsx +129 -0
  931. package/src/components/ui/tu-do/projects/projectId/dialogs/index.ts +1 -0
  932. package/src/components/ui/tu-do/projects/projectId/dialogs/link-task-dialog.tsx +114 -0
  933. package/src/components/ui/tu-do/projects/projectId/hooks/index.ts +4 -0
  934. package/src/components/ui/tu-do/projects/projectId/hooks/use-animation-variants.ts +68 -0
  935. package/src/components/ui/tu-do/projects/projectId/hooks/use-project-form.ts +214 -0
  936. package/src/components/ui/tu-do/projects/projectId/hooks/use-project-updates.ts +209 -0
  937. package/src/components/ui/tu-do/projects/projectId/hooks/use-task-linking.ts +101 -0
  938. package/src/components/ui/tu-do/projects/projectId/task-project-detail-page-client.tsx +85 -0
  939. package/src/components/ui/tu-do/projects/projectId/task-project-detail-page.tsx +78 -0
  940. package/src/components/ui/tu-do/projects/projectId/task-project-detail.tsx +365 -0
  941. package/src/components/ui/tu-do/projects/projectId/types.ts +50 -0
  942. package/src/components/ui/tu-do/projects/task-projects-client.tsx +226 -0
  943. package/src/components/ui/tu-do/projects/task-projects-page.tsx +97 -0
  944. package/src/components/ui/tu-do/projects/types.ts +59 -0
  945. package/src/components/ui/tu-do/providers/__tests__/task-dialog-provider.test.tsx +404 -0
  946. package/src/components/ui/tu-do/providers/task-dialog-provider.tsx +721 -0
  947. package/src/components/ui/tu-do/providers/workspace-presence-provider.tsx +88 -0
  948. package/src/components/ui/tu-do/shared/AccessibleButton.tsx +79 -0
  949. package/src/components/ui/tu-do/shared/__tests__/assignee-select.test.tsx +72 -0
  950. package/src/components/ui/tu-do/shared/__tests__/board-client.test.tsx +152 -0
  951. package/src/components/ui/tu-do/shared/__tests__/board-header.test.tsx +172 -0
  952. package/src/components/ui/tu-do/shared/__tests__/board-query-cache.test.ts +219 -0
  953. package/src/components/ui/tu-do/shared/__tests__/board-views.test.tsx +613 -0
  954. package/src/components/ui/tu-do/shared/__tests__/create-list-dialog.test.tsx +118 -0
  955. package/src/components/ui/tu-do/shared/__tests__/task-detail-page.test.tsx +170 -0
  956. package/src/components/ui/tu-do/shared/__tests__/task-dialog-manager.test.tsx +708 -0
  957. package/src/components/ui/tu-do/shared/__tests__/task-legacy-route-recovery.test.tsx +85 -0
  958. package/src/components/ui/tu-do/shared/__tests__/use-progressive-board-loader.test.tsx +588 -0
  959. package/src/components/ui/tu-do/shared/assignee-select.tsx +541 -0
  960. package/src/components/ui/tu-do/shared/board-broadcast-context.tsx +45 -0
  961. package/src/components/ui/tu-do/shared/board-client.tsx +268 -0
  962. package/src/components/ui/tu-do/shared/board-config-storage.ts +88 -0
  963. package/src/components/ui/tu-do/shared/board-header.tsx +1248 -0
  964. package/src/components/ui/tu-do/shared/board-layout-settings.tsx +1105 -0
  965. package/src/components/ui/tu-do/shared/board-query-cache.ts +157 -0
  966. package/src/components/ui/tu-do/shared/board-switcher.tsx +298 -0
  967. package/src/components/ui/tu-do/shared/board-user-presence-avatars.tsx +572 -0
  968. package/src/components/ui/tu-do/shared/board-views.tsx +847 -0
  969. package/src/components/ui/tu-do/shared/clear-menu-item.tsx +34 -0
  970. package/src/components/ui/tu-do/shared/create-list-dialog.tsx +401 -0
  971. package/src/components/ui/tu-do/shared/cursor-overlay-multi-wrapper.tsx +204 -0
  972. package/src/components/ui/tu-do/shared/cursor-overlay.tsx +78 -0
  973. package/src/components/ui/tu-do/shared/custom-date-picker/custom-date-picker-dialog.tsx +157 -0
  974. package/src/components/ui/tu-do/shared/description-overflow-warning-dialog.tsx +68 -0
  975. package/src/components/ui/tu-do/shared/edit-list-dialog.tsx +383 -0
  976. package/src/components/ui/tu-do/shared/empty-state-card.tsx +46 -0
  977. package/src/components/ui/tu-do/shared/estimation-mapping.test.ts +32 -0
  978. package/src/components/ui/tu-do/shared/estimation-mapping.ts +74 -0
  979. package/src/components/ui/tu-do/shared/estimation-utils.ts +54 -0
  980. package/src/components/ui/tu-do/shared/fade-setting-initializer.tsx +59 -0
  981. package/src/components/ui/tu-do/shared/label-chip.tsx +46 -0
  982. package/src/components/ui/tu-do/shared/list-view-context-menu.test.tsx +150 -0
  983. package/src/components/ui/tu-do/shared/list-view-sorting.test.ts +50 -0
  984. package/src/components/ui/tu-do/shared/list-view-sorting.ts +108 -0
  985. package/src/components/ui/tu-do/shared/list-view.tsx +987 -0
  986. package/src/components/ui/tu-do/shared/mention-system/__tests__/mention-system.test.ts +250 -0
  987. package/src/components/ui/tu-do/shared/mention-system/mention-menu.tsx +217 -0
  988. package/src/components/ui/tu-do/shared/mention-system/types.ts +141 -0
  989. package/src/components/ui/tu-do/shared/mention-system/use-mention-suggestions.ts +244 -0
  990. package/src/components/ui/tu-do/shared/progressive-loader-context.tsx +45 -0
  991. package/src/components/ui/tu-do/shared/recent-sidebar-events.ts +58 -0
  992. package/src/components/ui/tu-do/shared/recycle-bin-panel.tsx +603 -0
  993. package/src/components/ui/tu-do/shared/relationship-task-identifier.ts +14 -0
  994. package/src/components/ui/tu-do/shared/slash-commands/__tests__/slash-commands.test.ts +315 -0
  995. package/src/components/ui/tu-do/shared/slash-commands/definitions.ts +167 -0
  996. package/src/components/ui/tu-do/shared/slash-commands/slash-command-menu.tsx +114 -0
  997. package/src/components/ui/tu-do/shared/sync-warning-dialog.tsx +133 -0
  998. package/src/components/ui/tu-do/shared/task-board-errors.ts +19 -0
  999. package/src/components/ui/tu-do/shared/task-detail-page.tsx +176 -0
  1000. package/src/components/ui/tu-do/shared/task-detail-server-page.tsx +37 -0
  1001. package/src/components/ui/tu-do/shared/task-dialog-manager.tsx +557 -0
  1002. package/src/components/ui/tu-do/shared/task-dialog-wrapper.tsx +28 -0
  1003. package/src/components/ui/tu-do/shared/task-edit-dialog/components/mobile-floating-save-button.tsx +46 -0
  1004. package/src/components/ui/tu-do/shared/task-edit-dialog/components/quick-settings-popover.tsx +164 -0
  1005. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-description-editor.tsx +491 -0
  1006. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-dialog-header.tsx +511 -0
  1007. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-list-picker-panel.tsx +220 -0
  1008. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-list-selector.tsx +127 -0
  1009. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-list-trigger-styles.ts +69 -0
  1010. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-name-input.test.tsx +140 -0
  1011. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-name-input.tsx +163 -0
  1012. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-suggestion-menus.tsx +148 -0
  1013. package/src/components/ui/tu-do/shared/task-edit-dialog/constants.ts +18 -0
  1014. package/src/components/ui/tu-do/shared/task-edit-dialog/context-menu-guard.test.ts +37 -0
  1015. package/src/components/ui/tu-do/shared/task-edit-dialog/description-diff-viewer.tsx +1665 -0
  1016. package/src/components/ui/tu-do/shared/task-edit-dialog/field-diff-viewer.tsx +715 -0
  1017. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/__tests__/use-task-dialog-close.test.ts +218 -0
  1018. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/__tests__/use-task-dialog-keyboard-shortcuts.test.ts +140 -0
  1019. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/__tests__/use-task-overrides.test.ts +412 -0
  1020. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/__tests__/use-task-realtime-sync.test.tsx +209 -0
  1021. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/__tests__/use-task-yjs-sync.test.ts +190 -0
  1022. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/__tests__/use-update-shared-task.test.ts +103 -0
  1023. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/task-api.ts +127 -0
  1024. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-editor-commands.ts +314 -0
  1025. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-suggestion-menus.ts +503 -0
  1026. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-change-detection.ts +175 -0
  1027. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-data.ts +332 -0
  1028. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-dependencies.ts +773 -0
  1029. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-dialog-close.ts +193 -0
  1030. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-dialog-keyboard-shortcuts.ts +365 -0
  1031. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-form-reset.ts +215 -0
  1032. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-form-state.ts +307 -0
  1033. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-mutations.ts +536 -0
  1034. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-overrides.ts +122 -0
  1035. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-realtime-sync.ts +252 -0
  1036. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-relationships.test.tsx +149 -0
  1037. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-relationships.ts +545 -0
  1038. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-revert.ts +140 -0
  1039. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-save.test.ts +206 -0
  1040. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-save.ts +1450 -0
  1041. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-snapshot.ts +59 -0
  1042. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-yjs-sync.ts +224 -0
  1043. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-update-shared-task.ts +55 -0
  1044. package/src/components/ui/tu-do/shared/task-edit-dialog/personal-overrides-section.tsx +348 -0
  1045. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/components/clickable-task-item.tsx +90 -0
  1046. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/components/index.ts +4 -0
  1047. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/components/subtask-action-buttons.tsx +140 -0
  1048. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/components/tab-button.tsx +76 -0
  1049. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/components/task-relationship-action-buttons.tsx +178 -0
  1050. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/dependencies-section.tsx +129 -0
  1051. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/index.ts +35 -0
  1052. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/parent-section.tsx +65 -0
  1053. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/related-section.tsx +76 -0
  1054. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/subtasks-section.tsx +82 -0
  1055. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/task-search-popover.tsx +229 -0
  1056. package/src/components/ui/tu-do/shared/task-edit-dialog/relationships/types/task-relationships.types.ts +186 -0
  1057. package/src/components/ui/tu-do/shared/task-edit-dialog/selective-revert-panel.tsx +320 -0
  1058. package/src/components/ui/tu-do/shared/task-edit-dialog/task-activity-section.tsx +748 -0
  1059. package/src/components/ui/tu-do/shared/task-edit-dialog/task-delete-dialog.tsx +104 -0
  1060. package/src/components/ui/tu-do/shared/task-edit-dialog/task-dialog-actions.tsx +213 -0
  1061. package/src/components/ui/tu-do/shared/task-edit-dialog/task-instances-section.tsx +173 -0
  1062. package/src/components/ui/tu-do/shared/task-edit-dialog/task-properties-section.tsx +1895 -0
  1063. package/src/components/ui/tu-do/shared/task-edit-dialog/task-relationships-properties.tsx +273 -0
  1064. package/src/components/ui/tu-do/shared/task-edit-dialog/task-snapshot-dialog.tsx +162 -0
  1065. package/src/components/ui/tu-do/shared/task-edit-dialog/types/pending-relationship.test.ts +52 -0
  1066. package/src/components/ui/tu-do/shared/task-edit-dialog/types/pending-relationship.ts +134 -0
  1067. package/src/components/ui/tu-do/shared/task-edit-dialog/types.ts +64 -0
  1068. package/src/components/ui/tu-do/shared/task-edit-dialog/user-display.test.ts +58 -0
  1069. package/src/components/ui/tu-do/shared/task-edit-dialog/user-display.ts +45 -0
  1070. package/src/components/ui/tu-do/shared/task-edit-dialog/utils/inline-task-target-list.test.ts +98 -0
  1071. package/src/components/ui/tu-do/shared/task-edit-dialog/utils/inline-task-target-list.ts +39 -0
  1072. package/src/components/ui/tu-do/shared/task-edit-dialog/utils.test.ts +404 -0
  1073. package/src/components/ui/tu-do/shared/task-edit-dialog/utils.ts +473 -0
  1074. package/src/components/ui/tu-do/shared/task-edit-dialog/yjs-prosemirror-compat.test.ts +65 -0
  1075. package/src/components/ui/tu-do/shared/task-edit-dialog.tsx +2168 -0
  1076. package/src/components/ui/tu-do/shared/task-estimation-display.tsx +52 -0
  1077. package/src/components/ui/tu-do/shared/task-estimation-picker.tsx +223 -0
  1078. package/src/components/ui/tu-do/shared/task-filter.types.ts +65 -0
  1079. package/src/components/ui/tu-do/shared/task-label-selector.tsx +217 -0
  1080. package/src/components/ui/tu-do/shared/task-labels-display.test.tsx +51 -0
  1081. package/src/components/ui/tu-do/shared/task-labels-display.tsx +119 -0
  1082. package/src/components/ui/tu-do/shared/task-legacy-route-recovery.tsx +72 -0
  1083. package/src/components/ui/tu-do/shared/task-open-events.ts +94 -0
  1084. package/src/components/ui/tu-do/shared/task-projects-display.tsx +80 -0
  1085. package/src/components/ui/tu-do/shared/task-resource-search-field.tsx +49 -0
  1086. package/src/components/ui/tu-do/shared/task-resource-search-filters.ts +27 -0
  1087. package/src/components/ui/tu-do/shared/task-row-actions-menu.tsx +352 -0
  1088. package/src/components/ui/tu-do/shared/task-share-dialog/components/share-link-settings.tsx +86 -0
  1089. package/src/components/ui/tu-do/shared/task-share-dialog/components/shares-list.tsx +85 -0
  1090. package/src/components/ui/tu-do/shared/task-share-dialog/hooks/use-task-sharing.ts +296 -0
  1091. package/src/components/ui/tu-do/shared/task-share-dialog.tsx +144 -0
  1092. package/src/components/ui/tu-do/shared/task-url.ts +56 -0
  1093. package/src/components/ui/tu-do/shared/text-diff-viewer.tsx +55 -0
  1094. package/src/components/ui/tu-do/shared/types.ts +14 -0
  1095. package/src/components/ui/tu-do/shared/unsaved-changes-warning-dialog.tsx +71 -0
  1096. package/src/components/ui/tu-do/shared/use-progressive-board-loader.ts +310 -0
  1097. package/src/components/ui/tu-do/shared/user-avatar.tsx +46 -0
  1098. package/src/components/ui/tu-do/shared/user-presence-avatars.tsx +415 -0
  1099. package/src/components/ui/tu-do/shared/utils/translate-task-list-display-name.ts +28 -0
  1100. package/src/components/ui/tu-do/tasks-route-context.tsx +50 -0
  1101. package/src/components/ui/tu-do/templates/client.tsx +486 -0
  1102. package/src/components/ui/tu-do/templates/marketplace/client.tsx +451 -0
  1103. package/src/components/ui/tu-do/templates/marketplace/task-marketplace-page.tsx +169 -0
  1104. package/src/components/ui/tu-do/templates/save-as-template-dialog.tsx +381 -0
  1105. package/src/components/ui/tu-do/templates/task-templates-page.tsx +162 -0
  1106. package/src/components/ui/tu-do/templates/templateId/client.tsx +659 -0
  1107. package/src/components/ui/tu-do/templates/templateId/edit-template-dialog.tsx +300 -0
  1108. package/src/components/ui/tu-do/templates/templateId/share-template-dialog.tsx +261 -0
  1109. package/src/components/ui/tu-do/templates/templateId/task-template-detail-page-client.tsx +121 -0
  1110. package/src/components/ui/tu-do/templates/templateId/task-template-detail-page.tsx +89 -0
  1111. package/src/components/ui/tu-do/templates/templateId/use-template-dialog.tsx +165 -0
  1112. package/src/components/ui/tu-do/templates/types.ts +53 -0
  1113. package/src/components/ui/tu-do/utils/__tests__/label-colors.test.ts +43 -0
  1114. package/src/components/ui/tu-do/utils/__tests__/taskColorUtils.test.ts +267 -0
  1115. package/src/components/ui/tu-do/utils/__tests__/taskConstants.test.ts +178 -0
  1116. package/src/components/ui/tu-do/utils/__tests__/taskDateUtils.test.ts +226 -0
  1117. package/src/components/ui/tu-do/utils/__tests__/weekDateUtils.test.ts +182 -0
  1118. package/src/components/ui/tu-do/utils/label-colors.test.ts +15 -0
  1119. package/src/components/ui/tu-do/utils/label-colors.ts +59 -0
  1120. package/src/components/ui/tu-do/utils/taskColorUtils.ts +116 -0
  1121. package/src/components/ui/tu-do/utils/taskConstants.ts +102 -0
  1122. package/src/components/ui/tu-do/utils/taskDateUtils.ts +81 -0
  1123. package/src/components/ui/tu-do/utils/taskPriorityUtils.tsx +80 -0
  1124. package/src/components/ui/tu-do/utils/weekDateUtils.ts +64 -0
  1125. package/src/constants/boards.ts +9 -0
  1126. package/src/declarations.d.ts +2 -0
  1127. package/src/globals.css +609 -200
  1128. package/src/gsap.ts +2 -0
  1129. package/src/hooks/__tests__/supabase-provider.test.ts +346 -0
  1130. package/src/hooks/__tests__/use-calendar-readonly.test.tsx +90 -0
  1131. package/src/hooks/__tests__/use-forwarded-ref.test.tsx +127 -0
  1132. package/src/hooks/__tests__/use-local-storage.test.tsx +243 -0
  1133. package/src/hooks/__tests__/use-mobile.test.tsx +222 -0
  1134. package/src/hooks/__tests__/use-notifications-subscription.test.tsx +163 -0
  1135. package/src/hooks/__tests__/use-notifications.test.ts +59 -0
  1136. package/src/hooks/__tests__/use-stable-array.test.tsx +214 -0
  1137. package/src/hooks/__tests__/use-task-actions.test.tsx +1893 -0
  1138. package/src/hooks/__tests__/use-workspace-presence.test.tsx +217 -0
  1139. package/src/hooks/__tests__/useBoardRealtime.test.tsx +1156 -0
  1140. package/src/hooks/supabase-provider.ts +725 -0
  1141. package/src/hooks/task-actions-personal-external.ts +308 -0
  1142. package/src/hooks/time-blocking-provider.tsx +756 -0
  1143. package/src/hooks/use-ai-credits.ts +78 -0
  1144. package/src/hooks/use-analytics-filters.ts +269 -0
  1145. package/src/hooks/use-at-bottom.tsx +64 -0
  1146. package/src/hooks/use-board-actions.ts +213 -0
  1147. package/src/hooks/use-calendar-preferences.tsx +24 -0
  1148. package/src/hooks/use-calendar-sync.tsx +1184 -0
  1149. package/src/hooks/use-calendar.tsx +1972 -0
  1150. package/src/hooks/use-callback-ref.ts +1 -1
  1151. package/src/hooks/use-controllable-state.ts +3 -4
  1152. package/src/hooks/use-copy-to-clipboard.ts +1 -3
  1153. package/src/hooks/use-currency-formatter.ts +81 -0
  1154. package/src/hooks/use-debounce.ts +15 -0
  1155. package/src/hooks/use-dom-resolved-theme.ts +81 -0
  1156. package/src/hooks/use-enter-submit.tsx +23 -0
  1157. package/src/hooks/use-exchange-rates.ts +23 -0
  1158. package/src/hooks/use-finance-transaction-preferences.ts +58 -0
  1159. package/src/hooks/use-form.ts +8 -6
  1160. package/src/hooks/use-interest-preferences.ts +104 -0
  1161. package/src/hooks/use-local-storage.ts +42 -0
  1162. package/src/hooks/use-notifications.ts +704 -0
  1163. package/src/hooks/use-page-visibility.ts +27 -0
  1164. package/src/hooks/use-popover-manager.tsx +98 -0
  1165. package/src/hooks/use-semantic-task-search.ts +76 -0
  1166. package/src/hooks/use-session-history-query.ts +1 -0
  1167. package/src/hooks/use-stable-array.ts +23 -0
  1168. package/src/hooks/use-task-actions.ts +1915 -0
  1169. package/src/hooks/use-task-analytics.ts +354 -0
  1170. package/src/hooks/use-toast.ts +2 -3
  1171. package/src/hooks/use-user-config.ts +109 -0
  1172. package/src/hooks/use-view-transition.ts +69 -0
  1173. package/src/hooks/use-workspace-config.ts +49 -0
  1174. package/src/hooks/use-workspace-currency.ts +26 -0
  1175. package/src/hooks/use-workspace-members.ts +58 -0
  1176. package/src/hooks/use-workspace-permission.ts +61 -0
  1177. package/src/hooks/use-workspace-presence.ts +554 -0
  1178. package/src/hooks/use-workspace-user.ts +33 -0
  1179. package/src/hooks/use-yjs-collaboration.ts +297 -0
  1180. package/src/hooks/useBoardRealtime.ts +372 -0
  1181. package/src/hooks/useBoardRealtime.types.ts +45 -0
  1182. package/src/hooks/useBoardRealtimeEventHandler.ts +332 -0
  1183. package/src/hooks/useCursorTracking.ts +338 -0
  1184. package/src/hooks/useHorizontalScroll.ts +215 -0
  1185. package/src/hooks/usePresence.ts +272 -0
  1186. package/src/hooks/useSearchParams.tsx +133 -0
  1187. package/src/lib/__tests__/lunar-calendar.test.ts +137 -0
  1188. package/src/lib/calendar/planning-query-client.ts +197 -0
  1189. package/src/lib/calendar/preview-engine.ts +14 -0
  1190. package/src/lib/calendar-settings-resolver.ts +200 -0
  1191. package/src/lib/lunar-calendar.ts +71 -0
  1192. package/src/lib/template-background.ts +159 -0
  1193. package/src/lib/workspace-actions.ts +457 -0
  1194. package/src/utils/__tests__/label-colors.test.ts +219 -0
  1195. package/src/utils/__tests__/priority-styles.test.ts +78 -0
  1196. package/src/utils/label-colors.ts +4 -0
  1197. package/src/utils/priority-styles.ts +42 -0
  1198. package/src/xlsx.ts +3 -0
  1199. package/tsconfig.json +3 -11
  1200. package/tsconfig.typecheck.json +9 -0
  1201. package/vendor/xlsx-0.20.3.tgz +0 -0
  1202. package/vitest.config.ts +42 -0
  1203. package/vitest.setup.ts +37 -0
  1204. package/eslint.config.mjs +0 -20
  1205. package/rollup.config.js +0 -40
  1206. package/src/components/ui/icons.tsx +0 -506
  1207. package/src/components/ui/tag-input.tsx +0 -141
  1208. /package/src/hooks/{use-mobile.tsx → use-mobile.ts} +0 -0
@@ -0,0 +1,1430 @@
1
+ import { useQueryClient } from '@tanstack/react-query';
2
+ import {
3
+ AlertTriangle,
4
+ ArrowLeft,
5
+ ArrowRight,
6
+ Check,
7
+ Edit,
8
+ Eye,
9
+ Lock,
10
+ Palette,
11
+ Pencil,
12
+ RefreshCw,
13
+ Repeat,
14
+ Trash2,
15
+ Unlock,
16
+ } from '@tuturuuu/icons';
17
+ import type { CalendarEvent } from '@tuturuuu/types/primitives/calendar-event';
18
+ import type { SupportedColor } from '@tuturuuu/types/primitives/SupportedColors';
19
+ import { useCalendar } from '@tuturuuu/ui/hooks/use-calendar';
20
+ import { getEventStyles } from '@tuturuuu/utils/color-helper';
21
+ import { cn } from '@tuturuuu/utils/format';
22
+ import { containsHtml, sanitizeHtml } from '@tuturuuu/utils/html-sanitizer';
23
+ import dayjs from 'dayjs';
24
+ import timezone from 'dayjs/plugin/timezone';
25
+ import { useCallback, useEffect, useRef, useState } from 'react';
26
+ import {
27
+ ContextMenu,
28
+ ContextMenuContent,
29
+ ContextMenuItem,
30
+ ContextMenuSeparator,
31
+ ContextMenuSub,
32
+ ContextMenuSubContent,
33
+ ContextMenuSubTrigger,
34
+ ContextMenuTrigger,
35
+ } from '../../context-menu';
36
+ import { GRID_SNAP, HOUR_HEIGHT, MAX_HOURS, MIN_EVENT_HEIGHT } from './config';
37
+ import { useCalendarSettings } from './settings/settings-context';
38
+
39
+ dayjs.extend(timezone);
40
+
41
+ // Utility function to round time to nearest 15-minute interval
42
+ const roundToNearest15Minutes = (date: Date): Date => {
43
+ const minutes = date.getMinutes();
44
+ const remainder = minutes % 15;
45
+ const roundedMinutes =
46
+ remainder < 8 ? minutes - remainder : minutes + (15 - remainder);
47
+ const roundedDate = new Date(date);
48
+ roundedDate.setMinutes(roundedMinutes);
49
+ roundedDate.setSeconds(0);
50
+ roundedDate.setMilliseconds(0);
51
+ return roundedDate;
52
+ };
53
+
54
+ interface EventCardProps {
55
+ dates: Date[];
56
+ wsId: string;
57
+ event: CalendarEvent;
58
+ level?: number; // Level for stacking events
59
+ }
60
+
61
+ export function EventCard({ dates, event, level = 0 }: EventCardProps) {
62
+ const {
63
+ id,
64
+ title,
65
+ description,
66
+ // start_at,
67
+ end_at,
68
+ color = 'BLUE',
69
+ locked = false,
70
+ _isMultiDay,
71
+ _dayPosition,
72
+ _overlapCount,
73
+ _overlapGroup,
74
+ _column,
75
+ google_calendar_id,
76
+ _calendarName,
77
+ _calendarColor,
78
+ // Habit flags (from CalendarEventWithHabitInfo)
79
+ _isHabit,
80
+ _habitCompleted,
81
+ // Preview flags (from preview mode)
82
+ _isPreview,
83
+ _isReused,
84
+ _previewType,
85
+ _warning,
86
+ } = event as CalendarEvent & {
87
+ _isHabit?: boolean;
88
+ _habitCompleted?: boolean;
89
+ _isPreview?: boolean;
90
+ _isReused?: boolean;
91
+ _previewType?: 'habit' | 'task';
92
+ _warning?: string;
93
+ };
94
+
95
+ // Default values for overlap properties if not provided
96
+ const overlapCount = _overlapCount || 1;
97
+ const overlapGroup = _overlapGroup || [id];
98
+ const columnIndex = _column ?? 0;
99
+
100
+ const {
101
+ updateEvent,
102
+ hideModal,
103
+ openModal,
104
+ deleteEvent,
105
+ hoveredBaseEventId,
106
+ setHoveredBaseEventId,
107
+ hoveredEventColumn,
108
+ setHoveredEventColumn,
109
+ affectedEventIds,
110
+ } = useCalendar();
111
+
112
+ // NOTE: Event filtering for hideNonPreviewEvents is handled in CalendarEventMatrix
113
+ // This ensures proper elevation calculation. We no longer hide events here.
114
+ const { settings } = useCalendarSettings();
115
+ const queryClient = useQueryClient();
116
+ const tz = settings?.timezone?.timezone;
117
+
118
+ // Local state for immediate UI updates
119
+ const [localEvent, setLocalEvent] = useState<CalendarEvent>(event);
120
+
121
+ // Parse dates properly using selected time zone
122
+ const startDate =
123
+ tz === 'auto'
124
+ ? dayjs(localEvent.start_at)
125
+ : dayjs(localEvent.start_at).tz(tz);
126
+ const endDate =
127
+ tz === 'auto' ? dayjs(localEvent.end_at) : dayjs(localEvent.end_at).tz(tz);
128
+
129
+ // Calculate hours with decimal minutes for positioning
130
+ const startHours = Math.min(
131
+ MAX_HOURS - 0.01,
132
+ startDate.hour() + startDate.minute() / 60
133
+ );
134
+
135
+ const endHours = Math.min(MAX_HOURS, endDate.hour() + endDate.minute() / 60);
136
+
137
+ // Calculate duration, handling overnight events correctly
138
+ const duration =
139
+ endHours <= startHours && !_isMultiDay
140
+ ? MAX_HOURS - startHours + endHours
141
+ : endHours - startHours;
142
+
143
+ // Calculate duration in minutes
144
+ // const durationMs = (dayjs(endDate).valueOf() - dayjs(startDate).valueOf());
145
+ // const durationMinutes = Math.round(durationMs / (1000 * 60));
146
+
147
+ // Refs for DOM elements
148
+ const cardRef = useRef<HTMLButtonElement>(null);
149
+ const handleRef = useRef<HTMLDivElement>(null);
150
+ const contentRef = useRef<HTMLDivElement>(null);
151
+
152
+ // Refs for tracking interaction state without re-renders
153
+ const isDraggingRef = useRef(false);
154
+ const isResizingRef = useRef(false);
155
+ const wasDraggedRef = useRef(false);
156
+ const wasResizedRef = useRef(false);
157
+ const initialPositionRef = useRef({ x: 0, y: 0 });
158
+ const currentPositionRef = useRef({ top: 0, left: 0 });
159
+ const syncPendingRef = useRef(false);
160
+
161
+ // Visual states that trigger renders
162
+ const [isHovering, setIsHovering] = useState(false);
163
+ const [isSyncing, setIsSyncing] = useState(false);
164
+ const [updateStatus, setUpdateStatus] = useState<
165
+ 'idle' | 'syncing' | 'success' | 'error'
166
+ >('idle');
167
+ const [visualState, setVisualState] = useState({
168
+ isDragging: false,
169
+ isResizing: false,
170
+ });
171
+
172
+ // Status feedback timeout
173
+ const statusTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
174
+
175
+ // Show temporary status feedback
176
+ const showStatusFeedback = useCallback((status: 'success' | 'error') => {
177
+ setUpdateStatus(status);
178
+
179
+ // Clear any existing timeout
180
+ if (statusTimeoutRef.current) {
181
+ clearTimeout(statusTimeoutRef.current);
182
+ }
183
+
184
+ // Reset status after a short delay, regardless of pending updates
185
+ // This ensures status indicators don't stay visible indefinitely
186
+ statusTimeoutRef.current = setTimeout(() => {
187
+ // For success status, always clear after a short delay
188
+ if (status === 'success') {
189
+ setUpdateStatus('idle');
190
+ statusTimeoutRef.current = null;
191
+ } else if (status === 'error') {
192
+ // For errors, we might want to keep them visible a bit longer
193
+ // but still clear them eventually
194
+ setTimeout(() => {
195
+ setUpdateStatus('idle');
196
+ }, 3000);
197
+ statusTimeoutRef.current = null;
198
+ }
199
+ }, 1500);
200
+ }, []);
201
+
202
+ // Batch visual state updates to reduce renders
203
+ const updateVisualState = useCallback(
204
+ (updates: Partial<typeof visualState>) => {
205
+ setVisualState((prev) => ({ ...prev, ...updates }));
206
+ },
207
+ []
208
+ );
209
+
210
+ // Debounced update function to reduce API calls
211
+ const updateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
212
+ const pendingUpdateRef = useRef<{
213
+ start_at: string;
214
+ end_at: string;
215
+ } | null>(null);
216
+
217
+ // Schedule a throttled update
218
+ const scheduleUpdate = useCallback(
219
+ (updateData: { start_at: string; end_at: string }) => {
220
+ // For multi-day events, we need to update the original event
221
+ const eventId = event._originalId || id;
222
+
223
+ // Store the latest update data
224
+ pendingUpdateRef.current = updateData;
225
+ syncPendingRef.current = true;
226
+
227
+ // Immediately update local event data for UI rendering
228
+ // Include locked: true since moving/resizing auto-locks the event
229
+ setLocalEvent((prev) => ({
230
+ ...prev,
231
+ ...updateData,
232
+ locked: true,
233
+ }));
234
+
235
+ // Show syncing state immediately
236
+ setIsSyncing(true);
237
+ setUpdateStatus('syncing');
238
+
239
+ // Only start a new timer if there isn't one already
240
+ if (!updateTimeoutRef.current) {
241
+ updateTimeoutRef.current = setTimeout(() => {
242
+ if (pendingUpdateRef.current) {
243
+ updateEvent(eventId, pendingUpdateRef.current)
244
+ .then(() => {
245
+ showStatusFeedback('success');
246
+ })
247
+ .catch((error) => {
248
+ console.error('Failed to update event:', error);
249
+ showStatusFeedback('error');
250
+
251
+ // Revert to original data on error
252
+ setLocalEvent(event);
253
+ })
254
+ .finally(() => {
255
+ syncPendingRef.current = false;
256
+ setTimeout(() => {
257
+ if (!syncPendingRef.current) {
258
+ setIsSyncing(false);
259
+ }
260
+ }, 300);
261
+ });
262
+
263
+ pendingUpdateRef.current = null;
264
+ }
265
+
266
+ updateTimeoutRef.current = null;
267
+ }, 250); // Throttle to once every 250ms
268
+ }
269
+ },
270
+ [updateEvent, event, id, showStatusFeedback]
271
+ );
272
+
273
+ // Clean up any pending updates
274
+ useEffect(() => {
275
+ return () => {
276
+ if (updateTimeoutRef.current) {
277
+ clearTimeout(updateTimeoutRef.current);
278
+ }
279
+ };
280
+ }, []);
281
+
282
+ // Keep local state in sync with prop changes
283
+ useEffect(() => {
284
+ // Only update if we're not in the middle of a drag/resize operation
285
+ if (!isDraggingRef.current && !isResizingRef.current && !isSyncing) {
286
+ setLocalEvent(event);
287
+ }
288
+ }, [event, isSyncing]);
289
+
290
+ // Initial event positioning
291
+ useEffect(() => {
292
+ const cardEl = document.getElementById(`event-${id}`);
293
+ const cellEl = document.querySelector('.calendar-cell') as HTMLDivElement;
294
+
295
+ if (!cardEl || !cellEl) return;
296
+
297
+ // Calculate event height based on duration
298
+ let height = Math.max(MIN_EVENT_HEIGHT, duration * HOUR_HEIGHT);
299
+
300
+ // For multi-day events, adjust the height and position
301
+ if (_isMultiDay) {
302
+ if (_dayPosition === 'start') {
303
+ // First day - start at the event's start time, end at midnight
304
+ height = Math.max(
305
+ MIN_EVENT_HEIGHT,
306
+ (MAX_HOURS - startHours) * HOUR_HEIGHT
307
+ );
308
+ } else if (_dayPosition === 'end') {
309
+ // Last day - start at midnight, end at the event's end time
310
+ height = Math.max(MIN_EVENT_HEIGHT, endHours * HOUR_HEIGHT);
311
+ } else {
312
+ // Middle days - full day from midnight to midnight
313
+ height = MAX_HOURS * HOUR_HEIGHT;
314
+ }
315
+ }
316
+
317
+ // Ensure height doesn't exceed the day's bounds
318
+ height = Math.min(
319
+ height,
320
+ MAX_HOURS * HOUR_HEIGHT - startHours * HOUR_HEIGHT
321
+ );
322
+
323
+ // Calculate the index of the day the event is in
324
+ const dateIdx = dates.findIndex((date) => {
325
+ const eventDate = startDate;
326
+ return (
327
+ date.getFullYear() === eventDate.year() &&
328
+ date.getMonth() === eventDate.month() &&
329
+ date.getDate() === eventDate.date()
330
+ );
331
+ });
332
+
333
+ if (dateIdx === -1) {
334
+ cardEl.style.opacity = '0';
335
+ cardEl.style.pointerEvents = 'none';
336
+ return;
337
+ }
338
+
339
+ // Update event dimensions and position
340
+ cardEl.style.height = `${height - 4}px`;
341
+
342
+ // Position based on start time
343
+ if (_isMultiDay && _dayPosition !== 'start') {
344
+ // For middle and end segments, start at the top of the day
345
+ cardEl.style.top = '0px';
346
+ } else {
347
+ // Ensure startHours doesn't exceed 24 hours
348
+ const clampedStartHours = Math.min(startHours, MAX_HOURS - 0.01);
349
+ cardEl.style.top = `${clampedStartHours * HOUR_HEIGHT}px`;
350
+ }
351
+
352
+ const updatePosition = () => {
353
+ if (!cardEl || !cellEl) return;
354
+
355
+ const columnWidth = cellEl.offsetWidth;
356
+
357
+ // Calculate event index within its overlap group
358
+ // const overlapIndex = overlapGroup.indexOf(id);
359
+
360
+ // If this event has overlaps, distribute width among overlapping events
361
+ const hasOverlaps = overlapCount > 1;
362
+
363
+ // Width calculation based on overlap count
364
+ let eventWidth: number, eventLeft: number;
365
+
366
+ if (hasOverlaps) {
367
+ // Use the column index from the graph coloring algorithm
368
+ // Column 0 = base layer (full width), Column 1+ = stacked layers
369
+
370
+ // Configuration for layered stacking
371
+ const baseMargin = 4; // Base margin for the day column
372
+ const layerIndent = 16; // Indent for each layer (more visible)
373
+ const layerWidthReduction = 16; // Width reduction per layer
374
+ const minEventWidth = 60; // Minimum width to remain readable
375
+
376
+ if (columnIndex === 0) {
377
+ // Column 0 (base layer): FULL WIDTH - same as non-overlapping
378
+ eventWidth = columnWidth - baseMargin;
379
+ eventLeft = dateIdx * columnWidth + dateIdx * 2;
380
+ } else {
381
+ // Column 1+ (stacked layers): indented and slightly narrower
382
+ const indent = layerIndent * columnIndex;
383
+ const widthReduction = layerWidthReduction * columnIndex;
384
+
385
+ eventWidth = Math.max(
386
+ minEventWidth,
387
+ columnWidth - widthReduction - 4
388
+ );
389
+ eventLeft = dateIdx * columnWidth + indent + dateIdx * 2;
390
+ }
391
+ } else {
392
+ // No overlaps - use full width (with small margin)
393
+ eventWidth = columnWidth - 4;
394
+ eventLeft = dateIdx * columnWidth + dateIdx * 2;
395
+ }
396
+
397
+ cardEl.style.width = `${eventWidth}px`;
398
+ cardEl.style.left = `${eventLeft}px`;
399
+
400
+ // Smart z-index layering: Column-based stacking
401
+ // Column 0 = lower z-index (bottom layer)
402
+ // Column 1+ = higher z-index (top layer)
403
+ if (hasOverlaps) {
404
+ cardEl.style.zIndex = String(10 + columnIndex);
405
+ } else {
406
+ cardEl.style.zIndex = '10';
407
+ }
408
+
409
+ // Store the initial position
410
+ currentPositionRef.current = {
411
+ top: parseInt(cardEl.style.top, 10),
412
+ left: parseInt(cardEl.style.left, 10),
413
+ };
414
+ };
415
+
416
+ // Set initial position
417
+ updatePosition();
418
+
419
+ // Track resize for responsive layout
420
+ const observer = new ResizeObserver(() => {
421
+ requestAnimationFrame(updatePosition);
422
+ });
423
+
424
+ observer.observe(cellEl);
425
+
426
+ // Check if the event is in the past
427
+ const isPastEvent = endDate.isBefore(dayjs());
428
+
429
+ // Check if this event should be transparent due to hover state
430
+ // An event is transparent if:
431
+ // 1. There are overlaps
432
+ // 2. Another event is being hovered
433
+ // 3. This event's column is higher than the hovered event's column
434
+ // 4. Both events are in the same overlap group
435
+ const shouldBeTransparent =
436
+ overlapCount > 1 &&
437
+ hoveredBaseEventId &&
438
+ hoveredEventColumn !== null &&
439
+ columnIndex > hoveredEventColumn &&
440
+ overlapGroup.includes(hoveredBaseEventId);
441
+
442
+ // Set opacity based on transparency state, then past event state
443
+ if (shouldBeTransparent) {
444
+ cardEl.style.opacity = '0.05';
445
+ cardEl.style.pointerEvents = 'none';
446
+ } else if (isPastEvent) {
447
+ cardEl.style.opacity = '0.5';
448
+ cardEl.style.pointerEvents = 'all';
449
+ } else {
450
+ cardEl.style.opacity = '1';
451
+ cardEl.style.pointerEvents = 'all';
452
+ }
453
+
454
+ return () => observer.disconnect();
455
+ }, [
456
+ id,
457
+ startDate,
458
+ duration,
459
+ columnIndex,
460
+ dates,
461
+ _isMultiDay,
462
+ _dayPosition,
463
+ startHours,
464
+ endHours,
465
+ overlapCount,
466
+ overlapGroup,
467
+ hoveredBaseEventId,
468
+ hoveredEventColumn,
469
+ endDate,
470
+ ]);
471
+
472
+ // Event resizing - only enable for non-multi-day events or the start/end segments
473
+ useEffect(() => {
474
+ // Disable resizing for middle segments of multi-day events
475
+ // Note: locked events CAN still be resized - locked only prevents auto-scheduling
476
+ if (_isMultiDay && _dayPosition === 'middle') return;
477
+
478
+ const handleEl = handleRef.current;
479
+ const eventCardEl = document.getElementById(`event-${id}`);
480
+ if (!handleEl || !eventCardEl) return;
481
+
482
+ let startY = 0;
483
+ let startHeight = 0;
484
+ let hasMoved = false;
485
+
486
+ const handleMouseDown = (e: MouseEvent) => {
487
+ e.stopPropagation();
488
+ e.preventDefault();
489
+
490
+ // Don't allow multiple operations
491
+ if (isDraggingRef.current || isResizingRef.current) return;
492
+
493
+ startY = e.clientY;
494
+ startHeight = eventCardEl.offsetHeight;
495
+ isResizingRef.current = true;
496
+ wasResizedRef.current = false;
497
+ hasMoved = false;
498
+
499
+ // Update visual state
500
+ updateVisualState({ isResizing: true });
501
+ setUpdateStatus('idle'); // Reset any previous status
502
+
503
+ // Prevent interaction with other events
504
+ hideModal();
505
+
506
+ // Change cursor for better UX
507
+ document.body.style.cursor = 'ns-resize';
508
+ document.body.classList.add('select-none');
509
+
510
+ const handleMouseMove = (e: MouseEvent) => {
511
+ e.preventDefault();
512
+
513
+ if (!isResizingRef.current) return;
514
+
515
+ // Calculate height change
516
+ const dy = e.clientY - startY;
517
+
518
+ // Only process if there's significant movement
519
+ if (!hasMoved && Math.abs(dy) < 5) return;
520
+
521
+ hasMoved = true;
522
+ wasResizedRef.current = true;
523
+
524
+ // Snap to grid
525
+ const newHeight = Math.max(
526
+ MIN_EVENT_HEIGHT,
527
+ Math.round((startHeight + dy) / GRID_SNAP) * GRID_SNAP
528
+ );
529
+
530
+ // Update height with a maximum limit
531
+ const maxHeight = _isMultiDay
532
+ ? _dayPosition === 'start'
533
+ ? (MAX_HOURS - startHours) * HOUR_HEIGHT
534
+ : MAX_HOURS * HOUR_HEIGHT
535
+ : MAX_HOURS * HOUR_HEIGHT;
536
+
537
+ const constrainedHeight = Math.min(newHeight, maxHeight);
538
+ eventCardEl.style.height = `${constrainedHeight}px`;
539
+
540
+ // Calculate new end time
541
+ let newEndAt: dayjs.Dayjs;
542
+
543
+ if (_isMultiDay) {
544
+ if (_dayPosition === 'start') {
545
+ // For start segment, we're adjusting the end time of the first day
546
+ newEndAt = startDate.clone();
547
+ // Calculate hours directly from pixels for better precision
548
+ const newEndHours = constrainedHeight / HOUR_HEIGHT + startHours;
549
+ const newEndHour = Math.min(23, Math.floor(newEndHours));
550
+ const newEndMinute = Math.round(
551
+ (newEndHours - Math.floor(newEndHours)) * 60
552
+ );
553
+ newEndAt = newEndAt
554
+ .hour(newEndHour)
555
+ .minute(newEndMinute)
556
+ .second(0)
557
+ .millisecond(0);
558
+ // Snap to 15-minute intervals
559
+ newEndAt = dayjs(roundToNearest15Minutes(newEndAt.toDate()));
560
+ } else if (_dayPosition === 'end') {
561
+ // For end segment, we're adjusting the end time of the last day
562
+ newEndAt = endDate.clone();
563
+ const newDuration = constrainedHeight / HOUR_HEIGHT;
564
+ const newEndHour = Math.min(23, Math.floor(newDuration));
565
+ const newEndMinute = Math.round(
566
+ (newDuration - Math.floor(newDuration)) * 60
567
+ );
568
+ newEndAt = newEndAt
569
+ .hour(newEndHour)
570
+ .minute(newEndMinute)
571
+ .second(0)
572
+ .millisecond(0);
573
+ // Snap to 15-minute intervals
574
+ newEndAt = dayjs(roundToNearest15Minutes(newEndAt.toDate()));
575
+ } else {
576
+ return; // Should not happen
577
+ }
578
+ } else {
579
+ // Regular event
580
+ const newDuration = constrainedHeight / HOUR_HEIGHT; // Convert pixels to hours
581
+ // Calculate end time directly from start time + duration
582
+ newEndAt = startDate.clone().add(newDuration, 'hour');
583
+ // Snap to 15-minute intervals
584
+ newEndAt = dayjs(roundToNearest15Minutes(newEndAt.toDate()));
585
+ // Ensure end time doesn't wrap to the next day
586
+ if (newEndAt.isBefore(startDate)) {
587
+ newEndAt = newEndAt.add(1, 'day');
588
+ }
589
+ }
590
+
591
+ // After calculating the rounded end time, adjust the visual height to match
592
+ const durationInHours =
593
+ (dayjs(newEndAt).valueOf() - startDate.valueOf()) / (1000 * 60 * 60);
594
+ const adjustedHeight = durationInHours * HOUR_HEIGHT;
595
+ eventCardEl.style.height = `${Math.max(MIN_EVENT_HEIGHT, adjustedHeight)}px`;
596
+
597
+ // Schedule the update
598
+ scheduleUpdate({
599
+ start_at: startDate.toISOString(),
600
+ end_at: newEndAt.toISOString(),
601
+ });
602
+
603
+ // Explicitly set local event end time for immediate UI update
604
+ setLocalEvent((prev) => ({
605
+ ...prev,
606
+ end_at: newEndAt.toISOString(),
607
+ locked: true,
608
+ }));
609
+ };
610
+
611
+ const handleMouseUp = () => {
612
+ isResizingRef.current = false;
613
+ updateVisualState({ isResizing: false });
614
+
615
+ // Restore cursor
616
+ document.body.style.cursor = '';
617
+ document.body.classList.remove('select-none');
618
+
619
+ // Set resize flag
620
+ wasResizedRef.current = hasMoved;
621
+
622
+ // Send a final update if needed
623
+ if (pendingUpdateRef.current) {
624
+ setUpdateStatus('syncing'); // Start syncing animation immediately
625
+ updateEvent(event._originalId || id, pendingUpdateRef.current)
626
+ .then(() => {
627
+ showStatusFeedback('success');
628
+ })
629
+ .catch((error) => {
630
+ console.error('Failed to update event:', error);
631
+ showStatusFeedback('error');
632
+ });
633
+ pendingUpdateRef.current = null;
634
+ }
635
+
636
+ // Invalidate task schedule query to refresh sidebar
637
+ queryClient.invalidateQueries({
638
+ queryKey: ['task-schedule-batch'],
639
+ });
640
+
641
+ // Clean up
642
+ document.removeEventListener('mousemove', handleMouseMove);
643
+ document.removeEventListener('mouseup', handleMouseUp);
644
+ };
645
+
646
+ window.addEventListener('mousemove', handleMouseMove, { passive: false });
647
+ window.addEventListener('mouseup', handleMouseUp);
648
+ };
649
+
650
+ handleEl.addEventListener('mousedown', handleMouseDown);
651
+ return () => handleEl.removeEventListener('mousedown', handleMouseDown);
652
+ }, [
653
+ id,
654
+ startDate,
655
+ updateEvent,
656
+ hideModal,
657
+ _isMultiDay,
658
+ _dayPosition,
659
+ event._originalId,
660
+ startHours,
661
+ endDate,
662
+ scheduleUpdate,
663
+ showStatusFeedback, // Update visual state
664
+ updateVisualState,
665
+ queryClient,
666
+ ]);
667
+
668
+ // Event dragging - only enable for non-multi-day events
669
+ useEffect(() => {
670
+ // Disable dragging for multi-day events only
671
+ // Note: locked events CAN still be dragged - locked only prevents auto-scheduling
672
+ if (_isMultiDay) return;
673
+
674
+ const contentEl = contentRef.current;
675
+ const eventCardEl = document.getElementById(`event-${id}`);
676
+ const cellEl = document.querySelector('.calendar-cell') as HTMLDivElement;
677
+
678
+ if (!contentEl || !eventCardEl || !cellEl) return;
679
+
680
+ let startX = 0;
681
+ let startY = 0;
682
+ let initialCardPosition = { top: 0, left: 0 };
683
+ let columnWidth = 0;
684
+ let hasMoved = false;
685
+
686
+ const handleMouseDown = (e: MouseEvent) => {
687
+ // Only handle primary mouse button (left click)
688
+ if (e.button !== 0) return;
689
+
690
+ e.stopPropagation();
691
+
692
+ // Don't allow multiple operations
693
+ if (isResizingRef.current || isDraggingRef.current) return;
694
+
695
+ // Record initial positions
696
+ startX = e.clientX;
697
+ startY = e.clientY;
698
+
699
+ // Record initial card position
700
+ initialCardPosition = {
701
+ top: eventCardEl.offsetTop,
702
+ left: eventCardEl.offsetLeft,
703
+ };
704
+
705
+ // Update cached dimensions
706
+ columnWidth = cellEl.offsetWidth;
707
+
708
+ // Reset tracking state
709
+ hasMoved = false;
710
+ wasDraggedRef.current = false;
711
+ initialPositionRef.current = { x: e.clientX, y: e.clientY };
712
+ currentPositionRef.current = initialCardPosition;
713
+ isDraggingRef.current = true;
714
+
715
+ // Update visual state for immediate feedback
716
+ updateVisualState({ isDragging: true });
717
+ setUpdateStatus('idle'); // Reset any previous status
718
+
719
+ // Prevent interaction with other events
720
+ hideModal();
721
+
722
+ // Apply drag styling
723
+ document.body.style.cursor = 'grabbing';
724
+ document.body.classList.add('select-none');
725
+
726
+ const handleMouseMove = (e: MouseEvent) => {
727
+ e.preventDefault();
728
+
729
+ if (isResizingRef.current) return;
730
+
731
+ // Calculate delta movement
732
+ const dx = e.clientX - startX;
733
+ const dy = e.clientY - startY;
734
+
735
+ // Only start dragging if moved beyond threshold
736
+ if (!hasMoved) {
737
+ if (Math.abs(dx) < 8 && Math.abs(dy) < 8) return;
738
+
739
+ // Start drag mode
740
+ isDraggingRef.current = true;
741
+ wasDraggedRef.current = true;
742
+ hasMoved = true;
743
+
744
+ // Update visual state
745
+ updateVisualState({ isDragging: true });
746
+
747
+ // Other UI adjustments
748
+ hideModal();
749
+ document.body.classList.add('select-none');
750
+ }
751
+
752
+ // Snap to grid - ensure we move in whole units
753
+ const snapToGrid = (value: number, gridSize: number) => {
754
+ return Math.round(value / gridSize) * gridSize;
755
+ };
756
+
757
+ // Calculate new position with snapping
758
+ const newTop = snapToGrid(initialCardPosition.top + dy, GRID_SNAP);
759
+ const newLeft = snapToGrid(initialCardPosition.left + dx, columnWidth);
760
+
761
+ // Constrain vertical position to stay within the day (0-24h)
762
+ const constrainedTop = Math.max(
763
+ 0,
764
+ Math.min(newTop, MAX_HOURS * HOUR_HEIGHT - MIN_EVENT_HEIGHT)
765
+ );
766
+
767
+ // Keep track of the current position to avoid redundant updates
768
+ const positionChanged =
769
+ constrainedTop !== currentPositionRef.current.top ||
770
+ newLeft !== currentPositionRef.current.left;
771
+
772
+ if (positionChanged) {
773
+ // Update visual position immediately (with GPU acceleration)
774
+ eventCardEl.style.transform = `translate3d(${
775
+ newLeft - initialCardPosition.left
776
+ }px, ${constrainedTop - initialCardPosition.top}px, 0)`;
777
+
778
+ // Store the current position
779
+ currentPositionRef.current = { top: constrainedTop, left: newLeft };
780
+
781
+ // Calculate new times based on position
782
+ const newDateIdx = Math.floor(newLeft / columnWidth);
783
+ // Calculate hours directly from pixels - improve precision
784
+ const newStartHour = constrainedTop / HOUR_HEIGHT;
785
+ const newStartHourFloor = Math.floor(newStartHour);
786
+ const newStartMinute = Math.round(
787
+ (newStartHour - newStartHourFloor) * 60
788
+ );
789
+
790
+ const newStartAt = startDate.toDate();
791
+ newStartAt.setHours(newStartHourFloor);
792
+ newStartAt.setMinutes(newStartMinute);
793
+
794
+ // Snap start time to 15-minute intervals
795
+ const roundedStartAt = roundToNearest15Minutes(newStartAt);
796
+
797
+ // Adjust the visual position to match the snapped time
798
+ const roundedHours =
799
+ roundedStartAt.getHours() + roundedStartAt.getMinutes() / 60;
800
+ const roundedTop = roundedHours * HOUR_HEIGHT;
801
+
802
+ // Update the visual position to match the snapped time
803
+ eventCardEl.style.transform = `translate3d(${Math.max(
804
+ (newLeft - initialCardPosition.left) / 60 - 4,
805
+ 0
806
+ )}px, ${Math.max((roundedTop - initialCardPosition.top) / 60 - 4, 0)}px, 0)`;
807
+
808
+ // Update the current position reference
809
+ currentPositionRef.current = { top: roundedTop, left: newLeft };
810
+
811
+ // Update date if moved to different day
812
+ if (newDateIdx >= 0 && newDateIdx < dates.length) {
813
+ const newDate = dates[newDateIdx];
814
+ if (newDate) {
815
+ roundedStartAt.setFullYear(newDate.getFullYear());
816
+ roundedStartAt.setMonth(newDate.getMonth());
817
+ roundedStartAt.setDate(newDate.getDate());
818
+ }
819
+ }
820
+
821
+ // Calculate new end time maintaining original duration
822
+ const newEndAt = dayjs(roundedStartAt)
823
+ .add(endDate.valueOf() - startDate.valueOf(), 'millisecond')
824
+ .toDate();
825
+
826
+ // Schedule update
827
+ scheduleUpdate({
828
+ start_at: roundedStartAt.toISOString(),
829
+ end_at: newEndAt.toISOString(),
830
+ });
831
+
832
+ // Explicitly update local event for immediate UI update
833
+ setLocalEvent((prev) => ({
834
+ ...prev,
835
+ start_at: roundedStartAt.toISOString(),
836
+ end_at: newEndAt.toISOString(),
837
+ locked: true,
838
+ }));
839
+ }
840
+ };
841
+
842
+ const handleMouseUp = (e: MouseEvent) => {
843
+ if (hasMoved) {
844
+ // Reset drag state
845
+ isDraggingRef.current = false;
846
+ updateVisualState({ isDragging: false });
847
+ document.body.classList.remove('select-none');
848
+ document.body.style.cursor = '';
849
+
850
+ // Set flag to indicate this was a drag operation
851
+ wasDraggedRef.current = true;
852
+
853
+ // Need to update the actual position properties
854
+ // to match the transform we've been using
855
+ if (eventCardEl) {
856
+ const currentTop = currentPositionRef.current.top;
857
+ const currentLeft = currentPositionRef.current.left;
858
+
859
+ // Reset transform and set direct position
860
+ eventCardEl.style.transform = '';
861
+ eventCardEl.style.top = `${currentTop}px`;
862
+ eventCardEl.style.left = `${currentLeft}px`;
863
+
864
+ // Ensure final update is sent
865
+ if (pendingUpdateRef.current) {
866
+ setUpdateStatus('syncing'); // Start syncing animation immediately
867
+ updateEvent(event._originalId || id, pendingUpdateRef.current)
868
+ .then(() => {
869
+ showStatusFeedback('success');
870
+ })
871
+ .catch((error) => {
872
+ console.error('Failed to update event:', error);
873
+ showStatusFeedback('error');
874
+ });
875
+ pendingUpdateRef.current = null;
876
+ }
877
+ }
878
+ } else {
879
+ // Reset state if no actual drag occurred
880
+ isDraggingRef.current = false;
881
+ updateVisualState({ isDragging: false });
882
+ document.body.classList.remove('select-none');
883
+ document.body.style.cursor = '';
884
+
885
+ // Check if this was just a click (no significant movement)
886
+ const deltaX = Math.abs(e.clientX - initialPositionRef.current.x);
887
+ const deltaY = Math.abs(e.clientY - initialPositionRef.current.y);
888
+
889
+ if (deltaX < 5 && deltaY < 5) {
890
+ openModal(event._originalId || id);
891
+ }
892
+ }
893
+
894
+ window.removeEventListener('mousemove', handleMouseMove);
895
+ window.removeEventListener('mouseup', handleMouseUp);
896
+ };
897
+
898
+ window.addEventListener('mousemove', handleMouseMove, { passive: false });
899
+ window.addEventListener('mouseup', handleMouseUp);
900
+ };
901
+
902
+ contentEl.addEventListener('mousedown', handleMouseDown);
903
+ return () => contentEl.removeEventListener('mousedown', handleMouseDown);
904
+ }, [
905
+ id,
906
+ startDate,
907
+ endDate,
908
+ dates,
909
+ updateEvent,
910
+ hideModal,
911
+ openModal,
912
+ _isMultiDay,
913
+ event._originalId,
914
+ scheduleUpdate,
915
+ showStatusFeedback, // Update visual state for immediate feedback
916
+ updateVisualState,
917
+ ]);
918
+
919
+ // Color styles based on event color
920
+
921
+ const { bg, border, text, dragBg, syncingBg, successBg, errorBg } =
922
+ getEventStyles(color);
923
+
924
+ // Get the appropriate background based on event state
925
+ const getBackgroundStyle = () => {
926
+ if (updateStatus === 'syncing') return syncingBg;
927
+ if (updateStatus === 'success') return successBg;
928
+ if (updateStatus === 'error') return errorBg;
929
+ if (visualState.isDragging) return dragBg;
930
+ return bg;
931
+ };
932
+
933
+ // Use the visual state for UI rendering
934
+ const { isDragging, isResizing } = visualState;
935
+
936
+ // Determine if we should show continuation indicators for multi-day events
937
+ const showStartIndicator = _isMultiDay && _dayPosition !== 'start';
938
+ const showEndIndicator = _isMultiDay && _dayPosition !== 'end';
939
+
940
+ const { settings: calendarSettings } = useCalendarSettings();
941
+
942
+ // Format time for display
943
+ const formatEventTime = (date: Date | dayjs.Dayjs) => {
944
+ const timeFormat = calendarSettings.appearance.timeFormat;
945
+ const d = dayjs.isDayjs(date)
946
+ ? date
947
+ : tz === 'auto'
948
+ ? dayjs(date)
949
+ : dayjs(date).tz(tz);
950
+
951
+ // Special case: if time is 23:59, show as 12:00 AM (midnight)
952
+ if (d.hour() === 23 && d.minute() === 59) {
953
+ return timeFormat === '24h' ? '00:00' : '12:00 am';
954
+ }
955
+
956
+ return d.format(timeFormat === '24h' ? 'HH:mm' : 'h:mm a');
957
+ };
958
+
959
+ // Check if the event is in the past
960
+ const isPastEvent = new Date(end_at) < new Date();
961
+
962
+ // Check if this event is affected by preview (will be modified/deleted)
963
+ const isAffectedByPreview =
964
+ affectedEventIds?.has(id) || affectedEventIds?.has(event._originalId || '');
965
+
966
+ // Handle color change
967
+ const handleColorChange = (newColor: SupportedColor) => {
968
+ const eventId = event._originalId || id;
969
+ updateEvent(eventId, { color: newColor })
970
+ .then(() => {
971
+ showStatusFeedback('success');
972
+ })
973
+ .catch((error) => {
974
+ console.error('Failed to update event color:', error);
975
+ showStatusFeedback('error');
976
+ });
977
+ };
978
+
979
+ // Handle delete
980
+ const handleDelete = () => {
981
+ const eventId = event._originalId || id;
982
+ deleteEvent(eventId).catch((error) => {
983
+ console.error('Failed to delete event:', error);
984
+ });
985
+ };
986
+
987
+ // Handle lock/unlock
988
+ const handleLockToggle = () => {
989
+ const eventId = event._originalId || id;
990
+ const newLockedState = !locked;
991
+
992
+ console.log(
993
+ `Toggling lock status for event ${eventId} from ${locked} to ${newLockedState}`
994
+ );
995
+
996
+ updateEvent(eventId, { locked: newLockedState })
997
+ .then(() => {
998
+ console.log(`Successfully updated lock status to ${newLockedState}`);
999
+ // Update local state immediately for better UX
1000
+ setLocalEvent((prev) => ({
1001
+ ...prev,
1002
+ locked: newLockedState,
1003
+ }));
1004
+ showStatusFeedback('success');
1005
+ })
1006
+ .catch((error) => {
1007
+ console.error('Failed to update event lock status:', error);
1008
+ showStatusFeedback('error');
1009
+ });
1010
+ };
1011
+
1012
+ // Determine if this event has calendar source info
1013
+ const hasCalendarInfo =
1014
+ google_calendar_id && google_calendar_id !== 'primary';
1015
+ const calendarDisplayName =
1016
+ _calendarName ||
1017
+ (google_calendar_id === 'primary'
1018
+ ? 'Primary Calendar'
1019
+ : google_calendar_id);
1020
+
1021
+ // Calculate stacking position for visual effects
1022
+ // Note: Actual column-based positioning is handled in the useEffect
1023
+ const hasOverlaps = overlapCount > 1;
1024
+
1025
+ // Check if an event in the same group is being hovered
1026
+ // This event should be transparent if:
1027
+ // 1. There are overlaps
1028
+ // 2. Another event is being hovered
1029
+ // 3. This event's column is higher than the hovered event's column
1030
+ // 4. Both events are in the same overlap group
1031
+ const shouldBeTransparent =
1032
+ hasOverlaps &&
1033
+ hoveredBaseEventId &&
1034
+ hoveredEventColumn !== null &&
1035
+ columnIndex > hoveredEventColumn &&
1036
+ overlapGroup.includes(hoveredBaseEventId);
1037
+
1038
+ // For visual effects, check if this is likely a shorter event (higher in stack)
1039
+ // Shorter events get enhanced visual treatment
1040
+ const isLikelyTopEvent = hasOverlaps && duration < 1.5; // Events < 1.5 hours likely on top
1041
+
1042
+ return (
1043
+ <ContextMenu>
1044
+ <ContextMenuTrigger asChild>
1045
+ <button
1046
+ type="button"
1047
+ ref={cardRef}
1048
+ id={`event-${id}`}
1049
+ className={cn(
1050
+ 'pointer-events-auto absolute max-w-none select-none overflow-hidden rounded-r-md rounded-l transition-all duration-300',
1051
+ 'group hover:ring-1 focus:outline-none',
1052
+ {
1053
+ 'transform shadow-md': isDragging || isResizing, // Subtle transform during interaction
1054
+ 'shadow-sm': hasOverlaps && !isDragging && !isResizing, // Subtle shadow for stacked events
1055
+ 'hover:shadow-md': hasOverlaps, // Enhanced shadow on hover for stacked events
1056
+ 'opacity-50': isPastEvent && !isAffectedByPreview, // Lower opacity for past events
1057
+ 'opacity-30 grayscale transition-all duration-500':
1058
+ isAffectedByPreview, // Dim affected events during preview
1059
+ 'rounded-l-none border-l-4': showStartIndicator, // Special styling for continuation from previous day
1060
+ 'rounded-r-none border-r-4': showEndIndicator, // Special styling for continuation to next day
1061
+ 'border-l-[3px]': hasCalendarInfo, // Thicker border for calendar events
1062
+ // Habit-specific styling (icon only, no dashed border)
1063
+ 'opacity-60': _isHabit && _habitCompleted, // Dimmed for completed habits
1064
+ // Preview-specific styling - dashed border only for NEW/MOVED events (not reused)
1065
+ 'border-2 border-dashed': _isPreview && !_isReused,
1066
+ },
1067
+ level ? 'border border-l-2' : 'border-l-2',
1068
+ border,
1069
+ text,
1070
+ getBackgroundStyle() // Use dynamic background based on status
1071
+ )}
1072
+ style={{
1073
+ transition:
1074
+ isDragging || isResizing
1075
+ ? 'none' // No transition during interaction
1076
+ : 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)', // Smoother transition
1077
+ zIndex: isHovering || isDragging || isResizing ? 50 : 10 - level, // Use level for z-index
1078
+ willChange:
1079
+ isDragging || isResizing ? 'transform, top, left' : 'auto', // GPU acceleration
1080
+ transform: isDragging || isResizing ? 'translateZ(0)' : 'none', // Force GPU acceleration during interaction
1081
+ // Add calendar color accent if available
1082
+ borderLeftColor: _calendarColor || undefined,
1083
+ // Enhanced border for shorter events (likely on top)
1084
+ borderLeftWidth:
1085
+ hasOverlaps && isLikelyTopEvent ? '3px' : undefined,
1086
+ // Significantly lowered opacity for stacked events when base is hovered
1087
+ opacity: shouldBeTransparent ? 0.05 : 1,
1088
+ // Maintain pointer events even when transparent
1089
+ pointerEvents: shouldBeTransparent ? 'none' : undefined,
1090
+ }}
1091
+ onMouseEnter={() => {
1092
+ setIsHovering(true);
1093
+ // Set this event as hovered (any level) so events above it become transparent
1094
+ if (hasOverlaps) {
1095
+ setHoveredBaseEventId(id);
1096
+ setHoveredEventColumn(columnIndex);
1097
+ }
1098
+ }}
1099
+ onMouseLeave={() => {
1100
+ setIsHovering(false);
1101
+ // Clear hover state
1102
+ if (hasOverlaps) {
1103
+ setHoveredBaseEventId(null);
1104
+ setHoveredEventColumn(null);
1105
+ }
1106
+ }}
1107
+ tabIndex={0}
1108
+ onClick={(e) => {
1109
+ // Only open modal if we haven't just finished dragging or resizing
1110
+ if (!wasDraggedRef.current && !wasResizedRef.current) {
1111
+ e.stopPropagation();
1112
+ // Open the modal with the event, it will be read-only if locked
1113
+ openModal(event._originalId || id);
1114
+ }
1115
+
1116
+ // Reset state flags
1117
+ wasDraggedRef.current = false;
1118
+ wasResizedRef.current = false;
1119
+ }}
1120
+ aria-label={`Event: ${title || 'Untitled event'}${hasCalendarInfo ? ` from ${calendarDisplayName}` : ''}`}
1121
+ title={
1122
+ hasCalendarInfo ? `Calendar: ${calendarDisplayName}` : undefined
1123
+ }
1124
+ >
1125
+ {/* Continuation indicators for multi-day events */}
1126
+ {showStartIndicator && (
1127
+ <div className="absolute top-1/2 left-2 -translate-x-1 -translate-y-1/2">
1128
+ <ArrowLeft className={`h-3 w-3 ${text}`} />
1129
+ </div>
1130
+ )}
1131
+
1132
+ {showEndIndicator && (
1133
+ <div className="absolute top-1/2 right-2 translate-x-1 -translate-y-1/2">
1134
+ <ArrowRight className={`h-3 w-3 ${text}`} />
1135
+ </div>
1136
+ )}
1137
+
1138
+ {/* Habit indicator */}
1139
+ {_isHabit && (
1140
+ <div className="absolute top-1 right-1 z-10">
1141
+ <Repeat
1142
+ className={cn(
1143
+ 'h-3 w-3',
1144
+ _habitCompleted
1145
+ ? 'text-dynamic-green'
1146
+ : 'text-primary opacity-70'
1147
+ )}
1148
+ />
1149
+ </div>
1150
+ )}
1151
+
1152
+ {/* Warning indicator */}
1153
+ {_warning && (
1154
+ <div
1155
+ className={cn(
1156
+ 'absolute right-1 z-10',
1157
+ _isHabit ? 'top-5' : 'top-1'
1158
+ )}
1159
+ title={_warning}
1160
+ >
1161
+ <AlertTriangle className="h-3 w-3 text-dynamic-red" />
1162
+ </div>
1163
+ )}
1164
+
1165
+ {/* Edit button overlay */}
1166
+ <div
1167
+ className={cn(
1168
+ 'absolute top-2 rounded-full p-0.5 opacity-0 shadow-sm',
1169
+ _isHabit ? 'right-5' : 'right-2', // Offset if habit icon is shown
1170
+ 'z-10 transition-opacity group-hover:opacity-100', // Higher z-index
1171
+ {
1172
+ 'opacity-0!':
1173
+ isDragging || isResizing || updateStatus !== 'idle',
1174
+ } // Hide during interaction or status updates
1175
+ )}
1176
+ onClick={(e) => {
1177
+ e.stopPropagation();
1178
+ e.preventDefault();
1179
+ openModal(event._originalId || id);
1180
+ }}
1181
+ >
1182
+ <Pencil className="h-3 w-3" />
1183
+ </div>
1184
+
1185
+ {/* Status indicators */}
1186
+ {updateStatus === 'syncing' && (
1187
+ <div className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center bg-background/5">
1188
+ {/* <div
1189
+ className="animate-shimmer h-full w-full bg-linear-to-r from-transparent via-background/10 to-transparent"
1190
+ style={{ backgroundSize: '200% 100%' }}
1191
+ /> */}
1192
+ <div className="absolute top-2 right-2 rounded-full bg-background/30 p-1">
1193
+ <RefreshCw className="h-3 w-3 animate-spin" />
1194
+ </div>
1195
+ </div>
1196
+ )}
1197
+
1198
+ {updateStatus === 'success' && (
1199
+ <div className="pointer-events-none absolute top-2 right-2 z-20">
1200
+ <Check className="h-3 w-3 text-dynamic-light-green" />
1201
+ </div>
1202
+ )}
1203
+
1204
+ {updateStatus === 'error' && (
1205
+ <div className="pointer-events-none absolute top-2 right-2 z-20">
1206
+ <AlertTriangle className="h-3 w-3 text-dynamic-light-red" />
1207
+ </div>
1208
+ )}
1209
+
1210
+ <div
1211
+ ref={contentRef}
1212
+ className={cn(
1213
+ 'flex h-full select-none flex-col text-left',
1214
+ duration <= 0.25 ? 'px-1 py-0' : 'p-1',
1215
+ duration <= 0.5 ? 'text-xs' : 'text-sm',
1216
+ _isMultiDay && 'items-start'
1217
+ )}
1218
+ >
1219
+ <div
1220
+ className={cn(
1221
+ 'w-full flex-1',
1222
+ _isMultiDay && _dayPosition !== 'start' && 'pl-3'
1223
+ )}
1224
+ >
1225
+ <div
1226
+ className={cn(
1227
+ 'font-semibold text-xs',
1228
+ duration <= 0.5 ? 'line-clamp-1' : 'line-clamp-2'
1229
+ )}
1230
+ >
1231
+ {_isPreview && !_isReused && (
1232
+ <Eye
1233
+ className={cn(
1234
+ 'mr-1 inline-block h-3 w-3 align-middle opacity-80',
1235
+ _previewType === 'habit'
1236
+ ? 'text-dynamic-green'
1237
+ : _previewType === 'task'
1238
+ ? 'text-dynamic-purple'
1239
+ : 'text-dynamic-blue'
1240
+ )}
1241
+ />
1242
+ )}
1243
+ {localEvent.locked && !_isPreview && (
1244
+ <Lock className="mr-1 inline-block h-3 w-3 align-middle opacity-70" />
1245
+ )}
1246
+ <span>{localEvent.title || 'Untitled event'}</span>
1247
+ {_isPreview && !_isReused && (
1248
+ <span
1249
+ className={cn(
1250
+ 'ml-1 rounded px-1 font-medium text-[10px]',
1251
+ _previewType === 'habit'
1252
+ ? 'bg-dynamic-green/20 text-dynamic-green'
1253
+ : _previewType === 'task'
1254
+ ? 'bg-dynamic-purple/20 text-dynamic-purple'
1255
+ : 'bg-dynamic-blue/20 text-dynamic-blue'
1256
+ )}
1257
+ >
1258
+ {_previewType === 'habit'
1259
+ ? 'Habit'
1260
+ : _previewType === 'task'
1261
+ ? 'Task'
1262
+ : 'Preview'}
1263
+ </span>
1264
+ )}
1265
+ </div>
1266
+
1267
+ {/* Show time for regular events or start/end segments of multi-day events */}
1268
+ {((!_isMultiDay && duration > 0.5) ||
1269
+ (_isMultiDay &&
1270
+ (_dayPosition === 'start' || _dayPosition === 'end'))) && (
1271
+ <div className="mt-1 flex items-center text-xs opacity-80">
1272
+ {_isMultiDay ? (
1273
+ _dayPosition === 'start' ? (
1274
+ <span>Starts {formatEventTime(startDate)}</span>
1275
+ ) : (
1276
+ <span>Ends {formatEventTime(endDate)}</span>
1277
+ )
1278
+ ) : (
1279
+ <span>
1280
+ {formatEventTime(startDate)} - {formatEventTime(endDate)}
1281
+ </span>
1282
+ )}
1283
+ </div>
1284
+ )}
1285
+
1286
+ {/* Show description if there's enough space */}
1287
+ {(duration > 1 || _isMultiDay) && description && (
1288
+ <div
1289
+ className="event-description mt-1 line-clamp-2 text-xs"
1290
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: <html is sanitized>
1291
+ dangerouslySetInnerHTML={{
1292
+ __html: containsHtml(description)
1293
+ ? sanitizeHtml(description)
1294
+ : description,
1295
+ }}
1296
+ />
1297
+ )}
1298
+ </div>
1299
+ </div>
1300
+
1301
+ {/* Only show resize handle for non-multi-day events or start/end segments */}
1302
+ {(!_isMultiDay || _dayPosition !== 'middle') && (
1303
+ <div
1304
+ ref={handleRef}
1305
+ className={cn(
1306
+ 'absolute inset-x-0 bottom-0 cursor-s-resize hover:bg-primary/20',
1307
+ 'h-2 transition-colors'
1308
+ )}
1309
+ />
1310
+ )}
1311
+ </button>
1312
+ </ContextMenuTrigger>
1313
+ <ContextMenuContent className="w-48">
1314
+ <ContextMenuItem
1315
+ onClick={() => openModal(event._originalId || id)}
1316
+ className="flex items-center gap-2"
1317
+ >
1318
+ <Edit className="h-4 w-4" />
1319
+ <span>Edit Event</span>
1320
+ </ContextMenuItem>
1321
+
1322
+ <ContextMenuItem
1323
+ onClick={handleLockToggle}
1324
+ className="flex items-center gap-2"
1325
+ >
1326
+ {locked ? (
1327
+ <>
1328
+ <Unlock className="h-4 w-4" />
1329
+ <span>Unlock Event</span>
1330
+ </>
1331
+ ) : (
1332
+ <>
1333
+ <Lock className="h-4 w-4" />
1334
+ <span>Lock Event</span>
1335
+ </>
1336
+ )}
1337
+ </ContextMenuItem>
1338
+
1339
+ <ContextMenuSub>
1340
+ <ContextMenuSubTrigger className="flex items-center gap-2">
1341
+ <Palette className="h-4 w-4" />
1342
+ <span className="text-foreground">Change Color</span>
1343
+ </ContextMenuSubTrigger>
1344
+ <ContextMenuSubContent className="grid w-56 grid-cols-2 gap-1 p-2">
1345
+ <ContextMenuItem
1346
+ onClick={() => handleColorChange('RED')}
1347
+ className="flex items-center gap-2"
1348
+ >
1349
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-red/80 bg-calendar-bg-red"></div>
1350
+ <span>Red</span>
1351
+ </ContextMenuItem>
1352
+ <ContextMenuItem
1353
+ onClick={() => handleColorChange('BLUE')}
1354
+ className="flex items-center gap-2"
1355
+ >
1356
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-blue/80 bg-calendar-bg-blue"></div>
1357
+ <span>Blue</span>
1358
+ </ContextMenuItem>
1359
+ <ContextMenuItem
1360
+ onClick={() => handleColorChange('GREEN')}
1361
+ className="flex items-center gap-2"
1362
+ >
1363
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-green/80 bg-calendar-bg-green"></div>
1364
+ <span>Green</span>
1365
+ </ContextMenuItem>
1366
+ <ContextMenuItem
1367
+ onClick={() => handleColorChange('YELLOW')}
1368
+ className="flex items-center gap-2"
1369
+ >
1370
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-yellow/80 bg-calendar-bg-yellow"></div>
1371
+ <span>Yellow</span>
1372
+ </ContextMenuItem>
1373
+ <ContextMenuItem
1374
+ onClick={() => handleColorChange('PURPLE')}
1375
+ className="flex items-center gap-2"
1376
+ >
1377
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-purple/80 bg-calendar-bg-purple"></div>
1378
+ <span>Purple</span>
1379
+ </ContextMenuItem>
1380
+ <ContextMenuItem
1381
+ onClick={() => handleColorChange('PINK')}
1382
+ className="flex items-center gap-2"
1383
+ >
1384
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-pink/80 bg-calendar-bg-pink"></div>
1385
+ <span>Pink</span>
1386
+ </ContextMenuItem>
1387
+ <ContextMenuItem
1388
+ onClick={() => handleColorChange('ORANGE')}
1389
+ className="flex items-center gap-2"
1390
+ >
1391
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-orange/80 bg-calendar-bg-orange"></div>
1392
+ <span>Orange</span>
1393
+ </ContextMenuItem>
1394
+ <ContextMenuItem
1395
+ onClick={() => handleColorChange('INDIGO')}
1396
+ className="flex items-center gap-2"
1397
+ >
1398
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-indigo/80 bg-calendar-bg-indigo"></div>
1399
+ <span>Indigo</span>
1400
+ </ContextMenuItem>
1401
+ <ContextMenuItem
1402
+ onClick={() => handleColorChange('CYAN')}
1403
+ className="flex items-center gap-2"
1404
+ >
1405
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-cyan/80 bg-calendar-bg-cyan"></div>
1406
+ <span>Cyan</span>
1407
+ </ContextMenuItem>
1408
+ <ContextMenuItem
1409
+ onClick={() => handleColorChange('GRAY')}
1410
+ className="flex items-center gap-2"
1411
+ >
1412
+ <div className="h-4 w-4 flex-none rounded-full border border-dynamic-light-gray/80 bg-calendar-bg-gray"></div>
1413
+ <span>Gray</span>
1414
+ </ContextMenuItem>
1415
+ </ContextMenuSubContent>
1416
+ </ContextMenuSub>
1417
+
1418
+ <ContextMenuSeparator />
1419
+
1420
+ <ContextMenuItem
1421
+ onClick={handleDelete}
1422
+ className="flex items-center gap-2"
1423
+ >
1424
+ <Trash2 className="h-4 w-4" />
1425
+ <span>Delete Event</span>
1426
+ </ContextMenuItem>
1427
+ </ContextMenuContent>
1428
+ </ContextMenu>
1429
+ );
1430
+ }