@buerokratt-ria/common-gui-components 0.0.23 → 0.0.25

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.25] - 01-09-2025
8
+
9
+ - Added test column to display chats mark for test
10
+ - FIX: refetch based on updated domains
11
+
12
+ ## [0.0.24] - 14-08-2025
13
+
14
+ - Modified Start and End dates to send them in payload in iso format
15
+
7
16
  ## [0.0.23] - 21-07-2025
8
17
 
9
18
  - Initial support of multidomains
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buerokratt-ria/common-gui-components",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "description": "Common GUI components and pre defined templates.",
5
5
  "main": "index.ts",
6
6
  "author": "ExiRai",
@@ -1,5 +1,6 @@
1
1
  @import 'src/styles/tools/spacing';
2
2
  @import 'src/styles/tools/color';
3
+ @import 'src/styles/settings/variables/other';
3
4
  @import 'src/styles/settings/variables/typography';
4
5
 
5
6
  .input-wrapper {
@@ -13,6 +14,39 @@
13
14
  box-sizing: border-box;
14
15
  }
15
16
 
17
+ .checkbox-test {
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+
22
+ &__item {
23
+ input[type=checkbox] {
24
+ &::before {
25
+ content: '';
26
+ display: block;
27
+ width: 16px;
28
+ height: 16px;
29
+ box-shadow: inset 0 0 0 1px get-color(black-coral-2);
30
+ border-radius: 2px;
31
+ position: absolute;
32
+ left: 4px;
33
+ top: 4px;
34
+ }
35
+ }
36
+
37
+ &:checked {
38
+ &::before {
39
+ background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTEiIHZpZXdCb3g9IjAgMCAxNCAxMSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuNzQ5NzkgOC4xMjkwNkwxLjYyMjI5IDUuMDAxNTZMMC41NjEwMzUgNi4wNjI4MUw0Ljc0OTc5IDEwLjI1MTZMMTMuNzQ5OCAxLjI1MTU2TDEyLjY4ODUgMC4xOTAzMDhMNC43NDk3OSA4LjEyOTA2WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==');
40
+ background-color: get-color(sapphire-blue-10);
41
+ background-repeat: no-repeat;
42
+ background-position: center;
43
+ background-size: 13px 10px;
44
+ box-shadow: inset 0 0 0 1px get-color(sapphire-blue-10);
45
+ }
46
+ }
47
+ }
48
+ }
49
+
16
50
  .card-wrapper {
17
51
  flex: 1;
18
52
  overflow: auto;
@@ -1,8 +1,8 @@
1
- import React, {FC, PropsWithChildren, useEffect, useRef, useMemo, useState} from 'react';
1
+ import React, {FC, PropsWithChildren, useEffect, useMemo, useRef, useState} from 'react';
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} from 'date-fns';
5
+ import { format, startOfDay, endOfDay, formatISO } from "date-fns";
6
6
  import {AxiosError} from 'axios';
7
7
  import './History.scss';
8
8
  import {MdOutlineRemoveRedEye} from 'react-icons/md';
