@tuturuuu/ui 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/biome.json +1 -1
  3. package/package.json +73 -71
  4. package/src/components/ui/accordion.tsx +1 -1
  5. package/src/components/ui/breadcrumb.tsx +1 -1
  6. package/src/components/ui/calendar-app/calendar-page-shell.tsx +4 -0
  7. package/src/components/ui/calendar-app/components/calendar-connections-settings-content.tsx +239 -33
  8. package/src/components/ui/calendar-app/components/load-smart-scheduling-tasks.tsx +143 -0
  9. package/src/components/ui/calendar-app/components/priority-view.tsx +10 -3
  10. package/src/components/ui/calendar-app/components/tasks-sidebar.tsx +4 -116
  11. package/src/components/ui/calendar-app/components/use-calendar-connections-manager.ts +67 -2
  12. package/src/components/ui/calendar.tsx +1 -1
  13. package/src/components/ui/carousel.tsx +1 -1
  14. package/src/components/ui/chat/chat-agent-details-external-thread-panel.test.tsx +1 -1
  15. package/src/components/ui/chat/chat-agent-details-external-thread-panel.tsx +1 -1
  16. package/src/components/ui/chat/chat-agent-details-operations-panel.test.tsx +1 -1
  17. package/src/components/ui/chat/chat-agent-details-operations-panel.tsx +1 -1
  18. package/src/components/ui/chat/chat-agent-details-setup-panel.tsx +1 -1
  19. package/src/components/ui/chat/chat-agent-details-sidebar.test.tsx +1 -1
  20. package/src/components/ui/chat/chat-agent-details-sidebar.tsx +2 -2
  21. package/src/components/ui/chat/chat-agent-details-utils.test.ts +1 -1
  22. package/src/components/ui/chat/chat-agent-details-utils.tsx +1 -1
  23. package/src/components/ui/chat/chat-agent-details-zalo-personal-panel.tsx +2 -2
  24. package/src/components/ui/checkbox.tsx +1 -1
  25. package/src/components/ui/color-picker.tsx +1 -1
  26. package/src/components/ui/command.tsx +1 -1
  27. package/src/components/ui/context-menu.tsx +5 -1
  28. package/src/components/ui/custom/__tests__/settings-dialog-shell.test.tsx +3 -0
  29. package/src/components/ui/custom/__tests__/workspace-select-helpers.test.ts +19 -0
  30. package/src/components/ui/custom/combobox.test.tsx +195 -0
  31. package/src/components/ui/custom/combobox.tsx +273 -156
  32. package/src/components/ui/custom/education/modules/youtube/delete-link-button.tsx +5 -13
  33. package/src/components/ui/custom/facebook-mockup/facebook-mockup.tsx +7 -1
  34. package/src/components/ui/custom/facebook-mockup/form.tsx +1 -1
  35. package/src/components/ui/custom/facebook-mockup/image-upload-field.tsx +1 -1
  36. package/src/components/ui/custom/facebook-mockup/preview.tsx +1 -1
  37. package/src/components/ui/custom/settings-dialog-shell.tsx +2 -1
  38. package/src/components/ui/custom/theme-toggle.tsx +1 -1
  39. package/src/components/ui/custom/workspace-select.tsx +8 -3
  40. package/src/components/ui/dialog.test.tsx +52 -0
  41. package/src/components/ui/dialog.tsx +6 -2
  42. package/src/components/ui/dropdown-menu.tsx +5 -1
  43. package/src/components/ui/finance/debts/debt-loan-form.tsx +12 -5
  44. package/src/components/ui/finance/debts/debt-loan-summary.tsx +3 -2
  45. package/src/components/ui/finance/debts/debts-page.test.tsx +54 -5
  46. package/src/components/ui/finance/debts/debts-page.tsx +15 -2
  47. package/src/components/ui/finance/invoices/components/subscription-group-selector.tsx +3 -5
  48. package/src/components/ui/finance/invoices/new-invoice-page.test.tsx +25 -5
  49. package/src/components/ui/finance/invoices/new-invoice-page.tsx +7 -2
  50. package/src/components/ui/finance/invoices/standard-invoice.tsx +4 -2
  51. package/src/components/ui/finance/invoices/subscription-invoice.tsx +4 -2
  52. package/src/components/ui/finance/invoices/utils.ts +3 -1
  53. package/src/components/ui/finance/transactions/form-content-dialog.tsx +3 -0
  54. package/src/components/ui/finance/transactions/form-types.ts +1 -0
  55. package/src/components/ui/finance/transactions/form.tsx +2 -0
  56. package/src/components/ui/finance/transactions/infinite-transactions-list.tsx +2 -0
  57. package/src/components/ui/finance/transactions/period-charts/category-breakdown-dialog.tsx +1 -1
  58. package/src/components/ui/finance/transactions/transaction-edit-dialog.tsx +1 -4
  59. package/src/components/ui/finance/transactions/transactions-create-summary.tsx +3 -0
  60. package/src/components/ui/finance/transactions/transactions-page.tsx +4 -1
  61. package/src/components/ui/finance/wallets/form.test.tsx +51 -3
  62. package/src/components/ui/finance/wallets/form.tsx +15 -4
  63. package/src/components/ui/finance/wallets/walletId/wallet-details-actions.tsx +4 -0
  64. package/src/components/ui/finance/wallets/walletId/wallet-details-page.tsx +4 -2
  65. package/src/components/ui/finance/wallets/wallets-data-table.tsx +1 -0
  66. package/src/components/ui/finance/wallets/wallets-page.tsx +5 -2
  67. package/src/components/ui/input-otp.tsx +1 -1
  68. package/src/components/ui/legacy/calendar/all-day-event-bar.tsx +28 -39
  69. package/src/components/ui/legacy/calendar/calendar-cell.tsx +2 -0
  70. package/src/components/ui/legacy/calendar/calendar-content.tsx +10 -6
  71. package/src/components/ui/legacy/calendar/calendar-header.tsx +23 -3
  72. package/src/components/ui/legacy/calendar/calendar-loading-skeleton.tsx +135 -0
  73. package/src/components/ui/legacy/calendar/calendar-matrix.tsx +175 -237
  74. package/src/components/ui/legacy/calendar/event-card.test.tsx +177 -0
  75. package/src/components/ui/legacy/calendar/event-card.tsx +220 -131
  76. package/src/components/ui/legacy/calendar/event-modal.tsx +17 -17
  77. package/src/components/ui/legacy/calendar/event-provider-display.tsx +69 -0
  78. package/src/components/ui/legacy/calendar/smart-calendar.test.tsx +86 -4
  79. package/src/components/ui/legacy/calendar/smart-calendar.tsx +32 -2
  80. package/src/components/ui/legacy/meet/create-plan-dialog.tsx +19 -10
  81. package/src/components/ui/navigation-menu.tsx +1 -1
  82. package/src/components/ui/pagination.tsx +1 -1
  83. package/src/components/ui/radio-group.tsx +1 -1
  84. package/src/components/ui/select.tsx +5 -1
  85. package/src/components/ui/sheet.tsx +1 -1
  86. package/src/components/ui/sidebar.tsx +1 -1
  87. package/src/components/ui/storefront/cart-popover.tsx +61 -0
  88. package/src/components/ui/storefront/cart-summary-parts.tsx +290 -0
  89. package/src/components/ui/storefront/cart-summary.tsx +93 -154
  90. package/src/components/ui/storefront/checkout-overlay.tsx +4 -5
  91. package/src/components/ui/storefront/listing-card.tsx +1 -1
  92. package/src/components/ui/storefront/merch-sections.tsx +70 -0
  93. package/src/components/ui/storefront/product-detail.tsx +1 -1
  94. package/src/components/ui/storefront/storefront-surface.test.tsx +106 -11
  95. package/src/components/ui/storefront/storefront-surface.tsx +101 -166
  96. package/src/components/ui/storefront/types.ts +4 -0
  97. package/src/components/ui/storefront/utils.ts +6 -0
  98. package/src/components/ui/text-editor/__tests__/extensions.test.ts +123 -0
  99. package/src/components/ui/text-editor/background-color-extension.ts +62 -0
  100. package/src/components/ui/text-editor/color-controls.tsx +284 -0
  101. package/src/components/ui/text-editor/editor.tsx +69 -14
  102. package/src/components/ui/text-editor/extensions.ts +8 -2
  103. package/src/components/ui/text-editor/highlight-extension.ts +22 -0
  104. package/src/components/ui/text-editor/tool-bar.tsx +9 -16
  105. package/src/components/ui/toast.tsx +1 -1
  106. package/src/components/ui/tu-do/boards/__tests__/board-share-dialog.test.tsx +270 -0
  107. package/src/components/ui/tu-do/boards/board-public-link-section.tsx +231 -0
  108. package/src/components/ui/tu-do/boards/board-share-dialog.tsx +222 -109
  109. package/src/components/ui/tu-do/boards/boardId/board-column.tsx +112 -43
  110. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-clear-delete.ts +2 -0
  111. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-move.ts +5 -0
  112. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-updates.ts +3 -0
  113. package/src/components/ui/tu-do/boards/boardId/kanban/data/kanban-deadline-query.ts +50 -2
  114. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/__tests__/column-reorder.test.ts +17 -0
  115. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/column-reorder.ts +4 -1
  116. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-cache.ts +38 -9
  117. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-order.ts +2 -8
  118. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-sort-key.ts +47 -0
  119. package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.ts +81 -30
  120. package/src/components/ui/tu-do/boards/boardId/kanban/planner/__tests__/kanban-planner-island.test.tsx +380 -0
  121. package/src/components/ui/tu-do/boards/boardId/kanban/planner/kanban-planner-dialog.tsx +204 -0
  122. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-digest-panel.tsx +61 -0
  123. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-item-strip.tsx +54 -0
  124. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-plan-toolbar.tsx +251 -0
  125. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-scope-badge.tsx +27 -0
  126. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-section.tsx +58 -0
  127. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-share-dialog.tsx +238 -0
  128. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-target-controls.tsx +143 -0
  129. package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-utils.ts +65 -0
  130. package/src/components/ui/tu-do/boards/boardId/kanban/planner/use-kanban-planner-state.ts +234 -0
  131. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.test.tsx +397 -2
  132. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.tsx +103 -13
  133. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-deadline-panels.tsx +443 -19
  134. package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-skeleton.tsx +94 -32
  135. package/src/components/ui/tu-do/boards/boardId/kanban.tsx +213 -106
  136. package/src/components/ui/tu-do/boards/boardId/task-board-server-page.test.tsx +26 -4
  137. package/src/components/ui/tu-do/boards/boardId/task-board-server-page.tsx +5 -2
  138. package/src/components/ui/tu-do/boards/boardId/task-card/measured-task-card.tsx +3 -0
  139. package/src/components/ui/tu-do/boards/boardId/task-card/task-card-comparator.ts +3 -0
  140. package/src/components/ui/tu-do/boards/boardId/task-card/task-card.tsx +191 -28
  141. package/src/components/ui/tu-do/boards/boardId/task-filter.test.tsx +152 -0
  142. package/src/components/ui/tu-do/boards/boardId/task-filter.tsx +555 -545
  143. package/src/components/ui/tu-do/boards/boardId/task-list.tsx +7 -0
  144. package/src/components/ui/tu-do/boards/share-section.tsx +100 -0
  145. package/src/components/ui/tu-do/drafts/draft-convert-dialog.tsx +10 -12
  146. package/src/components/ui/tu-do/drafts/drafts-page.tsx +33 -16
  147. package/src/components/ui/tu-do/initiatives/task-initiatives-client.tsx +56 -88
  148. package/src/components/ui/tu-do/my-tasks/my-tasks-content.tsx +26 -2
  149. package/src/components/ui/tu-do/my-tasks/use-my-tasks-state.ts +55 -8
  150. package/src/components/ui/tu-do/notes/note-edit-dialog.tsx +1 -4
  151. package/src/components/ui/tu-do/shared/__tests__/board-client.test.tsx +25 -0
  152. package/src/components/ui/tu-do/shared/__tests__/board-header.test.tsx +341 -38
  153. package/src/components/ui/tu-do/shared/__tests__/board-switcher.test.tsx +253 -0
  154. package/src/components/ui/tu-do/shared/__tests__/board-views.test.tsx +203 -2
  155. package/src/components/ui/tu-do/shared/__tests__/task-board-loading-state.test.tsx +17 -0
  156. package/src/components/ui/tu-do/shared/__tests__/task-legacy-route-recovery.test.tsx +16 -0
  157. package/src/components/ui/tu-do/shared/board-client.tsx +2 -7
  158. package/src/components/ui/tu-do/shared/board-config-storage.ts +7 -1
  159. package/src/components/ui/tu-do/shared/board-header.tsx +464 -975
  160. package/src/components/ui/tu-do/shared/board-layout-settings.tsx +165 -136
  161. package/src/components/ui/tu-do/shared/board-switcher.tsx +209 -217
  162. package/src/components/ui/tu-do/shared/board-views.tsx +587 -75
  163. package/src/components/ui/tu-do/shared/list-view.tsx +227 -1
  164. package/src/components/ui/tu-do/shared/recycle-bin-panel.tsx +142 -94
  165. package/src/components/ui/tu-do/shared/special-task-list-pins.ts +51 -0
  166. package/src/components/ui/tu-do/shared/task-board-loading-state.tsx +28 -0
  167. package/src/components/ui/tu-do/shared/task-edit-dialog/field-diff-viewer.tsx +3 -2
  168. package/src/components/ui/tu-do/shared/task-edit-dialog/selective-revert-panel.test.tsx +91 -0
  169. package/src/components/ui/tu-do/shared/task-edit-dialog/selective-revert-panel.tsx +123 -78
  170. package/src/components/ui/tu-do/shared/task-edit-dialog/task-activity-section.tsx +7 -1
  171. package/src/components/ui/tu-do/shared/task-edit-dialog/task-snapshot-dialog.tsx +8 -3
  172. package/src/components/ui/tu-do/shared/task-edit-dialog.tsx +2 -1
  173. package/src/components/ui/tu-do/shared/task-legacy-route-recovery.tsx +2 -9
  174. package/src/declarations.d.ts +1 -0
  175. package/src/hooks/__tests__/use-calendar-readonly.test.tsx +322 -2
  176. package/src/hooks/__tests__/use-calendar-sync.test.tsx +446 -0
  177. package/src/hooks/use-calendar-sync.tsx +247 -243
  178. package/src/hooks/use-calendar.tsx +323 -138
  179. package/src/hooks/use-task-actions.ts +24 -0
  180. package/src/hooks/use-user-workspace-config.ts +75 -0
  181. package/src/hooks/use-workspace-currency.ts +8 -3
  182. package/src/hooks/useBoardRealtimeEventHandler.ts +11 -0
