@rebasepro/app 0.0.1-canary.4829d6e

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 (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/auth/api.d.ts +66 -0
  4. package/dist/auth/index.d.ts +13 -0
  5. package/dist/auth/types.d.ts +127 -0
  6. package/dist/auth/useRebaseAuthController.d.ts +13 -0
  7. package/dist/components/AIIcon.d.ts +17 -0
  8. package/dist/components/AuthSimulationMenu.d.ts +0 -0
  9. package/dist/components/ConfirmationDialog.d.ts +9 -0
  10. package/dist/components/Debug/UIReferenceView.d.ts +13 -0
  11. package/dist/components/Debug/UIStyleGuide.d.ts +2 -0
  12. package/dist/components/Debug/collection-views/CardViewDemo.d.ts +2 -0
  13. package/dist/components/Debug/collection-views/CollectionTableDemo.d.ts +2 -0
  14. package/dist/components/Debug/collection-views/KanbanBoardDemo.d.ts +2 -0
  15. package/dist/components/Debug/collection-views/index.d.ts +3 -0
  16. package/dist/components/Debug/collection-views/sample_data.d.ts +23 -0
  17. package/dist/components/Debug/crm-dashboard/CalendarWidget.d.ts +22 -0
  18. package/dist/components/Debug/crm-dashboard/CrmDashboardDemo.d.ts +2 -0
  19. package/dist/components/Debug/crm-dashboard/DashboardMetrics.d.ts +15 -0
  20. package/dist/components/Debug/crm-dashboard/PipelineOverview.d.ts +34 -0
  21. package/dist/components/Debug/crm-dashboard/RecentActivity.d.ts +19 -0
  22. package/dist/components/Debug/crm-dashboard/TaskFilters.d.ts +30 -0
  23. package/dist/components/Debug/crm-dashboard/TaskTable.d.ts +50 -0
  24. package/dist/components/Debug/crm-dashboard/TasksView.d.ts +41 -0
  25. package/dist/components/ErrorTooltip.d.ts +3 -0
  26. package/dist/components/ErrorView.d.ts +21 -0
  27. package/dist/components/LanguageToggle.d.ts +2 -0
  28. package/dist/components/LoginView/LoginView.d.ts +113 -0
  29. package/dist/components/LoginView/index.d.ts +2 -0
  30. package/dist/components/NotFoundPage.d.ts +2 -0
  31. package/dist/components/RebaseAuth.d.ts +10 -0
  32. package/dist/components/RebaseLogo.d.ts +7 -0
  33. package/dist/components/SchemaDriftBanner.d.ts +27 -0
  34. package/dist/components/UnsavedChangesDialog.d.ts +9 -0
  35. package/dist/components/UserDisplay.d.ts +7 -0
  36. package/dist/components/UserSelectPopover.d.ts +63 -0
  37. package/dist/components/UserSettingsView.d.ts +2 -0
  38. package/dist/components/common/index.d.ts +6 -0
  39. package/dist/components/common/table_height.d.ts +5 -0
  40. package/dist/components/common/types.d.ts +66 -0
  41. package/dist/components/common/useColumnsIds.d.ts +9 -0
  42. package/dist/components/common/useDataTableController.d.ts +45 -0
  43. package/dist/components/common/useDebouncedData.d.ts +9 -0
  44. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  45. package/dist/components/index.d.ts +18 -0
  46. package/dist/contexts/AdminModeController.d.ts +4 -0
  47. package/dist/contexts/AnalyticsContext.d.ts +3 -0
  48. package/dist/contexts/AuthControllerContext.d.ts +3 -0
  49. package/dist/contexts/CollectionScopeContext.d.ts +50 -0
  50. package/dist/contexts/ComponentOverrideContext.d.ts +42 -0
  51. package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
  52. package/dist/contexts/DataDriverContext.d.ts +3 -0
  53. package/dist/contexts/DataSourcesContext.d.ts +31 -0
  54. package/dist/contexts/DatabaseAdminContext.d.ts +3 -0
  55. package/dist/contexts/DialogsProvider.d.ts +4 -0
  56. package/dist/contexts/EffectiveRoleController.d.ts +4 -0
  57. package/dist/contexts/ModeController.d.ts +4 -0
  58. package/dist/contexts/RebaseClientInstanceContext.d.ts +6 -0
  59. package/dist/contexts/RebaseDataContext.d.ts +3 -0
  60. package/dist/contexts/SnackbarProvider.d.ts +2 -0
  61. package/dist/contexts/StorageSourceContext.d.ts +3 -0
  62. package/dist/contexts/StorageSourcesContext.d.ts +25 -0
  63. package/dist/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
  64. package/dist/contexts/index.d.ts +17 -0
  65. package/dist/core/PluginLifecycleManager.d.ts +17 -0
  66. package/dist/core/PluginProviderStack.d.ts +21 -0
  67. package/dist/core/Rebase.d.ts +15 -0
  68. package/dist/core/RebaseProps.d.ts +291 -0
  69. package/dist/core/RebaseRouter.d.ts +4 -0
  70. package/dist/core/RebaseRoutes.d.ts +17 -0
  71. package/dist/core/index.d.ts +4 -0
  72. package/dist/hooks/ApiConfigContext.d.ts +24 -0
  73. package/dist/hooks/data/delete.d.ts +33 -0
  74. package/dist/hooks/data/save.d.ts +40 -0
  75. package/dist/hooks/data/useCollection.d.ts +62 -0
  76. package/dist/hooks/data/useData.d.ts +13 -0
  77. package/dist/hooks/data/useDataOrder.d.ts +12 -0
  78. package/dist/hooks/data/useFetch.d.ts +43 -0
  79. package/dist/hooks/data/useRelationSelector.d.ts +52 -0
  80. package/dist/hooks/index.d.ts +36 -0
  81. package/dist/hooks/useAdminModeController.d.ts +19 -0
  82. package/dist/hooks/useAnalyticsController.d.ts +5 -0
  83. package/dist/hooks/useAuthController.d.ts +11 -0
  84. package/dist/hooks/useAuthSubscription.d.ts +2 -0
  85. package/dist/hooks/useBackendStorageSource.d.ts +30 -0
  86. package/dist/hooks/useBridgeRegistration.d.ts +18 -0
  87. package/dist/hooks/useBrowserTitleAndIcon.d.ts +6 -0
  88. package/dist/hooks/useBuildAdminModeController.d.ts +6 -0
  89. package/dist/hooks/useBuildEffectiveRoleController.d.ts +8 -0
  90. package/dist/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
  91. package/dist/hooks/useBuildModeController.d.ts +6 -0
  92. package/dist/hooks/useClipboard.d.ts +57 -0
  93. package/dist/hooks/useCollapsedGroups.d.ts +27 -0
  94. package/dist/hooks/useComponentOverride.d.ts +32 -0
  95. package/dist/hooks/useCustomizationController.d.ts +11 -0
  96. package/dist/hooks/useDialogsController.d.ts +11 -0
  97. package/dist/hooks/useEffectiveRoleController.d.ts +7 -0
  98. package/dist/hooks/useLargeLayout.d.ts +1 -0
  99. package/dist/hooks/useModeController.d.ts +19 -0
  100. package/dist/hooks/usePermissions.d.ts +12 -0
  101. package/dist/hooks/useRebaseClient.d.ts +5 -0
  102. package/dist/hooks/useRebaseContext.d.ts +11 -0
  103. package/dist/hooks/useRebaseRegistry.d.ts +34 -0
  104. package/dist/hooks/useResolvedComponent.d.ts +47 -0
  105. package/dist/hooks/useSlot.d.ts +18 -0
  106. package/dist/hooks/useSnackbarController.d.ts +20 -0
  107. package/dist/hooks/useStorageSource.d.ts +6 -0
  108. package/dist/hooks/useStudioBridge.d.ts +79 -0
  109. package/dist/hooks/useTranslation.d.ts +17 -0
  110. package/dist/hooks/useUnsavedChangesDialog.d.ts +12 -0
  111. package/dist/hooks/useUserConfigurationPersistence.d.ts +8 -0
  112. package/dist/i18n/RebaseI18nProvider.d.ts +33 -0
  113. package/dist/index.d.ts +16 -0
  114. package/dist/index.es.js +16843 -0
  115. package/dist/index.es.js.map +1 -0
  116. package/dist/index.umd.js +17021 -0
  117. package/dist/index.umd.js.map +1 -0
  118. package/dist/internal/common.d.ts +14 -0
  119. package/dist/internal/useRestoreScroll.d.ts +15 -0
  120. package/dist/locales/de.d.ts +2 -0
  121. package/dist/locales/en.d.ts +10 -0
  122. package/dist/locales/es.d.ts +10 -0
  123. package/dist/locales/fr.d.ts +2 -0
  124. package/dist/locales/hi.d.ts +2 -0
  125. package/dist/locales/it.d.ts +2 -0
  126. package/dist/locales/pt.d.ts +7 -0
  127. package/dist/util/constants.d.ts +1 -0
  128. package/dist/util/createFormexStub.d.ts +2 -0
  129. package/dist/util/entity_cache.d.ts +22 -0
  130. package/dist/util/enums.d.ts +5 -0
  131. package/dist/util/icon_list.d.ts +5 -0
  132. package/dist/util/icons.d.ts +20 -0
  133. package/dist/util/index.d.ts +8 -0
  134. package/dist/util/previews.d.ts +4 -0
  135. package/dist/util/useStorageUploadController.d.ts +44 -0
  136. package/dist/vitePlugin.d.ts +60 -0
  137. package/dist/vitePlugin.js +113 -0
  138. package/package.json +145 -0
  139. package/src/auth/api.ts +148 -0
  140. package/src/auth/index.ts +25 -0
  141. package/src/auth/types.ts +115 -0
  142. package/src/auth/useRebaseAuthController.ts +328 -0
  143. package/src/components/AIIcon.tsx +47 -0
  144. package/src/components/AuthSimulationMenu.tsx +0 -0
  145. package/src/components/ConfirmationDialog.tsx +48 -0
  146. package/src/components/Debug/UIReferenceView.tsx +958 -0
  147. package/src/components/Debug/UIStyleGuide.tsx +156 -0
  148. package/src/components/Debug/collection-views/CardViewDemo.tsx +85 -0
  149. package/src/components/Debug/collection-views/CollectionTableDemo.tsx +107 -0
  150. package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +90 -0
  151. package/src/components/Debug/collection-views/index.ts +3 -0
  152. package/src/components/Debug/collection-views/sample_data.ts +42 -0
  153. package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +389 -0
  154. package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +1102 -0
  155. package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +133 -0
  156. package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +290 -0
  157. package/src/components/Debug/crm-dashboard/RecentActivity.tsx +215 -0
  158. package/src/components/Debug/crm-dashboard/TaskFilters.tsx +184 -0
  159. package/src/components/Debug/crm-dashboard/TaskTable.tsx +427 -0
  160. package/src/components/Debug/crm-dashboard/TasksView.tsx +234 -0
  161. package/src/components/ErrorTooltip.tsx +12 -0
  162. package/src/components/ErrorView.tsx +94 -0
  163. package/src/components/LanguageToggle.tsx +59 -0
  164. package/src/components/LoginView/LoginView.tsx +932 -0
  165. package/src/components/LoginView/index.ts +2 -0
  166. package/src/components/NotFoundPage.tsx +27 -0
  167. package/src/components/RebaseAuth.tsx +27 -0
  168. package/src/components/RebaseLogo.tsx +29 -0
  169. package/src/components/SchemaDriftBanner.tsx +102 -0
  170. package/src/components/UnsavedChangesDialog.tsx +46 -0
  171. package/src/components/UserDisplay.tsx +54 -0
  172. package/src/components/UserSelectPopover.tsx +399 -0
  173. package/src/components/UserSettingsView.tsx +318 -0
  174. package/src/components/common/index.ts +6 -0
  175. package/src/components/common/table_height.tsx +21 -0
  176. package/src/components/common/types.tsx +66 -0
  177. package/src/components/common/useColumnsIds.tsx +222 -0
  178. package/src/components/common/useDataTableController.tsx +514 -0
  179. package/src/components/common/useDebouncedData.ts +49 -0
  180. package/src/components/common/useScrollRestoration.tsx +68 -0
  181. package/src/components/index.tsx +26 -0
  182. package/src/contexts/AdminModeController.tsx +11 -0
  183. package/src/contexts/AnalyticsContext.tsx +4 -0
  184. package/src/contexts/AuthControllerContext.tsx +4 -0
  185. package/src/contexts/CollectionScopeContext.tsx +67 -0
  186. package/src/contexts/ComponentOverrideContext.tsx +81 -0
  187. package/src/contexts/CustomizationControllerContext.tsx +4 -0
  188. package/src/contexts/DataDriverContext.tsx +4 -0
  189. package/src/contexts/DataSourcesContext.tsx +36 -0
  190. package/src/contexts/DatabaseAdminContext.tsx +4 -0
  191. package/src/contexts/DialogsProvider.tsx +56 -0
  192. package/src/contexts/EffectiveRoleController.tsx +12 -0
  193. package/src/contexts/ModeController.tsx +11 -0
  194. package/src/contexts/RebaseClientInstanceContext.tsx +7 -0
  195. package/src/contexts/RebaseDataContext.tsx +4 -0
  196. package/src/contexts/SnackbarProvider.tsx +15 -0
  197. package/src/contexts/StorageSourceContext.tsx +4 -0
  198. package/src/contexts/StorageSourcesContext.tsx +30 -0
  199. package/src/contexts/UserConfigurationPersistenceContext.tsx +4 -0
  200. package/src/contexts/index.ts +17 -0
  201. package/src/core/PluginLifecycleManager.tsx +95 -0
  202. package/src/core/PluginProviderStack.tsx +40 -0
  203. package/src/core/Rebase.tsx +439 -0
  204. package/src/core/RebaseProps.tsx +320 -0
  205. package/src/core/RebaseRouter.tsx +17 -0
  206. package/src/core/RebaseRoutes.tsx +24 -0
  207. package/src/core/index.tsx +5 -0
  208. package/src/hooks/ApiConfigContext.tsx +41 -0
  209. package/src/hooks/data/delete.ts +55 -0
  210. package/src/hooks/data/save.ts +77 -0
  211. package/src/hooks/data/useCollection.tsx +176 -0
  212. package/src/hooks/data/useData.tsx +18 -0
  213. package/src/hooks/data/useDataOrder.ts +26 -0
  214. package/src/hooks/data/useFetch.tsx +140 -0
  215. package/src/hooks/data/useRelationSelector.tsx +234 -0
  216. package/src/hooks/index.tsx +45 -0
  217. package/src/hooks/useAdminModeController.tsx +23 -0
  218. package/src/hooks/useAnalyticsController.tsx +8 -0
  219. package/src/hooks/useAuthController.tsx +14 -0
  220. package/src/hooks/useAuthSubscription.ts +87 -0
  221. package/src/hooks/useBackendStorageSource.ts +288 -0
  222. package/src/hooks/useBridgeRegistration.tsx +32 -0
  223. package/src/hooks/useBrowserTitleAndIcon.tsx +23 -0
  224. package/src/hooks/useBuildAdminModeController.tsx +24 -0
  225. package/src/hooks/useBuildEffectiveRoleController.tsx +31 -0
  226. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +75 -0
  227. package/src/hooks/useBuildModeController.tsx +71 -0
  228. package/src/hooks/useClipboard.tsx +158 -0
  229. package/src/hooks/useCollapsedGroups.ts +116 -0
  230. package/src/hooks/useComponentOverride.tsx +59 -0
  231. package/src/hooks/useCustomizationController.tsx +14 -0
  232. package/src/hooks/useDialogsController.tsx +15 -0
  233. package/src/hooks/useEffectiveRoleController.tsx +10 -0
  234. package/src/hooks/useLargeLayout.tsx +65 -0
  235. package/src/hooks/useModeController.tsx +23 -0
  236. package/src/hooks/usePermissions.ts +44 -0
  237. package/src/hooks/useRebaseClient.tsx +10 -0
  238. package/src/hooks/useRebaseContext.tsx +83 -0
  239. package/src/hooks/useRebaseRegistry.tsx +91 -0
  240. package/src/hooks/useResolvedComponent.tsx +159 -0
  241. package/src/hooks/useSlot.tsx +64 -0
  242. package/src/hooks/useSnackbarController.tsx +52 -0
  243. package/src/hooks/useStorageSource.tsx +11 -0
  244. package/src/hooks/useStudioBridge.tsx +209 -0
  245. package/src/hooks/useTranslation.ts +33 -0
  246. package/src/hooks/useUnsavedChangesDialog.tsx +64 -0
  247. package/src/hooks/useUserConfigurationPersistence.tsx +11 -0
  248. package/src/i18n/RebaseI18nProvider.tsx +160 -0
  249. package/src/index.ts +25 -0
  250. package/src/internal/common.tsx +16 -0
  251. package/src/internal/useRestoreScroll.tsx +69 -0
  252. package/src/locales/de.ts +902 -0
  253. package/src/locales/en.ts +980 -0
  254. package/src/locales/es.ts +922 -0
  255. package/src/locales/fr.ts +901 -0
  256. package/src/locales/hi.ts +901 -0
  257. package/src/locales/it.ts +901 -0
  258. package/src/locales/pt.ts +909 -0
  259. package/src/util/constants.ts +7 -0
  260. package/src/util/createFormexStub.tsx +66 -0
  261. package/src/util/entity_cache.ts +239 -0
  262. package/src/util/enums.ts +32 -0
  263. package/src/util/icon_list.ts +22 -0
  264. package/src/util/icons.tsx +149 -0
  265. package/src/util/index.ts +12 -0
  266. package/src/util/previews.ts +105 -0
  267. package/src/util/useStorageUploadController.tsx +350 -0
  268. package/src/vitePlugin.ts +196 -0
@@ -0,0 +1,234 @@
1
+ import React, { useState, useMemo, useCallback } from "react";
2
+ import { TaskFilters } from "./TaskFilters";
3
+ import { TaskTable } from "./TaskTable";
4
+
5
+ /* ── Types ──────────────────────────────────────────────────── */
6
+
7
+ interface TaskEntity {
8
+ id: string;
9
+ values: {
10
+ title: string;
11
+ status: string;
12
+ resolution: string | null;
13
+ dueDate: string | null;
14
+ stageId: string | null;
15
+ description: string | null;
16
+ notes: string | null;
17
+ clientId: string | null;
18
+ client?: { name?: string } | null;
19
+ priority?: string | null;
20
+ createdAt: string | null;
21
+ };
22
+ }
23
+
24
+ type QuickFilter = "all" | "overdue";
25
+
26
+ const PENDING_PAGE_SIZE = 50;
27
+
28
+ function isDueDateOverdue(dateStr: string | null): boolean {
29
+ if (!dateStr) return false;
30
+ const d = new Date(dateStr);
31
+ if (isNaN(d.getTime())) return false;
32
+ const now = new Date();
33
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
34
+ return d < today;
35
+ }
36
+
37
+ export interface TasksViewProps {
38
+ loading: boolean;
39
+ tasks: TaskEntity[];
40
+ togglingIds: Set<string>;
41
+ onToggleTask: (taskId: string, currentStatus: string) => void;
42
+ onOpenTask: (taskId: string) => void;
43
+ onOpenClient: (clientId: string) => void;
44
+ clientsMap: Map<string, { name: string; picture?: string }>;
45
+ pipelineStages: any[];
46
+ recentlyToggledIds: Set<string>;
47
+ completedTasks: TaskEntity[];
48
+ completedLoaded: boolean;
49
+ loadingCompleted: boolean;
50
+ completedHasMore: boolean;
51
+ onExpandCompleted: () => void;
52
+ onLoadMoreCompleted: () => void;
53
+ }
54
+
55
+ /* ── Component ──────────────────────────────────────────────── */
56
+
57
+ export function TasksView({
58
+ loading,
59
+ tasks,
60
+ togglingIds,
61
+ onToggleTask,
62
+ onOpenTask,
63
+ onOpenClient,
64
+ clientsMap,
65
+ pipelineStages,
66
+ recentlyToggledIds,
67
+ completedTasks,
68
+ completedLoaded,
69
+ loadingCompleted,
70
+ completedHasMore,
71
+ onExpandCompleted,
72
+ onLoadMoreCompleted
73
+ }: TasksViewProps) {
74
+ const stageLabels: Record<string, string> = useMemo(
75
+ () => Object.fromEntries(
76
+ pipelineStages.map(s => [s.values?.stageKey, s.values?.label])
77
+ ),
78
+ [pipelineStages]
79
+ );
80
+
81
+ const stageFilterOrder: string[] = useMemo(
82
+ () => pipelineStages.map(s => s.values?.stageKey).filter(Boolean),
83
+ [pipelineStages]
84
+ );
85
+
86
+ // ── Filtering state ──
87
+ const [quickFilter, setQuickFilter] = useState<QuickFilter>("all");
88
+ const [stageFilter, setStageFilter] = useState<string | null>(null);
89
+ const [clientFilter, setClientFilter] = useState<string | null>(null);
90
+ const [searchText, setSearchText] = useState<string>("");
91
+ const [visiblePendingCount, setVisiblePendingCount] = useState(PENDING_PAGE_SIZE);
92
+
93
+ /* ── Derived data ── */
94
+ const overdueTasks = useMemo(
95
+ () => tasks.filter(t =>
96
+ t.values?.status === "pending" &&
97
+ !recentlyToggledIds.has(t.id) &&
98
+ isDueDateOverdue(t.values?.dueDate)
99
+ ),
100
+ [tasks, recentlyToggledIds]
101
+ );
102
+
103
+ // Unique client IDs in current pending tasks
104
+ const activeClientIds = useMemo(() => {
105
+ const ids = new Set<string>();
106
+ tasks.forEach(t => {
107
+ if (t.values?.clientId) ids.add(t.values.clientId);
108
+ });
109
+ return Array.from(ids).sort((a, b) => {
110
+ const na = clientsMap.get(a)?.name || "";
111
+ const nb = clientsMap.get(b)?.name || "";
112
+ return na.localeCompare(nb);
113
+ });
114
+ }, [tasks, clientsMap]);
115
+
116
+ // Stage counts for badge display
117
+ const stageCounts = useMemo(() => {
118
+ const counts: Record<string, number> = {};
119
+ tasks.forEach(t => {
120
+ if (t.values?.status === "pending" && t.values?.stageId) {
121
+ counts[t.values.stageId] = (counts[t.values.stageId] || 0) + 1;
122
+ }
123
+ });
124
+ return counts;
125
+ }, [tasks]);
126
+
127
+ // Apply filters to pending tasks
128
+ const filteredPendingTasks = useMemo(() => {
129
+ let filtered = tasks.filter(t =>
130
+ t.values?.status === "pending" ||
131
+ (t.values?.status === "completed" && recentlyToggledIds.has(t.id))
132
+ );
133
+
134
+ if (quickFilter === "overdue") {
135
+ filtered = filtered.filter(t =>
136
+ isDueDateOverdue(t.values?.dueDate) ||
137
+ recentlyToggledIds.has(t.id)
138
+ );
139
+ }
140
+
141
+ if (stageFilter) {
142
+ filtered = filtered.filter(t =>
143
+ t.values?.stageId === stageFilter ||
144
+ recentlyToggledIds.has(t.id)
145
+ );
146
+ }
147
+
148
+ if (clientFilter) {
149
+ filtered = filtered.filter(t =>
150
+ t.values?.clientId === clientFilter ||
151
+ recentlyToggledIds.has(t.id)
152
+ );
153
+ }
154
+
155
+ if (searchText.trim()) {
156
+ const q = searchText.trim().toLowerCase();
157
+ filtered = filtered.filter(t => {
158
+ const title = (t.values?.title || "").toLowerCase();
159
+ const desc = (t.values?.description || "").toLowerCase();
160
+ const clientName = t.values?.clientId
161
+ ? (clientsMap.get(t.values.clientId)?.name || "").toLowerCase()
162
+ : "";
163
+ return title.includes(q) || desc.includes(q) || clientName.includes(q);
164
+ });
165
+ }
166
+
167
+ return filtered;
168
+ }, [tasks, recentlyToggledIds, quickFilter, stageFilter, clientFilter, searchText, clientsMap]);
169
+
170
+ const visiblePendingTasks = useMemo(() =>
171
+ filteredPendingTasks.slice(0, visiblePendingCount),
172
+ [filteredPendingTasks, visiblePendingCount]
173
+ );
174
+ const hasMorePending = filteredPendingTasks.length > visiblePendingCount;
175
+ const pendingCount = filteredPendingTasks.length;
176
+
177
+ const handleClearAllFilters = useCallback(() => {
178
+ setQuickFilter("all");
179
+ setStageFilter(null);
180
+ setClientFilter(null);
181
+ setSearchText("");
182
+ }, []);
183
+
184
+ const hasActiveFilter = quickFilter !== "all" || stageFilter !== null || clientFilter !== null || searchText !== "";
185
+
186
+ return (
187
+ <div className="flex flex-col h-full bg-white dark:bg-surface-900">
188
+ <div className="flex flex-col gap-4 overflow-y-auto flex-1">
189
+ <TaskFilters
190
+ quickFilter={quickFilter}
191
+ onQuickFilterChange={setQuickFilter}
192
+ stageFilter={stageFilter}
193
+ onStageFilterChange={setStageFilter}
194
+ clientFilter={clientFilter}
195
+ onClientFilterChange={setClientFilter}
196
+ searchText={searchText}
197
+ onSearchTextChange={setSearchText}
198
+ hasActiveFilter={hasActiveFilter}
199
+ onClearAllFilters={handleClearAllFilters}
200
+ overdueTasks={overdueTasks}
201
+ pendingTasks={tasks.filter(t => t.values?.status === "pending" && !recentlyToggledIds.has(t.id))}
202
+ stageLabels={stageLabels}
203
+ stageFilterOrder={stageFilterOrder}
204
+ stageCounts={stageCounts}
205
+ activeClientIds={activeClientIds}
206
+ clientsMap={clientsMap}
207
+ />
208
+
209
+ <TaskTable
210
+ tasks={tasks}
211
+ loading={loading}
212
+ pendingTasks={filteredPendingTasks}
213
+ visiblePendingTasks={visiblePendingTasks}
214
+ hasMorePending={hasMorePending}
215
+ onLoadMorePending={() => setVisiblePendingCount(prev => prev + PENDING_PAGE_SIZE)}
216
+ pendingCount={pendingCount}
217
+ togglingIds={togglingIds}
218
+ onToggleTask={onToggleTask}
219
+ onOpenTask={onOpenTask}
220
+ onOpenClient={onOpenClient}
221
+ clientsMap={clientsMap}
222
+ stageLabels={stageLabels}
223
+ recentlyToggledIds={recentlyToggledIds}
224
+ completedTasks={completedTasks}
225
+ completedLoaded={completedLoaded}
226
+ loadingCompleted={loadingCompleted}
227
+ completedHasMore={completedHasMore}
228
+ onExpandCompleted={onExpandCompleted}
229
+ onLoadMoreCompleted={onLoadMoreCompleted}
230
+ />
231
+ </div>
232
+ </div>
233
+ );
234
+ }
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import { Tooltip, TooltipProps } from "@rebasepro/ui";
3
+
4
+ export function ErrorTooltip(props: TooltipProps) {
5
+ return (
6
+ <Tooltip {...props}
7
+ className={props.className}
8
+ tooltipClassName={"text-red-500! bg-red-50"}>
9
+ {props.children}
10
+ </Tooltip>
11
+ );
12
+ }
@@ -0,0 +1,94 @@
1
+ import React from "react";
2
+ import { ErrorTooltip } from "./ErrorTooltip";
3
+ import { AlertTriangleIcon, Button, Typography, iconSize } from "@rebasepro/ui";
4
+
5
+ /**
6
+ * @group Components
7
+ */
8
+ export interface ErrorViewProps {
9
+ title?: string;
10
+ error: Error | React.ReactElement | string,
11
+ tooltip?: string,
12
+ onRetry?: () => void;
13
+ }
14
+
15
+ /**
16
+ * Generic error view. Displayed for example when an unexpected value comes
17
+ * from the driver in a collection view.
18
+ * @param title
19
+ * @param error
20
+ * @param tooltip
21
+ * @param onRetry
22
+
23
+ * @group Components
24
+ */
25
+ export function ErrorView({
26
+ title,
27
+ error,
28
+ tooltip,
29
+ onRetry
30
+ }: ErrorViewProps): React.ReactElement {
31
+ const message = error instanceof Error ? error.message : error;
32
+ // Extract error code from ApiError instances (e.g. PG error codes like "42P01")
33
+ const errorCode = error instanceof Error && "code" in error
34
+ ? (error as Error & { code?: string }).code
35
+ : undefined;
36
+
37
+ const body = (
38
+ <div className="flex flex-col m-2">
39
+ <div className="flex items-start gap-2.5">
40
+ <AlertTriangleIcon
41
+ size={iconSize.smallest}
42
+ className="shrink-0 text-red-500 dark:text-red-400 mt-0.5"
43
+ />
44
+ <div className="flex-1 min-w-0">
45
+ {title && (
46
+ <Typography
47
+ variant="body2"
48
+ color="primary"
49
+ className="font-semibold mb-0.5"
50
+ >
51
+ {title}
52
+ </Typography>
53
+ )}
54
+ <Typography
55
+ variant="body2"
56
+ color="secondary"
57
+ className="leading-relaxed"
58
+ >
59
+ {message}
60
+ </Typography>
61
+ {errorCode && (
62
+ <span
63
+ className="inline-block mt-1 px-1.5 py-0.5 text-[10px] font-mono rounded bg-surface-200 dark:bg-surface-700 text-text-secondary"
64
+ >
65
+ {errorCode}
66
+ </span>
67
+ )}
68
+ {onRetry && (
69
+ <div className="mt-3">
70
+ <Button
71
+ variant="outlined"
72
+ color="neutral"
73
+ size="small"
74
+ onClick={onRetry}
75
+ className="font-semibold"
76
+ >
77
+ Try again
78
+ </Button>
79
+ </div>
80
+ )}
81
+ </div>
82
+ </div>
83
+ </div>
84
+ );
85
+
86
+ if (tooltip) {
87
+ return (
88
+ <ErrorTooltip title={tooltip}>
89
+ {body}
90
+ </ErrorTooltip>
91
+ );
92
+ }
93
+ return body;
94
+ }
@@ -0,0 +1,59 @@
1
+ import React from "react";
2
+ import { CheckIcon, IconButton, iconSize, LanguagesIcon, Menu, MenuItem, Typography } from "@rebasepro/ui";
3
+ import { useTranslation } from "../hooks";
4
+
5
+ export function LanguageToggle() {
6
+ const { i18n } = useTranslation();
7
+
8
+ return (
9
+ <Menu
10
+ trigger={<IconButton
11
+ color="inherit"
12
+ aria-label="Change language">
13
+ <LanguagesIcon size={iconSize.small}/>
14
+ </IconButton>}>
15
+ <MenuItem onClick={() => i18n.changeLanguage("en")}>
16
+ <div className="flex w-full items-center justify-between gap-4">
17
+ <Typography variant="body2" className={i18n.language === "en" ? "font-bold" : ""}>English</Typography>
18
+ {i18n.language === "en" && <CheckIcon size={iconSize.small}/>}
19
+ </div>
20
+ </MenuItem>
21
+ <MenuItem onClick={() => i18n.changeLanguage("es")}>
22
+ <div className="flex w-full items-center justify-between gap-4">
23
+ <Typography variant="body2" className={i18n.language === "es" ? "font-bold" : ""}>Español</Typography>
24
+ {i18n.language === "es" && <CheckIcon size={iconSize.small}/>}
25
+ </div>
26
+ </MenuItem>
27
+ <MenuItem onClick={() => i18n.changeLanguage("de")}>
28
+ <div className="flex w-full items-center justify-between gap-4">
29
+ <Typography variant="body2" className={i18n.language === "de" ? "font-bold" : ""}>Deutsch</Typography>
30
+ {i18n.language === "de" && <CheckIcon size={iconSize.small}/>}
31
+ </div>
32
+ </MenuItem>
33
+ <MenuItem onClick={() => i18n.changeLanguage("fr")}>
34
+ <div className="flex w-full items-center justify-between gap-4">
35
+ <Typography variant="body2" className={i18n.language === "fr" ? "font-bold" : ""}>Français</Typography>
36
+ {i18n.language === "fr" && <CheckIcon size={iconSize.small}/>}
37
+ </div>
38
+ </MenuItem>
39
+ <MenuItem onClick={() => i18n.changeLanguage("it")}>
40
+ <div className="flex w-full items-center justify-between gap-4">
41
+ <Typography variant="body2" className={i18n.language === "it" ? "font-bold" : ""}>Italiano</Typography>
42
+ {i18n.language === "it" && <CheckIcon size={iconSize.small}/>}
43
+ </div>
44
+ </MenuItem>
45
+ <MenuItem onClick={() => i18n.changeLanguage("hi")}>
46
+ <div className="flex w-full items-center justify-between gap-4">
47
+ <Typography variant="body2" className={i18n.language === "hi" ? "font-bold" : ""}>हिन्दी</Typography>
48
+ {i18n.language === "hi" && <CheckIcon size={iconSize.small}/>}
49
+ </div>
50
+ </MenuItem>
51
+ <MenuItem onClick={() => i18n.changeLanguage("pt")}>
52
+ <div className="flex w-full items-center justify-between gap-4">
53
+ <Typography variant="body2" className={i18n.language === "pt" ? "font-bold" : ""}>Português</Typography>
54
+ {i18n.language === "pt" && <CheckIcon size={iconSize.small}/>}
55
+ </div>
56
+ </MenuItem>
57
+ </Menu>
58
+ );
59
+ }