@@ -13,6 +13,7 @@ import {
13
13
  DataTable,
14
14
  Dialog,
15
15
  Drawer,
16
+ FormCheckbox,
16
17
  FormDatepicker,
17
18
  FormInput,
18
19
  FormMultiselect,
@@ -72,8 +73,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
72
73
  const routerLocation = useLocation();
73
74
  const params = new URLSearchParams(routerLocation.search);
74
75
  let passedChatId = new URLSearchParams(routerLocation.search).get('chat');
75
- const passedStartDate = delegatedStartDate ?? params.get('start');
76
- const passedEndDate = delegatedStartDate ?? params.get('end');
76
+ const passedStartDate = delegatedStartDate ?? params.get("start");
77
+ const passedEndDate = delegatedEndDate ?? params.get("end");
77
78
  const skipNextSelectedColumnsEffect = useRef(false);
78
79
  const passedCustomerSupportIds = params.getAll('customerSupportIds');
79
80
  const [search, setSearch] = useState('');
@@ -108,7 +109,13 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
108
109
  const useStore = userDomains;
109
110
  const [updateKey, setUpdateKey] = useState<number>(0)
110
111
  const currentDomains = useStore.getState().userDomains;
111
- const multiDomainEnabled = import.meta.env.REACT_APP_ENABLE_MULTI_DOMAIN.toLowerCase() === 'true';
112
+ const multiDomainEnabled = import.meta.env.REACT_APP_ENABLE_MULTI_DOMAIN?.toLowerCase() === 'true';
113
+ const testMessageEnabled = import.meta.env.REACT_APP_SHOW_TEST_MESSAGE?.toLowerCase() === 'true';
114
+
115
+ const parseDateParam = (dateString: string | null) => {
116
+ if (!dateString) return new Date();
117
+ return new Date(dateString.split("+")[0]);
118
+ };
112
119
 
113
120
  const {control, setValue, watch} = useForm<{
114
121
  startDate: Date | string;
@@ -116,19 +123,11 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
116
123
  }>({
117
124
  defaultValues: {
118
125
  startDate: passedStartDate
119
- ? unifyDateFromat(passedStartDate)
120
- : new Date(
121
- new Date().getUTCFullYear(),
122
- new Date().getUTCMonth(),
123
- new Date().getUTCDate()
124
- ),
125
- endDate: passedEndDate
126
- ? unifyDateFromat(passedEndDate)
127
- : new Date(
128
- new Date().getUTCFullYear(),
129
- new Date().getUTCMonth(),
130
- new Date().getUTCDate()
131
- ),
126
+ ? parseDateParam(passedStartDate)
127
+ : new Date(new Date().setUTCHours(0, 0, 0, 0)),
128
+ endDate: passedEndDate
129
+ ? parseDateParam(passedEndDate)
130
+ : new Date(new Date().setUTCHours(23, 59, 59, 999)),
132
131
  },
133
132
  });
134
133
 
@@ -137,8 +136,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
137
136
 
138
137
  const debouncedGetAllEnded = useDebouncedCallback((search) => {
139
138
  getAllEndedChats.mutate({
140
- startDate: format(new Date(startDate), 'yyyy-MM-dd'),
141
- endDate: format(new Date(endDate), 'yyyy-MM-dd'),
139
+ startDate: formatISO(startOfDay(new Date(startDate))),
140
+ endDate: formatISO(endOfDay(new Date(endDate))),
142
141
  customerSupportIds: passedCustomerSupportIds,
143
142
  pagination,
144
143
  sorting,
@@ -146,9 +145,9 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
146
145
  });
147
146
  }, 500);
148
147
 
149
- if(multiDomainEnabled) {
148
+ if (multiDomainEnabled) {
150
149
  useStore.subscribe((state, prevState) => {
151
- if(JSON.stringify(state.userDomains) !== JSON.stringify(prevState.userDomains)) {
150
+ if (JSON.stringify(state.userDomains) !== JSON.stringify(prevState.userDomains)) {
152
151
  setUpdateKey(prevState => prevState + 1);
153
152
  }
154
153
  });
@@ -173,12 +172,12 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
173
172
  setValue('endDate', unifyDateFromat(delegatedEndDate));
174
173
  }
175
174
 
176
- if(initialLoad) {
175
+ if (initialLoad) {
177
176
  fetchData()
178
177
  } else {
179
178
  getAllEndedChats.mutate({
180
- startDate: hasStart ? unifyDateFromat(delegatedStartDate) : format(new Date(startDate), 'yyyy-MM-dd'),
181
- endDate: hasEnd ? unifyDateFromat(delegatedEndDate) : format(new Date(endDate), 'yyyy-MM-dd'),
179
+ startDate: hasStart ? unifyDateFromat(delegatedStartDate) : formatISO(startOfDay(new Date(startDate))),
180
+ endDate: hasEnd ? unifyDateFromat(delegatedEndDate) : formatISO(endOfDay(new Date(endDate))),
182
181
  customerSupportIds: passedCustomerSupportIds,
183
182
  pagination,
184
183
  sorting,
@@ -214,8 +213,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
214
213
  setCounterKey(prev => prev + 1);
215
214
 
216
215
  getAllEndedChats.mutate({
217
- startDate: format(new Date(startDate), 'yyyy-MM-dd'),
218
- endDate: format(new Date(endDate), 'yyyy-MM-dd'),
216
+ startDate: formatISO(startOfDay(new Date(startDate))),
217
+ endDate: formatISO(endOfDay(new Date(endDate))),
219
218
  customerSupportIds: passedCustomerSupportIds,
220
219
  pagination: updatedPagination,
221
220
  sorting,
@@ -243,15 +242,15 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
243
242
  skipNextSelectedColumnsEffect.current = false;
244
243
  } else {
245
244
  getAllEndedChats.mutate({
246
- startDate: format(new Date(startDate), 'yyyy-MM-dd'),
247
- endDate: format(new Date(endDate), 'yyyy-MM-dd'),
245
+ startDate: formatISO(startOfDay(new Date(startDate))),
246
+ endDate: formatISO(endOfDay(new Date(endDate))),
248
247
  customerSupportIds: passedCustomerSupportIds,
249
248
  pagination,
250
249
  sorting,
251
250
  search,
252
251
  });
253
252
  }
254
- }, [selectedColumns]);
253
+ }, [selectedColumns, currentDomains]);
255
254
 
256
255
  useEffect(() => {
257
256
  listCustomerSupportAgents.mutate();
@@ -288,8 +287,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
288
287
 
289
288
  return apiDev.post('agents/chats/ended', {
290
289
  customerSupportIds: data.customerSupportIds,
291
- startDate: format(new Date(data.startDate), 'yyyy-MM-dd'),
292
- endDate: format(new Date(data.endDate), 'yyyy-MM-dd'),
290
+ startDate: formatISO(startOfDay(new Date(data.startDate))),
291
+ endDate: formatISO(endOfDay(new Date(data.endDate))),
293
292
  urls: getDomainsArray(currentDomains),
294
293
  page: data.pagination.pageIndex + 1,
295
294
  page_size: data.pagination.pageSize,
@@ -359,11 +358,15 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
359
358
  ];
360
359
 
361
360
  if (showEmail) {
362
- columns.splice(4, 0, {label: t('global.email'), value: 'endUserEmail'}); // insert after name
361
+ columns.splice(4, 0, {label: t('global.email'), value: 'endUserEmail'});
362
+ }
363
+
364
+ if (testMessageEnabled) {
365
+ columns.splice(5, 0, {label: t('global.test'), value: 'istest'});
363
366
  }
364
367
 
365
368
  return columns;
366
- }, [t, showEmail])
369
+ }, [t, showEmail, testMessageEnabled])
367
370
 
368
371
  const chatStatusChangeMutation = useMutation({
369
372
  mutationFn: async (data: { chatId: string | number; event: string }) => {
@@ -397,8 +400,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
397
400
  onSuccess: () => {
398
401
  setMessagesTrigger(!messagesTrigger);
399
402
  getAllEndedChats.mutate({
400
- startDate: format(new Date(startDate), 'yyyy-MM-dd'),
401
- endDate: format(new Date(endDate), 'yyyy-MM-dd'),
403
+ startDate: formatISO(startOfDay(new Date(startDate))),
404
+ endDate: formatISO(endOfDay(new Date(endDate))),
402
405
  customerSupportIds: passedCustomerSupportIds,
403
406
  pagination,
404
407
  sorting,
@@ -454,6 +457,31 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
454
457
  },
455
458
  });
456
459
 
460
+ const chatTestChangeMutation = useMutation({
461
+ mutationFn: (data: {
462
+ chatId: string | number;
463
+ isTest: boolean;
464
+ }) => apiDev.post('chats/mark-test', data),
465
+ onSuccess: (res, {chatId, isTest}) => {
466
+ const updatedChatList = filteredEndedChatsList.map((chat) =>
467
+ chat.id === chatId ? {...chat, isTest} : chat
468
+ );
469
+ filterChatsList(updatedChatList);
470
+ toast?.open({
471
+ type: 'success',
472
+ title: t('global.notification'),
473
+ message: t('toast.success.updateSuccess'),
474
+ });
475
+ },
476
+ onError: (error: AxiosError) => {
477
+ toast?.open({
478
+ type: 'error',
479
+ title: t('global.notificationError'),
480
+ message: error.message,
481
+ });
482
+ },
483
+ });
484
+
457
485
  const columnHelper = createColumnHelper<ChatType>();
458
486
 
459
487
  const copyValueToClipboard = async (value: string) => {
@@ -523,6 +551,26 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
523
551
  </Tooltip>
524
552
  );
525
553
 
554
+ const markConversationAsTest = (props: any) => {
555
+ return <>
556
+ <FormCheckbox
557
+ label={''}
558
+ hideLabel
559
+ emptyItem={true}
560
+ name="active"
561
+
562
+ item={{
563
+ label: '',
564
+ value: 'active',
565
+ checked: props.getValue()
566
+ }}
567
+ onChange={(e) => {
568
+ return chatTestChangeMutation.mutate({chatId: props.row.original.id, isTest: e.target.checked})
569
+ }}
570
+ />
571
+ </>
572
+ }
573
+
526
574
  const detailsView = (props: any) => (
527
575
  <Button
528
576
  appearance="text"
@@ -577,8 +625,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
577
625
  }
578
626
  },
579
627
  {
580
- id: `customerSupportFullName`,
581
- header: t('chat.history.csaName') ?? '',
628
+ id: `customerSupportFullName`,
629
+ header: t('chat.history.csaName') ?? '',
582
630
  }
583
631
  ),
584
632
  columnHelper.accessor(
@@ -663,11 +711,19 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
663
711
  }));
664
712
  }
665
713
 
714
+ if (testMessageEnabled) {
715
+ columns.splice(4, 0, columnHelper.accessor('istest', {
716
+ id: 'istest',
717
+ header: t('global.test') ?? '',
718
+ cell: markConversationAsTest
719
+ }));
720
+ }
721
+
666
722
  return columns;
667
- }, [t, showEmail])
723
+ }, [t, showEmail, testMessageEnabled])
668
724
 
