@buerokratt-ria/common-gui-components 0.0.25 → 0.0.27
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
CHANGED
|
@@ -4,6 +4,15 @@ All changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## Template [MajorVersion.MediterraneanVersion.MinorVersion] - DD-MM-YYYY
|
|
6
6
|
|
|
7
|
+
## [0.0.27] - 02-10-2025
|
|
8
|
+
|
|
9
|
+
- Adding missing showTest with default to true if undefined.
|
|
10
|
+
|
|
11
|
+
## [0.0.26] - 15-09-2025
|
|
12
|
+
|
|
13
|
+
- Added download button do download chat history with currently selected criteriasa
|
|
14
|
+
- Added new optional param to enable this button(disabled by default)
|
|
15
|
+
|
|
7
16
|
## [0.0.25] - 01-09-2025
|
|
8
17
|
|
|
9
18
|
- Added test column to display chats mark for test
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buerokratt-ria/common-gui-components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.27",
|
|
4
4
|
"description": "Common GUI components and pre defined templates.",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"author": "ExiRai",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"downshift": "^7.0.5",
|
|
30
30
|
"esbuild": "^0.19.5",
|
|
31
31
|
"framer-motion": "^8.5.5",
|
|
32
|
+
"file-saver": "^2.0.5",
|
|
32
33
|
"i18next": "^22.4.5",
|
|
33
34
|
"i18next-browser-languagedetector": "^7.0.1",
|
|
34
35
|
"linkify-react": "^4.1.1",
|
package/services/file.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
|
|
3
|
+
export const saveFile = async (base64String: string, fileName: `${string}.${string}`, type: string) => {
|
|
4
|
+
const blob = new Blob([Buffer.from(base64String, 'base64')], {
|
|
5
|
+
type: type,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const extension = fileName.split('.').pop();
|
|
9
|
+
|
|
10
|
+
if (window.showSaveFilePicker) {
|
|
11
|
+
const handle = await window.showSaveFilePicker({
|
|
12
|
+
suggestedName: fileName,
|
|
13
|
+
types: [
|
|
14
|
+
{
|
|
15
|
+
description: extension!.toUpperCase() + ' file',
|
|
16
|
+
accept: { [type]: [`.${extension}` as `.${string}`] },
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
});
|
|
20
|
+
const writable = await handle.createWritable();
|
|
21
|
+
await writable.write(blob);
|
|
22
|
+
writable.close();
|
|
23
|
+
} else {
|
|
24
|
+
const url = window.URL.createObjectURL(blob);
|
|
25
|
+
const a = document.createElement('a');
|
|
26
|
+
a.href = url;
|
|
27
|
+
a.download = fileName;
|
|
28
|
+
a.click();
|
|
29
|
+
window.URL.revokeObjectURL(url);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -2,10 +2,11 @@ import React, {FC, PropsWithChildren, useEffect, useMemo, useRef, useState} from
|
|
|
2
2
|
import {useTranslation} from 'react-i18next';
|
|
3
3
|
import {useMutation} from '@tanstack/react-query';
|
|
4
4
|
import {ColumnPinningState, createColumnHelper, PaginationState, SortingState,} from '@tanstack/react-table';
|
|
5
|
-
import { format,
|
|
5
|
+
import {endOfDay, format, formatISO, startOfDay} from "date-fns";
|
|
6
6
|
import {AxiosError} from 'axios';
|
|
7
7
|
import './History.scss';
|
|
8
8
|
import {MdOutlineRemoveRedEye} from 'react-icons/md';
|
|
9
|
+
import {CgSpinner} from 'react-icons/cg';
|
|
9
10
|
|
|
10
11
|
import {
|
|
11
12
|
Button,
|
|
@@ -35,6 +36,7 @@ import {ToastContextType} from "../../../context";
|
|
|
35
36
|
|
|
36
37
|
import {getDomainsArray} from "../../../utils/multiDomain-utils";
|
|
37
38
|
import {StoreState} from "../../../store";
|
|
39
|
+
import {saveFile} from "../../../services/file";
|
|
38
40
|
|
|
39
41
|
type HistoryProps = {
|
|
40
42
|
user: UserInfo | null;
|
|
@@ -42,6 +44,7 @@ type HistoryProps = {
|
|
|
42
44
|
toastContext: ToastContextType | null;
|
|
43
45
|
onMessageClick?: (message: any) => void;
|
|
44
46
|
showComment?: boolean;
|
|
47
|
+
showDownload?: boolean;
|
|
45
48
|
showEmail?: boolean;
|
|
46
49
|
showSortingLabel?: boolean;
|
|
47
50
|
showStatus?: boolean;
|
|
@@ -52,12 +55,19 @@ type HistoryProps = {
|
|
|
52
55
|
delegatedEndDate?: string;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
type ExportResult = {
|
|
59
|
+
headers: string[];
|
|
60
|
+
rows: (string | number | null)[][];
|
|
61
|
+
chatIds: string[];
|
|
62
|
+
};
|
|
63
|
+
|
|
55
64
|
const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
56
65
|
user,
|
|
57
66
|
userDomains,
|
|
58
67
|
toastContext,
|
|
59
68
|
onMessageClick,
|
|
60
69
|
showComment = true,
|
|
70
|
+
showDownload = false,
|
|
61
71
|
showEmail = false,
|
|
62
72
|
showSortingLabel = false,
|
|
63
73
|
showStatus = true,
|
|
@@ -111,6 +121,9 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
111
121
|
const currentDomains = useStore.getState().userDomains;
|
|
112
122
|
const multiDomainEnabled = import.meta.env.REACT_APP_ENABLE_MULTI_DOMAIN?.toLowerCase() === 'true';
|
|
113
123
|
const testMessageEnabled = import.meta.env.REACT_APP_SHOW_TEST_MESSAGE?.toLowerCase() === 'true';
|
|
124
|
+
const envVal = import.meta.env.REACT_APP_SHOW_TEST_CONVERSATIONS;
|
|
125
|
+
const showTest = envVal === undefined ? true : envVal.toLowerCase() === 'true';
|
|
126
|
+
const [loading, setLoading] = useState(false);
|
|
114
127
|
|
|
115
128
|
const parseDateParam = (dateString: string | null) => {
|
|
116
129
|
if (!dateString) return new Date();
|
|
@@ -290,6 +303,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
290
303
|
startDate: formatISO(startOfDay(new Date(data.startDate))),
|
|
291
304
|
endDate: formatISO(endOfDay(new Date(data.endDate))),
|
|
292
305
|
urls: getDomainsArray(currentDomains),
|
|
306
|
+
showTest: showTest,
|
|
293
307
|
page: data.pagination.pageIndex + 1,
|
|
294
308
|
page_size: data.pagination.pageSize,
|
|
295
309
|
sorting: sortBy,
|
|
@@ -810,6 +824,120 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
810
824
|
);
|
|
811
825
|
};
|
|
812
826
|
|
|
827
|
+
const mapChatsToExportRows = (
|
|
828
|
+
chats: ChatType[],
|
|
829
|
+
allColumns: any[],
|
|
830
|
+
selectedColumns: string[],
|
|
831
|
+
t: (key: string) => string
|
|
832
|
+
): ExportResult => {
|
|
833
|
+
const activeColumns =
|
|
834
|
+
selectedColumns.length > 0
|
|
835
|
+
? allColumns.filter(
|
|
836
|
+
(col) => col.id && col.id !== 'detail' && selectedColumns.includes(col.id)
|
|
837
|
+
)
|
|
838
|
+
: allColumns.filter((col) => col.id && col.id !== 'detail');
|
|
839
|
+
|
|
840
|
+
const headers = activeColumns.map(
|
|
841
|
+
(col) => getColumnTranslation(col.id) || col.header || col.id
|
|
842
|
+
);
|
|
843
|
+
|
|
844
|
+
const rows = chats.map((chat) =>
|
|
845
|
+
activeColumns.map((col) => {
|
|
846
|
+
let rawValue: any = null;
|
|
847
|
+
|
|
848
|
+
if (typeof col.accessorFn === 'function') {
|
|
849
|
+
rawValue = col.accessorFn(chat, 0);
|
|
850
|
+
} else if (typeof col.accessorKey === 'string') {
|
|
851
|
+
rawValue = (chat as any)[col.accessorKey];
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
let processedValue: any = rawValue;
|
|
855
|
+
switch (col.id) {
|
|
856
|
+
case 'created':
|
|
857
|
+
case 'ended':
|
|
858
|
+
processedValue = rawValue
|
|
859
|
+
? format(
|
|
860
|
+
new Date(rawValue),
|
|
861
|
+
'dd.MM.yyyy HH:mm:ss',
|
|
862
|
+
i18n.language === 'et' ? {locale: et} : undefined
|
|
863
|
+
)
|
|
864
|
+
: '';
|
|
865
|
+
break;
|
|
866
|
+
case 'contactsMessage':
|
|
867
|
+
processedValue = rawValue ? t('global.yes') : t('global.no');
|
|
868
|
+
break;
|
|
869
|
+
case 'feedbackRating':
|
|
870
|
+
processedValue = rawValue != null ? `${rawValue}/10` : '';
|
|
871
|
+
break;
|
|
872
|
+
case 'status':
|
|
873
|
+
processedValue =
|
|
874
|
+
chat.status === CHAT_STATUS.ENDED
|
|
875
|
+
? t('chat.plainEvents.' + (chat.lastMessageEvent ?? ''))
|
|
876
|
+
: '';
|
|
877
|
+
break;
|
|
878
|
+
case 'endUserName':
|
|
879
|
+
processedValue = `${chat.endUserFirstName ?? ''} ${chat.endUserLastName ?? ''}`;
|
|
880
|
+
break;
|
|
881
|
+
default:
|
|
882
|
+
processedValue =
|
|
883
|
+
typeof rawValue === 'object' ? JSON.stringify(rawValue) : rawValue ?? '';
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
return processedValue;
|
|
887
|
+
})
|
|
888
|
+
);
|
|
889
|
+
|
|
890
|
+
const chatIds = chats.map((c) => c.id);
|
|
891
|
+
|
|
892
|
+
return {headers, rows, chatIds};
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
const downloadChatHistory = async () => {
|
|
897
|
+
setLoading(true);
|
|
898
|
+
try {
|
|
899
|
+
let sortBy = 'created desc';
|
|
900
|
+
if (sorting.length > 0) {
|
|
901
|
+
const sortType = sorting[0].desc ? 'desc' : 'asc';
|
|
902
|
+
sortBy = `${sorting[0].id} ${sortType}`;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
const chats = await apiDev.post('agents/chats/ended', {
|
|
906
|
+
customerSupportIds: passedCustomerSupportIds,
|
|
907
|
+
startDate: formatISO(startOfDay(new Date(startDate))),
|
|
908
|
+
endDate: formatISO(endOfDay(new Date(endDate))),
|
|
909
|
+
urls: getDomainsArray(currentDomains),
|
|
910
|
+
page: 1,
|
|
911
|
+
page_size: 1000,
|
|
912
|
+
sorting: sortBy,
|
|
913
|
+
search,
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
const {headers, rows, chatIds} = mapChatsToExportRows(
|
|
917
|
+
chats.data.response,
|
|
918
|
+
endedChatsColumns,
|
|
919
|
+
selectedColumns,
|
|
920
|
+
t
|
|
921
|
+
);
|
|
922
|
+
|
|
923
|
+
const response = await apiDev.post('chats/ended/download', {
|
|
924
|
+
headers, rows, chatIds
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
await saveFile(
|
|
929
|
+
response.data.base64String,
|
|
930
|
+
'history.xlsx',
|
|
931
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
932
|
+
);
|
|
933
|
+
|
|
934
|
+
} catch (error) {
|
|
935
|
+
console.error('Error getting CSV file:', error);
|
|
936
|
+
} finally {
|
|
937
|
+
setLoading(false);
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
|
|
813
941
|
const endUserFullName = getUserName();
|
|
814
942
|
|
|
815
943
|
if (!filteredEndedChatsList) return <>Loading... {{filteredEndedChatsList}} something is wrong </>;
|
|
@@ -820,6 +948,15 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
820
948
|
<h1>{t('chat.history.title')}</h1>
|
|
821
949
|
)}
|
|
822
950
|
|
|
951
|
+
{showDownload && (
|
|
952
|
+
<div>
|
|
953
|
+
<Button appearance={"primary"} onClick={downloadChatHistory}>
|
|
954
|
+
{loading && <CgSpinner className="spinner"/>}
|
|
955
|
+
{!loading && t('files.download_xlsx')}
|
|
956
|
+
</Button>
|
|
957
|
+
</div>
|
|
958
|
+
)}
|
|
959
|
+
|
|
823
960
|
<Card>
|
|
824
961
|
<Track gap={16}>
|
|
825
962
|
{displaySearchBar && (
|
|
Binary file
|