@buerokratt-ria/common-gui-components 0.0.57 → 0.0.59
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/CHANGELOG.md +10 -0
- package/package.json +1 -1
- package/templates/history-page/src/History.scss +33 -3
- package/templates/history-page/src/components/ChatMetadataPanel/ChatMetadataPanel.scss +18 -0
- package/templates/history-page/src/components/ChatMetadataPanel/index.tsx +206 -0
- package/templates/history-page/src/components/ChatMetadataPanelItem/index.tsx +17 -0
- package/templates/history-page/src/components/FilterTag/FilterTag.scss +42 -0
- package/templates/history-page/src/components/FilterTag/index.tsx +16 -0
- package/templates/history-page/src/components/HeaderCombobox/index.tsx +66 -0
- package/templates/history-page/src/components/QualitySettings/QualitySettings.scss +19 -0
- package/templates/history-page/src/components/QualitySettings/index.tsx +115 -0
- package/templates/history-page/src/components/SelectedFilterTags/SelectedFilterTags.scss +36 -0
- package/templates/history-page/src/components/SelectedFilterTags/index.tsx +224 -0
- package/templates/history-page/src/components/index.tsx +6 -0
- package/templates/history-page/src/index.tsx +943 -209
- package/templates/history-page/src/types/index.ts +17 -0
- package/translations/en/common.json +22 -2
- package/translations/et/common.json +22 -2
- package/types/chat.ts +3 -0
- package/ui-components/FormElements/FormCombobox/FormCombobox.scss +252 -0
- package/ui-components/FormElements/FormCombobox/index.tsx +334 -0
- package/ui-components/FormElements/index.tsx +1 -0
- package/ui-components/HistoricalChat/ChatMessage.tsx +24 -9
- package/ui-components/HistoricalChat/index.tsx +16 -6
- package/ui-components/Icon/index.tsx +1 -0
- package/ui-components/index.tsx +2 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {FC, PropsWithChildren, useEffect, useMemo, useRef, useState} from 'react';
|
|
2
|
+
import type {ComponentProps} from 'react';
|
|
2
3
|
import {useTranslation} from 'react-i18next';
|
|
3
|
-
import {useMutation} from '@tanstack/react-query';
|
|
4
|
+
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
|
4
5
|
import {ColumnPinningState, createColumnHelper, PaginationState, SortingState,} from '@tanstack/react-table';
|
|
5
6
|
import {endOfDay, format, formatISO, startOfDay} from "date-fns";
|
|
6
7
|
import {AxiosError} from 'axios';
|
|
7
8
|
import './History.scss';
|
|
8
|
-
import {MdOutlineRemoveRedEye
|
|
9
|
+
import {MdOutlineRemoveRedEye} from 'react-icons/md';
|
|
9
10
|
import {CgSpinner} from 'react-icons/cg';
|
|
10
11
|
|
|
11
12
|
import {
|
|
12
13
|
Button,
|
|
13
14
|
Card,
|
|
14
|
-
ClearFiltersButton,
|
|
15
15
|
DataTable,
|
|
16
16
|
Dialog,
|
|
17
17
|
Drawer,
|
|
@@ -38,6 +38,8 @@ import {ToastContextType} from "../../../context";
|
|
|
38
38
|
import {getDomainsArray} from "../../../utils/multiDomain-utils";
|
|
39
39
|
import {StoreState} from "../../../store";
|
|
40
40
|
import {saveFile} from "../../../services/file";
|
|
41
|
+
import {ChatMetadataPanel, HeaderCombobox, QualitySettings, SelectedFilterTags} from './components';
|
|
42
|
+
import { CharMeasurementType } from './types';
|
|
41
43
|
|
|
42
44
|
type HistoryProps = {
|
|
43
45
|
user: UserInfo | null;
|
|
@@ -62,7 +64,132 @@ type ExportResult = {
|
|
|
62
64
|
chatIds: string[];
|
|
63
65
|
};
|
|
64
66
|
|
|
67
|
+
type QualitySettingsConfig = {
|
|
68
|
+
readonly chatAnalysisEnabled: boolean;
|
|
69
|
+
readonly chatAnalysisTheme: string[];
|
|
70
|
+
readonly chatAnalysisBykResponseQuality: string[];
|
|
71
|
+
readonly chatAnalysisFollowUpAction: string[];
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type DomainSelection = {
|
|
75
|
+
readonly id: string;
|
|
76
|
+
readonly name: string;
|
|
77
|
+
readonly url: string;
|
|
78
|
+
readonly selected: boolean;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
type FeedbackConfig = {
|
|
82
|
+
readonly isFiveRatingScale?: string | boolean;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const GLOBAL_FEEDBACK_CONFIG_DOMAIN = 'none';
|
|
86
|
+
|
|
87
|
+
export const MEASUREMENT_TYPES = {
|
|
88
|
+
THEME: 'THEME',
|
|
89
|
+
QUALITY: 'QUALITY',
|
|
90
|
+
FOLLOW_UP_ACTION: 'FOLLOW_UP_ACTION',
|
|
91
|
+
} as const;
|
|
92
|
+
|
|
93
|
+
export type MeasurementType =
|
|
94
|
+
(typeof MEASUREMENT_TYPES)[keyof typeof MEASUREMENT_TYPES];
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
export const postQualityMeasurements = (body: {
|
|
98
|
+
readonly chatUuid: string;
|
|
99
|
+
readonly type: MeasurementType;
|
|
100
|
+
readonly value: string | string[];
|
|
101
|
+
}) =>
|
|
102
|
+
apiDev.post('chats/quality/measurements', body);
|
|
103
|
+
|
|
104
|
+
export const getQualityMeasurements = (params: {
|
|
105
|
+
readonly chatUuid: string;
|
|
106
|
+
}) =>
|
|
107
|
+
apiDev.get<{
|
|
108
|
+
readonly response: CharMeasurementType[];
|
|
109
|
+
}>('chats/quality/measurements', { params });
|
|
110
|
+
|
|
111
|
+
export const getWidgetData = async (userId: string) => {
|
|
112
|
+
const { data } = await apiDev.get<DomainSelection[]>('accounts/widget-data', {
|
|
113
|
+
params: {
|
|
114
|
+
user_id: userId,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const loadQualitySettingsConfig = async (domain: string): Promise<QualitySettingsConfig> => {
|
|
121
|
+
const response = await apiDev.get<{
|
|
122
|
+
readonly response: {
|
|
123
|
+
readonly chatAnalysisEnabled: boolean;
|
|
124
|
+
readonly chatAnalysisTheme: string; // can be an empty string if no themes are defined
|
|
125
|
+
readonly chatAnalysisBykResponseQuality: string; // can be an empty string if no qualities are defined
|
|
126
|
+
readonly chatAnalysisFollowUpAction: string; // can be an empty string if no follow-up actions are defined
|
|
127
|
+
};
|
|
128
|
+
}>('/configs/chat-analysis', {
|
|
129
|
+
params: { domain },
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
chatAnalysisEnabled: response.data.response.chatAnalysisEnabled,
|
|
133
|
+
chatAnalysisTheme: response.data.response.chatAnalysisTheme.split(',').filter(Boolean),
|
|
134
|
+
chatAnalysisBykResponseQuality: response.data.response.chatAnalysisBykResponseQuality.split(',').filter(Boolean),
|
|
135
|
+
chatAnalysisFollowUpAction: response.data.response.chatAnalysisFollowUpAction.split(',').filter(Boolean),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const loadFeedbackConfig = async (): Promise<FeedbackConfig> => {
|
|
140
|
+
const response = await apiDev.get('/configs/feedback', {
|
|
141
|
+
params: { domain: GLOBAL_FEEDBACK_CONFIG_DOMAIN },
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return response.data.response ?? response.data;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const isFiveRatingScaleEnabled = (value?: string | boolean | null) =>
|
|
148
|
+
value === true || value === 'true';
|
|
149
|
+
|
|
150
|
+
const formatChatAnalysisCell = (
|
|
151
|
+
value: string[] | null | undefined,
|
|
152
|
+
selectionEmptiedLabel: string
|
|
153
|
+
) => {
|
|
154
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
155
|
+
return '';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (value.length === 1 && value[0] === '') {
|
|
159
|
+
return selectionEmptiedLabel;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return value.join(', ');
|
|
163
|
+
};
|
|
164
|
+
|
|
65
165
|
const ALL_COLUMNS_VALUE = '__all__';
|
|
166
|
+
const BOOLEAN_SORT_COLUMN_IDS = new Set([
|
|
167
|
+
'authenticatedPerson',
|
|
168
|
+
'istest',
|
|
169
|
+
'isPreserve',
|
|
170
|
+
]);
|
|
171
|
+
const CHAT_STATUSES = [
|
|
172
|
+
CHAT_EVENTS.ACCEPTED,
|
|
173
|
+
CHAT_EVENTS.CLIENT_LEFT_FOR_UNKNOWN_REASONS,
|
|
174
|
+
CHAT_EVENTS.CLIENT_LEFT_WITH_ACCEPTED,
|
|
175
|
+
CHAT_EVENTS.CLIENT_LEFT_WITH_NO_RESOLUTION,
|
|
176
|
+
CHAT_EVENTS.HATE_SPEECH,
|
|
177
|
+
CHAT_EVENTS.OTHER,
|
|
178
|
+
CHAT_EVENTS.RESPONSE_SENT_TO_CLIENT_EMAIL,
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
const getEndedChatsSortBy = (sorting: SortingState) => {
|
|
182
|
+
if (sorting.length === 0) {
|
|
183
|
+
return 'created desc';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const [sortingObject] = sorting;
|
|
187
|
+
const sortType = BOOLEAN_SORT_COLUMN_IDS.has(sortingObject.id)
|
|
188
|
+
? sortingObject.desc ? 'asc' : 'desc'
|
|
189
|
+
: sortingObject.desc ? 'desc' : 'asc';
|
|
190
|
+
|
|
191
|
+
return `${sortingObject.id} ${sortType}`;
|
|
192
|
+
};
|
|
66
193
|
|
|
67
194
|
const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
68
195
|
user,
|
|
@@ -81,6 +208,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
81
208
|
delegatedStartDate = null
|
|
82
209
|
}) => {
|
|
83
210
|
const {t, i18n} = useTranslation();
|
|
211
|
+
const queryClient = useQueryClient();
|
|
84
212
|
const toast = toastContext;
|
|
85
213
|
const userInfo = user;
|
|
86
214
|
const routerLocation = useLocation();
|
|
@@ -89,6 +217,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
89
217
|
const passedStartDate = delegatedStartDate ?? params.get("start");
|
|
90
218
|
const passedEndDate = delegatedEndDate ?? params.get("end");
|
|
91
219
|
const skipNextSelectedColumnsEffect = useRef(false);
|
|
220
|
+
const skipInitialTableHeaderFilterEffect = useRef(true);
|
|
92
221
|
const [selectedChat, setSelectedChat] = useState<ChatType | null>(null);
|
|
93
222
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
94
223
|
const [statusChangeModal, setStatusChangeModal] = useState<string | null>(
|
|
@@ -119,7 +248,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
119
248
|
|
|
120
249
|
const useStore = userDomains;
|
|
121
250
|
const [updateKey, setUpdateKey] = useState<number>(0)
|
|
122
|
-
const currentDomains = useStore.getState().userDomains;
|
|
251
|
+
const currentDomains = useStore.getState().userDomains as string[];
|
|
123
252
|
const multiDomainEnabled = import.meta.env.REACT_APP_ENABLE_MULTI_DOMAIN?.toLowerCase() === 'true';
|
|
124
253
|
const testMessageEnabled = import.meta.env.REACT_APP_SHOW_TEST_MESSAGE?.toLowerCase() === 'true';
|
|
125
254
|
const envVal = import.meta.env.REACT_APP_SHOW_TEST_CONVERSATIONS;
|
|
@@ -129,6 +258,12 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
129
258
|
const loadingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
130
259
|
const timeoutAbortRef = useRef(false);
|
|
131
260
|
|
|
261
|
+
const userWidgetDomains = useQuery<DomainSelection[]>({
|
|
262
|
+
queryKey: ['accounts/widget-data', userInfo?.idCode],
|
|
263
|
+
queryFn: () => getWidgetData(userInfo!.idCode),
|
|
264
|
+
enabled: !!userInfo?.idCode,
|
|
265
|
+
});
|
|
266
|
+
|
|
132
267
|
const parseDateParam = (dateString: string | null) => {
|
|
133
268
|
if (!dateString) return new Date();
|
|
134
269
|
return new Date(dateString.split("+")[0]);
|
|
@@ -285,6 +420,19 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
285
420
|
},
|
|
286
421
|
});
|
|
287
422
|
|
|
423
|
+
const selectedChatDomainUuid = useMemo(() => {
|
|
424
|
+
return userWidgetDomains.data?.find(domain => domain.url === selectedChat?.endUserUrl)?.id ?? null;
|
|
425
|
+
}, [selectedChat]);
|
|
426
|
+
const qualitySettingsConfigQuery = useQuery<QualitySettingsConfig>({
|
|
427
|
+
queryKey: ['configs/chat-analysis'],
|
|
428
|
+
queryFn: () => loadQualitySettingsConfig(selectedChatDomainUuid ? selectedChatDomainUuid : GLOBAL_FEEDBACK_CONFIG_DOMAIN),
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
const isChatAnalysisEnabled = useMemo(() => {
|
|
432
|
+
return qualitySettingsConfigQuery.data?.chatAnalysisEnabled ?? false;
|
|
433
|
+
}, [qualitySettingsConfigQuery.data]);
|
|
434
|
+
console.log("IS CHAT ANALYSIS ENABLED", isChatAnalysisEnabled);
|
|
435
|
+
|
|
288
436
|
const getAllEndedChats = useMutation({
|
|
289
437
|
mutationFn: (data: {
|
|
290
438
|
startDate: string;
|
|
@@ -292,27 +440,25 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
292
440
|
pagination: PaginationState;
|
|
293
441
|
sorting: SortingState;
|
|
294
442
|
search: string;
|
|
443
|
+
urls?: string[];
|
|
295
444
|
}) => {
|
|
296
445
|
abortRef.current?.abort();
|
|
297
446
|
abortRef.current = new AbortController();
|
|
298
447
|
|
|
299
|
-
|
|
300
|
-
if (sorting.length > 0) {
|
|
301
|
-
const sortType = sorting[0].desc ? 'desc' : 'asc';
|
|
302
|
-
sortBy = `${sorting[0].id} ${sortType}`;
|
|
303
|
-
}
|
|
448
|
+
const sortBy = getEndedChatsSortBy(data.sorting);
|
|
304
449
|
|
|
305
450
|
return apiDevEnded.post('agents/chats/ended', {
|
|
306
451
|
startDate: formatISO(startOfDay(new Date(data.startDate))),
|
|
307
452
|
endDate: formatISO(endOfDay(new Date(data.endDate))),
|
|
308
|
-
|
|
309
|
-
|
|
453
|
+
...endedChatsFilterBody,
|
|
454
|
+
...(data.urls?.length ? {urls: getDomainsArray(data.urls)} : {}),
|
|
310
455
|
page: data.pagination.pageIndex + 1,
|
|
311
456
|
page_size: data.pagination.pageSize,
|
|
312
457
|
sorting: sortBy,
|
|
313
458
|
search,
|
|
314
459
|
},
|
|
315
460
|
{
|
|
461
|
+
params: { isChatAnalysisEnabled },
|
|
316
462
|
signal: abortRef.current.signal
|
|
317
463
|
}
|
|
318
464
|
);
|
|
@@ -390,8 +536,16 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
390
536
|
|
|
391
537
|
columns.splice(5, 0, {label: t('global.preserve'), value: 'isPreserve'});
|
|
392
538
|
|
|
539
|
+
if (isChatAnalysisEnabled) {
|
|
540
|
+
columns.push(
|
|
541
|
+
{label: t('chat.history.theme'), value: 'theme'},
|
|
542
|
+
{label: t('chat.history.responseQuality'), value: 'responseQuality'},
|
|
543
|
+
{label: t('chat.history.followUpStatus'), value: 'followUpStatus'}
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
|
|
393
547
|
return columns;
|
|
394
|
-
}, [t, showEmail, testMessageEnabled])
|
|
548
|
+
}, [t, showEmail, testMessageEnabled, isChatAnalysisEnabled])
|
|
395
549
|
|
|
396
550
|
const visibleColumnOptions = useMemo(() => [
|
|
397
551
|
{label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE},
|
|
@@ -732,6 +886,335 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
732
886
|
</Button>
|
|
733
887
|
);
|
|
734
888
|
|
|
889
|
+
const customerSupportAgentsQuery = useQuery({
|
|
890
|
+
queryKey: ['customer-support-agents'],
|
|
891
|
+
queryFn: () =>
|
|
892
|
+
apiDev.post<{
|
|
893
|
+
readonly response: {
|
|
894
|
+
readonly login: string;
|
|
895
|
+
readonly firstName: string;
|
|
896
|
+
readonly lastName: string;
|
|
897
|
+
readonly idCode: string;
|
|
898
|
+
readonly displayName: string;
|
|
899
|
+
readonly csaTitle: string;
|
|
900
|
+
readonly csaEmail: string;
|
|
901
|
+
readonly department: string;
|
|
902
|
+
readonly jiraAccountId: string;
|
|
903
|
+
readonly smaxAccountId: string;
|
|
904
|
+
readonly authorities: string[];
|
|
905
|
+
readonly customerSupportStatus: string;
|
|
906
|
+
readonly statusComment: string;
|
|
907
|
+
readonly statusCommentTimeStamp: string;
|
|
908
|
+
readonly domains: (string | null)[] | null;
|
|
909
|
+
readonly totalPages: number;
|
|
910
|
+
}[];
|
|
911
|
+
}>('accounts/customer-support-agents', {
|
|
912
|
+
page: 0,
|
|
913
|
+
page_size: 99999,
|
|
914
|
+
sorting: 'name asc',
|
|
915
|
+
show_active_only: false,
|
|
916
|
+
roles: ['ROLE_CUSTOMER_SUPPORT_AGENT'],
|
|
917
|
+
}),
|
|
918
|
+
select: (result) => {
|
|
919
|
+
return [
|
|
920
|
+
{ label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE },
|
|
921
|
+
{ label: 'Bürokratt', value: 'chatbot' },
|
|
922
|
+
...result.data.response.map((item) => ({
|
|
923
|
+
label: [item.firstName, item.lastName].join(' ').trim(),
|
|
924
|
+
value: item.idCode,
|
|
925
|
+
})),
|
|
926
|
+
]
|
|
927
|
+
},
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
const tableHeaderForm = useForm<{
|
|
931
|
+
readonly csaIdCodesFilter: string[];
|
|
932
|
+
readonly feedbackRatings: string[];
|
|
933
|
+
readonly showAuthenticatedPerson?: boolean;
|
|
934
|
+
readonly isTestFilter?: boolean;
|
|
935
|
+
readonly isPreserveFilter?: boolean;
|
|
936
|
+
readonly domains: string[];
|
|
937
|
+
readonly status: string[];
|
|
938
|
+
readonly theme: string[];
|
|
939
|
+
readonly responseQuality: string[];
|
|
940
|
+
readonly followUpStatus: string[];
|
|
941
|
+
}>({
|
|
942
|
+
defaultValues: {
|
|
943
|
+
csaIdCodesFilter: [],
|
|
944
|
+
feedbackRatings: [],
|
|
945
|
+
showAuthenticatedPerson: undefined,
|
|
946
|
+
isTestFilter: undefined,
|
|
947
|
+
isPreserveFilter: undefined,
|
|
948
|
+
domains: [],
|
|
949
|
+
status: [],
|
|
950
|
+
theme: [],
|
|
951
|
+
responseQuality: [],
|
|
952
|
+
followUpStatus: [],
|
|
953
|
+
},
|
|
954
|
+
});
|
|
955
|
+
const { reset: resetTableHeaderForm, setValue: setTableHeaderValue } = tableHeaderForm;
|
|
956
|
+
const csaIdCodesFilter = tableHeaderForm.watch('csaIdCodesFilter');
|
|
957
|
+
const feedbackRatings = tableHeaderForm.watch('feedbackRatings');
|
|
958
|
+
const showAuthenticatedPerson = tableHeaderForm.watch('showAuthenticatedPerson');
|
|
959
|
+
const isTestFilter = tableHeaderForm.watch('isTestFilter');
|
|
960
|
+
const isPreserveFilter = tableHeaderForm.watch('isPreserveFilter');
|
|
961
|
+
const domains = tableHeaderForm.watch('domains');
|
|
962
|
+
const status = tableHeaderForm.watch('status');
|
|
963
|
+
const theme = tableHeaderForm.watch('theme');
|
|
964
|
+
const responseQuality = tableHeaderForm.watch('responseQuality');
|
|
965
|
+
const followUpStatus = tableHeaderForm.watch('followUpStatus');
|
|
966
|
+
|
|
967
|
+
useEffect(() => {
|
|
968
|
+
if (skipInitialTableHeaderFilterEffect.current) {
|
|
969
|
+
skipInitialTableHeaderFilterEffect.current = false;
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const resetPagination = { pageIndex: 0, pageSize: pagination.pageSize };
|
|
974
|
+
setPagination(resetPagination);
|
|
975
|
+
setSearchParams((params) => {
|
|
976
|
+
params.set("page", "1");
|
|
977
|
+
return params;
|
|
978
|
+
});
|
|
979
|
+
getAllEndedChats.mutate({
|
|
980
|
+
startDate: formatISO(startOfDay(new Date(startDate))),
|
|
981
|
+
endDate: formatISO(endOfDay(new Date(endDate))),
|
|
982
|
+
pagination: resetPagination,
|
|
983
|
+
sorting,
|
|
984
|
+
search,
|
|
985
|
+
});
|
|
986
|
+
}, [csaIdCodesFilter, feedbackRatings, showAuthenticatedPerson, isTestFilter, isPreserveFilter, domains, status, theme, responseQuality, followUpStatus]);
|
|
987
|
+
|
|
988
|
+
const getBooleanComboboxValue = (value?: boolean) =>
|
|
989
|
+
value === undefined ? '' : String(value);
|
|
990
|
+
const getBooleanFormValue = (value: string) =>
|
|
991
|
+
value ? value === 'true' : undefined;
|
|
992
|
+
const getBooleanApiFilterValue = (value?: boolean) =>
|
|
993
|
+
value === undefined ? [] : [value];
|
|
994
|
+
const getRealStringFilterValues = (values: string[]) =>
|
|
995
|
+
values.filter((value) => value !== ALL_COLUMNS_VALUE);
|
|
996
|
+
const getAllStringFilterValues = (options: { readonly value: string }[]) =>
|
|
997
|
+
getRealStringFilterValues(options.map((option) => option.value));
|
|
998
|
+
const normalizeAllOptionFilterValues = (
|
|
999
|
+
values: string[],
|
|
1000
|
+
currentValues: string[],
|
|
1001
|
+
allValues: string[]
|
|
1002
|
+
) => {
|
|
1003
|
+
const currentAllSelected = currentValues.includes(ALL_COLUMNS_VALUE);
|
|
1004
|
+
const nextAllSelected = values.includes(ALL_COLUMNS_VALUE);
|
|
1005
|
+
|
|
1006
|
+
if (nextAllSelected && !currentAllSelected) {
|
|
1007
|
+
return [ALL_COLUMNS_VALUE, ...allValues];
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
if (!nextAllSelected && currentAllSelected) {
|
|
1011
|
+
return [];
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
const realValues = getRealStringFilterValues(values);
|
|
1015
|
+
|
|
1016
|
+
if (allValues.length > 0 && allValues.every((value) => realValues.includes(value))) {
|
|
1017
|
+
return [ALL_COLUMNS_VALUE, ...allValues];
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
return realValues;
|
|
1021
|
+
};
|
|
1022
|
+
const getRealCsaFilterValues = (values: string[]) =>
|
|
1023
|
+
getRealStringFilterValues(values);
|
|
1024
|
+
const getAllCsaFilterValues = () =>
|
|
1025
|
+
getRealCsaFilterValues(customerSupportAgentsQuery.data?.map((option) => option.value) ?? []);
|
|
1026
|
+
const getFeedbackRatingFilterValues = (values: string[]) =>
|
|
1027
|
+
values
|
|
1028
|
+
.map((value) => Number(value))
|
|
1029
|
+
.filter((value) => Number.isInteger(value));
|
|
1030
|
+
const normalizeCsaFilterValues = (values: string[]) => {
|
|
1031
|
+
const currentAllSelected = csaIdCodesFilter.includes(ALL_COLUMNS_VALUE);
|
|
1032
|
+
const nextAllSelected = values.includes(ALL_COLUMNS_VALUE);
|
|
1033
|
+
const allCsaFilterValues = getAllCsaFilterValues();
|
|
1034
|
+
|
|
1035
|
+
if (nextAllSelected && !currentAllSelected) {
|
|
1036
|
+
return [ALL_COLUMNS_VALUE, ...allCsaFilterValues];
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
if (!nextAllSelected && currentAllSelected) {
|
|
1040
|
+
return [];
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
const realValues = getRealCsaFilterValues(values);
|
|
1044
|
+
|
|
1045
|
+
if (allCsaFilterValues.length > 0 && allCsaFilterValues.every((value) => realValues.includes(value))) {
|
|
1046
|
+
return [ALL_COLUMNS_VALUE, ...allCsaFilterValues];
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
return realValues;
|
|
1050
|
+
};
|
|
1051
|
+
const csaFilterTagValues = getRealCsaFilterValues(csaIdCodesFilter);
|
|
1052
|
+
const csaFilterTagLabelsByValue = useMemo(() => {
|
|
1053
|
+
return new Map(
|
|
1054
|
+
(customerSupportAgentsQuery.data ?? []).map((option) => [option.value, option.label])
|
|
1055
|
+
);
|
|
1056
|
+
}, [customerSupportAgentsQuery.data]);
|
|
1057
|
+
const getCsaFilterTagLabel = (value: string) => csaFilterTagLabelsByValue.get(value) ?? value;
|
|
1058
|
+
const removeSelectedFilterTag: ComponentProps<typeof SelectedFilterTags>['onRemove'] = (filter, value) => {
|
|
1059
|
+
switch (filter) {
|
|
1060
|
+
case 'csaIdCodesFilter':
|
|
1061
|
+
setTableHeaderValue(
|
|
1062
|
+
filter,
|
|
1063
|
+
getRealCsaFilterValues(csaIdCodesFilter).filter((item) => item !== value)
|
|
1064
|
+
);
|
|
1065
|
+
return;
|
|
1066
|
+
case 'showAuthenticatedPerson':
|
|
1067
|
+
case 'isTestFilter':
|
|
1068
|
+
case 'isPreserveFilter':
|
|
1069
|
+
setTableHeaderValue(filter, undefined);
|
|
1070
|
+
return;
|
|
1071
|
+
case 'domains':
|
|
1072
|
+
setTableHeaderValue(filter, getRealStringFilterValues(domains).filter((item) => item !== value));
|
|
1073
|
+
return;
|
|
1074
|
+
case 'feedbackRatings':
|
|
1075
|
+
setTableHeaderValue(filter, getRealStringFilterValues(feedbackRatings).filter((item) => item !== value));
|
|
1076
|
+
return;
|
|
1077
|
+
case 'status':
|
|
1078
|
+
setTableHeaderValue(filter, getRealStringFilterValues(status).filter((item) => item !== value));
|
|
1079
|
+
return;
|
|
1080
|
+
case 'theme':
|
|
1081
|
+
setTableHeaderValue(filter, getRealStringFilterValues(theme).filter((item) => item !== value));
|
|
1082
|
+
return;
|
|
1083
|
+
case 'responseQuality':
|
|
1084
|
+
setTableHeaderValue(filter, getRealStringFilterValues(responseQuality).filter((item) => item !== value));
|
|
1085
|
+
return;
|
|
1086
|
+
case 'followUpStatus':
|
|
1087
|
+
setTableHeaderValue(filter, getRealStringFilterValues(followUpStatus).filter((item) => item !== value));
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1091
|
+
const globalFeedbackConfigQuery = useQuery<FeedbackConfig>({
|
|
1092
|
+
queryKey: ['configs/feedback', GLOBAL_FEEDBACK_CONFIG_DOMAIN],
|
|
1093
|
+
queryFn: loadFeedbackConfig,
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
const tableHeaderQualitySettingsConfigQuery = useQuery<QualitySettingsConfig>({
|
|
1097
|
+
queryKey: ['configs/chat-analysis', GLOBAL_FEEDBACK_CONFIG_DOMAIN],
|
|
1098
|
+
queryFn: () => loadQualitySettingsConfig(GLOBAL_FEEDBACK_CONFIG_DOMAIN),
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
const realRatingOptions = useMemo(() => {
|
|
1102
|
+
const isFiveRatingScale = isFiveRatingScaleEnabled(globalFeedbackConfigQuery.data?.isFiveRatingScale);
|
|
1103
|
+
const ratingMin = isFiveRatingScale ? 1 : 0;
|
|
1104
|
+
const ratingMax = isFiveRatingScale ? 5 : 10;
|
|
1105
|
+
|
|
1106
|
+
return Array.from({ length: ratingMax - ratingMin + 1 }, (_, index) => {
|
|
1107
|
+
const rating = ratingMin + index;
|
|
1108
|
+
|
|
1109
|
+
return {
|
|
1110
|
+
label: String(rating),
|
|
1111
|
+
value: String(rating),
|
|
1112
|
+
};
|
|
1113
|
+
});
|
|
1114
|
+
}, [globalFeedbackConfigQuery.data?.isFiveRatingScale]);
|
|
1115
|
+
|
|
1116
|
+
const ratingOptions = useMemo(() => [
|
|
1117
|
+
{ label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE },
|
|
1118
|
+
...realRatingOptions,
|
|
1119
|
+
], [t, realRatingOptions]);
|
|
1120
|
+
|
|
1121
|
+
const realStatusOptions = useMemo(() => {
|
|
1122
|
+
return CHAT_STATUSES.map((chatStatus) => ({
|
|
1123
|
+
label: t(`chat.plainEvents.${chatStatus}`),
|
|
1124
|
+
value: chatStatus,
|
|
1125
|
+
}));
|
|
1126
|
+
}, [t]);
|
|
1127
|
+
|
|
1128
|
+
const statusOptions = useMemo(() => [
|
|
1129
|
+
{ label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE },
|
|
1130
|
+
...realStatusOptions,
|
|
1131
|
+
], [t, realStatusOptions]);
|
|
1132
|
+
|
|
1133
|
+
const domainOptions = useMemo(() => [
|
|
1134
|
+
{ label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE },
|
|
1135
|
+
...currentDomains.map((domain) => ({
|
|
1136
|
+
label: domain,
|
|
1137
|
+
value: domain,
|
|
1138
|
+
})),
|
|
1139
|
+
], [t, currentDomains]);
|
|
1140
|
+
|
|
1141
|
+
const realThemeOptions = tableHeaderQualitySettingsConfigQuery.data?.chatAnalysisTheme.map(item => {
|
|
1142
|
+
return { label: item, value: item }
|
|
1143
|
+
}) ?? [];
|
|
1144
|
+
const realResponseQualityOptions = tableHeaderQualitySettingsConfigQuery.data?.chatAnalysisBykResponseQuality.map(item => {
|
|
1145
|
+
return { label: item, value: item }
|
|
1146
|
+
}) ?? [];
|
|
1147
|
+
const realFollowUpStatusOptions = tableHeaderQualitySettingsConfigQuery.data?.chatAnalysisFollowUpAction.map(item => {
|
|
1148
|
+
return { label: item, value: item }
|
|
1149
|
+
}) ?? [];
|
|
1150
|
+
|
|
1151
|
+
const themeOptions = useMemo(() => [
|
|
1152
|
+
{ label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE },
|
|
1153
|
+
...realThemeOptions,
|
|
1154
|
+
], [t, realThemeOptions]);
|
|
1155
|
+
|
|
1156
|
+
const responseQualityOptions = useMemo(() => [
|
|
1157
|
+
{ label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE },
|
|
1158
|
+
...realResponseQualityOptions,
|
|
1159
|
+
], [t, realResponseQualityOptions]);
|
|
1160
|
+
|
|
1161
|
+
const followUpStatusOptions = useMemo(() => [
|
|
1162
|
+
{ label: t('chat.history.chooseAll'), value: ALL_COLUMNS_VALUE },
|
|
1163
|
+
...realFollowUpStatusOptions,
|
|
1164
|
+
], [t, realFollowUpStatusOptions]);
|
|
1165
|
+
|
|
1166
|
+
const feedbackRatingFilterValues = getRealStringFilterValues(feedbackRatings);
|
|
1167
|
+
const statusFilterValues = getRealStringFilterValues(status);
|
|
1168
|
+
const domainFilterValues = getRealStringFilterValues(domains);
|
|
1169
|
+
const themeFilterValues = getRealStringFilterValues(theme);
|
|
1170
|
+
const responseQualityFilterValues = getRealStringFilterValues(responseQuality);
|
|
1171
|
+
const followUpStatusFilterValues = getRealStringFilterValues(followUpStatus);
|
|
1172
|
+
|
|
1173
|
+
const endedChatsFilterBody = useMemo(() => {
|
|
1174
|
+
const currentCustomerSupportIds = getRealCsaFilterValues(csaIdCodesFilter);
|
|
1175
|
+
const currentFeedbackRatings = getFeedbackRatingFilterValues(feedbackRatings);
|
|
1176
|
+
const currentStatusValues = getRealStringFilterValues(status);
|
|
1177
|
+
const currentDomainValues = getRealStringFilterValues(domains);
|
|
1178
|
+
const currentIsTestValues = getBooleanApiFilterValue(isTestFilter);
|
|
1179
|
+
const currentShowAuthenticatedPersonValues = getBooleanApiFilterValue(showAuthenticatedPerson);
|
|
1180
|
+
const currentIsPreserveValues = getBooleanApiFilterValue(isPreserveFilter);
|
|
1181
|
+
const currentThemeValues = getRealStringFilterValues(theme);
|
|
1182
|
+
const currentResponseQualityValues = getRealStringFilterValues(responseQuality);
|
|
1183
|
+
const currentFollowUpStatusValues = getRealStringFilterValues(followUpStatus);
|
|
1184
|
+
|
|
1185
|
+
return {
|
|
1186
|
+
urls: getDomainsArray(currentDomainValues.length > 0 ? currentDomainValues : currentDomains),
|
|
1187
|
+
showTest: showTest,
|
|
1188
|
+
theme: currentThemeValues,
|
|
1189
|
+
responseQuality: currentResponseQualityValues,
|
|
1190
|
+
followUpStatus: currentFollowUpStatusValues,
|
|
1191
|
+
...(currentCustomerSupportIds.length > 0 && {customerSupportIds: currentCustomerSupportIds}),
|
|
1192
|
+
...(currentFeedbackRatings.length > 0 && {feedbackRatings: currentFeedbackRatings}),
|
|
1193
|
+
...(currentIsTestValues.length > 0 && {isTest: currentIsTestValues}),
|
|
1194
|
+
...(currentShowAuthenticatedPersonValues.length > 0 && {authenticatedChats: currentShowAuthenticatedPersonValues}),
|
|
1195
|
+
...(currentIsPreserveValues.length > 0 && {isPreserve: currentIsPreserveValues}),
|
|
1196
|
+
...(currentStatusValues.length > 0 && {status: currentStatusValues}),
|
|
1197
|
+
};
|
|
1198
|
+
}, [
|
|
1199
|
+
csaIdCodesFilter,
|
|
1200
|
+
currentDomains,
|
|
1201
|
+
domains,
|
|
1202
|
+
feedbackRatings,
|
|
1203
|
+
followUpStatus,
|
|
1204
|
+
isPreserveFilter,
|
|
1205
|
+
isTestFilter,
|
|
1206
|
+
responseQuality,
|
|
1207
|
+
showAuthenticatedPerson,
|
|
1208
|
+
showTest,
|
|
1209
|
+
status,
|
|
1210
|
+
theme,
|
|
1211
|
+
]);
|
|
1212
|
+
|
|
1213
|
+
const booleanFilterOptions = useMemo(() => [
|
|
1214
|
+
{ label: t('global.yes') ?? '', value: 'true' },
|
|
1215
|
+
{ label: t('global.no') ?? '', value: 'false' },
|
|
1216
|
+
], [t]);
|
|
1217
|
+
|
|
735
1218
|
const endedChatsColumns = useMemo(() => {
|
|
736
1219
|
const columns = [
|
|
737
1220
|
columnHelper.accessor('created', {
|
|
@@ -774,7 +1257,20 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
774
1257
|
},
|
|
775
1258
|
{
|
|
776
1259
|
id: `customerSupportFullName`,
|
|
777
|
-
header:
|
|
1260
|
+
header: () => {
|
|
1261
|
+
return (
|
|
1262
|
+
<HeaderCombobox
|
|
1263
|
+
label={t('chat.history.csaName')}
|
|
1264
|
+
options={customerSupportAgentsQuery.data ?? []}
|
|
1265
|
+
value={csaIdCodesFilter}
|
|
1266
|
+
onChange={(value) => {
|
|
1267
|
+
const normalizedValue = normalizeCsaFilterValues(value);
|
|
1268
|
+
tableHeaderForm.setValue('csaIdCodesFilter', normalizedValue);
|
|
1269
|
+
}}
|
|
1270
|
+
/>
|
|
1271
|
+
);
|
|
1272
|
+
},
|
|
1273
|
+
sortDescFirst: false,
|
|
778
1274
|
}
|
|
779
1275
|
),
|
|
780
1276
|
columnHelper.accessor(
|
|
@@ -784,30 +1280,134 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
784
1280
|
},
|
|
785
1281
|
{
|
|
786
1282
|
id: 'authenticatedPerson',
|
|
787
|
-
header:
|
|
1283
|
+
header: () => {
|
|
1284
|
+
return (
|
|
1285
|
+
<HeaderCombobox
|
|
1286
|
+
label={t('chat.history.authenticatedPerson') ?? ''}
|
|
1287
|
+
options={booleanFilterOptions}
|
|
1288
|
+
value={getBooleanComboboxValue(showAuthenticatedPerson)}
|
|
1289
|
+
onChange={(value) => {
|
|
1290
|
+
setTableHeaderValue('showAuthenticatedPerson', getBooleanFormValue(value));
|
|
1291
|
+
}}
|
|
1292
|
+
multiple={false}
|
|
1293
|
+
isSearchEnabled={false}
|
|
1294
|
+
/>
|
|
1295
|
+
);
|
|
1296
|
+
},
|
|
1297
|
+
sortDescFirst: false,
|
|
788
1298
|
}
|
|
789
1299
|
),
|
|
1300
|
+
...showEmail ? [
|
|
1301
|
+
columnHelper.accessor('endUserEmail', {
|
|
1302
|
+
id: 'endUserEmail',
|
|
1303
|
+
header: t('global.email'),
|
|
1304
|
+
sortDescFirst: false,
|
|
1305
|
+
})
|
|
1306
|
+
] : [],
|
|
1307
|
+
...testMessageEnabled ? [
|
|
1308
|
+
columnHelper.accessor('istest', {
|
|
1309
|
+
id: 'istest',
|
|
1310
|
+
header: () => {
|
|
1311
|
+
return (
|
|
1312
|
+
<HeaderCombobox
|
|
1313
|
+
label={t('global.test')}
|
|
1314
|
+
options={booleanFilterOptions}
|
|
1315
|
+
value={getBooleanComboboxValue(isTestFilter)}
|
|
1316
|
+
onChange={(value) => {
|
|
1317
|
+
setTableHeaderValue('isTestFilter', getBooleanFormValue(value));
|
|
1318
|
+
}}
|
|
1319
|
+
multiple={false}
|
|
1320
|
+
isSearchEnabled={false}
|
|
1321
|
+
/>
|
|
1322
|
+
);
|
|
1323
|
+
},
|
|
1324
|
+
cell: markConversationAsTest,
|
|
1325
|
+
enableSorting: false,
|
|
1326
|
+
sortDescFirst: false,
|
|
1327
|
+
})
|
|
1328
|
+
] : [],
|
|
1329
|
+
columnHelper.accessor('isPreserve', {
|
|
1330
|
+
id: 'isPreserve',
|
|
1331
|
+
header: () => {
|
|
1332
|
+
return (
|
|
1333
|
+
<HeaderCombobox
|
|
1334
|
+
label={t('global.preserve')}
|
|
1335
|
+
options={booleanFilterOptions}
|
|
1336
|
+
value={getBooleanComboboxValue(isPreserveFilter)}
|
|
1337
|
+
onChange={(value) => {
|
|
1338
|
+
setTableHeaderValue('isPreserveFilter', getBooleanFormValue(value));
|
|
1339
|
+
}}
|
|
1340
|
+
multiple={false}
|
|
1341
|
+
isSearchEnabled={false}
|
|
1342
|
+
/>
|
|
1343
|
+
);
|
|
1344
|
+
},
|
|
1345
|
+
cell: markConversationAsPreserve,
|
|
1346
|
+
sortDescFirst: false,
|
|
1347
|
+
}),
|
|
790
1348
|
columnHelper.accessor('comment', {
|
|
791
1349
|
id: 'comment',
|
|
792
1350
|
header: t('chat.history.comment') ?? '',
|
|
793
1351
|
cell: commentView,
|
|
1352
|
+
enableSorting: false,
|
|
1353
|
+
sortDescFirst: false,
|
|
794
1354
|
}),
|
|
795
1355
|
columnHelper.accessor('feedbackRating', {
|
|
796
1356
|
id: 'feedbackRating',
|
|
797
|
-
header:
|
|
1357
|
+
header: () => {
|
|
1358
|
+
return (
|
|
1359
|
+
<HeaderCombobox
|
|
1360
|
+
label={t('chat.history.rating') ?? ''}
|
|
1361
|
+
options={ratingOptions}
|
|
1362
|
+
value={feedbackRatings}
|
|
1363
|
+
onChange={(value) => {
|
|
1364
|
+
setTableHeaderValue(
|
|
1365
|
+
'feedbackRatings',
|
|
1366
|
+
normalizeAllOptionFilterValues(
|
|
1367
|
+
value,
|
|
1368
|
+
feedbackRatings,
|
|
1369
|
+
getAllStringFilterValues(realRatingOptions)
|
|
1370
|
+
)
|
|
1371
|
+
);
|
|
1372
|
+
}}
|
|
1373
|
+
/>
|
|
1374
|
+
);
|
|
1375
|
+
},
|
|
798
1376
|
cell: (props) => {
|
|
799
1377
|
const value = props.getValue();
|
|
800
1378
|
return value !== null && value !== undefined ? <span>{`${value}/${props.row.original?.isFiveRatingScale === 'true' ? 5 : 10}`}</span> : null;
|
|
801
|
-
}
|
|
1379
|
+
},
|
|
1380
|
+
sortDescFirst: false,
|
|
802
1381
|
}),
|
|
803
1382
|
columnHelper.accessor('feedbackText', {
|
|
804
1383
|
id: 'feedbackText',
|
|
805
|
-
header: t('chat.history.feedback')
|
|
1384
|
+
header: t('chat.history.feedback'),
|
|
806
1385
|
cell: feedbackTextView,
|
|
1386
|
+
enableSorting: false,
|
|
1387
|
+
sortDescFirst: false,
|
|
807
1388
|
}),
|
|
808
1389
|
columnHelper.accessor('status', {
|
|
809
1390
|
id: 'status',
|
|
810
|
-
header:
|
|
1391
|
+
header: () => {
|
|
1392
|
+
return (
|
|
1393
|
+
<HeaderCombobox
|
|
1394
|
+
label={t('global.status') ?? ''}
|
|
1395
|
+
options={statusOptions}
|
|
1396
|
+
value={status}
|
|
1397
|
+
onChange={(value) => {
|
|
1398
|
+
setTableHeaderValue(
|
|
1399
|
+
'status',
|
|
1400
|
+
normalizeAllOptionFilterValues(
|
|
1401
|
+
value,
|
|
1402
|
+
status,
|
|
1403
|
+
getAllStringFilterValues(realStatusOptions)
|
|
1404
|
+
)
|
|
1405
|
+
);
|
|
1406
|
+
}}
|
|
1407
|
+
isSearchEnabled={true}
|
|
1408
|
+
/>
|
|
1409
|
+
);
|
|
1410
|
+
},
|
|
811
1411
|
cell: statusView,
|
|
812
1412
|
sortingFn: (a, b, isAsc) => {
|
|
813
1413
|
const statusA =
|
|
@@ -825,17 +1425,118 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
825
1425
|
}) * (isAsc ? 1 : -1)
|
|
826
1426
|
);
|
|
827
1427
|
},
|
|
1428
|
+
sortDescFirst: false,
|
|
828
1429
|
}),
|
|
829
1430
|
columnHelper.accessor('id', {
|
|
830
1431
|
id: 'id',
|
|
831
1432
|
header: 'ID',
|
|
832
1433
|
cell: idView,
|
|
1434
|
+
enableSorting: false,
|
|
1435
|
+
sortDescFirst: false,
|
|
833
1436
|
}),
|
|
834
1437
|
columnHelper.accessor('endUserUrl', {
|
|
835
1438
|
id: 'www',
|
|
836
|
-
header:
|
|
1439
|
+
header: () => {
|
|
1440
|
+
return (
|
|
1441
|
+
<HeaderCombobox
|
|
1442
|
+
label={t('chat.history.www') ?? ''}
|
|
1443
|
+
value={domains}
|
|
1444
|
+
options={domainOptions}
|
|
1445
|
+
onChange={(value) => {
|
|
1446
|
+
setTableHeaderValue(
|
|
1447
|
+
'domains',
|
|
1448
|
+
normalizeAllOptionFilterValues(value, domains, currentDomains)
|
|
1449
|
+
);
|
|
1450
|
+
}}
|
|
1451
|
+
/>
|
|
1452
|
+
);
|
|
1453
|
+
},
|
|
837
1454
|
cell: wwwView,
|
|
1455
|
+
sortDescFirst: false,
|
|
838
1456
|
}),
|
|
1457
|
+
...isChatAnalysisEnabled ? [
|
|
1458
|
+
columnHelper.display({
|
|
1459
|
+
id: 'theme',
|
|
1460
|
+
header: () => (
|
|
1461
|
+
<HeaderCombobox
|
|
1462
|
+
label={t('chat.history.theme')}
|
|
1463
|
+
options={themeOptions}
|
|
1464
|
+
value={theme}
|
|
1465
|
+
onChange={(value) => {
|
|
1466
|
+
setTableHeaderValue(
|
|
1467
|
+
'theme',
|
|
1468
|
+
normalizeAllOptionFilterValues(
|
|
1469
|
+
value,
|
|
1470
|
+
theme,
|
|
1471
|
+
getAllStringFilterValues(realThemeOptions)
|
|
1472
|
+
)
|
|
1473
|
+
);
|
|
1474
|
+
}}
|
|
1475
|
+
/>
|
|
1476
|
+
),
|
|
1477
|
+
cell: (props) => {
|
|
1478
|
+
return formatChatAnalysisCell(
|
|
1479
|
+
props.row.original.theme,
|
|
1480
|
+
t('chat.quality.selectionEmptied')
|
|
1481
|
+
);
|
|
1482
|
+
},
|
|
1483
|
+
enableSorting: true,
|
|
1484
|
+
}),
|
|
1485
|
+
columnHelper.display({
|
|
1486
|
+
id: 'responseQuality',
|
|
1487
|
+
header: () => (
|
|
1488
|
+
<HeaderCombobox
|
|
1489
|
+
label={t('chat.history.responseQuality')}
|
|
1490
|
+
options={responseQualityOptions}
|
|
1491
|
+
value={responseQuality}
|
|
1492
|
+
onChange={(value) => {
|
|
1493
|
+
setTableHeaderValue(
|
|
1494
|
+
'responseQuality',
|
|
1495
|
+
normalizeAllOptionFilterValues(
|
|
1496
|
+
value,
|
|
1497
|
+
responseQuality,
|
|
1498
|
+
getAllStringFilterValues(realResponseQualityOptions)
|
|
1499
|
+
)
|
|
1500
|
+
);
|
|
1501
|
+
}}
|
|
1502
|
+
/>
|
|
1503
|
+
),
|
|
1504
|
+
cell: (props) => {
|
|
1505
|
+
return formatChatAnalysisCell(
|
|
1506
|
+
props.row.original.responseQuality,
|
|
1507
|
+
t('chat.quality.selectionEmptied')
|
|
1508
|
+
);
|
|
1509
|
+
},
|
|
1510
|
+
enableSorting: true,
|
|
1511
|
+
}),
|
|
1512
|
+
columnHelper.display({
|
|
1513
|
+
id: 'followUpStatus',
|
|
1514
|
+
header: () => (
|
|
1515
|
+
<HeaderCombobox
|
|
1516
|
+
label={t('chat.history.followUpStatus')}
|
|
1517
|
+
options={followUpStatusOptions}
|
|
1518
|
+
value={followUpStatus}
|
|
1519
|
+
onChange={(value) => {
|
|
1520
|
+
setTableHeaderValue(
|
|
1521
|
+
'followUpStatus',
|
|
1522
|
+
normalizeAllOptionFilterValues(
|
|
1523
|
+
value,
|
|
1524
|
+
followUpStatus,
|
|
1525
|
+
getAllStringFilterValues(realFollowUpStatusOptions)
|
|
1526
|
+
)
|
|
1527
|
+
);
|
|
1528
|
+
}}
|
|
1529
|
+
/>
|
|
1530
|
+
),
|
|
1531
|
+
cell: (props) => {
|
|
1532
|
+
return formatChatAnalysisCell(
|
|
1533
|
+
props.row.original.followUpStatus,
|
|
1534
|
+
t('chat.quality.selectionEmptied')
|
|
1535
|
+
);
|
|
1536
|
+
},
|
|
1537
|
+
enableSorting: true,
|
|
1538
|
+
}),
|
|
1539
|
+
] : [],
|
|
839
1540
|
columnHelper.display({
|
|
840
1541
|
id: 'detail',
|
|
841
1542
|
cell: detailsView,
|
|
@@ -846,29 +1547,37 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
846
1547
|
}),
|
|
847
1548
|
];
|
|
848
1549
|
|
|
849
|
-
if (showEmail) {
|
|
850
|
-
columns.splice(4, 0, columnHelper.accessor('endUserEmail', {
|
|
851
|
-
id: 'endUserEmail',
|
|
852
|
-
header: t('global.email') ?? '',
|
|
853
|
-
}));
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
if (testMessageEnabled) {
|
|
857
|
-
columns.splice(4, 0, columnHelper.accessor('istest', {
|
|
858
|
-
id: 'istest',
|
|
859
|
-
header: t('global.test') ?? '',
|
|
860
|
-
cell: markConversationAsTest
|
|
861
|
-
}));
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
columns.splice(4, 0, columnHelper.accessor('isPreserve', {
|
|
865
|
-
id: 'isPreserve',
|
|
866
|
-
header: t('global.preserve') ?? '',
|
|
867
|
-
cell: markConversationAsPreserve
|
|
868
|
-
}));
|
|
869
|
-
|
|
870
1550
|
return columns;
|
|
871
|
-
}, [
|
|
1551
|
+
}, [
|
|
1552
|
+
t,
|
|
1553
|
+
showEmail,
|
|
1554
|
+
testMessageEnabled,
|
|
1555
|
+
customerSupportAgentsQuery.data,
|
|
1556
|
+
csaIdCodesFilter,
|
|
1557
|
+
feedbackRatings,
|
|
1558
|
+
showAuthenticatedPerson,
|
|
1559
|
+
isTestFilter,
|
|
1560
|
+
isPreserveFilter,
|
|
1561
|
+
domains,
|
|
1562
|
+
status,
|
|
1563
|
+
theme,
|
|
1564
|
+
responseQuality,
|
|
1565
|
+
followUpStatus,
|
|
1566
|
+
statusOptions,
|
|
1567
|
+
realStatusOptions,
|
|
1568
|
+
themeOptions,
|
|
1569
|
+
responseQualityOptions,
|
|
1570
|
+
followUpStatusOptions,
|
|
1571
|
+
realThemeOptions,
|
|
1572
|
+
realResponseQualityOptions,
|
|
1573
|
+
realFollowUpStatusOptions,
|
|
1574
|
+
currentDomains,
|
|
1575
|
+
ratingOptions,
|
|
1576
|
+
realRatingOptions,
|
|
1577
|
+
domainOptions,
|
|
1578
|
+
booleanFilterOptions,
|
|
1579
|
+
isChatAnalysisEnabled,
|
|
1580
|
+
])
|
|
872
1581
|
|
|
873
1582
|
const getSortingString = () => {
|
|
874
1583
|
if (sorting && sorting.length > 0) {
|
|
@@ -904,6 +1613,12 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
904
1613
|
return t('chat.history.rating') ?? ''
|
|
905
1614
|
case 'feedbackText':
|
|
906
1615
|
return t('chat.history.feedback') ?? ''
|
|
1616
|
+
case 'theme':
|
|
1617
|
+
return t('chat.history.theme') ?? ''
|
|
1618
|
+
case 'responseQuality':
|
|
1619
|
+
return t('chat.history.responseQuality') ?? ''
|
|
1620
|
+
case 'followUpStatus':
|
|
1621
|
+
return t('chat.history.followUpStatus') ?? ''
|
|
907
1622
|
case 'status':
|
|
908
1623
|
return t('global.status') ?? ''
|
|
909
1624
|
case 'endUserUrl':
|
|
@@ -1032,15 +1747,10 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1032
1747
|
return {headers, rows, chatIds};
|
|
1033
1748
|
};
|
|
1034
1749
|
|
|
1035
|
-
|
|
1036
1750
|
const downloadChatHistory = async () => {
|
|
1037
1751
|
setLoading(true);
|
|
1038
1752
|
try {
|
|
1039
|
-
|
|
1040
|
-
if (sorting.length > 0) {
|
|
1041
|
-
const sortType = sorting[0].desc ? 'desc' : 'asc';
|
|
1042
|
-
sortBy = `${sorting[0].id} ${sortType}`;
|
|
1043
|
-
}
|
|
1753
|
+
const sortBy = getEndedChatsSortBy(sorting);
|
|
1044
1754
|
|
|
1045
1755
|
const realSelectedColumns = getRealSelectedColumns(selectedColumns);
|
|
1046
1756
|
const { headers } = mapChatsToExportRows([], endedChatsColumns, realSelectedColumns, t);
|
|
@@ -1061,7 +1771,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1061
1771
|
language: i18n.language,
|
|
1062
1772
|
startDate: formatISO(startOfDay(new Date(startDate))),
|
|
1063
1773
|
endDate: formatISO(endOfDay(new Date(endDate))),
|
|
1064
|
-
|
|
1774
|
+
...endedChatsFilterBody,
|
|
1065
1775
|
sorting: sortBy,
|
|
1066
1776
|
search,
|
|
1067
1777
|
});
|
|
@@ -1079,27 +1789,151 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1079
1789
|
}
|
|
1080
1790
|
};
|
|
1081
1791
|
|
|
1082
|
-
const endUserFullName = getUserName();
|
|
1083
|
-
|
|
1084
|
-
const isClearFiltersVisible = useMemo(()=> {
|
|
1085
|
-
return search.length > 0 || selectedColumns.length > 0;
|
|
1086
|
-
}, [search, selectedColumns]);
|
|
1087
|
-
|
|
1088
1792
|
const onClearFilersClick = () => {
|
|
1089
|
-
const clearedColumns: string[] = [];
|
|
1090
|
-
setSelectedColumns(clearedColumns);
|
|
1091
1793
|
setCounterKey(0);
|
|
1092
1794
|
setValue('search', '');
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1795
|
+
resetTableHeaderForm({
|
|
1796
|
+
csaIdCodesFilter: [],
|
|
1797
|
+
feedbackRatings: [],
|
|
1798
|
+
showAuthenticatedPerson: undefined,
|
|
1799
|
+
isTestFilter: undefined,
|
|
1800
|
+
isPreserveFilter: undefined,
|
|
1801
|
+
domains: [],
|
|
1802
|
+
status: [],
|
|
1803
|
+
theme: [],
|
|
1804
|
+
responseQuality: [],
|
|
1805
|
+
followUpStatus: [],
|
|
1096
1806
|
});
|
|
1097
1807
|
};
|
|
1098
1808
|
|
|
1809
|
+
const chatQualityMeasurementQuery = useQuery({
|
|
1810
|
+
queryKey: ['chats/quality/measurements', selectedChat?.id],
|
|
1811
|
+
queryFn: () => getQualityMeasurements({ chatUuid: selectedChat!.id }),
|
|
1812
|
+
enabled: !!selectedChat?.id,
|
|
1813
|
+
});
|
|
1814
|
+
|
|
1815
|
+
const selectedQualityMeasurements = useMemo(() => {
|
|
1816
|
+
const measurements = chatQualityMeasurementQuery.data?.data.response ?? [];
|
|
1817
|
+
|
|
1818
|
+
const latest = {
|
|
1819
|
+
theme: {
|
|
1820
|
+
time: Number.NEGATIVE_INFINITY,
|
|
1821
|
+
values: [] as string[],
|
|
1822
|
+
},
|
|
1823
|
+
quality: {
|
|
1824
|
+
time: Number.NEGATIVE_INFINITY,
|
|
1825
|
+
value: '',
|
|
1826
|
+
},
|
|
1827
|
+
followUp: {
|
|
1828
|
+
time: Number.NEGATIVE_INFINITY,
|
|
1829
|
+
value: '',
|
|
1830
|
+
},
|
|
1831
|
+
};
|
|
1832
|
+
|
|
1833
|
+
measurements.forEach(({ type, value, createdAt }) => {
|
|
1834
|
+
const parsedTime = Date.parse(createdAt);
|
|
1835
|
+
const time = Number.isNaN(parsedTime) ? 0 : parsedTime;
|
|
1836
|
+
|
|
1837
|
+
if (type === MEASUREMENT_TYPES.THEME) {
|
|
1838
|
+
if (time > latest.theme.time) {
|
|
1839
|
+
latest.theme.time = time;
|
|
1840
|
+
latest.theme.values = value ? [value] : [];
|
|
1841
|
+
} else if (time === latest.theme.time && value) {
|
|
1842
|
+
latest.theme.values.push(value);
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
|
|
1849
|
+
if (type === MEASUREMENT_TYPES.QUALITY && time >= latest.quality.time) {
|
|
1850
|
+
latest.quality.time = time;
|
|
1851
|
+
latest.quality.value = value;
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
if (type === MEASUREMENT_TYPES.FOLLOW_UP_ACTION && time >= latest.followUp.time) {
|
|
1856
|
+
latest.followUp.time = time;
|
|
1857
|
+
latest.followUp.value = value;
|
|
1858
|
+
return;
|
|
1859
|
+
}
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
return {
|
|
1863
|
+
theme: latest.theme.values,
|
|
1864
|
+
quality: latest.quality.value,
|
|
1865
|
+
followUp: latest.followUp.value,
|
|
1866
|
+
};
|
|
1867
|
+
}, [chatQualityMeasurementQuery.data]);
|
|
1868
|
+
|
|
1869
|
+
const chatQualityMeasurementMutation = useMutation({
|
|
1870
|
+
mutationFn: postQualityMeasurements,
|
|
1871
|
+
onSuccess: (_data, variables) => {
|
|
1872
|
+
queryClient.invalidateQueries({
|
|
1873
|
+
queryKey: ['chats/quality/measurements', variables.chatUuid],
|
|
1874
|
+
});
|
|
1875
|
+
},
|
|
1876
|
+
onError: (error: AxiosError) => {
|
|
1877
|
+
toast?.open({
|
|
1878
|
+
type: 'error',
|
|
1879
|
+
title: t('global.notificationError'),
|
|
1880
|
+
message: error.message,
|
|
1881
|
+
});
|
|
1882
|
+
},
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
const saveChatQualityMeasurement = async (
|
|
1886
|
+
type: MeasurementType,
|
|
1887
|
+
value: string | string[],
|
|
1888
|
+
successMessage: string
|
|
1889
|
+
) => {
|
|
1890
|
+
if (!selectedChat?.id) return;
|
|
1891
|
+
|
|
1892
|
+
try {
|
|
1893
|
+
await chatQualityMeasurementMutation.mutateAsync({
|
|
1894
|
+
chatUuid: selectedChat.id,
|
|
1895
|
+
type,
|
|
1896
|
+
value,
|
|
1897
|
+
});
|
|
1898
|
+
|
|
1899
|
+
toast?.open({
|
|
1900
|
+
type: 'success',
|
|
1901
|
+
title: t('global.notification'),
|
|
1902
|
+
message: successMessage,
|
|
1903
|
+
});
|
|
1904
|
+
} catch {
|
|
1905
|
+
// Error toast is handled by the mutation's onError callback.
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
const onChatThemeChange = async (value: string[]) => {
|
|
1910
|
+
// TODO: array support in backend
|
|
1911
|
+
saveChatQualityMeasurement(
|
|
1912
|
+
MEASUREMENT_TYPES.THEME,
|
|
1913
|
+
value,
|
|
1914
|
+
t('toast.success.conversationThemeSaved')
|
|
1915
|
+
)
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
const onChatQualityChange = async (value: string) => {
|
|
1919
|
+
await saveChatQualityMeasurement(
|
|
1920
|
+
MEASUREMENT_TYPES.QUALITY,
|
|
1921
|
+
value,
|
|
1922
|
+
t('toast.success.conversationQualitySaved')
|
|
1923
|
+
);
|
|
1924
|
+
}
|
|
1925
|
+
const onChatFollowUpChange = async (value: string) => {
|
|
1926
|
+
await saveChatQualityMeasurement(
|
|
1927
|
+
MEASUREMENT_TYPES.FOLLOW_UP_ACTION,
|
|
1928
|
+
value,
|
|
1929
|
+
t('toast.success.conversationFollowUpActionSaved')
|
|
1930
|
+
);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1099
1933
|
if (!filteredEndedChatsList) return <>Loading... {{filteredEndedChatsList}} something is wrong </>;
|
|
1100
1934
|
|
|
1101
1935
|
return (
|
|
1102
|
-
|
|
1936
|
+
<div className="history-page-wrapper">
|
|
1103
1937
|
<div className="header-container">
|
|
1104
1938
|
{displayTitle && (
|
|
1105
1939
|
<h1>{t('chat.history.title')}{totalCount === null ? '' : ` (${totalCount.toLocaleString('et-EE')})`}</h1>
|
|
@@ -1250,12 +2084,23 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1250
2084
|
</Button>
|
|
1251
2085
|
</div>)
|
|
1252
2086
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
2087
|
+
<SelectedFilterTags
|
|
2088
|
+
csaFilterTagValues={csaFilterTagValues}
|
|
2089
|
+
getCsaFilterTagLabel={getCsaFilterTagLabel}
|
|
2090
|
+
showAuthenticatedPerson={showAuthenticatedPerson}
|
|
2091
|
+
showTestFilter={testMessageEnabled}
|
|
2092
|
+
isTestFilter={isTestFilter}
|
|
2093
|
+
isPreserveFilter={isPreserveFilter}
|
|
2094
|
+
domains={domainFilterValues}
|
|
2095
|
+
feedbackRatings={feedbackRatingFilterValues}
|
|
2096
|
+
status={statusFilterValues}
|
|
2097
|
+
theme={themeFilterValues}
|
|
2098
|
+
responseQuality={responseQualityFilterValues}
|
|
2099
|
+
followUpStatus={followUpStatusFilterValues}
|
|
2100
|
+
onRemove={removeSelectedFilterTag}
|
|
2101
|
+
onClearFiltersClick={onClearFilersClick}
|
|
2102
|
+
/>
|
|
2103
|
+
<div className="card-drawer-container" style={{height: '100%', overflow: 'auto', maxHeight: '60vh'}}>
|
|
1259
2104
|
<div className="card-wrapper">
|
|
1260
2105
|
<Card>
|
|
1261
2106
|
<DataTable
|
|
@@ -1329,141 +2174,37 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1329
2174
|
/>
|
|
1330
2175
|
</Drawer>
|
|
1331
2176
|
</div>
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
<p>
|
|
1364
|
-
<strong>{t('chat.endUserPhoneNumber')}</strong>
|
|
1365
|
-
</p>
|
|
1366
|
-
<p>{selectedChat.endUserPhone}</p>
|
|
1367
|
-
</div>
|
|
1368
|
-
)}
|
|
1369
|
-
{selectedChat.customerSupportDisplayName && (
|
|
1370
|
-
<div>
|
|
1371
|
-
<p>
|
|
1372
|
-
<strong>{t('chat.csaName')}</strong>
|
|
1373
|
-
</p>
|
|
1374
|
-
<p>{selectedChat.customerSupportDisplayName}</p>
|
|
1375
|
-
</div>
|
|
1376
|
-
)}
|
|
1377
|
-
<div>
|
|
1378
|
-
<p>
|
|
1379
|
-
<strong>{t('chat.startedAt')}</strong>
|
|
1380
|
-
</p>
|
|
1381
|
-
<p>
|
|
1382
|
-
{format(
|
|
1383
|
-
new Date(selectedChat.created),
|
|
1384
|
-
'dd. MMMM Y HH:mm:ss',
|
|
1385
|
-
{
|
|
1386
|
-
locale: et,
|
|
1387
|
-
}
|
|
1388
|
-
).toLowerCase()}
|
|
1389
|
-
</p>
|
|
1390
|
-
</div>
|
|
1391
|
-
<div>
|
|
1392
|
-
<p>
|
|
1393
|
-
<strong>{t('chat.device')}</strong>
|
|
1394
|
-
</p>
|
|
1395
|
-
<p>{selectedChat.endUserOs}</p>
|
|
1396
|
-
</div>
|
|
1397
|
-
<div>
|
|
1398
|
-
<p>
|
|
1399
|
-
<strong>{t('chat.location')}</strong>
|
|
1400
|
-
</p>
|
|
1401
|
-
<p>{selectedChat.endUserUrl}</p>
|
|
1402
|
-
</div>
|
|
1403
|
-
{selectedChat.comment && (
|
|
1404
|
-
<div>
|
|
1405
|
-
<p>
|
|
1406
|
-
<strong>{t('chat.history.comment')}</strong>
|
|
1407
|
-
</p>
|
|
1408
|
-
<p>{selectedChat.comment}</p>
|
|
1409
|
-
</div>
|
|
1410
|
-
)}
|
|
1411
|
-
{selectedChat.commentAuthor && (
|
|
1412
|
-
<div>
|
|
1413
|
-
<p>
|
|
1414
|
-
<strong>{t('chat.history.commentAuthor')}</strong>
|
|
1415
|
-
</p>
|
|
1416
|
-
<p>{selectedChat.commentAuthor}</p>
|
|
1417
|
-
</div>
|
|
1418
|
-
)}
|
|
1419
|
-
{selectedChat.commentAddedDate && (
|
|
1420
|
-
<div>
|
|
1421
|
-
<p>
|
|
1422
|
-
<strong>{t('chat.history.commentAddedDate')}</strong>
|
|
1423
|
-
</p>
|
|
1424
|
-
<p>
|
|
1425
|
-
{format(
|
|
1426
|
-
new Date(selectedChat.commentAddedDate),
|
|
1427
|
-
'dd.MM.yyyy'
|
|
1428
|
-
)}
|
|
1429
|
-
</p>
|
|
1430
|
-
</div>
|
|
1431
|
-
)}
|
|
1432
|
-
{selectedChat.lastMessageEvent && (
|
|
1433
|
-
<div>
|
|
1434
|
-
<p>
|
|
1435
|
-
<strong>{t('global.status')}</strong>
|
|
1436
|
-
</p>
|
|
1437
|
-
<p>
|
|
1438
|
-
{t('chat.plainEvents.' + selectedChat.lastMessageEvent)}
|
|
1439
|
-
</p>
|
|
1440
|
-
</div>
|
|
1441
|
-
)}
|
|
1442
|
-
{selectedChat.userDisplayName && (
|
|
1443
|
-
<div>
|
|
1444
|
-
<p>
|
|
1445
|
-
<strong>{t('chat.history.statusAdder')}</strong>
|
|
1446
|
-
</p>
|
|
1447
|
-
<p>{selectedChat.userDisplayName}</p>
|
|
1448
|
-
</div>
|
|
1449
|
-
)}
|
|
1450
|
-
{selectedChat.lastMessageTimestamp && (
|
|
1451
|
-
<div>
|
|
1452
|
-
<p>
|
|
1453
|
-
<strong>{t('chat.history.statusAddedDate')}</strong>
|
|
1454
|
-
</p>
|
|
1455
|
-
<p>
|
|
1456
|
-
{format(
|
|
1457
|
-
new Date(selectedChat.lastMessageTimestamp),
|
|
1458
|
-
'dd.MM.yyyy'
|
|
1459
|
-
)}
|
|
1460
|
-
</p>
|
|
1461
|
-
</div>
|
|
1462
|
-
)}
|
|
1463
|
-
</div>
|
|
1464
|
-
</>
|
|
1465
|
-
)}
|
|
1466
|
-
</div>
|
|
2177
|
+
<ChatMetadataPanel
|
|
2178
|
+
chat={selectedChat}
|
|
2179
|
+
chatMeasurments={chatQualityMeasurementQuery.data?.data.response ?? []}
|
|
2180
|
+
>
|
|
2181
|
+
<QualitySettings
|
|
2182
|
+
theme={{
|
|
2183
|
+
onChange: (value) => onChatThemeChange(value),
|
|
2184
|
+
options: qualitySettingsConfigQuery.data?.chatAnalysisTheme.map(item => {
|
|
2185
|
+
return { label: item, value: item }
|
|
2186
|
+
}) ?? [],
|
|
2187
|
+
value: selectedQualityMeasurements.theme,
|
|
2188
|
+
}}
|
|
2189
|
+
quality={{
|
|
2190
|
+
onChange: (value) => onChatQualityChange(value),
|
|
2191
|
+
options: qualitySettingsConfigQuery.data?.chatAnalysisBykResponseQuality.map(item => {
|
|
2192
|
+
return { label: item, value: item }
|
|
2193
|
+
}) ?? [],
|
|
2194
|
+
value: selectedQualityMeasurements.quality,
|
|
2195
|
+
}}
|
|
2196
|
+
followUp={{
|
|
2197
|
+
onChange: (value) => onChatFollowUpChange(value),
|
|
2198
|
+
options: qualitySettingsConfigQuery.data?.chatAnalysisFollowUpAction.map(item => {
|
|
2199
|
+
return { label: item, value: item }
|
|
2200
|
+
}) ?? [],
|
|
2201
|
+
value: selectedQualityMeasurements.followUp,
|
|
2202
|
+
}}
|
|
2203
|
+
/>
|
|
2204
|
+
</ChatMetadataPanel>
|
|
2205
|
+
</>
|
|
2206
|
+
)}
|
|
2207
|
+
</div>
|
|
1467
2208
|
</div>
|
|
1468
2209
|
|
|
1469
2210
|
{statusChangeModal && (
|
|
@@ -1496,15 +2237,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1496
2237
|
<p>{t('global.removeValidation')}</p>
|
|
1497
2238
|
</Dialog>
|
|
1498
2239
|
)}
|
|
1499
|
-
|
|
2240
|
+
</div>
|
|
1500
2241
|
);
|
|
1501
|
-
|
|
1502
|
-
function getUserName() {
|
|
1503
|
-
return selectedChat?.endUserFirstName !== '' &&
|
|
1504
|
-
selectedChat?.endUserLastName !== ''
|
|
1505
|
-
? `${selectedChat?.endUserFirstName} ${selectedChat?.endUserLastName}`
|
|
1506
|
-
: t('global.anonymous');
|
|
1507
|
-
}
|
|
1508
2242
|
};
|
|
1509
2243
|
|
|
1510
2244
|
export default ChatHistory;
|