669
725
  const getSortingString = () => {
670
- if(sorting && sorting.length > 0) {
726
+ if (sorting && sorting.length > 0) {
671
727
  const sortingObject = sorting[0];
672
728
  const sortingString = t('sorting.sorting');
673
729
  const orderingString = t(`sorting.${sortingObject.desc ? 'desc' : 'asc'}`);
@@ -678,7 +734,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
678
734
  }
679
735
  }
680
736
 
681
- const getColumnTranslation = (column: string) : string => {
737
+ const getColumnTranslation = (column: string): string => {
682
738
  switch (column) {
683
739
  case 'endUserId':
684
740
  return t('global.idCode') ?? ''
@@ -706,6 +762,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
706
762
  return 'www'
707
763
  case 'id':
708
764
  return 'id';
765
+ case 'istest':
766
+ return t('global.test') ?? ''
709
767
  default:
710
768
  return '';
711
769
  }
@@ -793,14 +851,14 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
793
851
  value={field.value ?? new Date()}
794
852
  onChange={(v) => {
795
853
  field.onChange(v);
796
- const start = format(new Date(v), 'yyyy-MM-dd');
854
+ const start = formatISO(startOfDay(new Date(v)));
797
855
  setSearchParams((params) => {
798
856
  params.set('start', start);
799
857
  return params;
800
858
  });
801
859
  getAllEndedChats.mutate({
802
860
  startDate: start,
803
- endDate: format(new Date(endDate), 'yyyy-MM-dd'),
861
+ endDate: formatISO(endOfDay(new Date(endDate))),
804
862
  customerSupportIds: passedCustomerSupportIds,
805
863
  pagination,
806
864
  sorting,
@@ -825,13 +883,13 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
825
883
  value={field.value ?? new Date()}
826
884
  onChange={(v) => {
827
885
  field.onChange(v);
828
- const end = format(new Date(v), 'yyyy-MM-dd');
886
+ const end = formatISO(endOfDay(new Date(v)));
829
887
  setSearchParams((params) => {
830
888
  params.set('end', end);
831
889
  return params;
832
890
  });
833
891
  getAllEndedChats.mutate({
834
- startDate: format(new Date(startDate), 'yyyy-MM-dd'),
892
+ startDate: formatISO(startOfDay(new Date(startDate))),
835
893
  endDate: end,
836
894
  customerSupportIds: passedCustomerSupportIds,
837
895
  pagination,
@@ -905,7 +963,7 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
905
963
  </Button>
906
964
  </div>)
907
965
  }
908
- <div className="card-drawer-container" style={{ height: '100%', overflow: 'auto' }}>
966
+ <div className="card-drawer-container" style={{height: '100%', overflow: 'auto'}}>
909
967
  <div className="card-wrapper">
910
968
  <Card>
911
969
  <DataTable
@@ -928,8 +986,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
928
986
  selected_columns: selectedColumns
929
987
  });
930
988
  getAllEndedChats.mutate({
931
- startDate: format(new Date(startDate), 'yyyy-MM-dd'),
932
- endDate: format(new Date(endDate), 'yyyy-MM-dd'),
989
+ startDate: formatISO(startOfDay(new Date(startDate))),
990
+ endDate: formatISO(endOfDay(new Date(endDate))),
933
991
  customerSupportIds: passedCustomerSupportIds,
934
992
  pagination: state,
935
993
  sorting,
@@ -939,8 +997,8 @@ const ChatHistory: FC<PropsWithChildren<HistoryProps>> = ({
939
997
  setSorting={(state: SortingState) => {
940
998
  setSorting(state);
941
999
  getAllEndedChats.mutate({
942
- startDate: format(new Date(startDate), 'yyyy-MM-dd'),
943
- endDate: format(new Date(endDate), 'yyyy-MM-dd'),
1000
+ startDate: formatISO(startOfDay(new Date(startDate))),
1001
+ endDate: formatISO(endOfDay(new Date(endDate))),
944
1002
  customerSupportIds: passedCustomerSupportIds,
945
1003
  pagination,
946
1004
  sorting: state,
@@ -17,6 +17,8 @@
17
17
  }
18
18
 
19
19
  &__item {
20
+ position: relative;
21
+
20
22
  input[type=checkbox] {
21
23
  display: none;
22
24
 
@@ -53,5 +55,18 @@
53
55
  }
54
56
  }
55
57
  }
58
+
59
+ &--nolabel {
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ width: 100%;
64
+
65
+ &::before {
66
+ position: static !important;
67
+ transform: none !important;
68
+ margin: 0;
69
+ }
70
+ }
56
71
  }
57
- }
72
+ }
@@ -6,6 +6,7 @@ type FormCheckboxType = InputHTMLAttributes<HTMLInputElement> & {
6
6
  label: string;
7
7
  name: string;
8
8
  hideLabel?: boolean;
9
+ emptyItem?: boolean;
9
10
  item: {
10
11
  label: string;
11
12
  value: string;
@@ -18,6 +19,7 @@ const FormCheckbox = forwardRef<HTMLInputElement, FormCheckboxType>((
18
19
  label,
19
20
  name,
20
21
  hideLabel,
22
+ emptyItem,
21
23
  item,
22
24
  ...rest
23
25
  },
@@ -28,9 +30,13 @@ const FormCheckbox = forwardRef<HTMLInputElement, FormCheckboxType>((
28
30
  return (
29
31
  <div className='checkbox'>
30
32
  {label && !hideLabel && <label className='checkbox__label'>{label}</label>}
31
- <div className='checkbox__item'>
33
+ <div className={`checkbox__item ${!emptyItem ? "checkbox__item--nolabel" : ""}`}>
32
34
  <input ref={ref} type='checkbox' name={name} id={uid} value={item.value} defaultChecked={item.checked} {...rest} />
33
- <label htmlFor={uid}>{item.label}</label>
35
+ {emptyItem ? (
36
+ <label htmlFor={uid} className="checkbox__item--nolabel" />
37
+ ) : (
38
+ <label htmlFor={uid}>{item.label}</label>
39
+ )}
34
40
  </div>
35
41
  </div>
36
42
  );
@@ -1,7 +1,5 @@
1
- import useStore from "../store";
2
-
3
1
  export const getDomainsArray = (currentDomains) => {
4
- const multiDomainEnabled = import.meta.env.REACT_APP_ENABLE_MULTI_DOMAIN.toLowerCase() === 'true';
2
+ const multiDomainEnabled = import.meta.env.REACT_APP_ENABLE_MULTI_DOMAIN?.toLowerCase() === 'true';
5
3
  const userDomains = currentDomains || [];
6
4
 
7
5
  return multiDomainEnabled ? (userDomains?.length > 0 ? userDomains : [null]) : [];