@startsimpli/ui 0.4.6 → 0.4.8

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 (122) hide show
  1. package/package.json +2 -1
  2. package/src/__mocks__/next/link.js +11 -0
  3. package/src/components/ActivityTimeline.tsx +173 -0
  4. package/src/components/LogActivityDialog.tsx +303 -0
  5. package/src/components/QuickLogButtons.tsx +32 -0
  6. package/src/components/account/__tests__/account.test.tsx +315 -0
  7. package/src/components/badge/StageBadge.tsx +31 -0
  8. package/src/components/badge/index.ts +3 -0
  9. package/src/components/command-palette/CommandGroup.tsx +23 -0
  10. package/src/components/command-palette/CommandPalette.tsx +327 -0
  11. package/src/components/command-palette/CommandResultItem.tsx +59 -0
  12. package/src/components/command-palette/__tests__/CommandGroup.test.tsx +81 -0
  13. package/src/components/command-palette/__tests__/CommandResultItem.test.tsx +166 -0
  14. package/src/components/command-palette/__tests__/command-palette-context.test.tsx +166 -0
  15. package/src/components/command-palette/__tests__/useCommandPaletteSearch.test.ts +271 -0
  16. package/src/components/command-palette/command-palette-context.tsx +51 -0
  17. package/src/components/command-palette/index.ts +9 -0
  18. package/src/components/command-palette/useCommandPaletteSearch.ts +114 -0
  19. package/src/components/compose/__tests__/compose.test.tsx +656 -0
  20. package/src/components/compose/compose-header.tsx +72 -0
  21. package/src/components/compose/compose-loading.tsx +13 -0
  22. package/src/components/compose/index.ts +6 -0
  23. package/src/components/compose/save-status-indicator.tsx +57 -0
  24. package/src/components/compose/send-confirmation-dialog.tsx +87 -0
  25. package/src/components/compose/subject-input.tsx +25 -0
  26. package/src/components/compose/useAutoSave.ts +93 -0
  27. package/src/components/dashboard/DashboardGrid.tsx +32 -0
  28. package/src/components/dashboard/DashboardSection.tsx +32 -0
  29. package/src/components/dashboard/MetricCard.tsx +129 -0
  30. package/src/components/dashboard/PeriodSelector.tsx +55 -0
  31. package/src/components/dashboard/PipelineFunnel.tsx +126 -0
  32. package/src/components/dashboard/SparklineTrend.tsx +102 -0
  33. package/src/components/dashboard/TopCampaigns.tsx +132 -0
  34. package/src/components/dashboard/__tests__/dashboard.test.tsx +785 -0
  35. package/src/components/dashboard/index.ts +20 -0
  36. package/src/components/dialog/ConfirmDialog.tsx +72 -0
  37. package/src/components/dialog/__tests__/ConfirmDialog.test.tsx +126 -0
  38. package/src/components/dialog/index.ts +3 -0
  39. package/src/components/email-dialogs/__tests__/email-dialogs.test.tsx +982 -0
  40. package/src/components/email-dialogs/index.ts +14 -0
  41. package/src/components/email-dialogs/merge-fields.tsx +196 -0
  42. package/src/components/email-dialogs/preview-dialog.tsx +194 -0
  43. package/src/components/email-dialogs/schedule-dialog.tsx +297 -0
  44. package/src/components/email-dialogs/template-picker.tsx +225 -0
  45. package/src/components/email-dialogs/test-send-dialog.tsx +188 -0
  46. package/src/components/email-editor/BlockRenderer.tsx +120 -0
  47. package/src/components/email-editor/__tests__/BlockRenderer.test.tsx +332 -0
  48. package/src/components/email-editor/__tests__/block-renderers.test.ts +624 -0
  49. package/src/components/email-editor/__tests__/email-html-renderer.test.ts +376 -0
  50. package/src/components/email-editor/add-block-menu.tsx +151 -0
  51. package/src/components/email-editor/block-toolbar.tsx +73 -0
  52. package/src/components/email-editor/blocks/__tests__/blocks.test.tsx +818 -0
  53. package/src/components/email-editor/blocks/button-block.tsx +44 -0
  54. package/src/components/email-editor/blocks/divider-block.tsx +43 -0
  55. package/src/components/email-editor/blocks/footer-block.tsx +39 -0
  56. package/src/components/email-editor/blocks/header-block.tsx +39 -0
  57. package/src/components/email-editor/blocks/image-block.tsx +61 -0
  58. package/src/components/email-editor/blocks/index.ts +9 -0
  59. package/src/components/email-editor/blocks/metrics-block.tsx +198 -0
  60. package/src/components/email-editor/blocks/social-block.tsx +75 -0
  61. package/src/components/email-editor/blocks/spacer-block.tsx +26 -0
  62. package/src/components/email-editor/blocks/text-block.tsx +75 -0
  63. package/src/components/email-editor/editor-sidebar.tsx +66 -0
  64. package/src/components/email-editor/email-editor.tsx +497 -0
  65. package/src/components/email-editor/hooks/__tests__/useDragDrop.test.ts +355 -0
  66. package/src/components/email-editor/hooks/__tests__/useEmailEditorState.test.ts +551 -0
  67. package/src/components/email-editor/hooks/useDragDrop.ts +181 -0
  68. package/src/components/email-editor/hooks/useEmailEditorState.ts +426 -0
  69. package/src/components/email-editor/index.ts +51 -0
  70. package/src/components/email-editor/panels/BlockPropertyPanel.tsx +637 -0
  71. package/src/components/email-editor/panels/GlobalStylesPanel.tsx +108 -0
  72. package/src/components/email-editor/panels/SectionSettingsPanel.tsx +80 -0
  73. package/src/components/email-editor/panels/__tests__/BlockPropertyPanel.test.tsx +707 -0
  74. package/src/components/email-editor/panels/__tests__/GlobalStylesPanel.test.tsx +226 -0
  75. package/src/components/email-editor/panels/index.ts +3 -0
  76. package/src/components/email-editor/renderer/block-renderers.ts +209 -0
  77. package/src/components/email-editor/renderer/email-html-renderer.ts +128 -0
  78. package/src/components/email-editor/types.ts +413 -0
  79. package/src/components/email-editor/utils/defaults.ts +116 -0
  80. package/src/components/email-editor/utils/undo-redo.ts +59 -0
  81. package/src/components/enrichment/EnrichButton.tsx +33 -0
  82. package/src/components/enrichment/EnrichmentProgress.tsx +66 -0
  83. package/src/components/enrichment/QualityBadge.tsx +43 -0
  84. package/src/components/enrichment/__tests__/enrichment.test.tsx +184 -0
  85. package/src/components/enrichment/index.ts +8 -0
  86. package/src/components/gantt/GanttBoardView.tsx +71 -0
  87. package/src/components/gantt/GanttChart.tsx +140 -887
  88. package/src/components/gantt/GanttFilterBar.tsx +100 -0
  89. package/src/components/gantt/GanttListView.tsx +63 -0
  90. package/src/components/gantt/GanttTimelineView.tsx +215 -0
  91. package/src/components/gantt/__tests__/GanttBoardView.test.tsx +305 -0
  92. package/src/components/gantt/__tests__/GanttFilterBar.test.tsx +544 -0
  93. package/src/components/gantt/__tests__/GanttListView.test.tsx +337 -0
  94. package/src/components/gantt/__tests__/GanttTimelineView.test.tsx +375 -0
  95. package/src/components/gantt/__tests__/gantt-utils.test.ts +341 -0
  96. package/src/components/gantt/__tests__/useGanttState.test.ts +535 -0
  97. package/src/components/gantt/hooks/useGanttState.ts +644 -0
  98. package/src/components/gantt/index.ts +10 -0
  99. package/src/components/gantt/types.ts +5 -5
  100. package/src/components/index.ts +46 -0
  101. package/src/components/integrations/ConnectionStatus.tsx +77 -0
  102. package/src/components/integrations/IntegrationCard.tsx +92 -0
  103. package/src/components/integrations/__tests__/integrations.test.tsx +191 -0
  104. package/src/components/integrations/index.ts +5 -0
  105. package/src/components/kanban/KanbanBoard.tsx +103 -0
  106. package/src/components/kanban/__tests__/kanban.test.tsx +157 -0
  107. package/src/components/kanban/index.ts +2 -0
  108. package/src/components/lists/CreateListDialog.tsx +158 -0
  109. package/src/components/lists/ListCard.tsx +77 -0
  110. package/src/components/lists/__tests__/lists.test.tsx +263 -0
  111. package/src/components/lists/index.ts +5 -0
  112. package/src/components/loading/__tests__/loading.test.tsx +114 -0
  113. package/src/components/navigation/__tests__/navigation.test.tsx +194 -0
  114. package/src/components/pipeline/StageTransitionModal.tsx +146 -0
  115. package/src/components/pipeline/__tests__/pipeline.test.tsx +169 -0
  116. package/src/components/pipeline/index.ts +2 -0
  117. package/src/components/settings/SettingsCard.tsx +33 -0
  118. package/src/components/settings/SettingsLayout.tsx +28 -0
  119. package/src/components/settings/SettingsNav.tsx +42 -0
  120. package/src/components/settings/__tests__/settings.test.tsx +181 -0
  121. package/src/components/settings/index.ts +6 -0
  122. package/src/components/wizard/__tests__/wizard.test.tsx +97 -0
