@tuturuuu/ui 0.4.0 → 0.5.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 (49) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/package.json +6 -6
  3. package/src/components/ui/chat/chat-agent-details-operations-panel.test.tsx +62 -0
  4. package/src/components/ui/chat/chat-agent-details-zalo-personal-panel.tsx +8 -2
  5. package/src/components/ui/chat/chat-sidebar-conversation-groups.tsx +332 -0
  6. package/src/components/ui/chat/chat-sidebar-groups.test.ts +44 -0
  7. package/src/components/ui/chat/chat-sidebar-panel.test.tsx +2 -0
  8. package/src/components/ui/chat/chat-sidebar-panel.tsx +6 -0
  9. package/src/components/ui/chat/chat-sidebar-sections.ts +199 -0
  10. package/src/components/ui/chat/chat-sidebar.tsx +11 -258
  11. package/src/components/ui/chat/chat-workspace.tsx +5 -0
  12. package/src/components/ui/chat/utils.ts +7 -0
  13. package/src/components/ui/custom/settings/task-settings.tsx +76 -0
  14. package/src/components/ui/custom/settings/task-sound-settings.test.tsx +126 -0
  15. package/src/components/ui/finance/transactions/infinite-transactions-list.tsx +29 -18
  16. package/src/components/ui/finance/transactions/transaction-card.tsx +75 -43
  17. package/src/components/ui/finance/transactions/transfer-merge.test.ts +90 -0
  18. package/src/components/ui/finance/transactions/transfer-merge.ts +52 -0
  19. package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoint-adjustment-dialog.tsx +172 -0
  20. package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoint-amount.tsx +32 -0
  21. package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoint-delete-dialog.tsx +50 -0
  22. package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoint-dialog.tsx +138 -0
  23. package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoint-panel.tsx +196 -0
  24. package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoint-sections.tsx +201 -0
  25. package/src/components/ui/finance/wallets/checkpoints/wallet-checkpoints.test.tsx +277 -0
  26. package/src/components/ui/finance/wallets/checkpoints/wallet-total-check-dialog.tsx +189 -0
  27. package/src/components/ui/finance/wallets/query-invalidation.ts +2 -0
  28. package/src/components/ui/finance/wallets/walletId/wallet-details-page.test.tsx +7 -3
  29. package/src/components/ui/finance/wallets/walletId/wallet-details-page.tsx +10 -0
  30. package/src/components/ui/finance/wallets/wallets-page.test.tsx +7 -0
  31. package/src/components/ui/finance/wallets/wallets-page.tsx +21 -5
  32. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/__tests__/bulk-mutations-move.test.tsx +14 -0
  33. package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-operations.ts +29 -0
  34. package/src/components/ui/tu-do/my-tasks/__tests__/use-task-context-actions.test.ts +11 -0
  35. package/src/components/ui/tu-do/my-tasks/use-task-context-actions.ts +10 -0
  36. package/src/components/ui/tu-do/shared/task-edit-dialog/components/compact-task-create-popover.test.tsx +141 -0
  37. package/src/components/ui/tu-do/shared/task-edit-dialog/components/compact-task-create-popover.tsx +208 -0
  38. package/src/components/ui/tu-do/shared/task-edit-dialog/components/quick-settings-popover.tsx +26 -0
  39. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-list-selector.tsx +36 -20
  40. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-name-input.test.tsx +24 -0
  41. package/src/components/ui/tu-do/shared/task-edit-dialog/components/task-name-input.tsx +18 -3
  42. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-save.test.ts +84 -1
  43. package/src/components/ui/tu-do/shared/task-edit-dialog/hooks/use-task-save.ts +5 -1
  44. package/src/components/ui/tu-do/shared/task-edit-dialog/task-properties-section.tsx +300 -172
  45. package/src/components/ui/tu-do/shared/task-edit-dialog.tsx +411 -323
  46. package/src/components/ui/tu-do/shared/task-sound-effects.test.ts +189 -0
  47. package/src/components/ui/tu-do/shared/task-sound-effects.tsx +468 -0
  48. package/src/hooks/__tests__/use-task-actions.test.tsx +61 -0
  49. package/src/hooks/use-task-actions.ts +45 -0
