@buerokratt-ria/common-gui-components 0.0.42 → 0.0.44
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,17 @@ 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.44] - 26.02.2026
|
|
8
|
+
|
|
9
|
+
- Removed _ from chosen CSA's list
|
|
10
|
+
|
|
11
|
+
## [0.0.43] - 06.02.2026
|
|
12
|
+
|
|
13
|
+
- Prevent url fetch in markdownify for non image urls
|
|
14
|
+
- Added Comment Settings to get-chat-by-id
|
|
15
|
+
- Enhance eventGroup Function
|
|
16
|
+
- Reset Pagination on search change
|
|
17
|
+
|
|
7
18
|
## [0.0.42] - 04.02.2026
|
|
8
19
|
|
|
9
20
|
- Fix comment display in chat content view
|
package/package.json
CHANGED
|
@@ -340,23 +340,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
340
340
|
chatId: passedChatId,
|
|
341
341
|
}),
|
|
342
342
|
onSuccess: (res: any) => {
|
|
343
|
-
setSelectedChat(
|
|
344
|
-
...res.data.response,
|
|
345
|
-
comment: selectedChat?.comment,
|
|
346
|
-
commentAddedDate: selectedChat?.commentAddedDate,
|
|
347
|
-
commentAuthor: selectedChat?.commentAuthor,
|
|
348
|
-
labels: selectedChat?.labels,
|
|
349
|
-
lastMessageEvent: selectedChat?.lastMessageEvent,
|
|
350
|
-
contactsMessage: selectedChat?.contactsMessage,
|
|
351
|
-
isFiveRatingScale: selectedChat?.isFiveRatingScale,
|
|
352
|
-
istest: selectedChat?.istest,
|
|
353
|
-
nps: selectedChat?.nps,
|
|
354
|
-
userDisplayName: selectedChat?.userDisplayName,
|
|
355
|
-
customerSupportFirstName: selectedChat?.customerSupportFirstName,
|
|
356
|
-
customerSupportLastName: selectedChat?.customerSupportLastName,
|
|
357
|
-
allCsa: selectedChat?.allCsa,
|
|
358
|
-
totalPages: selectedChat?.totalPages,
|
|
359
|
-
});
|
|
343
|
+
setSelectedChat(res.data.response);
|
|
360
344
|
setChatState(res.data.response);
|
|
361
345
|
},
|
|
362
346
|
});
|
|
@@ -372,7 +356,6 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
372
356
|
}),
|
|
373
357
|
onSuccess: (res: any) => {
|
|
374
358
|
setCustomerSupportAgents([
|
|
375
|
-
{label: '-', value: '-'},
|
|
376
359
|
{label: 'Bürokratt', value: 'chatbot'},
|
|
377
360
|
...res.data.response.map((item) => ({
|
|
378
361
|
label: [item.firstName, item.lastName].join(' ').trim(),
|
|
@@ -1015,6 +998,11 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1015
998
|
name="searchChats"
|
|
1016
999
|
placeholder={t('chat.history.searchChats') + '...'}
|
|
1017
1000
|
onChange={(e) => {
|
|
1001
|
+
setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
|
|
1002
|
+
setSearchParams((params) => {
|
|
1003
|
+
params.set("page", "1");
|
|
1004
|
+
return params;
|
|
1005
|
+
});
|
|
1018
1006
|
setSearch(e.target.value);
|
|
1019
1007
|
debouncedGetAllEnded(e.target.value);
|
|
1020
1008
|
}}
|
|
@@ -1125,18 +1113,27 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
|
|
|
1125
1113
|
setSearchParams((params) => {
|
|
1126
1114
|
params.delete('customerSupportIds');
|
|
1127
1115
|
params.set('page', '1');
|
|
1128
|
-
selection?.forEach((s) =>
|
|
1129
|
-
|
|
1130
|
-
|
|
1116
|
+
selection?.forEach((s) => {
|
|
1117
|
+
params.append("customerSupportIds", s.value);
|
|
1118
|
+
if (s.value === "chatbot") params.append("customerSupportIds", "-");
|
|
1119
|
+
return params;
|
|
1120
|
+
});
|
|
1131
1121
|
return params;
|
|
1132
1122
|
});
|
|
1133
1123
|
|
|
1134
1124
|
setPagination({pageIndex: 0, pageSize: pagination.pageSize});
|
|
1135
1125
|
|
|
1126
|
+
const customerSupportIds =
|
|
1127
|
+
selection?.reduce((acc, s) => {
|
|
1128
|
+
acc.push(s.value);
|
|
1129
|
+
if (s.value === "chatbot") acc.push("-");
|
|
1130
|
+
return acc;
|
|
1131
|
+
}, []) || [];
|
|
1132
|
+
|
|
1136
1133
|
getAllEndedChats.mutate({
|
|
1137
1134
|
startDate,
|
|
1138
1135
|
endDate,
|
|
1139
|
-
customerSupportIds:
|
|
1136
|
+
customerSupportIds: customerSupportIds,
|
|
1140
1137
|
pagination: {pageIndex: 0, pageSize: pagination.pageSize},
|
|
1141
1138
|
sorting,
|
|
1142
1139
|
search,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
1
|
import Markdown from "markdown-to-jsx";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
3
|
import sanitizeHtml from "sanitize-html";
|
|
4
4
|
|
|
5
5
|
interface MarkdownifyProps {
|
|
@@ -7,6 +7,27 @@ interface MarkdownifyProps {
|
|
|
7
7
|
sanitizeLinks?: boolean;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
const isValidImageUrl = (s: string): boolean => {
|
|
11
|
+
try {
|
|
12
|
+
const u = new URL(s);
|
|
13
|
+
if (!/^(https?|data):$/i.test(u.protocol)) return false;
|
|
14
|
+
if (s.startsWith("data:image/")) {
|
|
15
|
+
return /^data:image\/(png|jpe?g|gif|webp|svg\+xml|bmp);(base64,|charset=utf-8;)/i.test(s);
|
|
16
|
+
}
|
|
17
|
+
const path = u.pathname.toLowerCase();
|
|
18
|
+
const search = u.search.toLowerCase();
|
|
19
|
+
if (/\.(png|jpe?g|gif|webp|svg|ico|bmp|tiff?|avif|heic|heif|apng)([?#]|$)/i.test(path)) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (/\/(images?|img|photos?|pictures?|media|uploads?|thumb|avatar)\//i.test(path)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return /[?&](format|type|image|img|photo)=(png|jpe?g|gif|webp|svg|ico)/i.test(search);
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
10
31
|
const LinkPreview: React.FC<{
|
|
11
32
|
href: string;
|
|
12
33
|
children: React.ReactNode;
|
|
@@ -27,17 +48,25 @@ const LinkPreview: React.FC<{
|
|
|
27
48
|
);
|
|
28
49
|
}
|
|
29
50
|
|
|
30
|
-
|
|
51
|
+
if (!isValidImageUrl(href)) {
|
|
52
|
+
return (
|
|
53
|
+
<a href={href} target="_blank" rel="noopener noreferrer">
|
|
54
|
+
{children}
|
|
55
|
+
</a>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return hasError ? (
|
|
60
|
+
<a href={href} target="_blank" rel="noopener noreferrer">
|
|
61
|
+
{children}
|
|
62
|
+
</a>
|
|
63
|
+
) : (
|
|
31
64
|
<img
|
|
32
65
|
src={href}
|
|
33
66
|
alt={typeof children === "string" ? children : "Preview"}
|
|
34
67
|
style={{ maxWidth: "100%", height: "auto", borderRadius: "20px" }}
|
|
35
68
|
onError={() => setHasError(true)}
|
|
36
69
|
/>
|
|
37
|
-
) : (
|
|
38
|
-
<a href={href} target="_blank" rel="noopener noreferrer">
|
|
39
|
-
{children}
|
|
40
|
-
</a>
|
|
41
70
|
);
|
|
42
71
|
};
|
|
43
72
|
|
|
@@ -53,8 +82,14 @@ function formatMessage(message?: string): string {
|
|
|
53
82
|
.replaceAll(/\\?\$v\w*/g, "")
|
|
54
83
|
.replaceAll(/\\?\$g\w*/g, "");
|
|
55
84
|
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
const dataImagePattern = /((?:^|\s))(data:image\/[a-z0-9+]+;[^)\s]+)/gi;
|
|
86
|
+
const finalMessage = filteredMessage.replaceAll(
|
|
87
|
+
dataImagePattern,
|
|
88
|
+
(_, prefix, dataUrl) => `${prefix}[image](${dataUrl})`,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return finalMessage
|
|
92
|
+
.replaceAll(/&#x([0-9A-F]+);/gi, (_, hex: string) => String.fromCharCode(parseInt(hex, 16)))
|
|
58
93
|
.replaceAll("&", "&")
|
|
59
94
|
.replaceAll(">", ">")
|
|
60
95
|
.replaceAll("<", "<")
|
|
@@ -62,7 +97,7 @@ function formatMessage(message?: string): string {
|
|
|
62
97
|
.replaceAll("'", "'")
|
|
63
98
|
.replaceAll("'", "'")
|
|
64
99
|
.replaceAll(/(^|\n)(\d{4})\.\s/g, (match, prefix, year) => {
|
|
65
|
-
const remainingText =
|
|
100
|
+
const remainingText = finalMessage.substring(finalMessage.indexOf(match) + match.length);
|
|
66
101
|
const sentenceEnd = remainingText.indexOf("\n\n");
|
|
67
102
|
if (sentenceEnd !== -1) {
|
|
68
103
|
const currentSentence = remainingText.substring(0, sentenceEnd);
|
|
@@ -72,7 +107,7 @@ function formatMessage(message?: string): string {
|
|
|
72
107
|
}
|
|
73
108
|
return `${prefix}${year}\\. `;
|
|
74
109
|
})
|
|
75
|
-
.replaceAll(/(?<=\n)\d+\.\s/g, hasSpecialFormat(
|
|
110
|
+
.replaceAll(/(?<=\n)\d+\.\s/g, hasSpecialFormat(finalMessage) ? "\n\n$&" : "$&")
|
|
76
111
|
.replaceAll(/^(\s+)/g, (match) => match.replaceAll(" ", " "));
|
|
77
112
|
}
|
|
78
113
|
|
|
@@ -194,7 +194,52 @@ const HistoricalChat: FC<ChatProps> = ({
|
|
|
194
194
|
|
|
195
195
|
const eventGroup = (group: GroupedMessage) => {
|
|
196
196
|
return group.messages.map((message) => {
|
|
197
|
-
|
|
197
|
+
if (message.event) {
|
|
198
|
+
return <ChatEvent key={message.id} message={message} />;
|
|
199
|
+
} else {
|
|
200
|
+
return (
|
|
201
|
+
<div key={message.id}>
|
|
202
|
+
{group.name.trim() && (
|
|
203
|
+
<div className="historical-chat__group-header">
|
|
204
|
+
<div className="historical-chat__group-event-initials">
|
|
205
|
+
{group.type === "buerokratt" || group.type === "chatbot" ? (
|
|
206
|
+
<BykLogoWhite height={24} />
|
|
207
|
+
) : (
|
|
208
|
+
(() => {
|
|
209
|
+
if (group.name) {
|
|
210
|
+
const initials = group.name
|
|
211
|
+
.split(" ")
|
|
212
|
+
.map((n) => n[0])
|
|
213
|
+
.join("")
|
|
214
|
+
.toUpperCase();
|
|
215
|
+
return <>{initials}</>;
|
|
216
|
+
} else {
|
|
217
|
+
return <></>;
|
|
218
|
+
}
|
|
219
|
+
})()
|
|
220
|
+
)}
|
|
221
|
+
</div>
|
|
222
|
+
{group.name && (
|
|
223
|
+
<div className="historical-chat__group-event-name">
|
|
224
|
+
{group.name}
|
|
225
|
+
{group.title.length > 0 && <div className="title">{group.title}</div>}
|
|
226
|
+
</div>
|
|
227
|
+
)}
|
|
228
|
+
</div>
|
|
229
|
+
)}
|
|
230
|
+
<div className="historical-chat__messages">
|
|
231
|
+
<ChatMessage
|
|
232
|
+
message={message}
|
|
233
|
+
key={`${message.id ?? ""}`}
|
|
234
|
+
toastContext={toastContext}
|
|
235
|
+
onMessageClick={(message) => {
|
|
236
|
+
onMessageClick?.(message);
|
|
237
|
+
}}
|
|
238
|
+
/>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
198
243
|
});
|
|
199
244
|
};
|
|
200
245
|
|