@@ -0,0 +1,20 @@
1
+ export { MetricCard } from './MetricCard'
2
+ export type { MetricCardProps, MetricCardTrend } from './MetricCard'
3
+
4
+ export { PeriodSelector } from './PeriodSelector'
5
+ export type { PeriodSelectorProps, PeriodOption } from './PeriodSelector'
6
+
7
+ export { SparklineTrend } from './SparklineTrend'
8
+ export type { SparklineTrendProps } from './SparklineTrend'
9
+
10
+ export { DashboardGrid } from './DashboardGrid'
11
+ export type { DashboardGridProps } from './DashboardGrid'
12
+
13
+ export { DashboardSection } from './DashboardSection'
14
+ export type { DashboardSectionProps } from './DashboardSection'
15
+
16
+ export { PipelineFunnel } from './PipelineFunnel'
17
+ export type { PipelineFunnelProps, FunnelStage } from './PipelineFunnel'
18
+
19
+ export { TopCampaigns } from './TopCampaigns'
20
+ export type { TopCampaignsProps, TopCampaign } from './TopCampaigns'
@@ -0,0 +1,72 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Loader2 } from 'lucide-react'
5
+ import { BaseDialog } from './BaseDialog'
6
+ import { Button } from '../ui/button'
7
+
8
+ export interface ConfirmDialogProps {
9
+ open: boolean
10
+ onClose: () => void
11
+ onConfirm: () => void | Promise<void>
12
+ title: string
13
+ description?: string | React.ReactNode
14
+ confirmLabel?: string
15
+ cancelLabel?: string
16
+ destructive?: boolean
17
+ loading?: boolean
18
+ }
19
+
20
+ export function ConfirmDialog({
21
+ open,
22
+ onClose,
23
+ onConfirm,
24
+ title,
25
+ description,
26
+ confirmLabel = 'Confirm',
27
+ cancelLabel = 'Cancel',
28
+ destructive = false,
29
+ loading = false,
30
+ }: ConfirmDialogProps) {
31
+ const handleClose = () => {
32
+ if (loading) return
33
+ onClose()
34
+ }
35
+
36
+ return (
37
+ <BaseDialog
38
+ open={open}
39
+ onOpenChange={(o) => {
40
+ if (!o) handleClose()
41
+ }}
42
+ size="sm"
43
+ loading={loading}
44
+ >
45
+ <BaseDialog.Header>
46
+ <BaseDialog.Title>{title}</BaseDialog.Title>
47
+ </BaseDialog.Header>
48
+ {description && (
49
+ <BaseDialog.Body>
50
+ {typeof description === 'string' ? (
51
+ <p className="text-sm text-gray-600">{description}</p>
52
+ ) : (
53
+ description
54
+ )}
55
+ </BaseDialog.Body>
56
+ )}
57
+ <BaseDialog.Footer>
58
+ <Button variant="outline" onClick={handleClose} disabled={loading}>
59
+ {cancelLabel}
60
+ </Button>
61
+ <Button
62
+ variant={destructive ? 'destructive' : 'default'}
63
+ onClick={onConfirm}
64
+ disabled={loading}
65
+ >
66
+ {loading && <Loader2 className="w-4 h-4 animate-spin mr-2" />}
67
+ {confirmLabel}
68
+ </Button>
69
+ </BaseDialog.Footer>
70
+ </BaseDialog>
71
+ )
72
+ }
@@ -0,0 +1,126 @@
1
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react'
2
+ import { ConfirmDialog } from '../ConfirmDialog'
3
+
4
+ // Mock Radix portal to render inline
5
+ jest.mock('@radix-ui/react-dialog', () => {
6
+ const actual = jest.requireActual('@radix-ui/react-dialog')
7
+ return {
8
+ ...actual,
9
+ Portal: ({ children }: { children: React.ReactNode }) => <>{children}</>,
10
+ }
11
+ })
12
+
13
+ describe('ConfirmDialog', () => {
14
+ const defaultProps = {
15
+ open: true,
16
+ onClose: jest.fn(),
17
+ onConfirm: jest.fn(),
18
+ title: 'Delete item?',
19
+ }
20
+
21
+ beforeEach(() => {
22
+ jest.clearAllMocks()
23
+ })
24
+
25
+ it('renders title', () => {
26
+ render(<ConfirmDialog {...defaultProps} />)
27
+ expect(screen.getByText('Delete item?')).toBeInTheDocument()
28
+ })
29
+
30
+ it('renders string description', () => {
31
+ render(
32
+ <ConfirmDialog {...defaultProps} description="This cannot be undone." />
33
+ )
34
+ expect(screen.getByText('This cannot be undone.')).toBeInTheDocument()
35
+ })
36
+
37
+ it('renders ReactNode description', () => {
38
+ render(
39
+ <ConfirmDialog
40
+ {...defaultProps}
41
+ description={<span data-testid="custom">Custom content</span>}
42
+ />
43
+ )
44
+ expect(screen.getByTestId('custom')).toBeInTheDocument()
45
+ })
46
+
47
+ it('renders default button labels', () => {
48
+ render(<ConfirmDialog {...defaultProps} />)
49
+ expect(screen.getByText('Confirm')).toBeInTheDocument()
50
+ expect(screen.getByText('Cancel')).toBeInTheDocument()
51
+ })
52
+
53
+ it('renders custom button labels', () => {
54
+ render(
55
+ <ConfirmDialog
56
+ {...defaultProps}
57
+ confirmLabel="Delete"
58
+ cancelLabel="Keep"
59
+ />
60
+ )
61
+ expect(screen.getByText('Delete')).toBeInTheDocument()
62
+ expect(screen.getByText('Keep')).toBeInTheDocument()
63
+ })
64
+
65
+ it('calls onConfirm when confirm button is clicked', () => {
66
+ render(<ConfirmDialog {...defaultProps} />)
67
+ fireEvent.click(screen.getByText('Confirm'))
68
+ expect(defaultProps.onConfirm).toHaveBeenCalledTimes(1)
69
+ })
70
+
71
+ it('calls onClose when cancel button is clicked', () => {
72
+ render(<ConfirmDialog {...defaultProps} />)
73
+ fireEvent.click(screen.getByText('Cancel'))
74
+ expect(defaultProps.onClose).toHaveBeenCalledTimes(1)
75
+ })
76
+
77
+ it('disables buttons when loading', () => {
78
+ render(<ConfirmDialog {...defaultProps} loading />)
79
+ const confirmBtn = screen.getByText('Confirm').closest('button')
80
+ const cancelBtn = screen.getByText('Cancel').closest('button')
81
+ expect(confirmBtn).toBeDisabled()
82
+ expect(cancelBtn).toBeDisabled()
83
+ })
84
+
85
+ it('shows spinner when loading', () => {
86
+ const { container } = render(<ConfirmDialog {...defaultProps} loading />)
87
+ const spinner = container.querySelector('.animate-spin')
88
+ expect(spinner).toBeInTheDocument()
89
+ })
90
+
91
+ it('does not call onClose when cancel clicked during loading', () => {
92
+ render(<ConfirmDialog {...defaultProps} loading />)
93
+ // The button is disabled so the click handler won't fire,
94
+ // but also handleClose guards against it
95
+ const cancelBtn = screen.getByText('Cancel').closest('button')!
96
+ fireEvent.click(cancelBtn)
97
+ expect(defaultProps.onClose).not.toHaveBeenCalled()
98
+ })
99
+
100
+ it('applies destructive variant to confirm button', () => {
101
+ render(<ConfirmDialog {...defaultProps} destructive />)
102
+ const confirmBtn = screen.getByText('Confirm').closest('button')
103
+ expect(confirmBtn?.className).toMatch(/destructive/)
104
+ })
105
+
106
+ it('applies default variant when not destructive', () => {
107
+ render(<ConfirmDialog {...defaultProps} />)
108
+ const confirmBtn = screen.getByText('Confirm').closest('button')
109
+ expect(confirmBtn?.className).not.toMatch(/destructive/)
110
+ })
111
+
112
+ it('does not render body when no description provided', () => {
113
+ const { container } = render(<ConfirmDialog {...defaultProps} />)
114
+ // Body has class py-4, should not exist
115
+ expect(container.querySelector('.py-4')).not.toBeInTheDocument()
116
+ })
117
+
118
+ it('handles async onConfirm', async () => {
119
+ const asyncConfirm = jest.fn().mockResolvedValue(undefined)
120
+ render(<ConfirmDialog {...defaultProps} onConfirm={asyncConfirm} />)
121
+ fireEvent.click(screen.getByText('Confirm'))
122
+ await waitFor(() => {
123
+ expect(asyncConfirm).toHaveBeenCalledTimes(1)
124
+ })
125
+ })
126
+ })
@@ -6,3 +6,6 @@ export type {
6
6
  DialogBodyProps,
7
7
  DialogFooterProps,
8
8
  } from './BaseDialog'
9
+
10
+ export { ConfirmDialog } from './ConfirmDialog'
11
+ export type { ConfirmDialogProps } from './ConfirmDialog'