@consilioweb/payload-support 4.0.0 → 6.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.
- package/README.md +272 -35
- package/dist/components/RichTextEditor/index.js +1 -1
- package/dist/components/TicketConversation/RewriteDropdown.js +1 -1
- package/dist/components/TicketConversation/components/AISummaryPanel.js +3 -0
- package/dist/components/TicketConversation/components/ActionPanels.js +13 -8
- package/dist/components/TicketConversation/components/ClientHistory.js +1 -0
- package/dist/components/TicketConversation/components/CodeBlock.js +1 -0
- package/dist/components/TicketConversation/components/CodeBlockInserter.js +1 -1
- package/dist/components/TicketConversation/components/QuickActions.js +10 -8
- package/dist/components/TicketConversation/components/TicketHeader.js +2 -0
- package/dist/components/TicketConversation/components/TimeTrackingPanel.js +15 -9
- package/dist/components/TicketConversation/index.d.ts +10 -0
- package/dist/components/TicketConversation/index.js +25 -7
- package/dist/index.cjs +421 -73
- package/dist/index.d.cts +127 -38
- package/dist/index.d.ts +127 -38
- package/dist/index.js +415 -72
- package/dist/styles/BillingView.module.scss +11 -11
- package/dist/styles/ChatView.module.scss +7 -7
- package/dist/styles/CommandPalette.module.scss +1 -1
- package/dist/styles/CrmView.module.scss +9 -9
- package/dist/styles/EmailTracking.module.scss +6 -6
- package/dist/styles/ImportConversation.module.scss +5 -5
- package/dist/styles/Logs.module.scss +5 -5
- package/dist/styles/NewTicket.module.scss +2 -2
- package/dist/styles/PendingEmails.module.scss +13 -13
- package/dist/styles/SupportDashboard.module.scss +24 -8
- package/dist/styles/TicketDetail.module.scss +20 -20
- package/dist/styles/TicketInbox.module.scss +6 -6
- package/dist/styles/TicketingSettings.module.scss +10 -10
- package/dist/styles/TimeDashboard.module.scss +6 -6
- package/dist/styles/_tokens.scss +3 -1
- package/dist/utils/db.d.ts +34 -0
- package/dist/utils/readSettings.d.ts +90 -0
- package/dist/views/BillingView/client.js +15 -8
- package/dist/views/BillingView/index.js +4 -4
- package/dist/views/ChatView/client.js +2 -0
- package/dist/views/ChatView/index.js +4 -4
- package/dist/views/CrmView/client.js +2 -0
- package/dist/views/CrmView/index.js +4 -4
- package/dist/views/EmailTrackingView/client.js +23 -11
- package/dist/views/EmailTrackingView/index.js +4 -4
- package/dist/views/ImportConversationView/client.js +1 -0
- package/dist/views/ImportConversationView/index.js +4 -4
- package/dist/views/LogsView/client.js +1 -1
- package/dist/views/LogsView/index.js +4 -2
- package/dist/views/NewTicketView/client.js +20 -13
- package/dist/views/NewTicketView/index.js +4 -2
- package/dist/views/PendingEmailsView/client.js +9 -3
- package/dist/views/PendingEmailsView/index.js +4 -4
- package/dist/views/SupportDashboardView/client.js +17 -19
- package/dist/views/SupportDashboardView/index.js +4 -4
- package/dist/views/TicketDetailView/client.js +23 -11
- package/dist/views/TicketDetailView/index.js +4 -4
- package/dist/views/TicketInboxView/client.js +52 -26
- package/dist/views/TicketInboxView/index.js +4 -2
- package/dist/views/TicketingSettingsView/TicketingSettings.module.scss +7 -7
- package/dist/views/TicketingSettingsView/client.js +44 -26
- package/dist/views/TicketingSettingsView/index.js +4 -4
- package/dist/views/TimeDashboardView/client.js +10 -7
- package/dist/views/TimeDashboardView/index.js +4 -4
- package/dist/views/shared/ErrorBoundary.d.ts +36 -1
- package/dist/views/shared/ErrorBoundary.js +59 -28
- package/dist/views/shared/adminTokens.d.ts +15 -5
- package/dist/views/shared/adminTokens.js +23 -7
- package/dist/views/shared/icons.d.ts +49 -0
- package/dist/views/shared/icons.js +92 -0
- package/dist/views/shared/locales/en.json +15 -1
- package/dist/views/shared/locales/fr.json +15 -1
- package/dist/views/shared/viewAccess.d.ts +29 -0
- package/dist/views/shared/viewAccess.js +24 -0
- package/package.json +31 -21
- package/scripts/uninstall-data.mjs +178 -0
- package/scripts/uninstall.mjs +184 -0
- package/src/collections/Tickets.ts +7 -0
- package/src/collections/TimeEntries.ts +11 -3
- package/src/components/RichTextEditor/index.tsx +1 -1
- package/src/components/TicketConversation/RewriteDropdown.tsx +1 -1
- package/src/components/TicketConversation/components/AISummaryPanel.tsx +3 -0
- package/src/components/TicketConversation/components/ActionPanels.tsx +13 -8
- package/src/components/TicketConversation/components/ClientHistory.tsx +1 -0
- package/src/components/TicketConversation/components/CodeBlock.tsx +1 -0
- package/src/components/TicketConversation/components/CodeBlockInserter.tsx +1 -1
- package/src/components/TicketConversation/components/QuickActions.tsx +10 -8
- package/src/components/TicketConversation/components/TicketHeader.tsx +2 -0
- package/src/components/TicketConversation/components/TimeTrackingPanel.tsx +17 -9
- package/src/components/TicketConversation/index.tsx +41 -7
- package/src/endpoints/auth-2fa.ts +53 -8
- package/src/endpoints/capabilities.ts +2 -4
- package/src/endpoints/chatbot.ts +2 -2
- package/src/endpoints/delete-account.ts +191 -47
- package/src/endpoints/export-data.ts +104 -4
- package/src/endpoints/import-conversation.ts +2 -2
- package/src/endpoints/login.ts +13 -3
- package/src/endpoints/purge-logs.ts +6 -15
- package/src/endpoints/push.ts +14 -1
- package/src/endpoints/statuses.ts +17 -0
- package/src/index.ts +2 -0
- package/src/plugin.ts +51 -1
- package/src/portal/LiveChat.tsx +1 -1
- package/src/portal/auth/profile/page.tsx +3 -2
- package/src/portal/icons.tsx +91 -0
- package/src/portal/login/page.tsx +14 -4
- package/src/styles/BillingView.module.scss +11 -11
- package/src/styles/ChatView.module.scss +7 -7
- package/src/styles/CommandPalette.module.scss +1 -1
- package/src/styles/CrmView.module.scss +9 -9
- package/src/styles/EmailTracking.module.scss +6 -6
- package/src/styles/ImportConversation.module.scss +5 -5
- package/src/styles/Logs.module.scss +5 -5
- package/src/styles/NewTicket.module.scss +2 -2
- package/src/styles/PendingEmails.module.scss +13 -13
- package/src/styles/SupportDashboard.module.scss +24 -8
- package/src/styles/TicketDetail.module.scss +20 -20
- package/src/styles/TicketInbox.module.scss +6 -6
- package/src/styles/TicketingSettings.module.scss +10 -10
- package/src/styles/TimeDashboard.module.scss +6 -6
- package/src/styles/_tokens.scss +3 -1
- package/src/types.ts +20 -0
- package/src/utils/push.ts +22 -0
- package/src/utils/rateLimiter.ts +98 -0
- package/src/utils/retention.ts +111 -0
- package/src/utils/slugs.ts +15 -0
- package/src/utils/twoFactorChallenge.ts +6 -1
- package/src/utils/urlSafety.ts +36 -1
- package/src/views/BillingView/client.tsx +17 -8
- package/src/views/BillingView/index.tsx +4 -4
- package/src/views/ChatView/client.tsx +2 -0
- package/src/views/ChatView/index.tsx +4 -4
- package/src/views/CrmView/client.tsx +2 -0
- package/src/views/CrmView/index.tsx +4 -4
- package/src/views/EmailTrackingView/client.tsx +18 -7
- package/src/views/EmailTrackingView/index.tsx +4 -4
- package/src/views/ImportConversationView/client.tsx +1 -0
- package/src/views/ImportConversationView/index.tsx +4 -4
- package/src/views/LogsView/client.tsx +1 -1
- package/src/views/LogsView/index.tsx +4 -2
- package/src/views/NewTicketView/client.tsx +22 -13
- package/src/views/NewTicketView/index.tsx +4 -2
- package/src/views/PendingEmailsView/client.tsx +9 -3
- package/src/views/PendingEmailsView/index.tsx +4 -4
- package/src/views/SupportDashboardView/client.tsx +11 -5
- package/src/views/SupportDashboardView/index.tsx +4 -4
- package/src/views/TicketDetailView/client.tsx +25 -11
- package/src/views/TicketDetailView/index.tsx +4 -4
- package/src/views/TicketInboxView/client.tsx +47 -7
- package/src/views/TicketInboxView/index.tsx +4 -2
- package/src/views/TicketingSettingsView/TicketingSettings.module.scss +7 -7
- package/src/views/TicketingSettingsView/client.tsx +201 -144
- package/src/views/TicketingSettingsView/index.tsx +4 -4
- package/src/views/TimeDashboardView/client.tsx +10 -7
- package/src/views/TimeDashboardView/index.tsx +4 -4
- package/src/views/shared/ErrorBoundary.tsx +95 -31
- package/src/views/shared/adminTokens.ts +28 -11
- package/src/views/shared/icons.tsx +146 -0
- package/src/views/shared/locales/en.json +15 -1
- package/src/views/shared/locales/fr.json +15 -1
- package/src/views/shared/viewAccess.ts +73 -0
- package/src/types/lucide-react.d.ts +0 -42
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
font-family: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace;
|
|
53
53
|
font-size: 12px;
|
|
54
54
|
font-weight: 400;
|
|
55
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
55
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
56
56
|
display: inline-flex;
|
|
57
57
|
align-items: center;
|
|
58
58
|
gap: 8px;
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
|
|
65
65
|
> .ticketNumberCat,
|
|
66
66
|
> .ticketNumberSource {
|
|
67
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
67
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
68
68
|
display: inline-flex;
|
|
69
69
|
align-items: center;
|
|
70
70
|
gap: 4px;
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
text-transform: uppercase;
|
|
195
195
|
letter-spacing: 0.08em;
|
|
196
196
|
line-height: 1.3;
|
|
197
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
197
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
198
198
|
margin: 0 0 12px;
|
|
199
199
|
display: flex;
|
|
200
200
|
justify-content: space-between;
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
font-size: 11px;
|
|
354
354
|
font-weight: 500;
|
|
355
355
|
line-height: 1.3;
|
|
356
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
356
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
357
357
|
white-space: nowrap;
|
|
358
358
|
text-transform: uppercase;
|
|
359
359
|
letter-spacing: 0.08em;
|
|
@@ -450,7 +450,7 @@
|
|
|
450
450
|
font-size: 11px;
|
|
451
451
|
font-weight: 500;
|
|
452
452
|
line-height: 1.3;
|
|
453
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
453
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
454
454
|
}
|
|
455
455
|
|
|
456
456
|
// Pills "Interne" / "Solution" — pill style, 22px height
|
|
@@ -499,7 +499,7 @@
|
|
|
499
499
|
margin-top: 4px;
|
|
500
500
|
font-size: 11px;
|
|
501
501
|
font-weight: 500;
|
|
502
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
502
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
503
503
|
opacity: 0;
|
|
504
504
|
transition: opacity 80ms ease;
|
|
505
505
|
}
|
|
@@ -514,7 +514,7 @@
|
|
|
514
514
|
font-size: 11px;
|
|
515
515
|
font-weight: 500;
|
|
516
516
|
line-height: 1.3;
|
|
517
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
517
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
518
518
|
display: inline-flex;
|
|
519
519
|
align-items: center;
|
|
520
520
|
height: auto;
|
|
@@ -749,7 +749,7 @@
|
|
|
749
749
|
display: inline-flex;
|
|
750
750
|
align-items: center;
|
|
751
751
|
gap: 4px;
|
|
752
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
752
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
753
753
|
font-size: 11px;
|
|
754
754
|
font-weight: 500;
|
|
755
755
|
margin-left: auto;
|
|
@@ -910,7 +910,7 @@
|
|
|
910
910
|
background: none;
|
|
911
911
|
border: none;
|
|
912
912
|
cursor: pointer;
|
|
913
|
-
color: var(--theme-elevation-
|
|
913
|
+
color: var(--theme-elevation-650);
|
|
914
914
|
font-size: 13px;
|
|
915
915
|
font-weight: 600;
|
|
916
916
|
padding: 0;
|
|
@@ -941,7 +941,7 @@
|
|
|
941
941
|
|
|
942
942
|
.activityContent { flex: 1; min-width: 0; }
|
|
943
943
|
.activityText { font-weight: 500; color: var(--theme-text); font-size: 12px; }
|
|
944
|
-
.activityTime { font-size: 11px; color: var(--theme-elevation-
|
|
944
|
+
.activityTime { font-size: 11px; color: var(--theme-elevation-650); margin-top: 1px; }
|
|
945
945
|
|
|
946
946
|
// ─── DROPDOWN ───
|
|
947
947
|
.dropdown { position: relative; display: inline-block; }
|
|
@@ -1055,7 +1055,7 @@
|
|
|
1055
1055
|
|
|
1056
1056
|
.splitPreview {
|
|
1057
1057
|
font-size: 12px;
|
|
1058
|
-
color: var(--theme-elevation-
|
|
1058
|
+
color: var(--theme-elevation-650);
|
|
1059
1059
|
margin: 0 0 16px;
|
|
1060
1060
|
line-height: 1.5;
|
|
1061
1061
|
max-height: 80px;
|
|
@@ -1092,7 +1092,7 @@
|
|
|
1092
1092
|
background: none;
|
|
1093
1093
|
font-size: 13px;
|
|
1094
1094
|
font-weight: 600;
|
|
1095
|
-
color: var(--theme-elevation-
|
|
1095
|
+
color: var(--theme-elevation-650);
|
|
1096
1096
|
cursor: pointer;
|
|
1097
1097
|
&:hover { background: var(--theme-elevation-100); }
|
|
1098
1098
|
}
|
|
@@ -1145,7 +1145,7 @@
|
|
|
1145
1145
|
cursor: pointer;
|
|
1146
1146
|
font-size: 11px;
|
|
1147
1147
|
line-height: 1;
|
|
1148
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
1148
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
1149
1149
|
padding: 0;
|
|
1150
1150
|
display: inline-flex;
|
|
1151
1151
|
align-items: center;
|
|
@@ -1166,7 +1166,7 @@
|
|
|
1166
1166
|
font-size: 11px;
|
|
1167
1167
|
font-weight: 500;
|
|
1168
1168
|
line-height: 1;
|
|
1169
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
1169
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
1170
1170
|
cursor: pointer;
|
|
1171
1171
|
transition: border-color 80ms ease, color 80ms ease;
|
|
1172
1172
|
&:hover {
|
|
@@ -1607,7 +1607,7 @@
|
|
|
1607
1607
|
align-items: center;
|
|
1608
1608
|
gap: 6px;
|
|
1609
1609
|
font-size: 10px;
|
|
1610
|
-
color: var(--theme-elevation-
|
|
1610
|
+
color: var(--theme-elevation-650);
|
|
1611
1611
|
}
|
|
1612
1612
|
|
|
1613
1613
|
.previousTicketsStatus {
|
|
@@ -1755,7 +1755,7 @@
|
|
|
1755
1755
|
text-transform: uppercase;
|
|
1756
1756
|
letter-spacing: 0.08em;
|
|
1757
1757
|
line-height: 1.3;
|
|
1758
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
1758
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
1759
1759
|
margin: 12px 0 8px;
|
|
1760
1760
|
}
|
|
1761
1761
|
.aiCardNextActions {
|
|
@@ -1805,13 +1805,13 @@
|
|
|
1805
1805
|
}
|
|
1806
1806
|
.aiCardNextLabelDone {
|
|
1807
1807
|
text-decoration: line-through;
|
|
1808
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
1808
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
1809
1809
|
}
|
|
1810
1810
|
.aiCardNextWhen {
|
|
1811
1811
|
font-size: 11px;
|
|
1812
1812
|
font-weight: 500;
|
|
1813
1813
|
line-height: 1.3;
|
|
1814
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
1814
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
1815
1815
|
flex-shrink: 0;
|
|
1816
1816
|
}
|
|
1817
1817
|
|
|
@@ -1856,12 +1856,12 @@
|
|
|
1856
1856
|
margin: 0 2px;
|
|
1857
1857
|
}
|
|
1858
1858
|
.ticketNumberCat {
|
|
1859
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
1859
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
1860
1860
|
font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
1861
1861
|
font-weight: 400;
|
|
1862
1862
|
}
|
|
1863
1863
|
.ticketNumberSource {
|
|
1864
|
-
color: var(--theme-text-tertiary, var(--theme-elevation-
|
|
1864
|
+
color: var(--theme-text-tertiary, var(--theme-elevation-650));
|
|
1865
1865
|
font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
1866
1866
|
display: inline-flex;
|
|
1867
1867
|
align-items: center;
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
.subtitle {
|
|
28
28
|
font-size: 13px;
|
|
29
|
-
color: var(--theme-elevation-
|
|
29
|
+
color: var(--theme-elevation-650);
|
|
30
30
|
margin: 2px 0 0;
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
padding: 0 12px;
|
|
126
126
|
font-size: 13px;
|
|
127
127
|
font-weight: 500;
|
|
128
|
-
color: var(--theme-elevation-
|
|
128
|
+
color: var(--theme-elevation-650);
|
|
129
129
|
background: none;
|
|
130
130
|
border: none;
|
|
131
131
|
border-radius: 6px;
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
padding: 0 6px;
|
|
156
156
|
font-size: 11px;
|
|
157
157
|
font-weight: 600;
|
|
158
|
-
color: var(--theme-elevation-
|
|
158
|
+
color: var(--theme-elevation-650);
|
|
159
159
|
background: var(--theme-elevation-200);
|
|
160
160
|
border-radius: 999px;
|
|
161
161
|
}
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
.sortSelect {
|
|
180
180
|
font-size: 12px;
|
|
181
181
|
font-weight: 600;
|
|
182
|
-
color: var(--theme-elevation-
|
|
182
|
+
color: var(--theme-elevation-650);
|
|
183
183
|
background: none;
|
|
184
184
|
border: none;
|
|
185
185
|
cursor: pointer;
|
|
@@ -268,7 +268,7 @@
|
|
|
268
268
|
|
|
269
269
|
.client {
|
|
270
270
|
font-size: 12px;
|
|
271
|
-
color: var(--theme-elevation-
|
|
271
|
+
color: var(--theme-elevation-650);
|
|
272
272
|
overflow: hidden;
|
|
273
273
|
text-overflow: ellipsis;
|
|
274
274
|
white-space: nowrap;
|
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
334
334
|
font-size: 11px;
|
|
335
335
|
font-weight: 500;
|
|
336
|
-
color: var(--theme-elevation-
|
|
336
|
+
color: var(--theme-elevation-650);
|
|
337
337
|
display: flex;
|
|
338
338
|
gap: 12px;
|
|
339
339
|
z-index: 10;
|
|
@@ -15,7 +15,7 @@ $green: #16a34a;
|
|
|
15
15
|
|
|
16
16
|
.intro {
|
|
17
17
|
font-size: 13px;
|
|
18
|
-
color: var(--theme-elevation-
|
|
18
|
+
color: var(--theme-elevation-650);
|
|
19
19
|
margin: 0 0 24px;
|
|
20
20
|
line-height: 1.6;
|
|
21
21
|
}
|
|
@@ -59,7 +59,7 @@ $green: #16a34a;
|
|
|
59
59
|
|
|
60
60
|
.sectionChevron {
|
|
61
61
|
font-size: 16px;
|
|
62
|
-
color: var(--theme-elevation-
|
|
62
|
+
color: var(--theme-elevation-650);
|
|
63
63
|
transition: transform 150ms;
|
|
64
64
|
|
|
65
65
|
&.open {
|
|
@@ -73,7 +73,7 @@ $green: #16a34a;
|
|
|
73
73
|
|
|
74
74
|
.sectionDescription {
|
|
75
75
|
font-size: 12px;
|
|
76
|
-
color: var(--theme-elevation-
|
|
76
|
+
color: var(--theme-elevation-650);
|
|
77
77
|
margin: 0 0 16px;
|
|
78
78
|
line-height: 1.5;
|
|
79
79
|
}
|
|
@@ -97,7 +97,7 @@ $green: #16a34a;
|
|
|
97
97
|
|
|
98
98
|
.fieldDescription {
|
|
99
99
|
font-size: 11px;
|
|
100
|
-
color: var(--theme-elevation-
|
|
100
|
+
color: var(--theme-elevation-650);
|
|
101
101
|
font-weight: 400;
|
|
102
102
|
margin-top: 2px;
|
|
103
103
|
}
|
|
@@ -131,7 +131,7 @@ $green: #16a34a;
|
|
|
131
131
|
border-radius: 6px;
|
|
132
132
|
border: 1px solid var(--theme-elevation-300);
|
|
133
133
|
font-size: 13px;
|
|
134
|
-
color: var(--theme-elevation-
|
|
134
|
+
color: var(--theme-elevation-650);
|
|
135
135
|
background-color: var(--theme-elevation-100);
|
|
136
136
|
width: 100%;
|
|
137
137
|
max-width: 400px;
|
|
@@ -179,7 +179,7 @@ $green: #16a34a;
|
|
|
179
179
|
|
|
180
180
|
.inlineDesc {
|
|
181
181
|
font-size: 12px;
|
|
182
|
-
color: var(--theme-elevation-
|
|
182
|
+
color: var(--theme-elevation-650);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
// ─── BADGE ───
|
|
@@ -251,7 +251,7 @@ $green: #16a34a;
|
|
|
251
251
|
|
|
252
252
|
.featureDesc {
|
|
253
253
|
font-size: 12px;
|
|
254
|
-
color: var(--theme-elevation-
|
|
254
|
+
color: var(--theme-elevation-650);
|
|
255
255
|
line-height: 1.4;
|
|
256
256
|
}
|
|
257
257
|
|
|
@@ -271,7 +271,7 @@ $green: #16a34a;
|
|
|
271
271
|
|
|
272
272
|
.aiToggleDesc {
|
|
273
273
|
font-size: 12px;
|
|
274
|
-
color: var(--theme-elevation-
|
|
274
|
+
color: var(--theme-elevation-650);
|
|
275
275
|
margin-left: 8px;
|
|
276
276
|
}
|
|
277
277
|
|
|
@@ -290,7 +290,7 @@ $green: #16a34a;
|
|
|
290
290
|
background-color: transparent;
|
|
291
291
|
cursor: pointer;
|
|
292
292
|
font-size: 12px;
|
|
293
|
-
color: var(--theme-elevation-
|
|
293
|
+
color: var(--theme-elevation-650);
|
|
294
294
|
white-space: nowrap;
|
|
295
295
|
}
|
|
296
296
|
|
|
@@ -303,7 +303,7 @@ $green: #16a34a;
|
|
|
303
303
|
|
|
304
304
|
.slaHint {
|
|
305
305
|
font-size: 12px;
|
|
306
|
-
color: var(--theme-elevation-
|
|
306
|
+
color: var(--theme-elevation-650);
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
// ─── AI SUB FEATURES LABEL ───
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
.subtitle {
|
|
31
|
-
color: var(--theme-elevation-
|
|
31
|
+
color: var(--theme-elevation-650);
|
|
32
32
|
margin: 4px 0 0;
|
|
33
33
|
font-size: 14px;
|
|
34
34
|
}
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
.label {
|
|
81
81
|
font-size: 11px;
|
|
82
82
|
font-weight: 700;
|
|
83
|
-
color: var(--theme-elevation-
|
|
83
|
+
color: var(--theme-elevation-650);
|
|
84
84
|
margin-bottom: 3px;
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
font-size: 10px;
|
|
147
147
|
font-weight: 700;
|
|
148
148
|
text-transform: uppercase;
|
|
149
|
-
color: var(--theme-elevation-
|
|
149
|
+
color: var(--theme-elevation-650);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
.kpiValue {
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
border: 1px solid var(--theme-elevation-300);
|
|
202
202
|
border-radius: 8px;
|
|
203
203
|
background: var(--theme-elevation-100);
|
|
204
|
-
color: var(--theme-elevation-
|
|
204
|
+
color: var(--theme-elevation-650);
|
|
205
205
|
font-size: 14px;
|
|
206
206
|
}
|
|
207
207
|
|
|
@@ -257,13 +257,13 @@
|
|
|
257
257
|
|
|
258
258
|
.tdSubject {
|
|
259
259
|
padding: 6px 8px;
|
|
260
|
-
color: var(--theme-elevation-
|
|
260
|
+
color: var(--theme-elevation-650);
|
|
261
261
|
font-size: 12px;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
.tdDescription {
|
|
265
265
|
padding: 6px 8px;
|
|
266
|
-
color: var(--theme-elevation-
|
|
266
|
+
color: var(--theme-elevation-650);
|
|
267
267
|
font-size: 12px;
|
|
268
268
|
}
|
|
269
269
|
|
package/dist/styles/_tokens.scss
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Design tokens — based on Payload CMS CSS variables
|
|
2
2
|
$text: var(--theme-text);
|
|
3
|
-
|
|
3
|
+
// elevation-650, not 500: Payload's dark theme skips the 500 step, leaving it
|
|
4
|
+
// at rgb(128,128,128) — 3.62:1 light / 4.03:1 dark, below WCAG AA in both.
|
|
5
|
+
$text-secondary: var(--theme-elevation-650);
|
|
4
6
|
$text-muted: var(--theme-elevation-400);
|
|
5
7
|
$bg: var(--theme-elevation-50);
|
|
6
8
|
$bg-card: var(--theme-elevation-100);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Payload } from 'payload';
|
|
2
|
+
/**
|
|
3
|
+
* Thin typed wrappers around Payload data operations.
|
|
4
|
+
*
|
|
5
|
+
* Collection slugs are user-overridable config (`string`), not Payload's literal
|
|
6
|
+
* `CollectionSlug` union — so every call site otherwise needs `collection: X as any`.
|
|
7
|
+
* These helpers isolate that single unavoidable cast in ONE place, removing the
|
|
8
|
+
* ~200 scattered `as any` while staying an EXACT behavioral pass-through of options.
|
|
9
|
+
*
|
|
10
|
+
* Returns default to `any` (callers consume docs loosely, as before). Pass a type
|
|
11
|
+
* argument to opt into stronger typing: `dbFind<TicketData>(payload, slug, { ... })`.
|
|
12
|
+
*/
|
|
13
|
+
interface PaginatedResult<T> {
|
|
14
|
+
docs: T[];
|
|
15
|
+
totalDocs: number;
|
|
16
|
+
totalPages: number;
|
|
17
|
+
page?: number;
|
|
18
|
+
limit: number;
|
|
19
|
+
hasNextPage: boolean;
|
|
20
|
+
hasPrevPage: boolean;
|
|
21
|
+
nextPage?: number | null;
|
|
22
|
+
prevPage?: number | null;
|
|
23
|
+
}
|
|
24
|
+
export declare function dbFind<T = any>(payload: Payload, slug: string, options?: Record<string, unknown>): Promise<PaginatedResult<T>>;
|
|
25
|
+
export declare function dbFindByID<T = any>(payload: Payload, slug: string, options: {
|
|
26
|
+
id: number | string;
|
|
27
|
+
} & Record<string, unknown>): Promise<T>;
|
|
28
|
+
export declare function dbCreate<T = any>(payload: Payload, slug: string, options: Record<string, unknown>): Promise<T>;
|
|
29
|
+
export declare function dbUpdate<T = any>(payload: Payload, slug: string, options: Record<string, unknown>): Promise<T>;
|
|
30
|
+
export declare function dbCount(payload: Payload, slug: string, options?: Record<string, unknown>): Promise<{
|
|
31
|
+
totalDocs: number;
|
|
32
|
+
}>;
|
|
33
|
+
export declare function dbDelete<T = any>(payload: Payload, slug: string, options: Record<string, unknown>): Promise<T>;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Payload } from 'payload';
|
|
2
|
+
import { type TicketingFeatures } from './features.js';
|
|
3
|
+
export declare const SUPPORT_SETTINGS_PREF_KEY = "support-settings";
|
|
4
|
+
/**
|
|
5
|
+
* Key under which `plugin.ts` publishes the resolved staff collection slug on
|
|
6
|
+
* `config.custom`. It is the ONE source of truth shared by the read path (here)
|
|
7
|
+
* and the write path (`requireAdmin` → `slugs.users`).
|
|
8
|
+
*/
|
|
9
|
+
export declare const SUPPORT_STAFF_SLUG_CONFIG_KEY = "supportStaffCollection";
|
|
10
|
+
/**
|
|
11
|
+
* Owner scope for every `payload-preferences` row this plugin reads back.
|
|
12
|
+
*
|
|
13
|
+
* `payload-preferences` is writable by ANY authenticated principal, whatever its
|
|
14
|
+
* auth collection: Payload's `POST /api/payload-preferences/:key` handler only
|
|
15
|
+
* checks `!!req.user` before upserting the row. Reading a plugin-wide row by key
|
|
16
|
+
* alone therefore lets a front-office user (or a support-client) plant their own
|
|
17
|
+
* row and have the whole plugin read it — replyTo addresses, SLA escalation
|
|
18
|
+
* address, AI provider, feature flags.
|
|
19
|
+
*
|
|
20
|
+
* Every read below is constrained to `user.relationTo = <staff collection>`, the
|
|
21
|
+
* same scope the WRITE path already uses (endpoints/settings.ts, signature.ts,
|
|
22
|
+
* user-prefs.ts all upsert with `req.user.collection`, and all three are guarded
|
|
23
|
+
* by `requireAdmin`, which compares against `slugs.users`).
|
|
24
|
+
*
|
|
25
|
+
* TWO SOURCES OF TRUTH WERE THE BUG: this used to resolve the scope from
|
|
26
|
+
* `config.admin.user`, which Payload defaults to the FIRST auth collection of
|
|
27
|
+
* the app when the integrator did not declare it (config/sanitize.js). On a host
|
|
28
|
+
* whose first auth collection is the front office and whose staff collection is
|
|
29
|
+
* declared through `collectionSlugs.users`, the read scope named the front
|
|
30
|
+
* office while the write scope named the staff — and the poisoning this scope
|
|
31
|
+
* was added to defeat was open again. So the plugin now PUBLISHES the resolved
|
|
32
|
+
* `slugs.users` on `config.custom` (see plugin.ts) and reads it back here.
|
|
33
|
+
* `config.admin.user` remains a last-resort fallback for callers using these
|
|
34
|
+
* helpers outside of a plugin-built config; there is no plugin deployment in
|
|
35
|
+
* which it is consulted.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveStaffPrefSlug(payload: Payload, staffSlug?: string): string;
|
|
38
|
+
export interface SupportSettings {
|
|
39
|
+
email: {
|
|
40
|
+
fromAddress: string;
|
|
41
|
+
fromName: string;
|
|
42
|
+
replyToAddress: string;
|
|
43
|
+
};
|
|
44
|
+
ai: {
|
|
45
|
+
provider: string;
|
|
46
|
+
model: string;
|
|
47
|
+
enableSentiment: boolean;
|
|
48
|
+
enableSynthesis: boolean;
|
|
49
|
+
enableSuggestion: boolean;
|
|
50
|
+
enableRewrite: boolean;
|
|
51
|
+
};
|
|
52
|
+
sla: {
|
|
53
|
+
firstResponseMinutes: number;
|
|
54
|
+
resolutionMinutes: number;
|
|
55
|
+
businessHoursOnly: boolean;
|
|
56
|
+
escalationEmail: string;
|
|
57
|
+
};
|
|
58
|
+
autoClose: {
|
|
59
|
+
enabled: boolean;
|
|
60
|
+
daysBeforeClose: number;
|
|
61
|
+
reminderDaysBefore: number;
|
|
62
|
+
};
|
|
63
|
+
/** Ticketing feature flags — server-authoritative since 2.1 (used to be per-browser localStorage). */
|
|
64
|
+
features: TicketingFeatures;
|
|
65
|
+
}
|
|
66
|
+
export interface UserPrefs {
|
|
67
|
+
locale: 'fr' | 'en';
|
|
68
|
+
signature: string;
|
|
69
|
+
}
|
|
70
|
+
export declare const DEFAULT_SETTINGS: SupportSettings;
|
|
71
|
+
export declare const DEFAULT_USER_PREFS: UserPrefs;
|
|
72
|
+
export interface SupportSettingsState {
|
|
73
|
+
settings: SupportSettings;
|
|
74
|
+
/**
|
|
75
|
+
* False when the preference row carries no `features` object yet — a
|
|
76
|
+
* pre-2.1 install, or a fresh one. Clients use it to decide whether their
|
|
77
|
+
* legacy `localStorage` flags should seed the server.
|
|
78
|
+
*/
|
|
79
|
+
featuresConfigured: boolean;
|
|
80
|
+
}
|
|
81
|
+
/** Invalidate the settings cache — call right after writing support settings. */
|
|
82
|
+
export declare function invalidateSupportSettingsCache(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Merge a stored preference value onto the defaults.
|
|
85
|
+
* Exported for the settings endpoint, which must not re-implement the merge.
|
|
86
|
+
*/
|
|
87
|
+
export declare function mergeSupportSettings(stored: Partial<SupportSettings> | undefined | null, base?: SupportSettings): SupportSettings;
|
|
88
|
+
export declare function readSupportSettingsState(payload: Payload, staffSlug?: string): Promise<SupportSettingsState>;
|
|
89
|
+
export declare function readSupportSettings(payload: Payload, staffSlug?: string): Promise<SupportSettings>;
|
|
90
|
+
export declare function readUserPrefs(payload: Payload, userId: string | number, staffSlug?: string): Promise<UserPrefs>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import React, { useState, useCallback } from 'react';
|
|
3
|
+
import React, { useId, useState, useCallback } from 'react';
|
|
4
4
|
import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
|
|
5
5
|
import { DATE_LOCALE } from '../shared/dateLocale.js';
|
|
6
6
|
import styles from '../../styles/BillingView.module.scss';
|
|
@@ -42,6 +42,10 @@ function getQuarterRange(offset) {
|
|
|
42
42
|
}
|
|
43
43
|
const BillingClient = () => {
|
|
44
44
|
const { t } = useTranslation();
|
|
45
|
+
const fromId = useId();
|
|
46
|
+
const toId = useId();
|
|
47
|
+
const projectFilterId = useId();
|
|
48
|
+
const rateId = useId();
|
|
45
49
|
const [from, setFrom] = useState(() => getMonthRange(0).from);
|
|
46
50
|
const [to, setTo] = useState(() => getMonthRange(0).to);
|
|
47
51
|
const [projectId, setProjectId] = useState("");
|
|
@@ -218,26 +222,27 @@ const BillingClient = () => {
|
|
|
218
222
|
] }),
|
|
219
223
|
/* @__PURE__ */ jsxs("div", { className: styles.filterRow, children: [
|
|
220
224
|
/* @__PURE__ */ jsxs("div", { className: styles.fieldGroup, children: [
|
|
221
|
-
/* @__PURE__ */ jsx("label", { className: styles.label, children: t("billing.filters.from") }),
|
|
222
|
-
/* @__PURE__ */ jsx("input", { type: "date", value: from, onChange: (e) => setFrom(e.target.value), className: styles.input })
|
|
225
|
+
/* @__PURE__ */ jsx("label", { className: styles.label, htmlFor: fromId, children: t("billing.filters.from") }),
|
|
226
|
+
/* @__PURE__ */ jsx("input", { id: fromId, type: "date", value: from, onChange: (e) => setFrom(e.target.value), className: styles.input })
|
|
223
227
|
] }),
|
|
224
228
|
/* @__PURE__ */ jsxs("div", { className: styles.fieldGroup, children: [
|
|
225
|
-
/* @__PURE__ */ jsx("label", { className: styles.label, children: t("billing.filters.to") }),
|
|
226
|
-
/* @__PURE__ */ jsx("input", { type: "date", value: to, onChange: (e) => setTo(e.target.value), className: styles.input })
|
|
229
|
+
/* @__PURE__ */ jsx("label", { className: styles.label, htmlFor: toId, children: t("billing.filters.to") }),
|
|
230
|
+
/* @__PURE__ */ jsx("input", { id: toId, type: "date", value: to, onChange: (e) => setTo(e.target.value), className: styles.input })
|
|
227
231
|
] }),
|
|
228
232
|
/* @__PURE__ */ jsxs("div", { className: styles.fieldGroup, children: [
|
|
229
|
-
/* @__PURE__ */ jsx("label", { className: styles.label, children: t("billing.filters.project") }),
|
|
230
|
-
/* @__PURE__ */ jsxs("select", { value: projectId, onChange: (e) => setProjectId(e.target.value), className: styles.select, children: [
|
|
233
|
+
/* @__PURE__ */ jsx("label", { className: styles.label, htmlFor: projectFilterId, children: t("billing.filters.project") }),
|
|
234
|
+
/* @__PURE__ */ jsxs("select", { id: projectFilterId, value: projectId, onChange: (e) => setProjectId(e.target.value), className: styles.select, children: [
|
|
231
235
|
/* @__PURE__ */ jsx("option", { value: "", children: t("ticket.allProjects") }),
|
|
232
236
|
projects.map((p) => /* @__PURE__ */ jsx("option", { value: p.id, children: p.name }, p.id))
|
|
233
237
|
] })
|
|
234
238
|
] }),
|
|
235
239
|
/* @__PURE__ */ jsxs("div", { className: styles.fieldGroup, children: [
|
|
236
|
-
/* @__PURE__ */ jsx("label", { className: styles.label, children: t("billing.filters.hourlyRate") }),
|
|
240
|
+
/* @__PURE__ */ jsx("label", { className: styles.label, htmlFor: rateId, children: t("billing.filters.hourlyRate") }),
|
|
237
241
|
/* @__PURE__ */ jsxs("div", { className: styles.rateRow, children: [
|
|
238
242
|
/* @__PURE__ */ jsx(
|
|
239
243
|
"input",
|
|
240
244
|
{
|
|
245
|
+
id: rateId,
|
|
241
246
|
type: "number",
|
|
242
247
|
value: rate,
|
|
243
248
|
onChange: (e) => setRate(Number(e.target.value)),
|
|
@@ -293,6 +298,7 @@ const BillingClient = () => {
|
|
|
293
298
|
"input",
|
|
294
299
|
{
|
|
295
300
|
type: "checkbox",
|
|
301
|
+
"aria-label": t("billing.tableCheckboxTitle"),
|
|
296
302
|
checked: group.tickets.every((t2) => billedTickets.has(t2.id)),
|
|
297
303
|
onChange: () => {
|
|
298
304
|
const ids = group.tickets.map((t2) => t2.id);
|
|
@@ -326,6 +332,7 @@ const BillingClient = () => {
|
|
|
326
332
|
"input",
|
|
327
333
|
{
|
|
328
334
|
type: "checkbox",
|
|
335
|
+
"aria-label": isBilled ? t("billing.markUnbilledTitle") : t("billing.markBilledTitle"),
|
|
329
336
|
checked: isBilled,
|
|
330
337
|
onChange: () => toggleBilled(ticket.id),
|
|
331
338
|
className: styles.checkbox,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { DefaultTemplate } from '@payloadcms/next/templates';
|
|
3
3
|
import { redirect } from 'next/navigation';
|
|
4
|
+
import { supportViewRedirectTarget } from '../shared/viewAccess.js';
|
|
4
5
|
import { AdminErrorBoundary } from '../shared/ErrorBoundary.js';
|
|
5
6
|
import { BillingClient } from './client.js';
|
|
6
7
|
|
|
7
8
|
const BillingView = ({ initPageResult }) => {
|
|
8
9
|
const { req, visibleEntities } = initPageResult;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
10
|
+
const redirectTo = supportViewRedirectTarget(initPageResult);
|
|
11
|
+
if (redirectTo) redirect(redirectTo);
|
|
12
12
|
return /* @__PURE__ */ jsx(
|
|
13
13
|
DefaultTemplate,
|
|
14
14
|
{
|
|
@@ -18,7 +18,7 @@ const BillingView = ({ initPageResult }) => {
|
|
|
18
18
|
payload: req.payload,
|
|
19
19
|
permissions: initPageResult.permissions,
|
|
20
20
|
searchParams: {},
|
|
21
|
-
user: req.user,
|
|
21
|
+
user: req.user ?? void 0,
|
|
22
22
|
visibleEntities,
|
|
23
23
|
children: /* @__PURE__ */ jsx(AdminErrorBoundary, { viewName: "BillingView", children: /* @__PURE__ */ jsx(BillingClient, {}) })
|
|
24
24
|
}
|
|
@@ -252,6 +252,7 @@ const ChatViewClient = () => {
|
|
|
252
252
|
cannedResponses.length > 0 && /* @__PURE__ */ jsxs(
|
|
253
253
|
"select",
|
|
254
254
|
{
|
|
255
|
+
"aria-label": t("chat.quickReply"),
|
|
255
256
|
onChange: (e) => {
|
|
256
257
|
const cr = cannedResponses.find((c) => String(c.id) === e.target.value);
|
|
257
258
|
if (cr) setInput(cr.body);
|
|
@@ -269,6 +270,7 @@ const ChatViewClient = () => {
|
|
|
269
270
|
"input",
|
|
270
271
|
{
|
|
271
272
|
type: "text",
|
|
273
|
+
"aria-label": t("chat.inputPlaceholder"),
|
|
272
274
|
value: input,
|
|
273
275
|
onChange: (e) => setInput(e.target.value),
|
|
274
276
|
placeholder: t("chat.inputPlaceholder"),
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { DefaultTemplate } from '@payloadcms/next/templates';
|
|
3
3
|
import { redirect } from 'next/navigation';
|
|
4
|
+
import { supportViewRedirectTarget } from '../shared/viewAccess.js';
|
|
4
5
|
import { AdminErrorBoundary } from '../shared/ErrorBoundary.js';
|
|
5
6
|
import { ChatViewClient } from './client.js';
|
|
6
7
|
|
|
7
8
|
const ChatView = ({ initPageResult }) => {
|
|
8
9
|
const { req, visibleEntities } = initPageResult;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
10
|
+
const redirectTo = supportViewRedirectTarget(initPageResult);
|
|
11
|
+
if (redirectTo) redirect(redirectTo);
|
|
12
12
|
return /* @__PURE__ */ jsx(
|
|
13
13
|
DefaultTemplate,
|
|
14
14
|
{
|
|
@@ -18,7 +18,7 @@ const ChatView = ({ initPageResult }) => {
|
|
|
18
18
|
payload: req.payload,
|
|
19
19
|
permissions: initPageResult.permissions,
|
|
20
20
|
searchParams: {},
|
|
21
|
-
user: req.user,
|
|
21
|
+
user: req.user ?? void 0,
|
|
22
22
|
visibleEntities,
|
|
23
23
|
children: /* @__PURE__ */ jsx(AdminErrorBoundary, { viewName: "ChatView", children: /* @__PURE__ */ jsx(ChatViewClient, {}) })
|
|
24
24
|
}
|
|
@@ -211,6 +211,7 @@ Cette action est irr\xE9versible.`)) return;
|
|
|
211
211
|
"input",
|
|
212
212
|
{
|
|
213
213
|
type: "text",
|
|
214
|
+
"aria-label": t("crm.searchLabel"),
|
|
214
215
|
placeholder: t("crm.searchPlaceholder"),
|
|
215
216
|
value: search,
|
|
216
217
|
onChange: (e) => setSearch(e.target.value),
|
|
@@ -295,6 +296,7 @@ Cette action est irr\xE9versible.`)) return;
|
|
|
295
296
|
"input",
|
|
296
297
|
{
|
|
297
298
|
type: "text",
|
|
299
|
+
"aria-label": t("crm.mergeTitle"),
|
|
298
300
|
value: mergeSearch,
|
|
299
301
|
onChange: (e) => setMergeSearch(e.target.value),
|
|
300
302
|
placeholder: t("crm.mergeSearchPlaceholder"),
|