@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.
- package/CHANGELOG.md +40 -0
- package/biome.json +1 -1
- package/package.json +73 -71
- package/src/components/ui/accordion.tsx +1 -1
- package/src/components/ui/breadcrumb.tsx +1 -1
- package/src/components/ui/calendar-app/calendar-page-shell.tsx +4 -0
- package/src/components/ui/calendar-app/components/calendar-connections-settings-content.tsx +239 -33
- package/src/components/ui/calendar-app/components/load-smart-scheduling-tasks.tsx +143 -0
- package/src/components/ui/calendar-app/components/priority-view.tsx +10 -3
- package/src/components/ui/calendar-app/components/tasks-sidebar.tsx +4 -116
- package/src/components/ui/calendar-app/components/use-calendar-connections-manager.ts +67 -2
- package/src/components/ui/calendar.tsx +1 -1
- package/src/components/ui/carousel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-external-thread-panel.test.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-external-thread-panel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-operations-panel.test.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-operations-panel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-setup-panel.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-sidebar.test.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-sidebar.tsx +2 -2
- package/src/components/ui/chat/chat-agent-details-utils.test.ts +1 -1
- package/src/components/ui/chat/chat-agent-details-utils.tsx +1 -1
- package/src/components/ui/chat/chat-agent-details-zalo-personal-panel.tsx +2 -2
- package/src/components/ui/checkbox.tsx +1 -1
- package/src/components/ui/color-picker.tsx +1 -1
- package/src/components/ui/command.tsx +1 -1
- package/src/components/ui/context-menu.tsx +5 -1
- package/src/components/ui/custom/__tests__/settings-dialog-shell.test.tsx +3 -0
- package/src/components/ui/custom/__tests__/workspace-select-helpers.test.ts +19 -0
- package/src/components/ui/custom/combobox.test.tsx +195 -0
- package/src/components/ui/custom/combobox.tsx +273 -156
- package/src/components/ui/custom/education/modules/youtube/delete-link-button.tsx +5 -13
- package/src/components/ui/custom/facebook-mockup/facebook-mockup.tsx +7 -1
- package/src/components/ui/custom/facebook-mockup/form.tsx +1 -1
- package/src/components/ui/custom/facebook-mockup/image-upload-field.tsx +1 -1
- package/src/components/ui/custom/facebook-mockup/preview.tsx +1 -1
- package/src/components/ui/custom/settings-dialog-shell.tsx +2 -1
- package/src/components/ui/custom/theme-toggle.tsx +1 -1
- package/src/components/ui/custom/workspace-select.tsx +8 -3
- package/src/components/ui/dialog.test.tsx +52 -0
- package/src/components/ui/dialog.tsx +6 -2
- package/src/components/ui/dropdown-menu.tsx +5 -1
- package/src/components/ui/finance/debts/debt-loan-form.tsx +12 -5
- package/src/components/ui/finance/debts/debt-loan-summary.tsx +3 -2
- package/src/components/ui/finance/debts/debts-page.test.tsx +54 -5
- package/src/components/ui/finance/debts/debts-page.tsx +15 -2
- package/src/components/ui/finance/invoices/components/subscription-group-selector.tsx +3 -5
- package/src/components/ui/finance/invoices/new-invoice-page.test.tsx +25 -5
- package/src/components/ui/finance/invoices/new-invoice-page.tsx +7 -2
- package/src/components/ui/finance/invoices/standard-invoice.tsx +4 -2
- package/src/components/ui/finance/invoices/subscription-invoice.tsx +4 -2
- package/src/components/ui/finance/invoices/utils.ts +3 -1
- package/src/components/ui/finance/transactions/form-content-dialog.tsx +3 -0
- package/src/components/ui/finance/transactions/form-types.ts +1 -0
- package/src/components/ui/finance/transactions/form.tsx +2 -0
- package/src/components/ui/finance/transactions/infinite-transactions-list.tsx +2 -0
- package/src/components/ui/finance/transactions/period-charts/category-breakdown-dialog.tsx +1 -1
- package/src/components/ui/finance/transactions/transaction-edit-dialog.tsx +1 -4
- package/src/components/ui/finance/transactions/transactions-create-summary.tsx +3 -0
- package/src/components/ui/finance/transactions/transactions-page.tsx +4 -1
- package/src/components/ui/finance/wallets/form.test.tsx +51 -3
- package/src/components/ui/finance/wallets/form.tsx +15 -4
- package/src/components/ui/finance/wallets/walletId/wallet-details-actions.tsx +4 -0
- package/src/components/ui/finance/wallets/walletId/wallet-details-page.tsx +4 -2
- package/src/components/ui/finance/wallets/wallets-data-table.tsx +1 -0
- package/src/components/ui/finance/wallets/wallets-page.tsx +5 -2
- package/src/components/ui/input-otp.tsx +1 -1
- package/src/components/ui/legacy/calendar/all-day-event-bar.tsx +28 -39
- package/src/components/ui/legacy/calendar/calendar-cell.tsx +2 -0
- package/src/components/ui/legacy/calendar/calendar-content.tsx +10 -6
- package/src/components/ui/legacy/calendar/calendar-header.tsx +23 -3
- package/src/components/ui/legacy/calendar/calendar-loading-skeleton.tsx +135 -0
- package/src/components/ui/legacy/calendar/calendar-matrix.tsx +175 -237
- package/src/components/ui/legacy/calendar/event-card.test.tsx +177 -0
- package/src/components/ui/legacy/calendar/event-card.tsx +220 -131
- package/src/components/ui/legacy/calendar/event-modal.tsx +17 -17
- package/src/components/ui/legacy/calendar/event-provider-display.tsx +69 -0
- package/src/components/ui/legacy/calendar/smart-calendar.test.tsx +86 -4
- package/src/components/ui/legacy/calendar/smart-calendar.tsx +32 -2
- package/src/components/ui/legacy/meet/create-plan-dialog.tsx +19 -10
- package/src/components/ui/navigation-menu.tsx +1 -1
- package/src/components/ui/pagination.tsx +1 -1
- package/src/components/ui/radio-group.tsx +1 -1
- package/src/components/ui/select.tsx +5 -1
- package/src/components/ui/sheet.tsx +1 -1
- package/src/components/ui/sidebar.tsx +1 -1
- package/src/components/ui/storefront/cart-popover.tsx +61 -0
- package/src/components/ui/storefront/cart-summary-parts.tsx +290 -0
- package/src/components/ui/storefront/cart-summary.tsx +93 -154
- package/src/components/ui/storefront/checkout-overlay.tsx +4 -5
- package/src/components/ui/storefront/listing-card.tsx +1 -1
- package/src/components/ui/storefront/merch-sections.tsx +70 -0
- package/src/components/ui/storefront/product-detail.tsx +1 -1
- package/src/components/ui/storefront/storefront-surface.test.tsx +106 -11
- package/src/components/ui/storefront/storefront-surface.tsx +101 -166
- package/src/components/ui/storefront/types.ts +4 -0
- package/src/components/ui/storefront/utils.ts +6 -0
- package/src/components/ui/text-editor/__tests__/extensions.test.ts +123 -0
- package/src/components/ui/text-editor/background-color-extension.ts +62 -0
- package/src/components/ui/text-editor/color-controls.tsx +284 -0
- package/src/components/ui/text-editor/editor.tsx +69 -14
- package/src/components/ui/text-editor/extensions.ts +8 -2
- package/src/components/ui/text-editor/highlight-extension.ts +22 -0
- package/src/components/ui/text-editor/tool-bar.tsx +9 -16
- package/src/components/ui/toast.tsx +1 -1
- package/src/components/ui/tu-do/boards/__tests__/board-share-dialog.test.tsx +270 -0
- package/src/components/ui/tu-do/boards/board-public-link-section.tsx +231 -0
- package/src/components/ui/tu-do/boards/board-share-dialog.tsx +222 -109
- package/src/components/ui/tu-do/boards/boardId/board-column.tsx +112 -43
- package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-clear-delete.ts +2 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-move.ts +5 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/bulk/bulk-mutations-updates.ts +3 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/data/kanban-deadline-query.ts +50 -2
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/__tests__/column-reorder.test.ts +17 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/column-reorder.ts +4 -1
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-cache.ts +38 -9
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-drag-order.ts +2 -8
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/task-sort-key.ts +47 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/dnd/use-kanban-dnd.ts +81 -30
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/__tests__/kanban-planner-island.test.tsx +380 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/kanban-planner-dialog.tsx +204 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-digest-panel.tsx +61 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-item-strip.tsx +54 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-plan-toolbar.tsx +251 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-scope-badge.tsx +27 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-section.tsx +58 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-share-dialog.tsx +238 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-target-controls.tsx +143 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/planner-utils.ts +65 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/planner/use-kanban-planner-state.ts +234 -0
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.test.tsx +397 -2
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-columns.tsx +103 -13
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-deadline-panels.tsx +443 -19
- package/src/components/ui/tu-do/boards/boardId/kanban/rendering/kanban-skeleton.tsx +94 -32
- package/src/components/ui/tu-do/boards/boardId/kanban.tsx +213 -106
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.test.tsx +26 -4
- package/src/components/ui/tu-do/boards/boardId/task-board-server-page.tsx +5 -2
- package/src/components/ui/tu-do/boards/boardId/task-card/measured-task-card.tsx +3 -0
- package/src/components/ui/tu-do/boards/boardId/task-card/task-card-comparator.ts +3 -0
- package/src/components/ui/tu-do/boards/boardId/task-card/task-card.tsx +191 -28
- package/src/components/ui/tu-do/boards/boardId/task-filter.test.tsx +152 -0
- package/src/components/ui/tu-do/boards/boardId/task-filter.tsx +555 -545
- package/src/components/ui/tu-do/boards/boardId/task-list.tsx +7 -0
- package/src/components/ui/tu-do/boards/share-section.tsx +100 -0
- package/src/components/ui/tu-do/drafts/draft-convert-dialog.tsx +10 -12
- package/src/components/ui/tu-do/drafts/drafts-page.tsx +33 -16
- package/src/components/ui/tu-do/initiatives/task-initiatives-client.tsx +56 -88
- package/src/components/ui/tu-do/my-tasks/my-tasks-content.tsx +26 -2
- package/src/components/ui/tu-do/my-tasks/use-my-tasks-state.ts +55 -8
- package/src/components/ui/tu-do/notes/note-edit-dialog.tsx +1 -4
- package/src/components/ui/tu-do/shared/__tests__/board-client.test.tsx +25 -0
- package/src/components/ui/tu-do/shared/__tests__/board-header.test.tsx +341 -38
- package/src/components/ui/tu-do/shared/__tests__/board-switcher.test.tsx +253 -0
- package/src/components/ui/tu-do/shared/__tests__/board-views.test.tsx +203 -2
- package/src/components/ui/tu-do/shared/__tests__/task-board-loading-state.test.tsx +17 -0
- package/src/components/ui/tu-do/shared/__tests__/task-legacy-route-recovery.test.tsx +16 -0
- package/src/components/ui/tu-do/shared/board-client.tsx +2 -7
- package/src/components/ui/tu-do/shared/board-config-storage.ts +7 -1
- package/src/components/ui/tu-do/shared/board-header.tsx +464 -975
- package/src/components/ui/tu-do/shared/board-layout-settings.tsx +165 -136
- package/src/components/ui/tu-do/shared/board-switcher.tsx +209 -217
- package/src/components/ui/tu-do/shared/board-views.tsx +587 -75
- package/src/components/ui/tu-do/shared/list-view.tsx +227 -1
- package/src/components/ui/tu-do/shared/recycle-bin-panel.tsx +142 -94
- package/src/components/ui/tu-do/shared/special-task-list-pins.ts +51 -0
- package/src/components/ui/tu-do/shared/task-board-loading-state.tsx +28 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/field-diff-viewer.tsx +3 -2
- package/src/components/ui/tu-do/shared/task-edit-dialog/selective-revert-panel.test.tsx +91 -0
- package/src/components/ui/tu-do/shared/task-edit-dialog/selective-revert-panel.tsx +123 -78
- package/src/components/ui/tu-do/shared/task-edit-dialog/task-activity-section.tsx +7 -1
- package/src/components/ui/tu-do/shared/task-edit-dialog/task-snapshot-dialog.tsx +8 -3
- package/src/components/ui/tu-do/shared/task-edit-dialog.tsx +2 -1
- package/src/components/ui/tu-do/shared/task-legacy-route-recovery.tsx +2 -9
- package/src/declarations.d.ts +1 -0
- package/src/hooks/__tests__/use-calendar-readonly.test.tsx +322 -2
- package/src/hooks/__tests__/use-calendar-sync.test.tsx +446 -0
- package/src/hooks/use-calendar-sync.tsx +247 -243
- package/src/hooks/use-calendar.tsx +323 -138
- package/src/hooks/use-task-actions.ts +24 -0
- package/src/hooks/use-user-workspace-config.ts +75 -0
- package/src/hooks/use-workspace-currency.ts +8 -3
- package/src/hooks/useBoardRealtimeEventHandler.ts +11 -0
|
@@ -43,6 +43,7 @@ interface VirtualizedTaskListProps {
|
|
|
43
43
|
onLoadMore?: () => void;
|
|
44
44
|
hasMore?: boolean;
|
|
45
45
|
isLoadingMore?: boolean;
|
|
46
|
+
readOnly?: boolean;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
interface TaskListContentProps {
|
|
@@ -64,6 +65,7 @@ interface TaskListContentProps {
|
|
|
64
65
|
bulkUpdateCustomDueDate?: (date: Date | null) => Promise<void>;
|
|
65
66
|
startIndex?: number;
|
|
66
67
|
taskOrder?: Pick<Task, 'id'>[];
|
|
68
|
+
readOnly?: boolean;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
export function getTaskDragPreviewSlotIndex({
|
|
@@ -132,6 +134,7 @@ function TaskListContent({
|
|
|
132
134
|
bulkUpdateCustomDueDate,
|
|
133
135
|
startIndex = 0,
|
|
134
136
|
taskOrder = tasks,
|
|
137
|
+
readOnly = false,
|
|
135
138
|
}: TaskListContentProps) {
|
|
136
139
|
const slotIndex = getTaskDragPreviewSlotIndex({
|
|
137
140
|
columnId: column.id,
|
|
@@ -170,6 +173,7 @@ function TaskListContent({
|
|
|
170
173
|
optimisticUpdateInProgress={optimisticUpdateInProgress}
|
|
171
174
|
selectedTasks={selectedTasks}
|
|
172
175
|
bulkUpdateCustomDueDate={bulkUpdateCustomDueDate}
|
|
176
|
+
readOnly={readOnly}
|
|
173
177
|
/>
|
|
174
178
|
{slotIndex === globalIndex + 1 && (
|
|
175
179
|
<DragPreviewSlot
|
|
@@ -238,6 +242,7 @@ function VirtualizedTaskListInner({
|
|
|
238
242
|
onLoadMore,
|
|
239
243
|
hasMore,
|
|
240
244
|
isLoadingMore,
|
|
245
|
+
readOnly = false,
|
|
241
246
|
}: VirtualizedTaskListProps) {
|
|
242
247
|
const t = useTranslations('common');
|
|
243
248
|
const tTasks = useTranslations('ws-tasks');
|
|
@@ -474,6 +479,7 @@ function VirtualizedTaskListInner({
|
|
|
474
479
|
bulkUpdateCustomDueDate={bulkUpdateCustomDueDate}
|
|
475
480
|
startIndex={startIndex}
|
|
476
481
|
taskOrder={tasks}
|
|
482
|
+
readOnly={readOnly}
|
|
477
483
|
/>
|
|
478
484
|
</div>
|
|
479
485
|
</div>
|
|
@@ -502,6 +508,7 @@ function VirtualizedTaskListInner({
|
|
|
502
508
|
optimisticUpdateInProgress={optimisticUpdateInProgress}
|
|
503
509
|
bulkUpdateCustomDueDate={bulkUpdateCustomDueDate}
|
|
504
510
|
taskOrder={tasks}
|
|
511
|
+
readOnly={readOnly}
|
|
505
512
|
/>
|
|
506
513
|
{loadMoreSentinel}
|
|
507
514
|
</SortableContext>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ChevronDown, Info } from '@tuturuuu/icons';
|
|
4
|
+
import {
|
|
5
|
+
Collapsible,
|
|
6
|
+
CollapsibleContent,
|
|
7
|
+
CollapsibleTrigger,
|
|
8
|
+
} from '@tuturuuu/ui/collapsible';
|
|
9
|
+
import {
|
|
10
|
+
Tooltip,
|
|
11
|
+
TooltipContent,
|
|
12
|
+
TooltipProvider,
|
|
13
|
+
TooltipTrigger,
|
|
14
|
+
} from '@tuturuuu/ui/tooltip';
|
|
15
|
+
import { cn } from '@tuturuuu/utils/format';
|
|
16
|
+
import { useTranslations } from 'next-intl';
|
|
17
|
+
import type { ReactNode } from 'react';
|
|
18
|
+
|
|
19
|
+
function ShareInfoTooltip({
|
|
20
|
+
content,
|
|
21
|
+
label,
|
|
22
|
+
}: {
|
|
23
|
+
content: string;
|
|
24
|
+
label: string;
|
|
25
|
+
}) {
|
|
26
|
+
return (
|
|
27
|
+
<TooltipProvider delayDuration={0} skipDelayDuration={0}>
|
|
28
|
+
<Tooltip>
|
|
29
|
+
<TooltipTrigger asChild>
|
|
30
|
+
<button
|
|
31
|
+
type="button"
|
|
32
|
+
className="text-muted-foreground transition-colors hover:text-foreground"
|
|
33
|
+
aria-label={label}
|
|
34
|
+
>
|
|
35
|
+
<Info className="h-3.5 w-3.5" />
|
|
36
|
+
</button>
|
|
37
|
+
</TooltipTrigger>
|
|
38
|
+
<TooltipContent className="max-w-xs">{content}</TooltipContent>
|
|
39
|
+
</Tooltip>
|
|
40
|
+
</TooltipProvider>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface ShareSectionProps {
|
|
45
|
+
children: ReactNode;
|
|
46
|
+
icon: ReactNode;
|
|
47
|
+
onOpenChange: (open: boolean) => void;
|
|
48
|
+
open: boolean;
|
|
49
|
+
statusBadge: ReactNode;
|
|
50
|
+
title: string;
|
|
51
|
+
tooltip: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function ShareSection({
|
|
55
|
+
children,
|
|
56
|
+
icon,
|
|
57
|
+
onOpenChange,
|
|
58
|
+
open,
|
|
59
|
+
statusBadge,
|
|
60
|
+
title,
|
|
61
|
+
tooltip,
|
|
62
|
+
}: ShareSectionProps) {
|
|
63
|
+
const t = useTranslations();
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Collapsible
|
|
67
|
+
open={open}
|
|
68
|
+
onOpenChange={onOpenChange}
|
|
69
|
+
className="rounded-md border"
|
|
70
|
+
>
|
|
71
|
+
<div className="flex min-h-11 items-center gap-2 px-3">
|
|
72
|
+
<CollapsibleTrigger asChild>
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
className="flex min-w-0 flex-1 items-center gap-2 text-left transition-colors hover:text-foreground"
|
|
76
|
+
>
|
|
77
|
+
{icon}
|
|
78
|
+
<span className="min-w-0 flex-1 truncate font-medium text-sm">
|
|
79
|
+
{title}
|
|
80
|
+
</span>
|
|
81
|
+
{statusBadge}
|
|
82
|
+
<ChevronDown
|
|
83
|
+
className={cn(
|
|
84
|
+
'h-4 w-4 shrink-0 text-muted-foreground transition-transform',
|
|
85
|
+
open && 'rotate-180'
|
|
86
|
+
)}
|
|
87
|
+
/>
|
|
88
|
+
</button>
|
|
89
|
+
</CollapsibleTrigger>
|
|
90
|
+
<ShareInfoTooltip
|
|
91
|
+
label={t('ws-task-boards.share.note')}
|
|
92
|
+
content={tooltip}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
<CollapsibleContent className="border-t p-3">
|
|
96
|
+
{children}
|
|
97
|
+
</CollapsibleContent>
|
|
98
|
+
</Collapsible>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useQuery } from '@tanstack/react-query';
|
|
4
4
|
import {
|
|
5
|
+
convertWorkspaceTaskDraft,
|
|
5
6
|
listWorkspaceTaskBoards,
|
|
6
7
|
listWorkspaceTaskLists,
|
|
7
8
|
} from '@tuturuuu/internal-api';
|
|
@@ -46,6 +47,10 @@ export function DraftConvertDialog({
|
|
|
46
47
|
const [selectedBoardId, setSelectedBoardId] = useState<string>('');
|
|
47
48
|
const [selectedListId, setSelectedListId] = useState<string>('');
|
|
48
49
|
const [isConverting, setIsConverting] = useState(false);
|
|
50
|
+
const internalApiOptions =
|
|
51
|
+
typeof window !== 'undefined'
|
|
52
|
+
? { baseUrl: window.location.origin }
|
|
53
|
+
: undefined;
|
|
49
54
|
|
|
50
55
|
// Sync selections when draft changes (useState initializer only runs on mount)
|
|
51
56
|
useEffect(() => {
|
|
@@ -107,20 +112,13 @@ export function DraftConvertDialog({
|
|
|
107
112
|
|
|
108
113
|
setIsConverting(true);
|
|
109
114
|
try {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
body: JSON.stringify({ listId: selectedListId }),
|
|
116
|
-
}
|
|
115
|
+
await convertWorkspaceTaskDraft(
|
|
116
|
+
wsId,
|
|
117
|
+
draft.id,
|
|
118
|
+
{ listId: selectedListId },
|
|
119
|
+
internalApiOptions
|
|
117
120
|
);
|
|
118
121
|
|
|
119
|
-
if (!res.ok) {
|
|
120
|
-
const data = await res.json();
|
|
121
|
-
throw new Error(data.error || 'Failed to convert draft');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
122
|
toast.success(t('converted_success'));
|
|
125
123
|
onConverted();
|
|
126
124
|
onClose();
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
4
4
|
import { FileText } from '@tuturuuu/icons';
|
|
5
|
+
import {
|
|
6
|
+
deleteWorkspaceTaskDraft,
|
|
7
|
+
listWorkspaceTaskDrafts,
|
|
8
|
+
} from '@tuturuuu/internal-api/tasks';
|
|
5
9
|
import { toast } from '@tuturuuu/ui/sonner';
|
|
6
10
|
import { useTranslations } from 'next-intl';
|
|
7
11
|
import { useState } from 'react';
|
|
@@ -11,38 +15,51 @@ import { DraftConvertDialog } from './draft-convert-dialog';
|
|
|
11
15
|
|
|
12
16
|
interface DraftsPageProps {
|
|
13
17
|
wsId: string;
|
|
18
|
+
boardId?: string;
|
|
19
|
+
includeUnassignedForBoard?: boolean;
|
|
14
20
|
}
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
function getBrowserInternalApiOptions() {
|
|
23
|
+
return typeof window !== 'undefined'
|
|
24
|
+
? { baseUrl: window.location.origin }
|
|
25
|
+
: undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function DraftsPage({
|
|
29
|
+
wsId,
|
|
30
|
+
boardId,
|
|
31
|
+
includeUnassignedForBoard = false,
|
|
32
|
+
}: DraftsPageProps) {
|
|
17
33
|
const t = useTranslations('task-drafts');
|
|
18
34
|
const queryClient = useQueryClient();
|
|
19
35
|
const { editDraft } = useTaskDialogContext();
|
|
20
36
|
const [convertDraft, setConvertDraft] = useState<TaskDraft | null>(null);
|
|
37
|
+
const draftQueryKey = [
|
|
38
|
+
'task-drafts',
|
|
39
|
+
wsId,
|
|
40
|
+
boardId ?? 'all',
|
|
41
|
+
includeUnassignedForBoard,
|
|
42
|
+
] as const;
|
|
21
43
|
|
|
22
44
|
const { data: drafts = [], isLoading } = useQuery<TaskDraft[]>({
|
|
23
|
-
queryKey:
|
|
24
|
-
queryFn:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
45
|
+
queryKey: draftQueryKey,
|
|
46
|
+
queryFn: () =>
|
|
47
|
+
listWorkspaceTaskDrafts(
|
|
48
|
+
wsId,
|
|
49
|
+
{ boardId, includeUnassignedForBoard },
|
|
50
|
+
getBrowserInternalApiOptions()
|
|
51
|
+
) as Promise<TaskDraft[]>,
|
|
30
52
|
});
|
|
31
53
|
|
|
32
54
|
const deleteMutation = useMutation({
|
|
33
|
-
mutationFn: async (draftId: string) =>
|
|
34
|
-
|
|
35
|
-
`/api/v1/workspaces/${wsId}/task-drafts/${draftId}`,
|
|
36
|
-
{ method: 'DELETE' }
|
|
37
|
-
);
|
|
38
|
-
if (!res.ok) throw new Error('Failed to delete draft');
|
|
39
|
-
},
|
|
55
|
+
mutationFn: async (draftId: string) =>
|
|
56
|
+
deleteWorkspaceTaskDraft(wsId, draftId, getBrowserInternalApiOptions()),
|
|
40
57
|
onSuccess: () => {
|
|
41
58
|
queryClient.invalidateQueries({ queryKey: ['task-drafts', wsId] });
|
|
42
59
|
toast.success(t('deleted_success'));
|
|
43
60
|
},
|
|
44
61
|
onError: () => {
|
|
45
|
-
toast.error('
|
|
62
|
+
toast.error(t('delete_failed'));
|
|
46
63
|
},
|
|
47
64
|
});
|
|
48
65
|
|
|
@@ -13,6 +13,15 @@ import {
|
|
|
13
13
|
Trash2,
|
|
14
14
|
User,
|
|
15
15
|
} from '@tuturuuu/icons';
|
|
16
|
+
import {
|
|
17
|
+
createWorkspaceTaskInitiative,
|
|
18
|
+
deleteWorkspaceTaskInitiative,
|
|
19
|
+
linkWorkspaceTaskInitiativeProject,
|
|
20
|
+
listWorkspaceTaskInitiatives,
|
|
21
|
+
listWorkspaceTaskProjects,
|
|
22
|
+
unlinkWorkspaceTaskInitiativeProject,
|
|
23
|
+
updateWorkspaceTaskInitiative,
|
|
24
|
+
} from '@tuturuuu/internal-api/tasks';
|
|
16
25
|
import { Badge } from '@tuturuuu/ui/badge';
|
|
17
26
|
import { Button } from '@tuturuuu/ui/button';
|
|
18
27
|
import {
|
|
@@ -98,6 +107,12 @@ const STATUS_BADGE_CLASS: Record<InitiativeStatus, string> = {
|
|
|
98
107
|
cancelled: 'bg-dynamic-red/15 text-dynamic-red border-transparent',
|
|
99
108
|
};
|
|
100
109
|
|
|
110
|
+
function getBrowserInternalApiOptions() {
|
|
111
|
+
return typeof window !== 'undefined'
|
|
112
|
+
? { baseUrl: window.location.origin }
|
|
113
|
+
: undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
101
116
|
export function TaskInitiativesClient({
|
|
102
117
|
wsId,
|
|
103
118
|
initialInitiatives,
|
|
@@ -136,16 +151,8 @@ export function TaskInitiativesClient({
|
|
|
136
151
|
refetch: refetchInitiatives,
|
|
137
152
|
} = useQuery<TaskInitiative[]>({
|
|
138
153
|
queryKey: ['workspace', wsId, 'task-initiatives'],
|
|
139
|
-
queryFn:
|
|
140
|
-
|
|
141
|
-
`/api/v1/workspaces/${wsId}/task-initiatives`,
|
|
142
|
-
{ cache: 'no-store' }
|
|
143
|
-
);
|
|
144
|
-
if (!response.ok) {
|
|
145
|
-
throw new Error(t('errors.fetch_initiatives'));
|
|
146
|
-
}
|
|
147
|
-
return response.json();
|
|
148
|
-
},
|
|
154
|
+
queryFn: () =>
|
|
155
|
+
listWorkspaceTaskInitiatives(wsId, getBrowserInternalApiOptions()),
|
|
149
156
|
initialData: initialInitiatives,
|
|
150
157
|
staleTime: 30_000,
|
|
151
158
|
});
|
|
@@ -157,20 +164,12 @@ export function TaskInitiativesClient({
|
|
|
157
164
|
} = useQuery<TaskProjectOption[]>({
|
|
158
165
|
queryKey: ['workspace', wsId, 'task-projects-for-initiatives'],
|
|
159
166
|
queryFn: async () => {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const rawProjects = await response.json();
|
|
167
|
-
return (
|
|
168
|
-
rawProjects as Array<{
|
|
169
|
-
id: string;
|
|
170
|
-
name: string;
|
|
171
|
-
status?: string | null;
|
|
172
|
-
}>
|
|
173
|
-
).map((project) => ({
|
|
167
|
+
const rawProjects = await listWorkspaceTaskProjects(
|
|
168
|
+
wsId,
|
|
169
|
+
getBrowserInternalApiOptions()
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return rawProjects.map((project) => ({
|
|
174
173
|
id: project.id,
|
|
175
174
|
name: project.name,
|
|
176
175
|
status: project.status ?? null,
|
|
@@ -218,19 +217,13 @@ export function TaskInitiativesClient({
|
|
|
218
217
|
description?: string;
|
|
219
218
|
status: InitiativeStatus;
|
|
220
219
|
}) => {
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
220
|
+
const payload = { name, description: description ?? '', status };
|
|
221
|
+
|
|
222
|
+
return createWorkspaceTaskInitiative(
|
|
223
|
+
wsId,
|
|
224
|
+
payload,
|
|
225
|
+
getBrowserInternalApiOptions()
|
|
228
226
|
);
|
|
229
|
-
if (!response.ok) {
|
|
230
|
-
const errorData = await response.json().catch(() => ({}));
|
|
231
|
-
throw new Error(errorData.error || t('errors.create_initiative'));
|
|
232
|
-
}
|
|
233
|
-
return response.json();
|
|
234
227
|
},
|
|
235
228
|
onSuccess: () => {
|
|
236
229
|
toast.success(t('success.initiative_created'));
|
|
@@ -257,19 +250,14 @@ export function TaskInitiativesClient({
|
|
|
257
250
|
description?: string;
|
|
258
251
|
status: InitiativeStatus;
|
|
259
252
|
}) => {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
253
|
+
const payload = { name, description: description ?? '', status };
|
|
254
|
+
|
|
255
|
+
return updateWorkspaceTaskInitiative(
|
|
256
|
+
wsId,
|
|
257
|
+
initiativeId,
|
|
258
|
+
payload,
|
|
259
|
+
getBrowserInternalApiOptions()
|
|
267
260
|
);
|
|
268
|
-
if (!response.ok) {
|
|
269
|
-
const errorData = await response.json().catch(() => ({}));
|
|
270
|
-
throw new Error(errorData.error || t('errors.update_initiative'));
|
|
271
|
-
}
|
|
272
|
-
return response.json();
|
|
273
261
|
},
|
|
274
262
|
onSuccess: () => {
|
|
275
263
|
toast.success(t('success.initiative_updated'));
|
|
@@ -286,18 +274,12 @@ export function TaskInitiativesClient({
|
|
|
286
274
|
});
|
|
287
275
|
|
|
288
276
|
const deleteInitiativeMutation = useMutation({
|
|
289
|
-
mutationFn:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
);
|
|
296
|
-
if (!response.ok) {
|
|
297
|
-
const errorData = await response.json().catch(() => ({}));
|
|
298
|
-
throw new Error(errorData.error || t('errors.delete_initiative'));
|
|
299
|
-
}
|
|
300
|
-
},
|
|
277
|
+
mutationFn: (initiativeId: string) =>
|
|
278
|
+
deleteWorkspaceTaskInitiative(
|
|
279
|
+
wsId,
|
|
280
|
+
initiativeId,
|
|
281
|
+
getBrowserInternalApiOptions()
|
|
282
|
+
),
|
|
301
283
|
onSuccess: () => {
|
|
302
284
|
toast.success(t('success.initiative_deleted'));
|
|
303
285
|
refetchInitiatives();
|
|
@@ -314,21 +296,13 @@ export function TaskInitiativesClient({
|
|
|
314
296
|
}: {
|
|
315
297
|
initiativeId: string;
|
|
316
298
|
projectId: string;
|
|
317
|
-
}) =>
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
);
|
|
326
|
-
if (!response.ok) {
|
|
327
|
-
const errorData = await response.json().catch(() => ({}));
|
|
328
|
-
throw new Error(errorData.error || t('errors.link_project'));
|
|
329
|
-
}
|
|
330
|
-
return response.json();
|
|
331
|
-
},
|
|
299
|
+
}) =>
|
|
300
|
+
linkWorkspaceTaskInitiativeProject(
|
|
301
|
+
wsId,
|
|
302
|
+
initiativeId,
|
|
303
|
+
projectId,
|
|
304
|
+
getBrowserInternalApiOptions()
|
|
305
|
+
),
|
|
332
306
|
onSuccess: (_data, variables) => {
|
|
333
307
|
toast.success(t('success.project_linked'));
|
|
334
308
|
setProjectToLink('');
|
|
@@ -362,19 +336,13 @@ export function TaskInitiativesClient({
|
|
|
362
336
|
}: {
|
|
363
337
|
initiativeId: string;
|
|
364
338
|
projectId: string;
|
|
365
|
-
}) =>
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
)
|
|
372
|
-
if (!response.ok) {
|
|
373
|
-
const errorData = await response.json().catch(() => ({}));
|
|
374
|
-
throw new Error(errorData.error || t('errors.unlink_project'));
|
|
375
|
-
}
|
|
376
|
-
return response.json();
|
|
377
|
-
},
|
|
339
|
+
}) =>
|
|
340
|
+
unlinkWorkspaceTaskInitiativeProject(
|
|
341
|
+
wsId,
|
|
342
|
+
initiativeId,
|
|
343
|
+
projectId,
|
|
344
|
+
getBrowserInternalApiOptions()
|
|
345
|
+
),
|
|
378
346
|
onSuccess: (_data, variables) => {
|
|
379
347
|
toast.success(t('success.project_unlinked'));
|
|
380
348
|
if (variables) {
|
|
@@ -20,12 +20,30 @@ import { TaskPreviewDialog } from './task-preview-dialog';
|
|
|
20
20
|
import { useMyTasksState } from './use-my-tasks-state';
|
|
21
21
|
|
|
22
22
|
interface MyTasksContentProps {
|
|
23
|
+
disableAutoCreateBoard?: boolean;
|
|
24
|
+
embedded?: boolean;
|
|
25
|
+
initialBoard?: {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string | null;
|
|
28
|
+
};
|
|
29
|
+
initialListId?: string;
|
|
30
|
+
initialLists?: Array<{
|
|
31
|
+
deleted?: boolean | null;
|
|
32
|
+
id: string;
|
|
33
|
+
name: string | null;
|
|
34
|
+
position?: number | null;
|
|
35
|
+
}>;
|
|
23
36
|
wsId: string;
|
|
24
37
|
userId: string;
|
|
25
38
|
isPersonal: boolean;
|
|
26
39
|
}
|
|
27
40
|
|
|
28
41
|
export default function MyTasksContent({
|
|
42
|
+
disableAutoCreateBoard = false,
|
|
43
|
+
embedded = false,
|
|
44
|
+
initialBoard,
|
|
45
|
+
initialListId,
|
|
46
|
+
initialLists,
|
|
29
47
|
wsId,
|
|
30
48
|
userId,
|
|
31
49
|
isPersonal,
|
|
@@ -40,13 +58,17 @@ export default function MyTasksContent({
|
|
|
40
58
|
'enter'
|
|
41
59
|
);
|
|
42
60
|
const state = useMyTasksState({
|
|
61
|
+
...(disableAutoCreateBoard ? { disableAutoCreateBoard } : {}),
|
|
62
|
+
...(initialBoard ? { initialBoard } : {}),
|
|
63
|
+
...(initialListId ? { initialListId } : {}),
|
|
64
|
+
...(initialLists ? { initialLists } : {}),
|
|
43
65
|
wsId,
|
|
44
66
|
userId,
|
|
45
67
|
isPersonal,
|
|
46
68
|
});
|
|
47
69
|
|
|
48
70
|
return (
|
|
49
|
-
<div className=
|
|
71
|
+
<div className={embedded ? 'space-y-4' : 'space-y-4 md:space-y-6'}>
|
|
50
72
|
{/* Header with greeting + summary cards */}
|
|
51
73
|
<MyTasksHeader
|
|
52
74
|
overdueCount={state.filteredTasks.overdueTasks?.length ?? 0}
|
|
@@ -55,7 +77,9 @@ export default function MyTasksContent({
|
|
|
55
77
|
/>
|
|
56
78
|
|
|
57
79
|
{/* Command Bar */}
|
|
58
|
-
<div
|
|
80
|
+
<div
|
|
81
|
+
className={embedded ? 'mx-auto max-w-5xl' : 'mx-auto mb-32 max-w-5xl'}
|
|
82
|
+
>
|
|
59
83
|
<CommandBar
|
|
60
84
|
value={state.commandBarInput}
|
|
61
85
|
onValueChange={state.setCommandBarInput}
|
|
@@ -39,12 +39,28 @@ dayjs.extend(utc);
|
|
|
39
39
|
dayjs.extend(timezone);
|
|
40
40
|
|
|
41
41
|
interface UseMyTasksStateProps {
|
|
42
|
+
disableAutoCreateBoard?: boolean;
|
|
43
|
+
initialBoard?: {
|
|
44
|
+
id: string;
|
|
45
|
+
name: string | null;
|
|
46
|
+
};
|
|
47
|
+
initialListId?: string;
|
|
48
|
+
initialLists?: Array<{
|
|
49
|
+
deleted?: boolean | null;
|
|
50
|
+
id: string;
|
|
51
|
+
name: string | null;
|
|
52
|
+
position?: number | null;
|
|
53
|
+
}>;
|
|
42
54
|
wsId: string;
|
|
43
55
|
userId: string;
|
|
44
56
|
isPersonal: boolean;
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
export function useMyTasksState({
|
|
60
|
+
disableAutoCreateBoard = false,
|
|
61
|
+
initialBoard,
|
|
62
|
+
initialListId,
|
|
63
|
+
initialLists,
|
|
48
64
|
wsId,
|
|
49
65
|
userId,
|
|
50
66
|
isPersonal,
|
|
@@ -96,8 +112,16 @@ export function useMyTasksState({
|
|
|
96
112
|
// Board selector state
|
|
97
113
|
const [boardSelectorOpen, setBoardSelectorOpen] = useState(false);
|
|
98
114
|
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string>(wsId);
|
|
99
|
-
const [selectedBoardId, setSelectedBoardId] = useState<string>(
|
|
100
|
-
|
|
115
|
+
const [selectedBoardId, setSelectedBoardId] = useState<string>(
|
|
116
|
+
initialBoard?.id ?? ''
|
|
117
|
+
);
|
|
118
|
+
const [selectedListId, setSelectedListId] = useState<string>(
|
|
119
|
+
initialListId ??
|
|
120
|
+
initialLists
|
|
121
|
+
?.filter((list) => !list.deleted)
|
|
122
|
+
.sort((a, b) => (a.position ?? 0) - (b.position ?? 0))[0]?.id ??
|
|
123
|
+
''
|
|
124
|
+
);
|
|
101
125
|
const [newBoardDialogOpen, setNewBoardDialogOpen] = useState(false);
|
|
102
126
|
const [newBoardName, setNewBoardName] = useState<string>('');
|
|
103
127
|
const [newListDialogOpen, setNewListDialogOpen] = useState(false);
|
|
@@ -276,6 +300,7 @@ export function useMyTasksState({
|
|
|
276
300
|
});
|
|
277
301
|
return payload.count ?? 0;
|
|
278
302
|
},
|
|
303
|
+
enabled: !disableAutoCreateBoard,
|
|
279
304
|
});
|
|
280
305
|
|
|
281
306
|
// Auto-create a board if the workspace has none
|
|
@@ -294,7 +319,13 @@ export function useMyTasksState({
|
|
|
294
319
|
);
|
|
295
320
|
|
|
296
321
|
useEffect(() => {
|
|
297
|
-
if (
|
|
322
|
+
if (
|
|
323
|
+
disableAutoCreateBoard ||
|
|
324
|
+
wsBoardCountLoading ||
|
|
325
|
+
wsBoardCount === undefined
|
|
326
|
+
) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
298
329
|
if (wsBoardCount > 0) return;
|
|
299
330
|
if (autoCreateAttemptedRef.current) return;
|
|
300
331
|
autoCreateAttemptedRef.current = true;
|
|
@@ -344,6 +375,7 @@ export function useMyTasksState({
|
|
|
344
375
|
queryClient,
|
|
345
376
|
defaultBoardName,
|
|
346
377
|
defaultListNames,
|
|
378
|
+
disableAutoCreateBoard,
|
|
347
379
|
]);
|
|
348
380
|
|
|
349
381
|
// Fetch boards with lists for selected workspace
|
|
@@ -422,11 +454,16 @@ export function useMyTasksState({
|
|
|
422
454
|
const availableLists = useMemo(() => {
|
|
423
455
|
if (!selectedBoardId) return [];
|
|
424
456
|
const board = boardsData.find((b: any) => b.id === selectedBoardId);
|
|
425
|
-
if (!board?.task_lists)
|
|
457
|
+
if (!board?.task_lists) {
|
|
458
|
+
if (selectedBoardId !== initialBoard?.id) return [];
|
|
459
|
+
return (initialLists ?? [])
|
|
460
|
+
.filter((list) => !list.deleted)
|
|
461
|
+
.sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
|
|
462
|
+
}
|
|
426
463
|
return (board.task_lists as any[])
|
|
427
464
|
.filter((l: any) => !l.deleted)
|
|
428
465
|
.sort((a: any, b: any) => (a.position || 0) - (b.position || 0));
|
|
429
|
-
}, [selectedBoardId, boardsData]);
|
|
466
|
+
}, [selectedBoardId, boardsData, initialBoard?.id, initialLists]);
|
|
430
467
|
|
|
431
468
|
const hasValidSelectedList = useMemo(
|
|
432
469
|
() => availableLists.some((list: any) => list.id === selectedListId),
|
|
@@ -794,13 +831,23 @@ export function useMyTasksState({
|
|
|
794
831
|
const selectedDestination = useMemo(() => {
|
|
795
832
|
if (!selectedBoardId || !selectedListId) return null;
|
|
796
833
|
const board = boardsData.find((b: any) => b.id === selectedBoardId);
|
|
797
|
-
const
|
|
834
|
+
const isInitialBoard = selectedBoardId === initialBoard?.id;
|
|
835
|
+
const lists =
|
|
836
|
+
(board?.task_lists as any[]) ||
|
|
837
|
+
(isInitialBoard ? (initialLists ?? []) : []);
|
|
798
838
|
const list = lists.find((l: any) => l.id === selectedListId);
|
|
799
839
|
return {
|
|
800
|
-
boardName: board?.name || 'Unknown Board',
|
|
840
|
+
boardName: board?.name || initialBoard?.name || 'Unknown Board',
|
|
801
841
|
listName: list?.name || 'Unknown List',
|
|
802
842
|
};
|
|
803
|
-
}, [
|
|
843
|
+
}, [
|
|
844
|
+
selectedBoardId,
|
|
845
|
+
selectedListId,
|
|
846
|
+
boardsData,
|
|
847
|
+
initialBoard?.id,
|
|
848
|
+
initialBoard?.name,
|
|
849
|
+
initialLists,
|
|
850
|
+
]);
|
|
804
851
|
|
|
805
852
|
const handleClearDestination = () => {
|
|
806
853
|
setSelectedBoardId('');
|
|
@@ -41,10 +41,7 @@ export function NoteEditDialog({
|
|
|
41
41
|
|
|
42
42
|
return (
|
|
43
43
|
<Dialog open={isOpen} onOpenChange={onOpenChange} modal={true}>
|
|
44
|
-
<DialogContent
|
|
45
|
-
showCloseButton={false}
|
|
46
|
-
className="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"
|
|
47
|
-
>
|
|
44
|
+
<DialogContent showCloseButton={false} presentation="fullscreen">
|
|
48
45
|
{/* Main content area - Note title and description */}
|
|
49
46
|
<div className="flex min-w-0 flex-1 flex-col bg-background transition-all duration-300">
|
|
50
47
|
{/* Enhanced Header with gradient */}
|