@@ -15,6 +15,7 @@ import {
15
15
  } from '@tuturuuu/utils/task-list-status';
16
16
  import { addDays } from 'date-fns';
17
17
  import { useCallback } from 'react';
18
+ import { invalidateKanbanDeadlineTasks } from '../components/ui/tu-do/boards/boardId/kanban/data/kanban-deadline-query';
18
19
  import { useBoardBroadcast } from '../components/ui/tu-do/shared/board-broadcast-context';
19
20
  import {
20
21
  dispatchTaskSoundCue,
@@ -81,6 +82,9 @@ export function useTaskActions({
81
82
  }: UseTaskActionsProps) {
82
83
  const queryClient = useQueryClient();
83
84
  const broadcast = useBoardBroadcast();
85
+ const invalidateDeadlineTasks = useCallback(() => {
86
+ void invalidateKanbanDeadlineTasks(queryClient, boardId);
87
+ }, [boardId, queryClient]);
84
88
 
85
89
  const resolveWorkspaceIdForTask = useCallback(
86
90
  async (taskRecord?: Task) => {
@@ -272,6 +276,7 @@ export function useTaskActions({
272
276
  description: `Task marked as ${targetCompletionList.status === 'done' ? 'done' : 'closed'} and moved to ${targetCompletionList.name}`,
273
277
  });
274
278
  dispatchTaskActionSound('complete');
279
+ invalidateDeadlineTasks();
275
280
  } catch (error) {
276
281
  console.error('Failed to complete external task:', error);
277
282
  toast.error('Error', {
@@ -337,6 +342,7 @@ export function useTaskActions({
337
342
  closed_at: movedTask?.closed_at,
338
343
  },
339
344
  });
345
+ invalidateDeadlineTasks();
340
346
 
341
347
  toast.success('Task completed', {
342
348
  description: `Task marked as done and moved to ${targetCompletionList.name}`,
@@ -395,6 +401,7 @@ export function useTaskActions({
395
401
  },
396
402
  });
397
403
  dispatchTaskActionSound(newClosedState ? 'complete' : 'update');
404
+ invalidateDeadlineTasks();
398
405
  } catch (error) {
399
406
  // Rollback on error
400
407
  if (previousTasks) {
@@ -422,6 +429,7 @@ export function useTaskActions({
422
429
  getWorkspaceId,
423
430
  markLocallyMutatedTask,
424
431
  mergeLocallyMutatedTask,
432
+ invalidateDeadlineTasks,
425
433
  ]);
426
434
 
427
435
  const handleMoveToCompletion = useCallback(async () => {
@@ -452,6 +460,7 @@ export function useTaskActions({
452
460
  description: `Task marked as ${targetCompletionList.status === 'done' ? 'done' : 'closed'} and moved to ${targetCompletionList.name}`,
453
461
  });
454
462
  dispatchTaskActionSound('complete');
463
+ invalidateDeadlineTasks();
455
464
  return;
456
465
  }
457
466
 
@@ -514,6 +523,7 @@ export function useTaskActions({
514
523
  }
515
524
  }
516
525
  if (successCount === 0) throw new Error('Failed to move any tasks');
526
+ invalidateDeadlineTasks();
517
527
 
518
528
  if (failedTaskIds.length > 0) {
519
529
  toast.warning('Partial completion update', {
@@ -561,6 +571,7 @@ export function useTaskActions({
561
571
  getWorkspaceId,
562
572
  markLocallyMutatedTask,
563
573
  rollbackTaskIds,
574
+ invalidateDeadlineTasks,
564
575
  ]);
565
576
 
566
577
  const handleMoveToClose = useCallback(async () => {
@@ -590,6 +601,7 @@ export function useTaskActions({
590
601
  description: 'Task marked as closed',
591
602
  });
592
603
  dispatchTaskActionSound('complete');
604
+ invalidateDeadlineTasks();
593
605
  return;
594
606
  }
595
607
 
@@ -648,6 +660,7 @@ export function useTaskActions({
648
660
  }
649
661
  }
650
662
  if (successCount === 0) throw new Error('Failed to move any tasks');
663
+ invalidateDeadlineTasks();
651
664
 
652
665
  if (failedTaskIds.length > 0) {
653
666
  toast.warning('Partial close update', {
@@ -692,6 +705,7 @@ export function useTaskActions({
692
705
  getWorkspaceId,
693
706
  markLocallyMutatedTask,
694
707
  rollbackTaskIds,
708
+ invalidateDeadlineTasks,
695
709
  ]);
696
710
 
697
711
  const handleDelete = useCallback(async () => {
@@ -764,6 +778,7 @@ export function useTaskActions({
764
778
  }
765
779
 
766
780
  if (successCount === 0) throw new Error('Failed to delete any tasks');
781
+ invalidateDeadlineTasks();
767
782
 
768
783
  if (failedTaskIds.length > 0) {
769
784
  toast.warning('Partial delete update', {
@@ -812,6 +827,7 @@ export function useTaskActions({
812
827
  broadcast,
813
828
  getWorkspaceId,
814
829
  restoreDeletedTaskIds,
830
+ invalidateDeadlineTasks,
815
831
  ]);
816
832
 
817
833
  const handleRemoveAllAssignees = useCallback(async () => {
@@ -1010,6 +1026,7 @@ export function useTaskActions({
1010
1026
  description: `Task moved to ${targetList.name || 'selected list'}`,
1011
1027
  });
1012
1028
  dispatchTaskActionSound(getMoveSoundCue(targetList));
1029
+ invalidateDeadlineTasks();
1013
1030
  } catch (error) {
1014
1031
  console.error('Failed to move external task:', error);
1015
1032
  toast.error('Error', {
@@ -1115,6 +1132,7 @@ export function useTaskActions({
1115
1132
  }
1116
1133
  }
1117
1134
  if (successCount === 0) throw new Error('Failed to move any tasks');
1135
+ invalidateDeadlineTasks();
1118
1136
 
1119
1137
  if (failedTaskIds.length > 0) {
1120
1138
  toast.warning('Partial move update', {
@@ -1161,6 +1179,7 @@ export function useTaskActions({
1161
1179
  markLocallyMutatedTask,
1162
1180
  resolveWorkspaceIdForTask,
1163
1181
  rollbackTaskIds,
1182
+ invalidateDeadlineTasks,
1164
1183
  ]
1165
1184
  );
1166
1185
 
@@ -1243,6 +1262,7 @@ export function useTaskActions({
1243
1262
  task: { id: tid, end_date: newDate },
1244
1263
  });
1245
1264
  }
1265
+ invalidateDeadlineTasks();
1246
1266
 
1247
1267
  if (failedTaskIds.length > 0) {
1248
1268
  toast.warning('Partial due date update', {
@@ -1283,6 +1303,7 @@ export function useTaskActions({
1283
1303
  boardId,
1284
1304
  task,
1285
1305
  broadcast,
1306
+ invalidateDeadlineTasks,
1286
1307
  ]
1287
1308
  );
1288
1309
 
@@ -1575,6 +1596,7 @@ export function useTaskActions({
1575
1596
  // Use the centralized bulk update function from useBulkOperations
1576
1597
  try {
1577
1598
  await bulkUpdateCustomDueDate(date || null);
1599
+ invalidateDeadlineTasks();
1578
1600
  } catch (error) {
1579
1601
  console.error('Bulk custom date update failed', error);
1580
1602
  toast.error('Failed to update due date for selected tasks');
@@ -1610,6 +1632,7 @@ export function useTaskActions({
1610
1632
  broadcast?.('task:upsert', {
1611
1633
  task: { id: task.id, end_date: newDate },
1612
1634
  });
1635
+ invalidateDeadlineTasks();
1613
1636
 
1614
1637
  toast.success('Due date updated', {
1615
1638
  description: newDate
@@ -1639,6 +1662,7 @@ export function useTaskActions({
1639
1662
  queryClient,
1640
1663
  boardId,
1641
1664
  broadcast,
1665
+ invalidateDeadlineTasks,
1642
1666
  ]
1643
1667
  );
1644
1668
 
@@ -0,0 +1,75 @@
1
+ 'use client';
2
+
3
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
4
+ import {
5
+ getUserWorkspaceConfig,
6
+ updateUserWorkspaceConfig,
7
+ } from '@tuturuuu/internal-api/users';
8
+
9
+ export function getUserWorkspaceConfigQueryKey(
10
+ workspaceId: string,
11
+ configId: string
12
+ ) {
13
+ return ['user-workspace-config', workspaceId, configId] as const;
14
+ }
15
+
16
+ export function useUserWorkspaceConfig(
17
+ workspaceId: string,
18
+ configId: string,
19
+ defaultValue: string | null = null,
20
+ options?: {
21
+ enabled?: boolean;
22
+ staleTime?: number;
23
+ }
24
+ ) {
25
+ return useQuery({
26
+ queryKey: getUserWorkspaceConfigQueryKey(workspaceId, configId),
27
+ queryFn: async () => {
28
+ const data = await getUserWorkspaceConfig(workspaceId, configId);
29
+ return data.value ?? defaultValue;
30
+ },
31
+ enabled: options?.enabled !== false && Boolean(workspaceId && configId),
32
+ staleTime: options?.staleTime ?? 5 * 60 * 1000,
33
+ });
34
+ }
35
+
36
+ export function useUpdateUserWorkspaceConfig() {
37
+ const queryClient = useQueryClient();
38
+
39
+ return useMutation({
40
+ mutationFn: async ({
41
+ configId,
42
+ value,
43
+ workspaceId,
44
+ }: {
45
+ configId: string;
46
+ value: string | null;
47
+ workspaceId: string;
48
+ }) => updateUserWorkspaceConfig(workspaceId, configId, value),
49
+ onMutate: async ({ configId, value, workspaceId }) => {
50
+ const queryKey = getUserWorkspaceConfigQueryKey(workspaceId, configId);
51
+ await queryClient.cancelQueries({ queryKey });
52
+
53
+ const previousValue = queryClient.getQueryData<string | null>(queryKey);
54
+ queryClient.setQueryData(queryKey, value);
55
+
56
+ return { configId, previousValue, workspaceId };
57
+ },
58
+ onError: (_error, _variables, context) => {
59
+ if (!context) return;
60
+
61
+ queryClient.setQueryData(
62
+ getUserWorkspaceConfigQueryKey(context.workspaceId, context.configId),
63
+ context.previousValue ?? null
64
+ );
65
+ },
66
+ onSettled: (_data, _error, variables) => {
67
+ queryClient.invalidateQueries({
68
+ queryKey: getUserWorkspaceConfigQueryKey(
69
+ variables.workspaceId,
70
+ variables.configId
71
+ ),
72
+ });
73
+ },
74
+ });
75
+ }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  getCurrencyLocale,
3
+ resolveSupportedCurrency,
3
4
  type SupportedCurrency,
4
5
  } from '@tuturuuu/utils/currencies';
5
6
 
@@ -8,14 +9,18 @@ import { useWorkspaceConfig } from './use-workspace-config';
8
9
  // Re-export for convenience
9
10
  export type { SupportedCurrency } from '@tuturuuu/utils/currencies';
10
11
 
11
- export const useWorkspaceCurrency = (wsId: string) => {
12
+ export const useWorkspaceCurrency = (
13
+ wsId: string,
14
+ fallbackCurrency = 'USD'
15
+ ) => {
16
+ const fallback = resolveSupportedCurrency(fallbackCurrency);
12
17
  const { data, isLoading, error } = useWorkspaceConfig<SupportedCurrency>(
13
18
  wsId,
14
19
  'DEFAULT_CURRENCY',
15
- 'USD'
20
+ fallback
16
21
  );
17
22
 
18
- const currency = (data as SupportedCurrency) ?? 'USD';
23
+ const currency = resolveSupportedCurrency(data, fallback);
19
24
 
20
25
  return {
21
26
  currency,
@@ -188,6 +188,16 @@ function invalidateTaskMembershipQueries(
188
188
  void queryClient.invalidateQueries({
189
189
  queryKey: ['task-list-counts', boardId],
190
190
  });
191
+ void queryClient.invalidateQueries({
192
+ predicate: (query) => {
193
+ const queryKey = query.queryKey;
194
+ return (
195
+ Array.isArray(queryKey) &&
196
+ queryKey[0] === 'kanban-deadline-tasks' &&
197
+ queryKey[2] === boardId
198
+ );
199
+ },
200
+ });
191
201
  void queryClient.invalidateQueries({ queryKey: ['my-tasks'] });
192
202
  void queryClient.invalidateQueries({ queryKey: ['my-completed-tasks'] });
193
203
  }
@@ -342,6 +352,7 @@ export function useBoardRealtimeEventHandler({
342
352
  patchMyTasksCaches(queryClient, taskData);
343
353
  if (
344
354
  'list_id' in taskData ||
355
+ 'end_date' in taskData ||
345
356
  'completed' in taskData ||
346
357
  'completed_at' in taskData ||
347
358
  'closed_at' in taskData ||