@consilioweb/payload-support 2.0.1 → 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 (215) hide show
  1. package/README.md +636 -402
  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/index.d.ts +4 -0
  29. package/dist/components/TicketConversation/index.js +2 -2
  30. package/dist/components/TicketConversation/types.d.ts +56 -0
  31. package/dist/components/TicketConversation/utils.d.ts +2 -0
  32. package/dist/index.cjs +392 -320
  33. package/dist/index.d.cts +100 -3
  34. package/dist/index.d.ts +100 -3
  35. package/dist/index.js +388 -321
  36. package/dist/utils/features.d.ts +123 -0
  37. package/dist/utils/features.js +147 -0
  38. package/dist/views/BillingView/client.d.ts +2 -0
  39. package/dist/views/BillingView/index.d.ts +4 -0
  40. package/dist/views/ChatView/client.d.ts +2 -0
  41. package/dist/views/ChatView/client.js +9 -9
  42. package/dist/views/ChatView/index.d.ts +4 -0
  43. package/dist/views/CrmView/client.d.ts +2 -0
  44. package/dist/views/CrmView/client.js +6 -9
  45. package/dist/views/CrmView/index.d.ts +4 -0
  46. package/dist/views/EmailTrackingView/client.d.ts +2 -0
  47. package/dist/views/EmailTrackingView/index.d.ts +4 -0
  48. package/dist/views/ImportConversationView/client.d.ts +2 -0
  49. package/dist/views/ImportConversationView/index.d.ts +4 -0
  50. package/dist/views/LogsView/client.d.ts +2 -0
  51. package/dist/views/LogsView/index.d.ts +4 -0
  52. package/dist/views/NewTicketView/client.d.ts +2 -0
  53. package/dist/views/NewTicketView/index.d.ts +4 -0
  54. package/dist/views/PendingEmailsView/client.d.ts +2 -0
  55. package/dist/views/PendingEmailsView/index.d.ts +4 -0
  56. package/dist/views/SupportDashboardView/client.d.ts +2 -0
  57. package/dist/views/SupportDashboardView/index.d.ts +4 -0
  58. package/dist/views/TicketDetailView/NextActionItem.d.ts +6 -0
  59. package/dist/views/TicketDetailView/RewriteDropdown.d.ts +7 -0
  60. package/dist/views/TicketDetailView/client.d.ts +2 -0
  61. package/dist/views/TicketDetailView/client.js +2 -2
  62. package/dist/views/TicketDetailView/constants.d.ts +13 -0
  63. package/dist/views/TicketDetailView/helpers.d.ts +2 -0
  64. package/dist/views/TicketDetailView/index.d.ts +4 -0
  65. package/dist/views/TicketDetailView/types.d.ts +40 -0
  66. package/dist/views/TicketInboxView/client.d.ts +2 -0
  67. package/dist/views/TicketInboxView/client.js +5 -5
  68. package/dist/views/TicketInboxView/index.d.ts +4 -0
  69. package/dist/views/TicketingSettingsView/client.d.ts +2 -0
  70. package/dist/views/TicketingSettingsView/client.js +5 -4
  71. package/dist/views/TicketingSettingsView/index.d.ts +4 -0
  72. package/dist/views/TimeDashboardView/client.d.ts +2 -0
  73. package/dist/views/TimeDashboardView/index.d.ts +4 -0
  74. package/dist/views/shared/AdminViewHeader.d.ts +13 -0
  75. package/dist/views/shared/ErrorBoundary.d.ts +17 -0
  76. package/dist/views/shared/Skeleton.d.ts +21 -0
  77. package/dist/views/shared/StatusPill.d.ts +8 -0
  78. package/dist/views/shared/adminTokens.d.ts +19 -0
  79. package/dist/views/shared/config.d.ts +8 -0
  80. package/dist/views/shared/config.js +1 -40
  81. package/dist/views/shared/dateLocale.d.ts +5 -0
  82. package/dist/views/shared/index.d.ts +12 -0
  83. package/dist/views/shared/index.js +2 -1
  84. package/dist/views/shared/sla.d.ts +14 -0
  85. package/dist/views.d.ts +13 -13
  86. package/package.json +16 -31
  87. package/src/collections/SupportClients.ts +29 -0
  88. package/src/collections/TicketCollaborators.ts +6 -1
  89. package/src/collections/TicketMessages.ts +46 -24
  90. package/src/collections/Tickets.ts +117 -79
  91. package/src/collections/TimeEntries.ts +57 -32
  92. package/src/components/TicketConversation/config.ts +16 -80
  93. package/src/components/TicketConversation/hooks/useFeatures.ts +109 -0
  94. package/src/components/TicketConversation/index.tsx +2 -2
  95. package/src/endpoints/ai.ts +2 -1
  96. package/src/endpoints/client-intelligence.ts +2 -1
  97. package/src/endpoints/process-scheduled.ts +13 -8
  98. package/src/endpoints/round-robin-config.ts +30 -20
  99. package/src/endpoints/settings.ts +28 -77
  100. package/src/index.ts +6 -2
  101. package/src/portal/LiveChat.tsx +33 -22
  102. package/src/portal/auth/tickets/detail/TicketPolling.tsx +5 -1
  103. package/src/types/lucide-react.d.ts +10 -2
  104. package/src/utils/aiAgent.ts +2 -1
  105. package/src/utils/aiProvider.ts +21 -0
  106. package/src/utils/features.ts +297 -0
  107. package/src/utils/fireWebhooks.ts +6 -0
  108. package/src/utils/generateTicketSynthesis.ts +2 -1
  109. package/src/utils/index.ts +4 -2
  110. package/src/utils/readSettings.ts +82 -9
  111. package/src/utils/webhookDispatcher.ts +19 -7
  112. package/src/views/ChatView/client.tsx +13 -9
  113. package/src/views/CrmView/client.tsx +10 -11
  114. package/src/views/TicketDetailView/client.tsx +2 -2
  115. package/src/views/TicketInboxView/client.tsx +10 -5
  116. package/src/views/TicketingSettingsView/client.tsx +8 -6
  117. package/src/views/shared/config.ts +14 -80
  118. package/src/views/shared/index.ts +3 -1
  119. package/dist/components/RichTextEditor/index.cjs +0 -279
  120. package/dist/components/TicketConversation/RewriteDropdown.cjs +0 -98
  121. package/dist/components/TicketConversation/SkeletonText.cjs +0 -21
  122. package/dist/components/TicketConversation/components/AISummaryPanel.cjs +0 -85
  123. package/dist/components/TicketConversation/components/ActionPanels.cjs +0 -193
  124. package/dist/components/TicketConversation/components/ActivityLog.cjs +0 -24
  125. package/dist/components/TicketConversation/components/ClientBar.cjs +0 -43
  126. package/dist/components/TicketConversation/components/ClientHistory.cjs +0 -138
  127. package/dist/components/TicketConversation/components/CodeBlock.cjs +0 -171
  128. package/dist/components/TicketConversation/components/CodeBlockInserter.cjs +0 -156
  129. package/dist/components/TicketConversation/components/QuickActions.cjs +0 -87
  130. package/dist/components/TicketConversation/components/TicketHeader.cjs +0 -93
  131. package/dist/components/TicketConversation/components/TimeTrackingPanel.cjs +0 -134
  132. package/dist/components/TicketConversation/config.cjs +0 -44
  133. package/dist/components/TicketConversation/constants.cjs +0 -127
  134. package/dist/components/TicketConversation/context.cjs +0 -13
  135. package/dist/components/TicketConversation/hooks/useAI.cjs +0 -196
  136. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +0 -20
  137. package/dist/components/TicketConversation/hooks/useMessageActions.cjs +0 -136
  138. package/dist/components/TicketConversation/hooks/useReply.cjs +0 -188
  139. package/dist/components/TicketConversation/hooks/useTicketActions.cjs +0 -290
  140. package/dist/components/TicketConversation/hooks/useTimeTracking.cjs +0 -123
  141. package/dist/components/TicketConversation/hooks/useTranslation.cjs +0 -101
  142. package/dist/components/TicketConversation/index.cjs +0 -1114
  143. package/dist/components/TicketConversation/types.cjs +0 -2
  144. package/dist/components/TicketConversation/utils.cjs +0 -27
  145. package/dist/views/BillingView/client.cjs +0 -469
  146. package/dist/views/BillingView/index.cjs +0 -34
  147. package/dist/views/ChatView/client.cjs +0 -301
  148. package/dist/views/ChatView/index.cjs +0 -34
  149. package/dist/views/CrmView/client.cjs +0 -458
  150. package/dist/views/CrmView/index.cjs +0 -34
  151. package/dist/views/EmailTrackingView/client.cjs +0 -171
  152. package/dist/views/EmailTrackingView/index.cjs +0 -34
  153. package/dist/views/ImportConversationView/client.cjs +0 -238
  154. package/dist/views/ImportConversationView/index.cjs +0 -34
  155. package/dist/views/LogsView/client.cjs +0 -148
  156. package/dist/views/LogsView/index.cjs +0 -32
  157. package/dist/views/NewTicketView/client.cjs +0 -213
  158. package/dist/views/NewTicketView/index.cjs +0 -32
  159. package/dist/views/PendingEmailsView/client.cjs +0 -471
  160. package/dist/views/PendingEmailsView/index.cjs +0 -34
  161. package/dist/views/SupportDashboardView/client.cjs +0 -437
  162. package/dist/views/SupportDashboardView/index.cjs +0 -34
  163. package/dist/views/TicketDetailView/NextActionItem.cjs +0 -40
  164. package/dist/views/TicketDetailView/RewriteDropdown.cjs +0 -80
  165. package/dist/views/TicketDetailView/client.cjs +0 -1412
  166. package/dist/views/TicketDetailView/constants.cjs +0 -20
  167. package/dist/views/TicketDetailView/helpers.cjs +0 -23
  168. package/dist/views/TicketDetailView/index.cjs +0 -34
  169. package/dist/views/TicketDetailView/types.cjs +0 -2
  170. package/dist/views/TicketInboxView/client.cjs +0 -359
  171. package/dist/views/TicketInboxView/index.cjs +0 -32
  172. package/dist/views/TicketingSettingsView/client.cjs +0 -740
  173. package/dist/views/TicketingSettingsView/index.cjs +0 -34
  174. package/dist/views/TimeDashboardView/client.cjs +0 -180
  175. package/dist/views/TimeDashboardView/index.cjs +0 -34
  176. package/dist/views/shared/AdminViewHeader.cjs +0 -68
  177. package/dist/views/shared/ErrorBoundary.cjs +0 -55
  178. package/dist/views/shared/Skeleton.cjs +0 -77
  179. package/dist/views/shared/StatusPill.cjs +0 -47
  180. package/dist/views/shared/adminTokens.cjs +0 -34
  181. package/dist/views/shared/config.cjs +0 -44
  182. package/dist/views/shared/dateLocale.cjs +0 -5
  183. package/dist/views/shared/index.cjs +0 -72
  184. package/dist/views/shared/sla.cjs +0 -37
  185. package/dist/views.cjs +0 -86
  186. package/dist/views.d.cts +0 -13
  187. package/src/__tests__/aiSummaryRendering.test.ts +0 -21
  188. package/src/__tests__/authResponses.test.ts +0 -69
  189. package/src/__tests__/capabilities.test.ts +0 -71
  190. package/src/__tests__/generateTrackingToken.test.ts +0 -67
  191. package/src/__tests__/integration/ai-agent.test.ts +0 -46
  192. package/src/__tests__/integration/auth.test.ts +0 -43
  193. package/src/__tests__/integration/automation-rules.test.ts +0 -68
  194. package/src/__tests__/integration/buildTestPayload.ts +0 -52
  195. package/src/__tests__/integration/channels.test.ts +0 -52
  196. package/src/__tests__/integration/core-behaviors.test.ts +0 -81
  197. package/src/__tests__/integration/dashboard-volume.test.ts +0 -31
  198. package/src/__tests__/integration/digest.test.ts +0 -48
  199. package/src/__tests__/integration/invoice-pdf.test.ts +0 -30
  200. package/src/__tests__/integration/isolation.test.ts +0 -81
  201. package/src/__tests__/integration/mentions-invoice.test.ts +0 -50
  202. package/src/__tests__/integration/nps.test.ts +0 -37
  203. package/src/__tests__/integration/per-team-sla.test.ts +0 -44
  204. package/src/__tests__/integration/push.test.ts +0 -75
  205. package/src/__tests__/integration/sanitization.test.ts +0 -35
  206. package/src/__tests__/integration/sla-pause.test.ts +0 -39
  207. package/src/__tests__/integration/smoke.test.ts +0 -26
  208. package/src/__tests__/integration/snooze.test.ts +0 -68
  209. package/src/__tests__/integration/teams.test.ts +0 -38
  210. package/src/__tests__/rateLimiter.test.ts +0 -83
  211. package/src/__tests__/sanitizeHtml.test.ts +0 -165
  212. package/src/__tests__/sla.test.ts +0 -258
  213. package/src/__tests__/trackOpenEndpoint.test.ts +0 -54
  214. package/src/__tests__/translations.test.ts +0 -67
  215. 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
+ };