@consilioweb/payload-support 2.0.0 → 3.0.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 (222) hide show
  1. package/README.md +656 -355
  2. package/dist/components/RichTextEditor/index.d.ts +19 -0
  3. package/dist/components/TicketConversation/RewriteDropdown.d.ts +6 -0
  4. package/dist/components/TicketConversation/SkeletonText.d.ts +4 -0
  5. package/dist/components/TicketConversation/components/AISummaryPanel.d.ts +14 -0
  6. package/dist/components/TicketConversation/components/ActionPanels.d.ts +47 -0
  7. package/dist/components/TicketConversation/components/ActivityLog.d.ts +5 -0
  8. package/dist/components/TicketConversation/components/ClientBar.d.ts +5 -0
  9. package/dist/components/TicketConversation/components/ClientHistory.d.ts +24 -0
  10. package/dist/components/TicketConversation/components/CodeBlock.d.ts +26 -0
  11. package/dist/components/TicketConversation/components/CodeBlockInserter.d.ts +12 -0
  12. package/dist/components/TicketConversation/components/QuickActions.d.ts +32 -0
  13. package/dist/components/TicketConversation/components/TicketHeader.d.ts +19 -0
  14. package/dist/components/TicketConversation/components/TimeTrackingPanel.d.ts +24 -0
  15. package/dist/components/TicketConversation/config.d.ts +10 -0
  16. package/dist/components/TicketConversation/config.js +1 -40
  17. package/dist/components/TicketConversation/constants.d.ts +56 -0
  18. package/dist/components/TicketConversation/context.d.ts +53 -0
  19. package/dist/components/TicketConversation/hooks/useAI.d.ts +21 -0
  20. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.d.ts +3 -0
  21. package/dist/components/TicketConversation/hooks/useFeatures.d.ts +23 -0
  22. package/dist/components/TicketConversation/hooks/useFeatures.js +61 -0
  23. package/dist/components/TicketConversation/hooks/useMessageActions.d.ts +20 -0
  24. package/dist/components/TicketConversation/hooks/useReply.d.ts +27 -0
  25. package/dist/components/TicketConversation/hooks/useTicketActions.d.ts +58 -0
  26. package/dist/components/TicketConversation/hooks/useTimeTracking.d.ts +18 -0
  27. package/dist/components/TicketConversation/hooks/useTranslation.d.ts +33 -0
  28. package/dist/components/TicketConversation/hooks/useTranslation.js +22 -3
  29. package/dist/components/TicketConversation/index.d.ts +4 -0
  30. package/dist/components/TicketConversation/index.js +2 -2
  31. package/dist/components/TicketConversation/types.d.ts +56 -0
  32. package/dist/components/TicketConversation/utils.d.ts +2 -0
  33. package/dist/index.cjs +392 -320
  34. package/dist/index.d.cts +100 -3
  35. package/dist/index.d.ts +100 -3
  36. package/dist/index.js +388 -321
  37. package/dist/utils/features.d.ts +123 -0
  38. package/dist/utils/features.js +147 -0
  39. package/dist/views/BillingView/client.d.ts +2 -0
  40. package/dist/views/BillingView/index.d.ts +4 -0
  41. package/dist/views/ChatView/client.d.ts +2 -0
  42. package/dist/views/ChatView/client.js +9 -9
  43. package/dist/views/ChatView/index.d.ts +4 -0
  44. package/dist/views/CrmView/client.d.ts +2 -0
  45. package/dist/views/CrmView/client.js +6 -9
  46. package/dist/views/CrmView/index.d.ts +4 -0
  47. package/dist/views/EmailTrackingView/client.d.ts +2 -0
  48. package/dist/views/EmailTrackingView/index.d.ts +4 -0
  49. package/dist/views/ImportConversationView/client.d.ts +2 -0
  50. package/dist/views/ImportConversationView/index.d.ts +4 -0
  51. package/dist/views/LogsView/client.d.ts +2 -0
  52. package/dist/views/LogsView/index.d.ts +4 -0
  53. package/dist/views/NewTicketView/client.d.ts +2 -0
  54. package/dist/views/NewTicketView/index.d.ts +4 -0
  55. package/dist/views/PendingEmailsView/client.d.ts +2 -0
  56. package/dist/views/PendingEmailsView/index.d.ts +4 -0
  57. package/dist/views/SupportDashboardView/client.d.ts +2 -0
  58. package/dist/views/SupportDashboardView/client.js +1 -1
  59. package/dist/views/SupportDashboardView/index.d.ts +4 -0
  60. package/dist/views/TicketDetailView/NextActionItem.d.ts +6 -0
  61. package/dist/views/TicketDetailView/RewriteDropdown.d.ts +7 -0
  62. package/dist/views/TicketDetailView/client.d.ts +2 -0
  63. package/dist/views/TicketDetailView/client.js +2 -2
  64. package/dist/views/TicketDetailView/constants.d.ts +13 -0
  65. package/dist/views/TicketDetailView/helpers.d.ts +2 -0
  66. package/dist/views/TicketDetailView/index.d.ts +4 -0
  67. package/dist/views/TicketDetailView/types.d.ts +40 -0
  68. package/dist/views/TicketInboxView/client.d.ts +2 -0
  69. package/dist/views/TicketInboxView/client.js +5 -5
  70. package/dist/views/TicketInboxView/index.d.ts +4 -0
  71. package/dist/views/TicketingSettingsView/client.d.ts +2 -0
  72. package/dist/views/TicketingSettingsView/client.js +6 -5
  73. package/dist/views/TicketingSettingsView/index.d.ts +4 -0
  74. package/dist/views/TimeDashboardView/client.d.ts +2 -0
  75. package/dist/views/TimeDashboardView/index.d.ts +4 -0
  76. package/dist/views/shared/AdminViewHeader.d.ts +13 -0
  77. package/dist/views/shared/ErrorBoundary.d.ts +17 -0
  78. package/dist/views/shared/Skeleton.d.ts +21 -0
  79. package/dist/views/shared/StatusPill.d.ts +8 -0
  80. package/dist/views/shared/adminTokens.d.ts +19 -0
  81. package/dist/views/shared/config.d.ts +8 -0
  82. package/dist/views/shared/config.js +1 -40
  83. package/dist/views/shared/dateLocale.d.ts +5 -0
  84. package/dist/views/shared/index.d.ts +12 -0
  85. package/dist/views/shared/index.js +2 -1
  86. package/dist/views/shared/locales/en.json +708 -0
  87. package/dist/views/shared/locales/fr.json +708 -0
  88. package/dist/views/shared/sla.d.ts +14 -0
  89. package/dist/views.d.ts +13 -13
  90. package/package.json +26 -41
  91. package/src/collections/SupportClients.ts +29 -0
  92. package/src/collections/TicketCollaborators.ts +6 -1
  93. package/src/collections/TicketMessages.ts +46 -24
  94. package/src/collections/Tickets.ts +117 -79
  95. package/src/collections/TimeEntries.ts +57 -32
  96. package/src/components/TicketConversation/config.ts +16 -80
  97. package/src/components/TicketConversation/hooks/useFeatures.ts +109 -0
  98. package/src/components/TicketConversation/hooks/useTranslation.ts +38 -4
  99. package/src/components/TicketConversation/index.tsx +2 -2
  100. package/src/endpoints/ai.ts +2 -1
  101. package/src/endpoints/client-intelligence.ts +2 -1
  102. package/src/endpoints/process-scheduled.ts +13 -8
  103. package/src/endpoints/round-robin-config.ts +30 -20
  104. package/src/endpoints/settings.ts +28 -77
  105. package/src/index.ts +6 -2
  106. package/src/portal/LiveChat.tsx +33 -22
  107. package/src/portal/auth/tickets/detail/TicketPolling.tsx +5 -1
  108. package/src/types/lucide-react.d.ts +10 -2
  109. package/src/utils/aiAgent.ts +2 -1
  110. package/src/utils/aiProvider.ts +21 -0
  111. package/src/utils/features.ts +297 -0
  112. package/src/utils/fireWebhooks.ts +6 -0
  113. package/src/utils/generateTicketSynthesis.ts +2 -1
  114. package/src/utils/index.ts +4 -2
  115. package/src/utils/readSettings.ts +82 -9
  116. package/src/utils/webhookDispatcher.ts +19 -7
  117. package/src/views/ChatView/client.tsx +13 -9
  118. package/src/views/CrmView/client.tsx +10 -11
  119. package/src/views/SupportDashboardView/client.tsx +1 -1
  120. package/src/views/TicketDetailView/client.tsx +2 -2
  121. package/src/views/TicketInboxView/client.tsx +10 -5
  122. package/src/views/TicketingSettingsView/client.tsx +9 -7
  123. package/src/views/shared/config.ts +14 -80
  124. package/src/views/shared/index.ts +3 -1
  125. package/src/views/shared/locales/en.json +2 -2
  126. package/src/views/shared/locales/fr.json +2 -2
  127. package/dist/components/RichTextEditor/index.cjs +0 -279
  128. package/dist/components/TicketConversation/RewriteDropdown.cjs +0 -98
  129. package/dist/components/TicketConversation/SkeletonText.cjs +0 -21
  130. package/dist/components/TicketConversation/components/AISummaryPanel.cjs +0 -85
  131. package/dist/components/TicketConversation/components/ActionPanels.cjs +0 -193
  132. package/dist/components/TicketConversation/components/ActivityLog.cjs +0 -24
  133. package/dist/components/TicketConversation/components/ClientBar.cjs +0 -43
  134. package/dist/components/TicketConversation/components/ClientHistory.cjs +0 -138
  135. package/dist/components/TicketConversation/components/CodeBlock.cjs +0 -171
  136. package/dist/components/TicketConversation/components/CodeBlockInserter.cjs +0 -156
  137. package/dist/components/TicketConversation/components/QuickActions.cjs +0 -87
  138. package/dist/components/TicketConversation/components/TicketHeader.cjs +0 -93
  139. package/dist/components/TicketConversation/components/TimeTrackingPanel.cjs +0 -134
  140. package/dist/components/TicketConversation/config.cjs +0 -44
  141. package/dist/components/TicketConversation/constants.cjs +0 -127
  142. package/dist/components/TicketConversation/context.cjs +0 -13
  143. package/dist/components/TicketConversation/hooks/useAI.cjs +0 -196
  144. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +0 -20
  145. package/dist/components/TicketConversation/hooks/useMessageActions.cjs +0 -136
  146. package/dist/components/TicketConversation/hooks/useReply.cjs +0 -188
  147. package/dist/components/TicketConversation/hooks/useTicketActions.cjs +0 -290
  148. package/dist/components/TicketConversation/hooks/useTimeTracking.cjs +0 -123
  149. package/dist/components/TicketConversation/hooks/useTranslation.cjs +0 -78
  150. package/dist/components/TicketConversation/index.cjs +0 -1114
  151. package/dist/components/TicketConversation/types.cjs +0 -2
  152. package/dist/components/TicketConversation/utils.cjs +0 -27
  153. package/dist/views/BillingView/client.cjs +0 -469
  154. package/dist/views/BillingView/index.cjs +0 -34
  155. package/dist/views/ChatView/client.cjs +0 -301
  156. package/dist/views/ChatView/index.cjs +0 -34
  157. package/dist/views/CrmView/client.cjs +0 -458
  158. package/dist/views/CrmView/index.cjs +0 -34
  159. package/dist/views/EmailTrackingView/client.cjs +0 -171
  160. package/dist/views/EmailTrackingView/index.cjs +0 -34
  161. package/dist/views/ImportConversationView/client.cjs +0 -238
  162. package/dist/views/ImportConversationView/index.cjs +0 -34
  163. package/dist/views/LogsView/client.cjs +0 -148
  164. package/dist/views/LogsView/index.cjs +0 -32
  165. package/dist/views/NewTicketView/client.cjs +0 -213
  166. package/dist/views/NewTicketView/index.cjs +0 -32
  167. package/dist/views/PendingEmailsView/client.cjs +0 -471
  168. package/dist/views/PendingEmailsView/index.cjs +0 -34
  169. package/dist/views/SupportDashboardView/client.cjs +0 -437
  170. package/dist/views/SupportDashboardView/index.cjs +0 -34
  171. package/dist/views/TicketDetailView/NextActionItem.cjs +0 -40
  172. package/dist/views/TicketDetailView/RewriteDropdown.cjs +0 -80
  173. package/dist/views/TicketDetailView/client.cjs +0 -1412
  174. package/dist/views/TicketDetailView/constants.cjs +0 -20
  175. package/dist/views/TicketDetailView/helpers.cjs +0 -23
  176. package/dist/views/TicketDetailView/index.cjs +0 -34
  177. package/dist/views/TicketDetailView/types.cjs +0 -2
  178. package/dist/views/TicketInboxView/client.cjs +0 -359
  179. package/dist/views/TicketInboxView/index.cjs +0 -32
  180. package/dist/views/TicketingSettingsView/client.cjs +0 -740
  181. package/dist/views/TicketingSettingsView/index.cjs +0 -34
  182. package/dist/views/TimeDashboardView/client.cjs +0 -180
  183. package/dist/views/TimeDashboardView/index.cjs +0 -34
  184. package/dist/views/shared/AdminViewHeader.cjs +0 -68
  185. package/dist/views/shared/ErrorBoundary.cjs +0 -55
  186. package/dist/views/shared/Skeleton.cjs +0 -77
  187. package/dist/views/shared/StatusPill.cjs +0 -47
  188. package/dist/views/shared/adminTokens.cjs +0 -34
  189. package/dist/views/shared/config.cjs +0 -44
  190. package/dist/views/shared/dateLocale.cjs +0 -5
  191. package/dist/views/shared/index.cjs +0 -72
  192. package/dist/views/shared/sla.cjs +0 -37
  193. package/dist/views.cjs +0 -86
  194. package/dist/views.d.cts +0 -13
  195. package/src/__tests__/aiSummaryRendering.test.ts +0 -21
  196. package/src/__tests__/authResponses.test.ts +0 -69
  197. package/src/__tests__/capabilities.test.ts +0 -71
  198. package/src/__tests__/generateTrackingToken.test.ts +0 -67
  199. package/src/__tests__/integration/ai-agent.test.ts +0 -46
  200. package/src/__tests__/integration/auth.test.ts +0 -43
  201. package/src/__tests__/integration/automation-rules.test.ts +0 -68
  202. package/src/__tests__/integration/buildTestPayload.ts +0 -52
  203. package/src/__tests__/integration/channels.test.ts +0 -52
  204. package/src/__tests__/integration/core-behaviors.test.ts +0 -81
  205. package/src/__tests__/integration/dashboard-volume.test.ts +0 -31
  206. package/src/__tests__/integration/digest.test.ts +0 -48
  207. package/src/__tests__/integration/invoice-pdf.test.ts +0 -30
  208. package/src/__tests__/integration/isolation.test.ts +0 -81
  209. package/src/__tests__/integration/mentions-invoice.test.ts +0 -50
  210. package/src/__tests__/integration/nps.test.ts +0 -37
  211. package/src/__tests__/integration/per-team-sla.test.ts +0 -44
  212. package/src/__tests__/integration/push.test.ts +0 -75
  213. package/src/__tests__/integration/sanitization.test.ts +0 -35
  214. package/src/__tests__/integration/sla-pause.test.ts +0 -39
  215. package/src/__tests__/integration/smoke.test.ts +0 -26
  216. package/src/__tests__/integration/snooze.test.ts +0 -68
  217. package/src/__tests__/integration/teams.test.ts +0 -38
  218. package/src/__tests__/rateLimiter.test.ts +0 -83
  219. package/src/__tests__/sanitizeHtml.test.ts +0 -165
  220. package/src/__tests__/sla.test.ts +0 -258
  221. package/src/__tests__/trackOpenEndpoint.test.ts +0 -54
  222. package/src/__tests__/webhookSecurity.test.ts +0 -58
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ export interface RichTextEditorHandle {
3
+ clear: () => void;
4
+ setContent: (html: string) => void;
5
+ getHtml: () => string;
6
+ getPlainText: () => string;
7
+ focus: () => void;
8
+ }
9
+ interface Props {
10
+ initialValue?: string;
11
+ onChange: (html: string, plainText: string) => void;
12
+ placeholder?: string;
13
+ minHeight?: number;
14
+ onFileUpload?: (file: File) => Promise<string | null>;
15
+ borderColor?: string;
16
+ focusBorderColor?: string;
17
+ }
18
+ export declare const RichTextEditor: React.ForwardRefExoticComponent<Props & React.RefAttributes<RichTextEditorHandle>>;
19
+ export {};
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export declare const RewriteDropdown: React.FC<{
3
+ disabled: boolean;
4
+ loading: boolean;
5
+ onSelect: (style: string) => void;
6
+ }>;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export declare function SkeletonText({ lines }: {
3
+ lines?: number;
4
+ }): React.JSX.Element;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ interface AISummaryPanelProps {
3
+ showAiSummary: boolean;
4
+ setShowAiSummary: (v: boolean) => void;
5
+ aiSummary: string;
6
+ aiGenerating: boolean;
7
+ aiSaving: boolean;
8
+ aiSaved: boolean;
9
+ handleAiGenerate: () => void;
10
+ handleAiSave: () => void;
11
+ }
12
+ export declare function renderAiSummary(summary: string): React.ReactNode[];
13
+ export declare function AISummaryPanel({ showAiSummary, setShowAiSummary, aiSummary, aiGenerating, aiSaving, aiSaved, handleAiGenerate, handleAiSave, }: AISummaryPanelProps): React.JSX.Element;
14
+ export {};
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ interface MergePanelProps {
3
+ mergeTarget: string;
4
+ setMergeTarget: (v: string) => void;
5
+ mergeTargetInfo: {
6
+ id: number;
7
+ ticketNumber: string;
8
+ subject: string;
9
+ } | null;
10
+ setMergeTargetInfo: (v: null) => void;
11
+ mergeError: string;
12
+ setMergeError: (v: string) => void;
13
+ merging: boolean;
14
+ handleMergeLookup: () => void;
15
+ handleMerge: () => void;
16
+ }
17
+ export declare function MergePanel({ mergeTarget, setMergeTarget, mergeTargetInfo, setMergeTargetInfo, mergeError, setMergeError, merging, handleMergeLookup, handleMerge, }: MergePanelProps): React.JSX.Element;
18
+ interface ExtMessagePanelProps {
19
+ extMsgBody: string;
20
+ setExtMsgBody: (v: string) => void;
21
+ extMsgAuthor: 'client' | 'admin';
22
+ setExtMsgAuthor: (v: 'client' | 'admin') => void;
23
+ extMsgDate: string;
24
+ setExtMsgDate: (v: string) => void;
25
+ extMsgFiles: File[];
26
+ setExtMsgFiles: React.Dispatch<React.SetStateAction<File[]>>;
27
+ sendingExtMsg: boolean;
28
+ handleSendExtMsg: () => void;
29
+ handleExtFileChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
30
+ }
31
+ export declare function ExtMessagePanel({ extMsgBody, setExtMsgBody, extMsgAuthor, setExtMsgAuthor, extMsgDate, setExtMsgDate, extMsgFiles, setExtMsgFiles, sendingExtMsg, handleSendExtMsg, handleExtFileChange, }: ExtMessagePanelProps): React.JSX.Element;
32
+ interface ReminderPanelProps {
33
+ clientFirstName: string;
34
+ clientEmail: string;
35
+ reminderHours: number;
36
+ setReminderHours: (v: number) => void;
37
+ reminderSending: boolean;
38
+ reminderError: string;
39
+ handleSendReminder: () => void;
40
+ }
41
+ export declare function ReminderPanel({ clientFirstName, clientEmail, reminderHours, setReminderHours, reminderSending, reminderError, handleSendReminder, }: ReminderPanelProps): React.JSX.Element;
42
+ interface SnoozePanelProps {
43
+ snoozeSaving: boolean;
44
+ handleSnooze: (days: number | null, customDate?: string) => void;
45
+ }
46
+ export declare function SnoozePanel({ snoozeSaving, handleSnooze }: SnoozePanelProps): React.JSX.Element;
47
+ export {};
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { ActivityEntry } from '../types.js';
3
+ export declare function ActivityLog({ activityLog }: {
4
+ activityLog: ActivityEntry[];
5
+ }): React.JSX.Element;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { ClientInfo } from '../types.js';
3
+ export declare function ClientBar({ client }: {
4
+ client: ClientInfo;
5
+ }): React.JSX.Element;
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import type { ClientInfo } from '../types.js';
3
+ interface ClientHistoryProps {
4
+ client: ClientInfo;
5
+ clientTickets: Array<{
6
+ id: number;
7
+ ticketNumber: string;
8
+ subject: string;
9
+ status: string;
10
+ createdAt: string;
11
+ }>;
12
+ clientProjects: Array<{
13
+ id: number;
14
+ name: string;
15
+ status: string;
16
+ }>;
17
+ clientNotes: string;
18
+ onNotesChange: (notes: string) => void;
19
+ onNotesSave: () => void;
20
+ savingNotes: boolean;
21
+ notesSaved: boolean;
22
+ }
23
+ export declare function ClientHistory({ client: _client, clientTickets, clientProjects, clientNotes, onNotesChange, onNotesSave, savingNotes, notesSaved, }: ClientHistoryProps): React.JSX.Element;
24
+ export {};
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ /**
3
+ * Checks if text contains fenced code blocks.
4
+ */
5
+ export declare function hasCodeBlocks(text: string): boolean;
6
+ /**
7
+ * Renders the FULL message text, replacing fenced code blocks with styled components.
8
+ * Use this INSTEAD of rendering msg.body directly when code blocks are present.
9
+ */
10
+ export declare function MessageWithCodeBlocks({ text, style }: {
11
+ text: string;
12
+ style?: React.CSSProperties;
13
+ }): React.JSX.Element;
14
+ /**
15
+ * For HTML content: strips tags (preserving newlines), then renders with code blocks.
16
+ */
17
+ export declare function MessageWithCodeBlocksHtml({ html, style }: {
18
+ html: string;
19
+ style?: React.CSSProperties;
20
+ }): React.JSX.Element | null;
21
+ export declare function CodeBlockRenderer({ text }: {
22
+ text: string;
23
+ }): React.JSX.Element | null;
24
+ export declare function CodeBlockRendererHtml({ html }: {
25
+ html: string;
26
+ }): React.JSX.Element;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ interface CodeBlockInserterProps {
3
+ onInsert: (block: string) => void;
4
+ className?: string;
5
+ style?: React.CSSProperties;
6
+ }
7
+ /**
8
+ * Toolbar button that opens a language picker dropdown.
9
+ * When a language is selected, calls onInsert with the fenced code block template.
10
+ */
11
+ export declare function CodeBlockInserter({ onInsert, className, style }: CodeBlockInserterProps): React.JSX.Element;
12
+ export {};
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ interface QuickActionsProps {
3
+ statusTransitions: Array<{
4
+ status: string;
5
+ label: string;
6
+ color: string;
7
+ }>;
8
+ statusUpdating: boolean;
9
+ onStatusChange: (status: string) => void;
10
+ snoozeUntil: string | null;
11
+ snoozeSaving: boolean;
12
+ onCancelSnooze: () => void;
13
+ showMerge: boolean;
14
+ showExtMsg: boolean;
15
+ showSnooze: boolean;
16
+ onToggleMerge: () => void;
17
+ onToggleExtMsg: () => void;
18
+ onToggleSnooze: () => void;
19
+ onNextTicket: () => void;
20
+ showReminderButton: boolean;
21
+ onToggleReminder: () => void;
22
+ autoCloseScheduledAt: string | null;
23
+ onCancelScheduledClose: () => void;
24
+ cancelingClose: boolean;
25
+ reminderSuccess: boolean;
26
+ showNextTicket: boolean;
27
+ nextTicketId: number | null;
28
+ nextTicketInfo: string;
29
+ onCloseNextTicket: () => void;
30
+ }
31
+ export declare function QuickActions({ statusTransitions, statusUpdating, onStatusChange, snoozeUntil, snoozeSaving, onCancelSnooze, showMerge: _showMerge, showExtMsg: _showExtMsg, showSnooze: _showSnooze, onToggleMerge, onToggleExtMsg, onToggleSnooze, onNextTicket, showReminderButton, onToggleReminder, autoCloseScheduledAt, onCancelScheduledClose, cancelingClose, reminderSuccess, showNextTicket, nextTicketId, nextTicketInfo, onCloseNextTicket, }: QuickActionsProps): React.JSX.Element;
32
+ export {};
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import type { SatisfactionSurvey } from '../types.js';
3
+ interface TicketHeaderProps {
4
+ ticketNumber: string;
5
+ currentStatus: string;
6
+ clientSentiment: {
7
+ emoji: string;
8
+ label: string;
9
+ color: string;
10
+ } | null;
11
+ ticketSource: string;
12
+ chatSession: string;
13
+ snoozeUntil: string | null;
14
+ satisfaction: SatisfactionSurvey | null;
15
+ copiedLink: 'admin' | 'client' | null;
16
+ onCopyLink: (type: 'admin' | 'client') => void;
17
+ }
18
+ export declare function TicketHeader({ ticketNumber, currentStatus, clientSentiment, ticketSource, chatSession, snoozeUntil, satisfaction, copiedLink, onCopyLink, }: TicketHeaderProps): React.JSX.Element;
19
+ export {};
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import type { TimeEntry } from '../types.js';
3
+ interface TimeTrackingPanelProps {
4
+ timeEntries: TimeEntry[];
5
+ totalMinutes: number;
6
+ timerRunning: boolean;
7
+ timerSeconds: number;
8
+ setTimerSeconds: React.Dispatch<React.SetStateAction<number>>;
9
+ timerDescription: string;
10
+ setTimerDescription: (v: string) => void;
11
+ handleTimerStart: (reset?: boolean) => void;
12
+ handleTimerStop: () => void;
13
+ handleTimerSave: () => void;
14
+ handleTimerDiscard: () => void;
15
+ duration: string;
16
+ setDuration: (v: string) => void;
17
+ timeDescription: string;
18
+ setTimeDescription: (v: string) => void;
19
+ handleAddTime: () => void;
20
+ addingTime: boolean;
21
+ timeSuccess: string;
22
+ }
23
+ export declare function TimeTrackingPanel({ timeEntries, totalMinutes, timerRunning, timerSeconds, setTimerSeconds, timerDescription, setTimerDescription, handleTimerStart, handleTimerStop, handleTimerSave, handleTimerDiscard, duration, setDuration, timeDescription, setTimeDescription, handleAddTime, addingTime, timeSuccess, }: TimeTrackingPanelProps): React.JSX.Element;
24
+ export {};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Ticketing feature flags — re-export of the shared implementation.
3
+ *
4
+ * The flags used to be defined (twice, byte-for-byte) here and in
5
+ * `views/shared/config.ts`, each reading `localStorage` directly. The single
6
+ * implementation now lives in `utils/features.ts` and is backed by the server;
7
+ * both modules are kept as import sites so existing paths keep working.
8
+ */
9
+ export { DEFAULT_TICKETING_FEATURES, DEFAULT_TICKETING_FEATURES as DEFAULT_FEATURES, FEATURES_CACHE_KEY, fetchFeatures, getFeatures, normalizeFeatures, saveFeatures, } from '../../utils/features.js';
10
+ export type { TicketingFeatures } from '../../utils/features.js';
@@ -1,41 +1,2 @@
1
1
  "use client";