@@ -40,9 +40,13 @@ import {
40
40
  import { DescriptionOverflowWarningDialog } from './description-overflow-warning-dialog';
41
41
  import { createInitialSuggestionState } from './mention-system/types';
42
42
  import { SyncWarningDialog } from './sync-warning-dialog';
43
+ import { CompactTaskCreatePopover } from './task-edit-dialog/components/compact-task-create-popover';
43
44
  import { MobileFloatingSaveButton } from './task-edit-dialog/components/mobile-floating-save-button';
44
45
  import { TaskDescriptionEditor } from './task-edit-dialog/components/task-description-editor';
45
- import { TaskDialogHeader } from './task-edit-dialog/components/task-dialog-header';
46
+ import {
47
+ getTaskDialogHeaderInfo,
48
+ TaskDialogHeader,
49
+ } from './task-edit-dialog/components/task-dialog-header';
46
50
  import { TaskNameInput } from './task-edit-dialog/components/task-name-input';
47
51
  import { TaskSuggestionMenus } from './task-edit-dialog/components/task-suggestion-menus';
48
52
  import { NAME_UPDATE_DEBOUNCE_MS } from './task-edit-dialog/constants';
@@ -181,6 +185,7 @@ export function TaskEditDialog({
181
185
  const pathname = usePathname();
182
186
  const queryClient = useQueryClient();
183
187
  const t = useTranslations('common');
188
+ const rootT = useTranslations();
184
189
  const dialogT = useTranslations('ws-task-boards.dialog');
185
190
  const { registerCloseRequestHandler } = useTaskDialogContext();
186
191
 
@@ -504,6 +509,8 @@ export function TaskEditDialog({
504
509
  useState(false);
505
510
  const [showShareDialog, setShowShareDialog] = useState(false);
506
511
  const [saveAsDraft, setSaveAsDraft] = useState(draftModeEnabled);
512
+ const [isCreateFullscreen, setIsCreateFullscreen] = useState(false);
513
+ const previousOpenRef = useRef(false);
507
514
  const [isTitleVisible, setIsTitleVisible] = useState(true);
508
515
  const [scrollContainer, setScrollContainer] = useState<HTMLDivElement | null>(
509
516
  null
@@ -1522,6 +1529,20 @@ export function TaskEditDialog({
1522
1529
  }
1523
1530
  }, [isOpen, draftModeEnabled, draftId]);
1524
1531
 
1532
+ useEffect(() => {
1533
+ const justOpened = isOpen && !previousOpenRef.current;
1534
+ previousOpenRef.current = isOpen;
1535
+
1536
+ if (!isOpen) {
1537
+ setIsCreateFullscreen(false);
1538
+ return;
1539
+ }
1540
+
1541
+ if (justOpened && isCreateMode && !draftId) {
1542
+ setIsCreateFullscreen(false);
1543
+ }
1544
+ }, [isOpen, isCreateMode, draftId]);
1545
+
1525
1546
  // Track whether the title input is scrolled out of view
1526
1547
  useEffect(() => {
1527
1548
  const el = titleInputRef.current;
@@ -1583,11 +1604,110 @@ export function TaskEditDialog({
1583
1604
  taskSearchQuery,
1584
1605
  ]);
1585
1606
 
1607
+ const showCompactCreate =
1608
+ isCreateMode && !draftId && !isCreateFullscreen && !disabled;
1609
+ const compactHeaderInfo = useMemo(
1610
+ () =>
1611
+ getTaskDialogHeaderInfo(
1612
+ {
1613
+ isCreateMode,
1614
+ parentTaskId,
1615
+ parentTaskName,
1616
+ pendingRelationship,
1617
+ draftId,
1618
+ },
1619
+ rootT
1620
+ ),
1621
+ [
1622
+ isCreateMode,
1623
+ parentTaskId,
1624
+ parentTaskName,
1625
+ pendingRelationship,
1626
+ draftId,
1627
+ rootT,
1628
+ ]
1629
+ );
1630
+
1586
1631
  // Update refs
1587
1632
  quickDueRef.current = handleQuickDueDate;
1588
1633
  updateEstimationRef.current = updateEstimation;
1589
1634
  handleConvertToTaskRef.current = handleConvertToTask;
1590
1635
 
1636
+ const renderTaskPropertiesSection = (
1637
+ variant: 'default' | 'compact' = 'default'
1638
+ ) => (
1639
+ <TaskPropertiesSection
1640
+ wsId={effectiveTaskWsId}
1641
+ boardId={boardId}
1642
+ taskId={task?.id}
1643
+ priority={formState.priority}
1644
+ startDate={formState.startDate}
1645
+ endDate={formState.endDate}
1646
+ estimationPoints={formState.estimationPoints}
1647
+ selectedLabels={formState.selectedLabels}
1648
+ selectedProjects={formState.selectedProjects}
1649
+ selectedListId={formState.selectedListId}
1650
+ selectedAssignees={formState.selectedAssignees}
1651
+ isLoading={isLoading}
1652
+ isPersonalWorkspace={isPersonalWorkspace}
1653
+ totalDuration={formState.totalDuration}
1654
+ isSplittable={formState.isSplittable}
1655
+ minSplitDurationMinutes={formState.minSplitDurationMinutes}
1656
+ maxSplitDurationMinutes={formState.maxSplitDurationMinutes}
1657
+ calendarHours={formState.calendarHours}
1658
+ autoSchedule={formState.autoSchedule}
1659
+ availableLists={availableLists}
1660
+ availableLabels={availableLabels}
1661
+ taskProjects={taskProjects}
1662
+ workspaceMembers={workspaceMembers}
1663
+ boardConfig={boardConfig}
1664
+ onPriorityChange={updatePriority}
1665
+ onStartDateChange={updateStartDate}
1666
+ onEndDateChange={updateEndDate}
1667
+ onEstimationChange={updateEstimation}
1668
+ onLabelToggle={toggleLabel}
1669
+ onProjectToggle={toggleProject}
1670
+ onListChange={updateList}
1671
+ onAssigneeToggle={toggleAssignee}
1672
+ onQuickDueDate={handleQuickDueDate}
1673
+ onShowNewLabelDialog={() => {
1674
+ setNewLabelColor((previousColor) =>
1675
+ getRandomNewLabelColor(previousColor)
1676
+ );
1677
+ setShowNewLabelDialog(true);
1678
+ }}
1679
+ onShowNewProjectDialog={() => setShowNewProjectDialog(true)}
1680
+ onShowEstimationConfigDialog={() => setShowEstimationConfigDialog(true)}
1681
+ onTotalDurationChange={formState.setTotalDuration}
1682
+ onIsSplittableChange={formState.setIsSplittable}
1683
+ onMinSplitDurationChange={formState.setMinSplitDurationMinutes}
1684
+ onMaxSplitDurationChange={formState.setMaxSplitDurationMinutes}
1685
+ onCalendarHoursChange={formState.setCalendarHours}
1686
+ onAutoScheduleChange={formState.setAutoSchedule}
1687
+ isCreateMode={isCreateMode}
1688
+ savedSchedulingSettings={
1689
+ personalScheduleData?.task
1690
+ ? {
1691
+ totalDuration: personalScheduleData.task.total_duration ?? null,
1692
+ isSplittable: !!personalScheduleData.task.is_splittable,
1693
+ minSplitDurationMinutes:
1694
+ personalScheduleData.task.min_split_duration_minutes ?? null,
1695
+ maxSplitDurationMinutes:
1696
+ personalScheduleData.task.max_split_duration_minutes ?? null,
1697
+ calendarHours: personalScheduleData.task.calendar_hours ?? null,
1698
+ autoSchedule: !!personalScheduleData.task.auto_schedule,
1699
+ }
1700
+ : undefined
1701
+ }
1702
+ onSaveSchedulingSettings={saveSchedulingSettings}
1703
+ schedulingSaving={schedulingSaving}
1704
+ scheduledEvents={localCalendarEvents}
1705
+ disabled={disabled}
1706
+ isDraftMode={!!draftId || (isCreateMode && saveAsDraft)}
1707
+ variant={variant}
1708
+ />
1709
+ );
1710
+
1591
1711
  return (
1592
1712
  <>
1593
1713
  <TaskSuggestionMenus
@@ -1622,7 +1742,11 @@ export function TaskEditDialog({
1622
1742
  <Dialog open={isOpen} onOpenChange={handleDialogOpenChange} modal={true}>
1623
1743
  <DialogContent
1624
1744
  showCloseButton={false}
1625
- className="data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:slide-out-to-bottom-2 data-[state=open]:slide-in-from-bottom-2 inset-0! top-0! left-0! flex h-screen max-h-screen w-screen max-w-none! translate-x-0! translate-y-0! gap-0 rounded-none! border-0 p-0"
1745
+ className={
1746
+ showCompactCreate
1747
+ ? 'w-[min(calc(100vw-2rem),30rem)] max-w-[30rem] gap-0 overflow-hidden rounded-lg border p-0 shadow-xl'
1748
+ : 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:slide-out-to-bottom-2 data-[state=open]:slide-in-from-bottom-2 inset-0! top-0! left-0! flex h-screen max-h-screen w-screen max-w-none! translate-x-0! translate-y-0! gap-0 rounded-none! border-0 p-0'
1749
+ }
1626
1750
  onContextMenu={(e) => {
1627
1751
  if (shouldPreserveNativeContextMenu(e.target)) {
1628
1752
  return;
@@ -1648,74 +1772,14 @@ export function TaskEditDialog({
1648
1772
  e.preventDefault();
1649
1773
  }}
1650
1774
  >
1651
- <div className="flex min-w-0 flex-1 flex-col bg-background transition-all duration-300">
1652
- {disabled && (
1653
- <DialogTitle className="sr-only">Task Details</DialogTitle>
1654
- )}
1655
- {!disabled && (
1656
- <TaskDialogHeader
1657
- isCreateMode={isCreateMode}
1658
- collaborationMode={collaborationMode}
1659
- realtimeEnabled={realtimeEnabled}
1660
- isOpen={isOpen}
1661
- synced={synced}
1662
- connected={connected}
1663
- taskId={task?.id}
1664
- parentTaskId={parentTaskId}
1665
- parentTaskName={parentTaskName}
1666
- pendingRelationship={pendingRelationship}
1667
- saveAsDraft={saveAsDraft}
1668
- setSaveAsDraft={setSaveAsDraft}
1669
- draftId={draftId}
1670
- isTitleVisible={isTitleVisible}
1671
- taskName={formState.name}
1672
- ticketPrefix={boardConfig?.ticket_prefix}
1673
- displayNumber={task?.display_number}
1674
- user={
1675
- user
1676
- ? {
1677
- id: user.id || '',
1678
- display_name: user.display_name ?? null,
1679
- avatar_url: user.avatar_url ?? null,
1680
- email: user.email ?? null,
1681
- }
1682
- : null
1683
- }
1684
- createMultiple={createMultiple}
1685
- hasDraft={formState.hasDraft}
1686
- wsId={effectiveTaskWsId}
1687
- boardId={boardId}
1688
- pathname={pathname}
1689
- canSave={canSave && !isDescriptionOverLimit}
1690
- isLoading={isLoading}
1691
- setCreateMultiple={setCreateMultiple}
1692
- handleClose={handleAttemptClose}
1693
- setShowDeleteConfirm={setShowDeleteConfirm}
1694
- clearDraftState={formState.clearDraftState}
1695
- handleSave={handleSave}
1696
- onNavigateBack={
1697
- isCreateMode && (pendingRelationship || parentTaskId)
1698
- ? handleNavigateBack
1699
- : undefined
1700
- }
1701
- isPersonalWorkspace={isPersonalWorkspace}
1702
- onOpenShareDialog={
1703
- !isCreateMode && task?.id
1704
- ? () => setShowShareDialog(true)
1705
- : undefined
1706
- }
1707
- disabled={disabled}
1708
- onScrollToUserCursor={
1709
- collaborationMode ? scrollToUserCursor : undefined
1710
- }
1711
- />
1712
- )}
1713
-
1714
- <div
1715
- ref={setScrollContainer}
1716
- className="relative flex min-h-0 flex-1 flex-col overflow-y-auto"
1717
- >
1718
- <div className="flex flex-col">
1775
+ {showCompactCreate ? (
1776
+ <CompactTaskCreatePopover
1777
+ title={compactHeaderInfo.title}
1778
+ description={compactHeaderInfo.description}
1779
+ icon={compactHeaderInfo.icon}
1780
+ iconBgClass={compactHeaderInfo.iconBgClass}
1781
+ iconRingClass={compactHeaderInfo.iconRingClass}
1782
+ titleInput={
1719
1783
  <TaskNameInput
1720
1784
  name={formState.name}
1721
1785
  isCreateMode={isCreateMode}
@@ -1727,274 +1791,298 @@ export function TaskEditDialog({
1727
1791
  updateName={updateName}
1728
1792
  flushNameUpdate={flushNameUpdate}
1729
1793
  disabled={disabled}
1794
+ variant="compact"
1795
+ onSubmit={handleSave}
1730
1796
  />
1731
-
1797
+ }
1798
+ propertyControls={renderTaskPropertiesSection('compact')}
1799
+ saveAsDraft={saveAsDraft}
1800
+ createMultiple={createMultiple}
1801
+ canSave={canSave && !isDescriptionOverLimit}
1802
+ isLoading={isLoading}
1803
+ isPersonalWorkspace={isPersonalWorkspace}
1804
+ onSaveAsDraftChange={setSaveAsDraft}
1805
+ onCreateMultipleChange={setCreateMultiple}
1806
+ onClose={handleAttemptClose}
1807
+ onFullscreen={() => setIsCreateFullscreen(true)}
1808
+ onSave={handleSave}
1809
+ />
1810
+ ) : (
1811
+ <>
1812
+ <div className="flex min-w-0 flex-1 flex-col bg-background transition-all duration-300">
1813
+ {disabled && (
1814
+ <DialogTitle className="sr-only">Task Details</DialogTitle>
1815
+ )}
1732
1816
  {!disabled && (
1733
- <TaskPropertiesSection
1734
- wsId={effectiveTaskWsId}
1735
- boardId={boardId}
1736
- taskId={task?.id}
1737
- priority={formState.priority}
1738
- startDate={formState.startDate}
1739
- endDate={formState.endDate}
1740
- estimationPoints={formState.estimationPoints}
1741
- selectedLabels={formState.selectedLabels}
1742
- selectedProjects={formState.selectedProjects}
1743
- selectedListId={formState.selectedListId}
1744
- selectedAssignees={formState.selectedAssignees}
1745
- isLoading={isLoading}
1746
- isPersonalWorkspace={isPersonalWorkspace}
1747
- totalDuration={formState.totalDuration}
1748
- isSplittable={formState.isSplittable}
1749
- minSplitDurationMinutes={formState.minSplitDurationMinutes}
1750
- maxSplitDurationMinutes={formState.maxSplitDurationMinutes}
1751
- calendarHours={formState.calendarHours}
1752
- autoSchedule={formState.autoSchedule}
1753
- availableLists={availableLists}
1754
- availableLabels={availableLabels}
1755
- taskProjects={taskProjects}
1756
- workspaceMembers={workspaceMembers}
1757
- boardConfig={boardConfig}
1758
- onPriorityChange={updatePriority}
1759
- onStartDateChange={updateStartDate}
1760
- onEndDateChange={updateEndDate}
1761
- onEstimationChange={updateEstimation}
1762
- onLabelToggle={toggleLabel}
1763
- onProjectToggle={toggleProject}
1764
- onListChange={updateList}
1765
- onAssigneeToggle={toggleAssignee}
1766
- onQuickDueDate={handleQuickDueDate}
1767
- onShowNewLabelDialog={() => {
1768
- setNewLabelColor((previousColor) =>
1769
- getRandomNewLabelColor(previousColor)
1770
- );
1771
- setShowNewLabelDialog(true);
1772
- }}
1773
- onShowNewProjectDialog={() => setShowNewProjectDialog(true)}
1774
- onShowEstimationConfigDialog={() =>
1775
- setShowEstimationConfigDialog(true)
1776
- }
1777
- onTotalDurationChange={formState.setTotalDuration}
1778
- onIsSplittableChange={formState.setIsSplittable}
1779
- onMinSplitDurationChange={
1780
- formState.setMinSplitDurationMinutes
1781
- }
1782
- onMaxSplitDurationChange={
1783
- formState.setMaxSplitDurationMinutes
1784
- }
1785
- onCalendarHoursChange={formState.setCalendarHours}
1786
- onAutoScheduleChange={formState.setAutoSchedule}
1817
+ <TaskDialogHeader
1787
1818
  isCreateMode={isCreateMode}
1788
- savedSchedulingSettings={
1789
- personalScheduleData?.task
1819
+ collaborationMode={collaborationMode}
1820
+ realtimeEnabled={realtimeEnabled}
1821
+ isOpen={isOpen}
1822
+ synced={synced}
1823
+ connected={connected}
1824
+ taskId={task?.id}
1825
+ parentTaskId={parentTaskId}
1826
+ parentTaskName={parentTaskName}
1827
+ pendingRelationship={pendingRelationship}
1828
+ saveAsDraft={saveAsDraft}
1829
+ setSaveAsDraft={setSaveAsDraft}
1830
+ draftId={draftId}
1831
+ isTitleVisible={isTitleVisible}
1832
+ taskName={formState.name}
1833
+ ticketPrefix={boardConfig?.ticket_prefix}
1834
+ displayNumber={task?.display_number}
1835
+ user={
1836
+ user
1790
1837
  ? {
1791
- totalDuration:
1792
- personalScheduleData.task.total_duration ?? null,
1793
- isSplittable:
1794
- !!personalScheduleData.task.is_splittable,
1795
- minSplitDurationMinutes:
1796
- personalScheduleData.task
1797
- .min_split_duration_minutes ?? null,
1798
- maxSplitDurationMinutes:
1799
- personalScheduleData.task
1800
- .max_split_duration_minutes ?? null,
1801
- calendarHours:
1802
- personalScheduleData.task.calendar_hours ?? null,
1803
- autoSchedule:
1804
- !!personalScheduleData.task.auto_schedule,
1838
+ id: user.id || '',
1839
+ display_name: user.display_name ?? null,
1840
+ avatar_url: user.avatar_url ?? null,
1841
+ email: user.email ?? null,
1805
1842
  }
1806
- : undefined
1843
+ : null
1807
1844
  }
1808
- onSaveSchedulingSettings={saveSchedulingSettings}
1809
- schedulingSaving={schedulingSaving}
1810
- scheduledEvents={localCalendarEvents}
1811
- disabled={disabled}
1812
- isDraftMode={!!draftId || (isCreateMode && saveAsDraft)}
1813
- />
1814
- )}
1815
-
1816
- {!disabled && !isCreateMode && (
1817
- <PersonalOverridesSection
1818
- taskId={task?.id}
1819
- isCreateMode={isCreateMode}
1820
- boardConfig={boardConfig}
1821
- onUpdate={onUpdate}
1822
- />
1823
- )}
1824
-
1825
- {!disabled && !draftId && !(isCreateMode && saveAsDraft) && (
1826
- <TaskRelationshipsProperties
1845
+ createMultiple={createMultiple}
1846
+ hasDraft={formState.hasDraft}
1827
1847
  wsId={effectiveTaskWsId}
1828
- taskId={task?.id}
1829
1848
  boardId={boardId}
1830
- listId={task?.list_id}
1831
- isCreateMode={isCreateMode}
1832
- initialActiveTab={
1833
- seededPendingRelationships.initialActiveTab
1834
- }
1835
- initialDependencySubTab={
1836
- seededPendingRelationships.initialDependencySubTab
1837
- }
1838
- parentTask={parentTask}
1839
- childTasks={childTasks}
1840
- blockingTasks={blockingTasks}
1841
- blockedByTasks={blockedByTasks}
1842
- relatedTasks={relatedTasks}
1843
- isLoading={dependenciesLoading}
1844
- onSetParent={setParentTask}
1845
- onRemoveParent={() => setParentTask(null)}
1846
- onAddBlockingTask={addBlockingTask}
1847
- onRemoveBlockingTask={removeBlockingTask}
1848
- onAddBlockedByTask={addBlockedByTask}
1849
- onRemoveBlockedByTask={removeBlockedByTask}
1850
- onAddRelatedTask={addRelatedTask}
1851
- onRemoveRelatedTask={removeRelatedTask}
1852
- onNavigateToTask={async (taskId) => {
1853
- if (onNavigateToTask) await onNavigateToTask(taskId);
1854
- }}
1855
- onAddSubtask={isCreateMode ? undefined : onAddSubtask}
1856
- onAddParentTask={isCreateMode ? undefined : onAddParentTask}
1857
- onAddBlockingTaskDialog={
1858
- isCreateMode ? undefined : onAddBlockingTask
1859
- }
1860
- onAddBlockedByTaskDialog={
1861
- isCreateMode ? undefined : onAddBlockedByTask
1849
+ pathname={pathname}
1850
+ canSave={canSave && !isDescriptionOverLimit}
1851
+ isLoading={isLoading}
1852
+ setCreateMultiple={setCreateMultiple}
1853
+ handleClose={handleAttemptClose}
1854
+ setShowDeleteConfirm={setShowDeleteConfirm}
1855
+ clearDraftState={formState.clearDraftState}
1856
+ handleSave={handleSave}
1857
+ onNavigateBack={
1858
+ isCreateMode && (pendingRelationship || parentTaskId)
1859
+ ? handleNavigateBack
1860
+ : undefined
1862
1861
  }
1863
- onAddRelatedTaskDialog={
1864
- isCreateMode ? undefined : onAddRelatedTask
1862
+ isPersonalWorkspace={isPersonalWorkspace}
1863
+ onOpenShareDialog={
1864
+ !isCreateMode && task?.id
1865
+ ? () => setShowShareDialog(true)
1866
+ : undefined
1865
1867
  }
1866
- onAddExistingAsSubtask={addChildTask}
1867
- isSaving={!!savingRelationship}
1868
- savingTaskId={savingRelationship}
1869
1868
  disabled={disabled}
1869
+ onScrollToUserCursor={
1870
+ collaborationMode ? scrollToUserCursor : undefined
1871
+ }
1870
1872
  />
1871
1873
  )}
1872
1874
 
1873
- <TaskDescriptionEditor
1874
- description={formState.description}
1875
- setDescription={formState.setDescription}
1876
- isOpen={isOpen}
1877
- isCreateMode={isCreateMode}
1878
- collaborationMode={collaborationMode}
1879
- realtimeEnabled={realtimeEnabled}
1880
- isYjsSyncing={isYjsSyncing}
1881
- wsId={effectiveTaskWsId}
1882
- boardId={boardId}
1883
- taskId={task?.id}
1884
- availableLists={availableLists}
1885
- queryClient={queryClient}
1886
- editorRef={editorRef}
1887
- richTextEditorRef={richTextEditorRef}
1888
- titleInputRef={titleInputRef}
1889
- lastCursorPositionRef={lastCursorPositionRef}
1890
- targetEditorCursorRef={targetEditorCursorRef}
1891
- flushEditorPendingRef={flushEditorPendingRef}
1892
- yjsDoc={doc}
1893
- yjsProvider={provider ?? undefined}
1894
- collaborationUser={
1895
- user
1896
- ? {
1897
- id: user.id || '',
1898
- name: userDisplayName,
1899
- color: userColor || '',
1900
- }
1901
- : null
1902
- }
1903
- onImageUpload={imageUploadHandler}
1904
- onEditorReady={handleEditorReady}
1905
- onConvertToTask={handleConvertToTask}
1906
- onDescriptionStorageLengthChange={
1907
- handleDescriptionStorageLengthChange
1908
- }
1909
- descriptionStorageLength={descriptionStorageLength}
1910
- descriptionPercentLeft={descriptionPercentLeft}
1911
- descriptionLimit={MAX_TASK_DESCRIPTION_LENGTH}
1912
- isDescriptionOverLimit={isDescriptionOverLimit}
1913
- disabled={disabled}
1914
- mentionTranslations={{
1915
- delete_task: t('delete_task'),
1916
- delete_task_confirmation: (name: string) =>
1917
- t('delete_task_confirmation', { name }),
1918
- cancel: t('cancel'),
1919
- deleting: t('deleting'),
1920
- set_custom_due_date: t('set_custom_due_date'),
1921
- custom_due_date_description: t(
1922
- 'custom_due_date_description'
1923
- ),
1924
- remove_due_date: t('remove_due_date'),
1925
- create_new_label: t('create_new_label'),
1926
- create_new_label_description: t(
1927
- 'create_new_label_description'
1928
- ),
1929
- label_name: t('label_name'),
1930
- color: t('color'),
1931
- preview: t('preview'),
1932
- creating: t('creating'),
1933
- create_label: t('create_label'),
1934
- create_new_project: t('create_new_project'),
1935
- create_new_project_description: t(
1936
- 'create_new_project_description'
1937
- ),
1938
- project_name: t('project_name'),
1939
- create_project: t('create_project'),
1940
- }}
1941
- />
1942
-
1943
- {!isCreateMode && localCalendarEvents && (
1944
- <TaskInstancesSection
1945
- wsId={effectiveTaskWsId}
1946
- taskId={task?.id}
1947
- scheduledEvents={localCalendarEvents}
1948
- onLockToggle={handleLockToggle}
1949
- isLocking={lockingEventId}
1950
- />
1951
- )}
1952
-
1953
- {!disabled && !isCreateMode && task && (
1954
- <TaskActivitySection
1955
- wsId={effectiveTaskWsId}
1956
- taskId={task.id}
1957
- boardId={boardId}
1958
- currentTask={{
1959
- id: task.id,
1960
- name: formState.name || task.name || '',
1961
- description: formState.description,
1962
- priority: formState.priority,
1963
- start_date: formState.startDate?.toISOString() || null,
1964
- end_date: formState.endDate?.toISOString() || null,
1965
- estimation_points: formState.estimationPoints ?? null,
1966
- list_id: formState.selectedListId || task.list_id || '',
1967
- list_name:
1968
- availableLists?.find(
1969
- (l) => l.id === formState.selectedListId
1970
- )?.name || null,
1971
- completed: !!task.completed_at,
1972
- assignees: formState.selectedAssignees.map((a) => ({
1973
- id: a.id,
1974
- user_id: a.id,
1975
- })),
1976
- labels: formState.selectedLabels.map((l) => ({
1977
- id: l.id,
1978
- })),
1979
- projects: formState.selectedProjects.map((p) => ({
1980
- id: p.id,
1981
- })),
1982
- }}
1983
- revertDisabled={true}
1984
- />
1985
- )}
1875
+ <div
1876
+ ref={setScrollContainer}
1877
+ className="relative flex min-h-0 flex-1 flex-col overflow-y-auto"
1878
+ >
1879
+ <div className="flex flex-col">
1880
+ <TaskNameInput
1881
+ name={formState.name}
1882
+ isCreateMode={isCreateMode}
1883
+ titleInputRef={titleInputRef}
1884
+ editorRef={editorRef}
1885
+ lastCursorPositionRef={lastCursorPositionRef}
1886
+ targetEditorCursorRef={targetEditorCursorRef}
1887
+ setName={formState.setName}
1888
+ updateName={updateName}
1889
+ flushNameUpdate={flushNameUpdate}
1890
+ disabled={disabled}
1891
+ />
1892
+
1893
+ {!disabled && renderTaskPropertiesSection()}
1894
+
1895
+ {!disabled && !isCreateMode && (
1896
+ <PersonalOverridesSection
1897
+ taskId={task?.id}
1898
+ isCreateMode={isCreateMode}
1899
+ boardConfig={boardConfig}
1900
+ onUpdate={onUpdate}
1901
+ />
1902
+ )}
1903
+
1904
+ {!disabled &&
1905
+ !draftId &&
1906
+ !(isCreateMode && saveAsDraft) && (
1907
+ <TaskRelationshipsProperties
1908
+ wsId={effectiveTaskWsId}
1909
+ taskId={task?.id}
1910
+ boardId={boardId}
1911
+ listId={task?.list_id}
1912
+ isCreateMode={isCreateMode}
1913
+ initialActiveTab={
1914
+ seededPendingRelationships.initialActiveTab
1915
+ }
1916
+ initialDependencySubTab={
1917
+ seededPendingRelationships.initialDependencySubTab
1918
+ }
1919
+ parentTask={parentTask}
1920
+ childTasks={childTasks}
1921
+ blockingTasks={blockingTasks}
1922
+ blockedByTasks={blockedByTasks}
1923
+ relatedTasks={relatedTasks}
1924
+ isLoading={dependenciesLoading}
1925
+ onSetParent={setParentTask}
1926
+ onRemoveParent={() => setParentTask(null)}
1927
+ onAddBlockingTask={addBlockingTask}
1928
+ onRemoveBlockingTask={removeBlockingTask}
1929
+ onAddBlockedByTask={addBlockedByTask}
1930
+ onRemoveBlockedByTask={removeBlockedByTask}
1931
+ onAddRelatedTask={addRelatedTask}
1932
+ onRemoveRelatedTask={removeRelatedTask}
1933
+ onNavigateToTask={async (taskId) => {
1934
+ if (onNavigateToTask)
1935
+ await onNavigateToTask(taskId);
1936
+ }}
1937
+ onAddSubtask={isCreateMode ? undefined : onAddSubtask}
1938
+ onAddParentTask={
1939
+ isCreateMode ? undefined : onAddParentTask
1940
+ }
1941
+ onAddBlockingTaskDialog={
1942
+ isCreateMode ? undefined : onAddBlockingTask
1943
+ }
1944
+ onAddBlockedByTaskDialog={
1945
+ isCreateMode ? undefined : onAddBlockedByTask
1946
+ }
1947
+ onAddRelatedTaskDialog={
1948
+ isCreateMode ? undefined : onAddRelatedTask
1949
+ }
1950
+ onAddExistingAsSubtask={addChildTask}
1951
+ isSaving={!!savingRelationship}
1952
+ savingTaskId={savingRelationship}
1953
+ disabled={disabled}
1954
+ />
1955
+ )}
1956
+
1957
+ <TaskDescriptionEditor
1958
+ description={formState.description}
1959
+ setDescription={formState.setDescription}
1960
+ isOpen={isOpen}
1961
+ isCreateMode={isCreateMode}
1962
+ collaborationMode={collaborationMode}
1963
+ realtimeEnabled={realtimeEnabled}
1964
+ isYjsSyncing={isYjsSyncing}
1965
+ wsId={effectiveTaskWsId}
1966
+ boardId={boardId}
1967
+ taskId={task?.id}
1968
+ availableLists={availableLists}
1969
+ queryClient={queryClient}
1970
+ editorRef={editorRef}
1971
+ richTextEditorRef={richTextEditorRef}
1972
+ titleInputRef={titleInputRef}
1973
+ lastCursorPositionRef={lastCursorPositionRef}
1974
+ targetEditorCursorRef={targetEditorCursorRef}
1975
+ flushEditorPendingRef={flushEditorPendingRef}
1976
+ yjsDoc={doc}
1977
+ yjsProvider={provider ?? undefined}
1978
+ collaborationUser={
1979
+ user
1980
+ ? {
1981
+ id: user.id || '',
1982
+ name: userDisplayName,
1983
+ color: userColor || '',
1984
+ }
1985
+ : null
1986
+ }
1987
+ onImageUpload={imageUploadHandler}
1988
+ onEditorReady={handleEditorReady}
1989
+ onConvertToTask={handleConvertToTask}
1990
+ onDescriptionStorageLengthChange={
1991
+ handleDescriptionStorageLengthChange
1992
+ }
1993
+ descriptionStorageLength={descriptionStorageLength}
1994
+ descriptionPercentLeft={descriptionPercentLeft}
1995
+ descriptionLimit={MAX_TASK_DESCRIPTION_LENGTH}
1996
+ isDescriptionOverLimit={isDescriptionOverLimit}
1997
+ disabled={disabled}
1998
+ mentionTranslations={{
1999
+ delete_task: t('delete_task'),
2000
+ delete_task_confirmation: (name: string) =>
2001
+ t('delete_task_confirmation', { name }),
2002
+ cancel: t('cancel'),
2003
+ deleting: t('deleting'),
2004
+ set_custom_due_date: t('set_custom_due_date'),
2005
+ custom_due_date_description: t(
2006
+ 'custom_due_date_description'
2007
+ ),
2008
+ remove_due_date: t('remove_due_date'),
2009
+ create_new_label: t('create_new_label'),
2010
+ create_new_label_description: t(
2011
+ 'create_new_label_description'
2012
+ ),
2013
+ label_name: t('label_name'),
2014
+ color: t('color'),
2015
+ preview: t('preview'),
2016
+ creating: t('creating'),
2017
+ create_label: t('create_label'),
2018
+ create_new_project: t('create_new_project'),
2019
+ create_new_project_description: t(
2020
+ 'create_new_project_description'
2021
+ ),
2022
+ project_name: t('project_name'),
2023
+ create_project: t('create_project'),
2024
+ }}
2025
+ />
2026
+
2027
+ {!isCreateMode && localCalendarEvents && (
2028
+ <TaskInstancesSection
2029
+ wsId={effectiveTaskWsId}
2030
+ taskId={task?.id}
2031
+ scheduledEvents={localCalendarEvents}
2032
+ onLockToggle={handleLockToggle}
2033
+ isLocking={lockingEventId}
2034
+ />
2035
+ )}
2036
+
2037
+ {!disabled && !isCreateMode && task && (
2038
+ <TaskActivitySection
2039
+ wsId={effectiveTaskWsId}
2040
+ taskId={task.id}
2041
+ boardId={boardId}
2042
+ currentTask={{
2043
+ id: task.id,
2044
+ name: formState.name || task.name || '',
2045
+ description: formState.description,
2046
+ priority: formState.priority,
2047
+ start_date:
2048
+ formState.startDate?.toISOString() || null,
2049
+ end_date: formState.endDate?.toISOString() || null,
2050
+ estimation_points: formState.estimationPoints ?? null,
2051
+ list_id:
2052
+ formState.selectedListId || task.list_id || '',
2053
+ list_name:
2054
+ availableLists?.find(
2055
+ (l) => l.id === formState.selectedListId
2056
+ )?.name || null,
2057
+ completed: !!task.completed_at,
2058
+ assignees: formState.selectedAssignees.map((a) => ({
2059
+ id: a.id,
2060
+ user_id: a.id,
2061
+ })),
2062
+ labels: formState.selectedLabels.map((l) => ({
2063
+ id: l.id,
2064
+ })),
2065
+ projects: formState.selectedProjects.map((p) => ({
2066
+ id: p.id,
2067
+ })),
2068
+ }}
2069
+ revertDisabled={true}
2070
+ />
2071
+ )}
2072
+ </div>
2073
+ </div>
1986
2074
  </div>
1987
- </div>
1988
- </div>
1989
-
1990
- <MobileFloatingSaveButton
1991
- isCreateMode={isCreateMode}
1992
- collaborationMode={collaborationMode}
1993
- isLoading={isLoading}
1994
- canSave={canSave && !isDescriptionOverLimit}
1995
- handleSave={handleSave}
1996
- disabled={disabled}
1997
- />
2075
+
2076
+ <MobileFloatingSaveButton
2077
+ isCreateMode={isCreateMode}
2078
+ collaborationMode={collaborationMode}
2079
+ isLoading={isLoading}
2080
+ canSave={canSave && !isDescriptionOverLimit}
2081
+ handleSave={handleSave}
2082
+ disabled={disabled}
2083
+ />
2084
+ </>
2085
+ )}
1998
2086
  </DialogContent>
1999
2087
  </Dialog>
2000
2088