2
- const DEFAULT_FEATURES = {
3
- timeTracking: true,
4
- ai: true,
5
- satisfaction: true,
6
- chat: true,
7
- emailTracking: true,
8
- canned: true,
9
- merge: true,
10
- snooze: true,
11
- externalMessages: true,
12
- clientHistory: true,
13
- activityLog: true,
14
- splitTicket: true,
15
- scheduledReplies: true,
16
- autoClose: true,
17
- autoCloseDays: 7,
18
- roundRobin: false
19
- };
20
- const STORAGE_KEY = "ticketing_features";
21
- function getFeatures() {
22
- if (typeof window === "undefined") return DEFAULT_FEATURES;
23
- try {
24
- const stored = localStorage.getItem(STORAGE_KEY);
25
- if (stored) {
26
- const parsed = JSON.parse(stored);
27
- return { ...DEFAULT_FEATURES, ...parsed };
28
- }
29
- } catch {
30
- }
31
- return DEFAULT_FEATURES;
32
- }
33
- function saveFeatures(features) {
34
- if (typeof window === "undefined") return;
35
- try {
36
- localStorage.setItem(STORAGE_KEY, JSON.stringify(features));
37
- } catch {
38
- }
39
- }
40
-
41
- export { DEFAULT_FEATURES, getFeatures, saveFeatures };
2
+ export { DEFAULT_TICKETING_FEATURES as DEFAULT_FEATURES, DEFAULT_TICKETING_FEATURES, FEATURES_CACHE_KEY, fetchFeatures, getFeatures, normalizeFeatures, saveFeatures } from '../../utils/features.js';
@@ -0,0 +1,56 @@
1
+ import type React from 'react';
2
+ export declare const REWRITE_STYLES: {
3
+ id: string;
4
+ label: string;
5
+ desc: string;
6
+ }[];
7
+ export declare const layoutStyles: {
8
+ root: React.CSSProperties;
9
+ twoColumns: React.CSSProperties;
10
+ mainColumn: React.CSSProperties;
11
+ sideColumn: React.CSSProperties;
12
+ };
13
+ export declare const statusLabels: Record<string, {
14
+ label: string;
15
+ bg: string;
16
+ color: string;
17
+ }>;
18
+ export declare const projectStatusLabels: Record<string, {
19
+ label: string;
20
+ bg: string;
21
+ color: string;
22
+ }>;
23
+ export declare const C: {
24
+ blue: string;
25
+ amber: string;
26
+ orange: string;
27
+ black: string;
28
+ white: string;
29
+ bg: string;
30
+ textPrimary: string;
31
+ textSecondary: string;
32
+ textMuted: string;
33
+ border: string;
34
+ statusOpen: string;
35
+ statusProgress: string;
36
+ statusWaiting: string;
37
+ statusResolved: string;
38
+ statusClosed: string;
39
+ adminBg: string;
40
+ adminBorder: string;
41
+ clientBg: string;
42
+ clientBorder: string;
43
+ emailBg: string;
44
+ emailBorder: string;
45
+ internalBg: string;
46
+ internalBorder: string;
47
+ };
48
+ export declare const s: {
49
+ section: React.CSSProperties;
50
+ sectionTitle: React.CSSProperties;
51
+ btn: (bg: string, disabled?: boolean) => React.CSSProperties;
52
+ ghostBtn: (color: string, disabled?: boolean) => React.CSSProperties;
53
+ outlineBtn: (color: string, disabled?: boolean) => React.CSSProperties;
54
+ input: React.CSSProperties;
55
+ badge: (bg: string, color: string) => React.CSSProperties;
56
+ };
@@ -0,0 +1,53 @@
1
+ import type { Message, TimeEntry, ClientInfo, CannedResponse, ActivityEntry, SatisfactionSurvey } from './types.js';
2
+ /**
3
+ * Handle interface for the RichTextEditor component.
4
+ * When used inside the plugin, the consumer must provide a compatible editor
5
+ * or leave the ref unused.
6
+ */
7
+ export interface RichTextEditorHandle {
8
+ setContent: (html: string) => void;
9
+ clear: () => void;
10
+ focus: () => void;
11
+ }
12
+ export interface TicketContextValue {
13
+ id: string | number | undefined;
14
+ messages: Message[];
15
+ timeEntries: TimeEntry[];
16
+ client: ClientInfo | null;
17
+ cannedResponses: CannedResponse[];
18
+ activityLog: ActivityEntry[];
19
+ satisfaction: SatisfactionSurvey | null;
20
+ loading: boolean;
21
+ currentStatus: string;
22
+ ticketNumber: string;
23
+ ticketSubject: string;
24
+ ticketSource: string;
25
+ chatSession: string;
26
+ snoozeUntil: string | null;
27
+ lastClientReadAt: string | null;
28
+ clientTickets: Array<{
29
+ id: number;
30
+ ticketNumber: string;
31
+ subject: string;
32
+ status: string;
33
+ createdAt: string;
34
+ }>;
35
+ clientProjects: Array<{
36
+ id: number;
37
+ name: string;
38
+ status: string;
39
+ }>;
40
+ clientNotes: string;
41
+ clientSentiment: {
42
+ emoji: string;
43
+ label: string;
44
+ color: string;
45
+ } | null;
46
+ clientTyping: boolean;
47
+ clientTypingName: string;
48
+ fetchAll: () => void;
49
+ sendAdminTyping: () => void;
50
+ replyEditorRef: React.RefObject<RichTextEditorHandle | null>;
51
+ }
52
+ export declare const TicketContext: import("react").Context<TicketContextValue | null>;
53
+ export declare function useTicketContext(): TicketContextValue;
@@ -0,0 +1,21 @@
1
+ import type { Message, ClientInfo } from '../types.js';
2
+ import type { RichTextEditorHandle } from '../context.js';
3
+ export declare function useAI(messages: Message[], client: ClientInfo | null, ticketSubject: string, replyBody: string, setReplyBody: (v: string) => void, setReplyHtml: (v: string) => void, replyEditorRef: React.RefObject<RichTextEditorHandle | null>): {
4
+ clientSentiment: {
5
+ emoji: string;
6
+ label: string;
7
+ color: string;
8
+ } | null;
9
+ aiReplying: boolean;
10
+ handleAiSuggestReply: () => Promise<void>;
11
+ aiRewriting: boolean;
12
+ handleAiRewrite: (style?: string) => Promise<void>;
13
+ showAiSummary: boolean;
14
+ setShowAiSummary: import("react").Dispatch<import("react").SetStateAction<boolean>>;
15
+ aiSummary: string;
16
+ aiGenerating: boolean;
17
+ handleAiGenerate: () => Promise<void>;
18
+ aiSaving: boolean;
19
+ aiSaved: boolean;
20
+ handleAiSave: (id: string | number | undefined, fetchAll: () => void) => Promise<void>;
21
+ };
@@ -0,0 +1,3 @@
1
+ export declare function useDocumentIdFromUrl(): {
2
+ id: string | number | undefined;
3
+ };
@@ -0,0 +1,23 @@
1
+ import { type TicketingFeatures } from '../../../utils/features.js';
2
+ export interface UseFeaturesResult {
3
+ /** Current flags — cached values on first paint, server values once loaded. */
4
+ features: TicketingFeatures;
5
+ /** True until the first server round-trip settles. */
6
+ loading: boolean;
7
+ /** True when the server could not be reached and cached/default values are shown. */
8
+ offline: boolean;
9
+ /** Replace the flags locally without persisting (for a settings form). */
10
+ setFeatures: (features: TicketingFeatures) => void;
11
+ /** Persist the flags server-side. Resolves to false when the write failed. */
12
+ save: (features: TicketingFeatures) => Promise<boolean>;
13
+ }
14
+ /**
15
+ * Read the ticketing feature flags from the server, with the local cache as a
16
+ * fallback so a screen never blocks on the settings call.
17
+ *
18
+ * Also performs the one-shot migration of pre-2.1 installs: when this browser
19
+ * still holds flags in `localStorage` and the server has never had any saved,
20
+ * the local values are pushed up once and become the shared truth. Afterwards
21
+ * the server always wins and `localStorage` is only a cache.
22
+ */
23
+ export declare function useFeatures(): UseFeaturesResult;
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import { useState, useRef, useEffect, useCallback } from 'react';
3
+ import { getFeatures, fetchFeatures, readLegacyFeatures, saveFeatures, markLegacyFeaturesAdopted, hasAdoptedLegacyFeatures, writeFeaturesCache } from '../../../utils/features.js';
4
+
5
+ function useFeatures() {
6
+ const [features, setFeatures] = useState(() => getFeatures());
7
+ const [loading, setLoading] = useState(true);
8
+ const [offline, setOffline] = useState(false);
9
+ const migrationAttempted = useRef(false);
10
+ const dirty = useRef(false);
11
+ useEffect(() => {
12
+ const controller = new AbortController();
13
+ let cancelled = false;
14
+ void (async () => {
15
+ const result = await fetchFeatures(controller.signal);
16
+ if (cancelled) return;
17
+ if (!result.offline && !result.configured && !migrationAttempted.current && !dirty.current) {
18
+ migrationAttempted.current = true;
19
+ const legacy = readLegacyFeatures();
20
+ if (legacy) {
21
+ const ok = await saveFeatures(legacy);
22
+ if (cancelled) return;
23
+ if (ok) {
24
+ markLegacyFeaturesAdopted();
25
+ setFeatures(legacy);
26
+ setLoading(false);
27
+ return;
28
+ }
29
+ }
30
+ }
31
+ if (!result.offline && !hasAdoptedLegacyFeatures()) {
32
+ markLegacyFeaturesAdopted();
33
+ }
34
+ if (!dirty.current) setFeatures(result.features);
35
+ setOffline(result.offline);
36
+ setLoading(false);
37
+ })();
38
+ return () => {
39
+ cancelled = true;
40
+ controller.abort();
41
+ };
42
+ }, []);
43
+ const setLocalFeatures = useCallback((next) => {
44
+ dirty.current = true;
45
+ setFeatures(next);
46
+ writeFeaturesCache(next);
47
+ }, []);
48
+ const save = useCallback(async (next) => {
49
+ const ok = await saveFeatures(next);
50
+ if (ok) {
51
+ markLegacyFeaturesAdopted();
52
+ dirty.current = false;
53
+ setFeatures(next);
54
+ setOffline(false);
55
+ }
56
+ return ok;
57
+ }, []);
58
+ return { features, loading, offline, setFeatures: setLocalFeatures, save };
59
+ }
60
+
61
+ export { useFeatures };
@@ -0,0 +1,20 @@
1
+ import type { Message, ClientInfo } from '../types.js';
2
+ export declare function useMessageActions(id: string | number | undefined, client: ClientInfo | null, fetchAll: () => void): {
3
+ togglingAuthor: string | number | null;
4
+ editingMsg: string | number | null;
5
+ editBody: string;
6
+ editHtml: string;
7
+ setEditHtml: import("react").Dispatch<import("react").SetStateAction<string>>;
8
+ savingEdit: boolean;
9
+ handleEditStart: (msg: Message) => void;
10
+ handleEditSave: (msgId: string | number) => Promise<void>;
11
+ handleEditCancel: () => void;
12
+ deletingMsg: string | number | null;
13
+ handleDelete: (msgId: string | number) => Promise<void>;
14
+ resendingMsg: string | number | null;
15
+ resendSuccess: string | number | null;
16
+ handleResend: (msgId: string | number) => Promise<void>;
17
+ handleToggleAuthor: (msgId: string | number, currentType: string) => Promise<void>;
18
+ handleSplitMessage: (msgId: string | number, ticketSubject: string) => Promise<void>;
19
+ setEditBody: import("react").Dispatch<import("react").SetStateAction<string>>;
20
+ };
@@ -0,0 +1,27 @@
1
+ import type { ClientInfo, CannedResponse } from '../types.js';
2
+ import type { RichTextEditorHandle } from '../context.js';
3
+ export declare function useReply(id: string | number | undefined, client: ClientInfo | null, cannedResponses: CannedResponse[], ticketNumber: string, ticketSubject: string, fetchAll: () => void, handleNextTicket: () => void, replyEditorRef: React.RefObject<RichTextEditorHandle | null>): {
4
+ fileInputRef: import("react").RefObject<HTMLInputElement | null>;
5
+ replyBody: string;
6
+ setReplyBody: import("react").Dispatch<import("react").SetStateAction<string>>;
7
+ replyHtml: string;
8
+ setReplyHtml: import("react").Dispatch<import("react").SetStateAction<string>>;
9
+ replyFiles: File[];
10
+ setReplyFiles: import("react").Dispatch<import("react").SetStateAction<File[]>>;
11
+ isInternal: boolean;
12
+ setIsInternal: import("react").Dispatch<import("react").SetStateAction<boolean>>;
13
+ notifyClient: boolean;
14
+ setNotifyClient: import("react").Dispatch<import("react").SetStateAction<boolean>>;
15
+ sendAsClient: boolean;
16
+ setSendAsClient: import("react").Dispatch<import("react").SetStateAction<boolean>>;
17
+ sending: boolean;
18
+ showSchedule: boolean;
19
+ setShowSchedule: import("react").Dispatch<import("react").SetStateAction<boolean>>;
20
+ scheduleDate: string;
21
+ setScheduleDate: import("react").Dispatch<import("react").SetStateAction<string>>;
22
+ handleEditorFileUpload: (file: File) => Promise<string | null>;
23
+ handleCannedSelect: (e: React.ChangeEvent<HTMLSelectElement>) => void;
24
+ handleReplyFileChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
25
+ handleSendReply: () => Promise<void>;
26
+ handleScheduleReply: () => Promise<void>;
27
+ };
@@ -0,0 +1,58 @@
1
+ export declare function useTicketActions(id: string | number | undefined, fetchAll: () => void): {
2
+ statusUpdating: boolean;
3
+ handleStatusChange: (newStatus: string) => Promise<void>;
4
+ showMerge: boolean;
5
+ setShowMerge: import("react").Dispatch<import("react").SetStateAction<boolean>>;
6
+ mergeTarget: string;
7
+ setMergeTarget: import("react").Dispatch<import("react").SetStateAction<string>>;
8
+ mergeTargetInfo: {
9
+ id: number;
10
+ ticketNumber: string;
11
+ subject: string;
12
+ } | null;
13
+ setMergeTargetInfo: import("react").Dispatch<import("react").SetStateAction<{
14
+ id: number;
15
+ ticketNumber: string;
16
+ subject: string;
17
+ } | null>>;
18
+ mergeError: string;
19
+ setMergeError: import("react").Dispatch<import("react").SetStateAction<string>>;
20
+ merging: boolean;
21
+ handleMergeLookup: () => Promise<void>;
22
+ handleMerge: () => Promise<void>;
23
+ showExtMsg: boolean;
24
+ setShowExtMsg: import("react").Dispatch<import("react").SetStateAction<boolean>>;
25
+ extMsgBody: string;
26
+ setExtMsgBody: import("react").Dispatch<import("react").SetStateAction<string>>;
27
+ extMsgAuthor: "client" | "admin";
28
+ setExtMsgAuthor: import("react").Dispatch<import("react").SetStateAction<"client" | "admin">>;
29
+ extMsgDate: string;
30
+ setExtMsgDate: import("react").Dispatch<import("react").SetStateAction<string>>;
31
+ extMsgFiles: File[];
32
+ setExtMsgFiles: import("react").Dispatch<import("react").SetStateAction<File[]>>;
33
+ sendingExtMsg: boolean;
34
+ handleExtFileChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
35
+ handleSendExtMsg: () => Promise<void>;
36
+ showSnooze: boolean;
37
+ setShowSnooze: import("react").Dispatch<import("react").SetStateAction<boolean>>;
38
+ snoozeUntil: string | null;
39
+ setSnoozeUntil: import("react").Dispatch<import("react").SetStateAction<string | null>>;
40
+ snoozeSaving: boolean;
41
+ handleSnooze: (days: number | null, customDate?: string) => Promise<void>;
42
+ showReminder: boolean;
43
+ setShowReminder: import("react").Dispatch<import("react").SetStateAction<boolean>>;
44
+ reminderHours: number;
45
+ setReminderHours: import("react").Dispatch<import("react").SetStateAction<number>>;
46
+ reminderSending: boolean;
47
+ reminderError: string;
48
+ setReminderError: import("react").Dispatch<import("react").SetStateAction<string>>;
49
+ reminderSuccess: boolean;
50
+ handleSendReminder: () => Promise<void>;
51
+ cancelingClose: boolean;
52
+ handleCancelScheduledClose: () => Promise<void>;
53
+ showNextTicket: boolean;
54
+ setShowNextTicket: import("react").Dispatch<import("react").SetStateAction<boolean>>;
55
+ nextTicketId: number | null;
56
+ nextTicketInfo: string;
57
+ handleNextTicket: () => Promise<void>;
58
+ };
@@ -0,0 +1,18 @@
1
+ export declare function useTimeTracking(id: string | number | undefined, fetchAll: () => void): {
2
+ duration: string;
3
+ setDuration: import("react").Dispatch<import("react").SetStateAction<string>>;
4
+ timeDescription: string;
5
+ setTimeDescription: import("react").Dispatch<import("react").SetStateAction<string>>;
6
+ addingTime: boolean;
7
+ timeSuccess: string;
8
+ timerRunning: boolean;
9
+ timerSeconds: number;
10
+ setTimerSeconds: import("react").Dispatch<import("react").SetStateAction<number>>;
11
+ timerDescription: string;
12
+ setTimerDescription: import("react").Dispatch<import("react").SetStateAction<string>>;
13
+ handleAddTime: () => Promise<void>;
14
+ handleTimerStart: (reset?: boolean) => void;
15
+ handleTimerStop: () => void;
16
+ handleTimerSave: () => Promise<void>;
17
+ handleTimerDiscard: () => void;
18
+ };