@nyris/nyris-webapp 0.3.91 → 0.3.92

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.
Files changed (106) hide show
  1. package/build/asset-manifest.json +6 -6
  2. package/build/data/related-parts.json +83 -0
  3. package/build/index.html +1 -1
  4. package/build/js/settings.example.js +3 -0
  5. package/build/static/css/main.5ea01690.css +4 -0
  6. package/build/static/css/main.5ea01690.css.map +1 -0
  7. package/build/static/js/main.36b77705.js +3 -0
  8. package/build/static/js/{main.f2255597.js.map → main.36b77705.js.map} +1 -1
  9. package/package.json +4 -3
  10. package/public/data/related-parts.json +83 -0
  11. package/public/js/settings.example.js +3 -0
  12. package/src/App.test.tsx +0 -1
  13. package/src/App.tsx +0 -1
  14. package/src/assets/arrow_down_expanded.svg +3 -0
  15. package/src/assets/arrow_enter.svg +3 -0
  16. package/src/assets/camera.svg +3 -0
  17. package/src/assets/close.svg +3 -0
  18. package/src/assets/enter.svg +3 -0
  19. package/src/assets/refresh.svg +3 -0
  20. package/src/assets/vizo_avatar.svg +16 -0
  21. package/src/components/Cadenas/CadenasWebViewer.tsx +1 -1
  22. package/src/components/Cart.tsx +48 -36
  23. package/src/components/ChatAssistant/ChatAssistant.tsx +289 -0
  24. package/src/components/ChatAssistant/MobileChatAssistant.tsx +291 -0
  25. package/src/components/ChatAssistant/OptionChip.tsx +78 -0
  26. package/src/components/ChatAssistant/index.ts +3 -0
  27. package/src/components/ChatAssistant/useChatAssistantLogic.ts +745 -0
  28. package/src/components/CurrentRefinements.tsx +2 -2
  29. package/src/components/CustomCameraDrawer.tsx +56 -13
  30. package/src/components/DragDropFile.tsx +5 -5
  31. package/src/components/ExperienceVisualSearch/ExperienceVisualSearch.tsx +1 -1
  32. package/src/components/Header.tsx +116 -96
  33. package/src/components/Hint.tsx +1 -2
  34. package/src/components/HitsPerPage.tsx +9 -3
  35. package/src/components/ImagePreview.tsx +32 -17
  36. package/src/components/ImageUpload.tsx +16 -8
  37. package/src/components/Inquiry/InquiryBanner.tsx +1 -1
  38. package/src/components/Inquiry/InquiryModal.tsx +35 -29
  39. package/src/components/ItemSpecification.tsx +58 -126
  40. package/src/components/LocationInfoPopup.tsx +33 -33
  41. package/src/components/MatchNotificationBanner.tsx +90 -36
  42. package/src/components/PostFilter/PostFilter.tsx +1 -1
  43. package/src/components/PostFilter/PostFilterComponent.tsx +0 -1
  44. package/src/components/PostFilter/PostFilterFindApi.tsx +0 -1
  45. package/src/components/PoweredBy.tsx +1 -1
  46. package/src/components/PreFilter/PreFilter.tsx +14 -3
  47. package/src/components/PreFilter/PreFilterModal.tsx +0 -1
  48. package/src/components/Product/Product.tsx +15 -11
  49. package/src/components/Product/ProductAttribute.tsx +4 -5
  50. package/src/components/Product/ProductDetailViewModal.tsx +2 -4
  51. package/src/components/Product/ProductList.tsx +26 -13
  52. package/src/components/Rfq/RfqModal.tsx +1 -1
  53. package/src/components/SidePanel.tsx +124 -91
  54. package/src/components/SmartFilter.tsx +320 -0
  55. package/src/components/TextSearch.tsx +134 -70
  56. package/src/components/UploadDisclaimer.tsx +1 -1
  57. package/src/hooks/useBadResultsRecovery.ts +407 -0
  58. package/src/hooks/useEffectiveGroundingResults.ts +54 -0
  59. package/src/hooks/useGoodResultsChat.ts +651 -0
  60. package/src/hooks/useGroundedSearch.ts +88 -0
  61. package/src/hooks/useImageSearch.ts +139 -187
  62. package/src/hooks/useResultEvaluator.ts +417 -0
  63. package/src/index.css +1 -1
  64. package/src/index.tsx +0 -1
  65. package/src/layouts/AppLayout.tsx +53 -2
  66. package/src/pages/Home.tsx +11 -52
  67. package/src/pages/Login.tsx +1 -2
  68. package/src/pages/Logout.tsx +1 -1
  69. package/src/pages/Result.tsx +198 -200
  70. package/src/providers/AuthProvider.tsx +0 -1
  71. package/src/services/Feedback.ts +1 -1
  72. package/src/services/visualSearch.ts +0 -21
  73. package/src/services/vizo.ts +192 -4
  74. package/src/stores/chat/chatStore.ts +150 -0
  75. package/src/stores/chat/conversationStore.ts +300 -0
  76. package/src/stores/request/Misc/misc.slice.ts +2 -2
  77. package/src/stores/request/filter/filter.slice.ts +8 -8
  78. package/src/stores/request/query/query.slice.ts +2 -2
  79. package/src/stores/request/requestImage/requestImage.slice.ts +6 -6
  80. package/src/stores/request/specifications/specifications.slice.ts +10 -7
  81. package/src/stores/result/detectedRegions/detectedRegions.slice.ts +1 -1
  82. package/src/stores/result/prodcuts/products.initialState.ts +12 -0
  83. package/src/stores/result/prodcuts/products.slice.ts +28 -8
  84. package/src/stores/result/session/session.slice.ts +2 -2
  85. package/src/stores/smartFilters/smartFiltersStore.ts +270 -0
  86. package/src/stores/types.ts +41 -0
  87. package/src/stores/ui/ai/ai.initialState.ts +5 -0
  88. package/src/stores/ui/ai/ai.slice.ts +15 -0
  89. package/src/stores/ui/banner/banner.initialState.ts +6 -0
  90. package/src/stores/ui/banner/banner.slice.ts +14 -0
  91. package/src/stores/ui/feedback/feedback.slice.ts +1 -1
  92. package/src/stores/ui/loading/loading.slice.ts +4 -4
  93. package/src/stores/ui/uiStore.ts +7 -1
  94. package/src/styles/product.scss +0 -2
  95. package/src/types.ts +3 -7
  96. package/src/utils/cropImageToBase64.ts +32 -0
  97. package/src/utils/fetchProductImage.ts +109 -0
  98. package/src/utils/imageConverters.ts +124 -0
  99. package/src/utils/relatedParts.ts +35 -0
  100. package/src/utils/specificationFilter.ts +1 -5
  101. package/tailwind.config.js +3 -2
  102. package/build/static/css/main.734b52e1.css +0 -4
  103. package/build/static/css/main.734b52e1.css.map +0 -1
  104. package/build/static/js/main.f2255597.js +0 -3
  105. package/src/utils/addAssets.ts +0 -40
  106. /package/build/static/js/{main.f2255597.js.LICENSE.txt → main.36b77705.js.LICENSE.txt} +0 -0
@@ -30,7 +30,7 @@ function CurrentRefinements({ className }: { className?: string }) {
30
30
  key={value}
31
31
  className="h-6 pl-2 pr-0.5 py-0.5 bg-[#f3f3f5] rounded-[1px] border border-solid border-[#e0e0e0] justify-start items-center gap-2 inline-flex"
32
32
  >
33
- <div className="text-[#2b2c46] text-xs font-normal ">{value}</div>
33
+ <div className="text-[#3B3E5F] text-xs font-normal ">{value}</div>
34
34
  <div className="w-5 h-5 rounded-sm justify-center items-center flex cursor-pointer">
35
35
  <Icon
36
36
  name="close"
@@ -60,7 +60,7 @@ function CurrentRefinements({ className }: { className?: string }) {
60
60
  key={refinement.label}
61
61
  className="h-6 pl-2 pr-0.5 py-0.5 bg-[#f3f3f5] rounded-[1px] border border-solid border-[#e0e0e0] justify-start items-center gap-2 inline-flex"
62
62
  >
63
- <div className="text-[#2b2c46] text-xs font-normal ">
63
+ <div className="text-[#3B3E5F] text-xs font-normal ">
64
64
  {refinement.label}
65
65
  </div>
66
66
  <div className="w-5 h-5 rounded-sm justify-center items-center flex cursor-pointer">
@@ -25,12 +25,18 @@ interface Props {
25
25
  show: boolean;
26
26
  onClose: any;
27
27
  newSearch?: boolean;
28
+ handleImageUpload?: (image: any) => void;
28
29
  }
29
30
 
30
31
  const FACING_MODE_USER = 'environment';
31
32
 
32
33
  function CustomCamera(props: Props) {
33
- const { show: isToggle, onClose: onToggleModal, newSearch } = props;
34
+ const {
35
+ show: isToggle,
36
+ onClose: onToggleModal,
37
+ newSearch,
38
+ handleImageUpload,
39
+ } = props;
34
40
  const settings = window.settings;
35
41
  const webcamRef: any = useRef(null);
36
42
  const navigate = useNavigate();
@@ -44,12 +50,16 @@ function CustomCamera(props: Props) {
44
50
  const specifications = useRequestStore(state => state.specifications);
45
51
  const setSpecifications = useRequestStore(state => state.setSpecifications);
46
52
  const setRequestImages = useRequestStore(state => state.setRequestImages);
47
- const setNameplateNotificationText = useRequestStore(state => state.setNameplateNotificationText);
53
+ const setNameplateNotificationText = useRequestStore(
54
+ state => state.setNameplateNotificationText,
55
+ );
48
56
  const setAlgoliaFilter = useRequestStore(state => state.setAlgoliaFilter);
49
57
  const setPreFilter = useRequestStore(state => state.setPreFilter);
50
58
  const setShowLoading = useRequestStore(state => state.setShowLoading);
51
59
  const setNameplateImage = useRequestStore(state => state.setNameplateImage);
52
- const setShowNotMatchedError = useRequestStore(state => state.setShowNotMatchedError);
60
+ const setShowNotMatchedError = useRequestStore(
61
+ state => state.setShowNotMatchedError,
62
+ );
53
63
  const [capturedImages, setCapturedImages] = useState<HTMLCanvasElement[]>([]);
54
64
  const [currentIndex, setCurrentIndex] = useState(0);
55
65
  const [imageCaptureHelpModal, setImageCaptureHelpModal] = useState(false);
@@ -60,6 +70,12 @@ function CustomCamera(props: Props) {
60
70
  };
61
71
 
62
72
  const handlerFindImage = async (image: any) => {
73
+ if (handleImageUpload) {
74
+ handleImageUpload(image);
75
+ handleClose();
76
+ return;
77
+ }
78
+
63
79
  if (location.pathname !== '/result') {
64
80
  navigate('/result');
65
81
  }
@@ -77,35 +93,62 @@ function CustomCamera(props: Props) {
77
93
  settings,
78
94
  newSearch,
79
95
  showFeedback: true,
80
- }).then((singleImageResp) => {
81
- const specificationPrefilter = singleImageResp.image_analysis?.specification?.prefilter_value || null;
82
- const hasPrefilter = preFilterList.filter((filter: any) => filter.values.includes(specificationPrefilter));
96
+ }).then(singleImageResp => {
97
+ const specificationPrefilter =
98
+ singleImageResp.image_analysis?.specification?.prefilter_value || null;
99
+
100
+ const hasPrefilter = preFilterList.filter((filter: any) =>
101
+ filter.values.includes(specificationPrefilter),
102
+ );
83
103
  if (specificationPrefilter) {
84
104
  setRequestImages([]);
85
105
  setShowNotMatchedError(false);
86
106
  if (hasPrefilter.length) {
87
- setSpecifications(clone(singleImageResp.image_analysis.specification));
107
+ setSpecifications(
108
+ clone(singleImageResp.image_analysis.specification),
109
+ );
88
110
  setNameplateImage(image);
89
- setPreFilter({[singleImageResp.image_analysis?.specification?.prefilter_value]: true});
90
- setAlgoliaFilter(`${settings.alogoliaFilterField}:'${singleImageResp.image_analysis?.specification?.prefilter_value}'`);
111
+ setPreFilter({
112
+ [singleImageResp.image_analysis?.specification?.prefilter_value]:
113
+ true,
114
+ });
115
+ setAlgoliaFilter(
116
+ `${settings.alogoliaFilterField}:'${singleImageResp.image_analysis?.specification?.prefilter_value}'`,
117
+ );
91
118
 
92
119
  setShowLoading(false);
93
120
  handleClose();
94
121
 
95
- setNameplateNotificationText(t('We have successfully defined the search criteria', { prefilter_value: specificationPrefilter, preFilterTitle: window.settings.preFilterTitle?.toLocaleLowerCase() }));
122
+ setNameplateNotificationText(
123
+ t('We have successfully defined the search criteria', {
124
+ prefilter_value: specificationPrefilter,
125
+ preFilterTitle:
126
+ window.settings.preFilterTitle?.toLocaleLowerCase(),
127
+ }),
128
+ );
96
129
  setTimeout(() => {
97
130
  setNameplateNotificationText('');
98
131
  }, 5000);
99
132
  }
100
133
  if (!hasPrefilter.length && window.settings.preFilterOption) {
101
- setSpecifications(clone({...singleImageResp.image_analysis.specification, specificationPrefilter}));
134
+ setSpecifications(
135
+ clone({
136
+ ...singleImageResp.image_analysis.specification,
137
+ specificationPrefilter,
138
+ }),
139
+ );
102
140
  setPreFilter({});
103
141
  setAlgoliaFilter('');
104
142
  setShowLoading(false);
105
143
  handleClose();
106
144
  setShowNotMatchedError(true);
107
145
  setTimeout(() => {
108
- setNameplateNotificationText(t('Extracted details from the nameplate could not be matched', { preFilterTitle: window.settings.preFilterTitle?.toLocaleLowerCase() }));
146
+ setNameplateNotificationText(
147
+ t('Extracted details from the nameplate could not be matched', {
148
+ preFilterTitle:
149
+ window.settings.preFilterTitle?.toLocaleLowerCase(),
150
+ }),
151
+ );
109
152
  }, 1000);
110
153
  setTimeout(() => {
111
154
  setNameplateNotificationText('');
@@ -113,7 +156,7 @@ function CustomCamera(props: Props) {
113
156
  }
114
157
  } else {
115
158
  if (!specifications?.is_nameplate) {
116
- setSpecifications({...specifications, is_nameplate: false});
159
+ setSpecifications({ ...specifications, is_nameplate: false });
117
160
  }
118
161
  setShowLoading(false);
119
162
  handleClose();
@@ -46,7 +46,7 @@ function DragDropFile(props: Props) {
46
46
  file: file,
47
47
  settings: window.settings,
48
48
  newSearch: true,
49
- }).then(res => {});
49
+ }).then(() => {});
50
50
 
51
51
  return;
52
52
  }
@@ -61,7 +61,7 @@ function DragDropFile(props: Props) {
61
61
  newSearch: true,
62
62
  }).then(singleImageResp => {
63
63
  const specificationPrefilter =
64
- singleImageResp.image_analysis?.specification?.prefilter_value || null;
64
+ singleImageResp?.image_analysis?.specification?.prefilter_value || null;
65
65
  const hasPrefilter = preFilterList.filter((filter: any) =>
66
66
  filter.values.includes(specificationPrefilter),
67
67
  );
@@ -154,9 +154,9 @@ function DragDropFile(props: Props) {
154
154
  <div
155
155
  className={twMerge([
156
156
  'drag-n-drop-inner',
157
- 'flex flex-col items-center w-full cursor-pointer pb-4 pt-4 rounded-[12px]',
158
- 'text-[#cacad1] hover:text-primary',
159
- 'border-2 border-dashed border-transparent hover:border-[#e0e0e0]',
157
+ 'flex flex-col items-center w-full cursor-pointer py-10 rounded-[12px]',
158
+ 'text-[#767A9F] hover:text-primary',
159
+ 'border-2 border-dashed border-[#BBBDCF]',
160
160
  isDragging && 'text-primary border-[#e0e0e0]',
161
161
  ])}
162
162
  >
@@ -51,7 +51,7 @@ function ExperienceVisualSearch({
51
51
  Start your visual search by selecting an image below.
52
52
  </div>
53
53
  <div className="custom-modal-body-content experience-visual-search-images">
54
- {new Array(4).fill(1).map((val, index) => {
54
+ {new Array(4).fill(1).map((_val, index) => {
55
55
  let itemImage: any;
56
56
 
57
57
  if (index <= experienceVisualSearchBlobs.length - 1) {
@@ -9,18 +9,20 @@ import TextSearch from './TextSearch';
9
9
  import useRequestStore from 'stores/request/requestStore';
10
10
  import { useState } from 'react';
11
11
  import LogoutModal from './LogoutModal';
12
- import { Popover, PopoverContent, PopoverTrigger } from './popover';
13
12
  import useResultStore from 'stores/result/resultStore';
14
13
  import Cart from './Cart';
14
+ import useUiStore from 'stores/ui/uiStore';
15
15
 
16
16
  function Header() {
17
17
  const { theme, auth0 } = window.settings;
18
- const { isAuthenticated, user, logout } = useAuth0();
18
+ const { isAuthenticated } = useAuth0();
19
19
  let location = useLocation();
20
20
 
21
21
  const reset = useRequestStore(state => state.reset);
22
22
  const resetResultStore = useResultStore(state => state.reset);
23
23
  const setSpecifications = useRequestStore(state => state.setSpecifications);
24
+ const showSidePanel = useUiStore(state => state.showSidePanel);
25
+ const setShowSidePanel = useUiStore(state => state.setShowSidePanel);
24
26
 
25
27
  const showSearchBar = location?.pathname === '/result';
26
28
 
@@ -29,124 +31,142 @@ function Header() {
29
31
  return (
30
32
  <div
31
33
  className={twMerge([
32
- 'h-12',
33
- 'desktop:h-[58px]',
34
- 'desktop:min-h-[58px]',
35
- location?.pathname === '/result' &&
36
- 'border-solid border-b border-[#afafaf52]',
37
- 'desktop:border-solid desktop:border-b desktop:border-[#E0E0E0]',
38
- 'pr-6',
39
- 'pl-4',
34
+ 'h-[56px]',
35
+ 'desktop:h-[68px]',
36
+ 'desktop:min-h-[68px]',
37
+ 'px-2',
38
+ 'desktop:px-4',
40
39
  'w-full',
41
40
  'flex-shrink-0',
41
+ 'bg-transparent',
42
+ 'mt-2',
43
+ 'desktop:mt-4',
44
+ 'mb-4',
45
+ 'desktop:mb-2',
46
+ 'flex',
47
+ 'gap-2',
48
+ 'justify-between',
49
+ 'desktop:items-start',
42
50
  ])}
43
- style={{ background: theme?.headerColor }}
44
51
  >
52
+ {location?.pathname === '/result' && (
53
+ <div
54
+ className={twMerge(
55
+ 'hidden desktop:flex',
56
+ 'h-[56px] min-w-[56px]',
57
+ 'desktop:min-w-[68px] desktop:h-[68px]',
58
+ 'border border-solid border-[#DDDEE7] items-center justify-center cursor-pointer bg-white',
59
+ 'rounded-2xl',
60
+ 'shadow-ds-1',
61
+ )}
62
+ onClick={() => {
63
+ setShowSidePanel(!showSidePanel);
64
+ }}
65
+ >
66
+ <Icon name={showSidePanel ? 'close' : 'hamburger'} />
67
+ </div>
68
+ )}
69
+
45
70
  <div
46
- className={twMerge(['w-full', 'flex', 'items-center', 'h-full'])}
47
- style={{ display: 'flex', alignItems: 'center', height: '100%' }}
71
+ className={twMerge(
72
+ 'h-[56px]',
73
+ 'min-w-[268px] desktop:h-[68px] flex items-center justify-between',
74
+ 'border border-solid border-[#DDDEE7]',
75
+ 'bg-white',
76
+ 'rounded-2xl',
77
+ 'shadow-ds-1',
78
+ location?.pathname === '/result' && 'flex-grow',
79
+ )}
48
80
  >
49
- {/* Left: Logo */}
50
- <div
51
- className="flex items-center justify-start min-w-0"
52
- style={{ flex: '0 0 auto' }}
81
+ <NavLink
82
+ to="/"
83
+ style={{ lineHeight: 0 }}
84
+ onClick={() => {
85
+ reset();
86
+ resetResultStore();
87
+ setSpecifications(null);
88
+ }}
89
+ className="pl-6"
53
90
  >
54
- <NavLink
55
- to="/"
56
- style={{ lineHeight: 0 }}
57
- onClick={() => {
58
- reset();
59
- resetResultStore();
60
- setSpecifications(null);
91
+ <img
92
+ src={theme?.appBarLogoUrl}
93
+ alt="logo"
94
+ style={{
95
+ aspectRatio: 1,
96
+ width: theme?.logoWidth,
97
+ height: theme?.logoHeight,
61
98
  }}
62
- >
63
- <img
64
- src={theme?.appBarLogoUrl}
65
- alt="logo"
66
- style={{
67
- aspectRatio: 1,
68
- width: theme?.logoWidth,
69
- height: theme?.logoHeight,
70
- }}
71
- />
72
- </NavLink>
73
- </div>
74
- {/* Center: Search bar */}
75
- <div className="flex-1 flex justify-center items-center min-w-0">
76
- <div
77
- className={twMerge(['hidden', showSearchBar && 'desktop:block'])}
78
- >
79
- <TextSearch />
80
- </div>
81
- </div>
82
- {/* Right: Cart and user actions */}
99
+ />
100
+ </NavLink>
101
+
83
102
  <div
84
- className="flex items-center justify-end min-w-0 gap-4"
85
- style={{ flex: '0 0 auto' }}
103
+ className={twMerge([
104
+ 'hidden',
105
+ showSearchBar && 'desktop:flex',
106
+ 'flex-1',
107
+ 'justify-center',
108
+ 'min-w-0',
109
+ ])}
86
110
  >
87
- {window.settings.cart && <Cart />}
111
+ <TextSearch className="w-full max-w-[531px] min-w-0" aiMode={true} />
112
+ </div>
88
113
 
89
- {auth0.enabled && isAuthenticated && (
114
+ {auth0.enabled &&
115
+ isAuthenticated &&
116
+ location?.pathname === '/result' && (
90
117
  <>
91
118
  <div
92
- className="hidden desktop:block"
93
- style={{ position: 'relative' }}
94
- >
95
- <Popover>
96
- <PopoverTrigger>
97
- <div
98
- style={{
99
- display: 'flex',
100
- columnGap: '16px',
101
- alignItems: 'center',
102
- cursor: 'pointer',
103
- }}
104
- >
105
- <p style={{ color: '#2B2C46' }}>{user?.email}</p>
106
- <Icon name="avatar" />
107
- </div>
108
- </PopoverTrigger>
109
- <PopoverContent className="w-[152px] bg-white p-2 shadow-outer">
110
- <div
111
- className={twMerge([
112
- 'flex',
113
- 'w-[75px]',
114
- 'h-[24px]',
115
- 'px-2',
116
- 'items-center',
117
- 'bg-[#2B2C46]',
118
- 'text-white',
119
- 'text-[10px]',
120
- 'cursor-pointer',
121
- ])}
122
- onClick={() => {
123
- logout({
124
- logoutParams: { returnTo: window.location.origin },
125
- });
126
- }}
127
- >
128
- Sign out
129
- </div>
130
- </PopoverContent>
131
- </Popover>
132
- </div>
133
- <div
134
- className="block desktop:hidden cursor-pointer"
119
+ className={twMerge(
120
+ 'cursor-pointer w-10 h-10 rounded-full bg-[#FAFAFA] flex items-center justify-center',
121
+ 'mr-3.5',
122
+ )}
135
123
  onClick={() => {
136
124
  setShowLogoutModal(true);
137
125
  }}
138
126
  >
139
127
  <Icon
140
128
  name="logout"
141
- className="text-[#AAABB5]"
142
- width={24}
143
- height={24}
129
+ className="text-black"
130
+ width={16}
131
+ height={16}
144
132
  />
145
133
  </div>
146
134
  </>
147
135
  )}
148
- </div>
149
136
  </div>
137
+ <div className="flex gap-2">
138
+ {auth0.enabled &&
139
+ isAuthenticated &&
140
+ location?.pathname !== '/result' && (
141
+ <>
142
+ <div
143
+ className={twMerge(
144
+ 'h-[56px] min-w-[56px]',
145
+ 'desktop:min-w-[68px] desktop:h-[68px] bg-white rounded-2xl flex items-center justify-center ',
146
+ 'border border-solid border-[#DDDEE7]',
147
+ 'shadow-ds-1',
148
+ )}
149
+ >
150
+ <button
151
+ className={twMerge(
152
+ 'relative flex items-center justify-center rounded-2xl',
153
+ 'h-10 w-10',
154
+ )}
155
+ style={{
156
+ backgroundColor: '#FAFAFA',
157
+ }}
158
+ onClick={() => {
159
+ setShowLogoutModal(true);
160
+ }}
161
+ >
162
+ <Icon name="logout" className={twMerge('text-[#BBBDCF]')} />
163
+ </button>
164
+ </div>
165
+ </>
166
+ )}
167
+ {window.settings.cart && <Cart />}
168
+ </div>
169
+
150
170
  <LogoutModal
151
171
  setShowLogoutModal={setShowLogoutModal}
152
172
  showModal={showLogoutModal}
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import { Icon } from '@nyris/nyris-react-components';
3
2
  import { useTranslation } from 'react-i18next';
4
3
 
@@ -95,4 +94,4 @@ const Hint = () => {
95
94
  );
96
95
  };
97
96
 
98
- export default Hint;
97
+ export default Hint;
@@ -1,6 +1,7 @@
1
1
  import { useTranslation } from 'react-i18next';
2
2
  import { useHitsPerPage, UseHitsPerPageProps } from 'react-instantsearch';
3
3
  import PoweredBy from './PoweredBy';
4
+ import { twMerge } from 'tailwind-merge';
4
5
 
5
6
  export const HitsPerPage = (props: UseHitsPerPageProps) => {
6
7
  const { items, refine } = useHitsPerPage(props);
@@ -11,9 +12,14 @@ export const HitsPerPage = (props: UseHitsPerPageProps) => {
11
12
 
12
13
  return (
13
14
  <>
14
- <div className="w-full px-4 h-10 bg-white border border-solid border-[#DDDEE7] items-center hidden desktop:inline-flex justify-between">
15
- <div className="self-stretch pr-6 border-r border-solid border-[#DDDEE7] justify-center items-center gap-1 flex">
16
- <div className="text-[#2b2c46] text-[13px] font-normal font-['Source Sans 3'] leading-none tracking-tight">
15
+ <div
16
+ className={twMerge(
17
+ 'w-full min-h-10 bg-[#FFFFFF] border border-solid border-[#DDDEE7] items-center hidden desktop:inline-flex rounded-3xl justify-between pr-4',
18
+ 'shadow-ds-1',
19
+ )}
20
+ >
21
+ <div className="self-stretch pl-4 pr-6 border-r border-solid border-[#DDDEE7] justify-center items-center gap-1 flex">
22
+ <div className="text-[#3B3E5F] text-[13px] font-normal font-['Source Sans 3'] leading-none tracking-tight">
17
23
  {t('Items per page')}:
18
24
  </div>
19
25
  <select
@@ -108,7 +108,7 @@ function ImagePreviewComponent({
108
108
  compress: false,
109
109
  }).then((res: any) => {
110
110
  const specificationPrefilter =
111
- res.image_analysis?.specification?.prefilter_value || null;
111
+ res?.image_analysis?.specification?.prefilter_value || null;
112
112
  const hasPrefilter = preFilterList.filter((filter: any) =>
113
113
  filter.values.includes(specificationPrefilter),
114
114
  );
@@ -188,7 +188,7 @@ function ImagePreviewComponent({
188
188
 
189
189
  // eslint-disable-next-line react-hooks/exhaustive-deps
190
190
  const debouncedOnImageSelectionChange = useCallback(
191
- debounce((r: RectCoords, index?: number) => {
191
+ debounce((r: RectCoords, _index?: number) => {
192
192
  findItemsInSelection(r, requestImages[0]);
193
193
  }, 0),
194
194
  [findItemsInSelection, requestImages, updateRegion],
@@ -200,7 +200,7 @@ function ImagePreviewComponent({
200
200
  <div
201
201
  ref={previewWrapperRef}
202
202
  className={twMerge([
203
- 'bg-primary',
203
+ 'bg-[#545987]',
204
204
  'justify-center',
205
205
  isVisible ? (!isMultiImageSearchEnabled ? 'py-5' : 'pt-6') : '',
206
206
  'px-7',
@@ -211,6 +211,7 @@ function ImagePreviewComponent({
211
211
  'hidden',
212
212
  'desktop:flex',
213
213
  // 'rounded',
214
+ 'rounded-[24px]',
214
215
  ])}
215
216
  // style={{
216
217
  // height: '100%',
@@ -228,9 +229,9 @@ function ImagePreviewComponent({
228
229
  >
229
230
  <div
230
231
  className={twMerge([
231
- // 'w-[243px]',
232
232
  'w-full',
233
- 'bg-[#55566b] aspect-square flex just items-center',
233
+ 'bg-[#545987] aspect-square flex just items-center',
234
+ 'rounded-[24px]',
234
235
  ])}
235
236
  >
236
237
  <Preview
@@ -295,7 +296,7 @@ function ImagePreviewComponent({
295
296
  {/* Image preview Mobile*/}
296
297
  <div
297
298
  className={twMerge([
298
- 'bg-primary',
299
+ 'bg-[#545987]',
299
300
  'justify-center',
300
301
  'p-5',
301
302
  !editActive ? 'py-2' : '',
@@ -303,11 +304,13 @@ function ImagePreviewComponent({
303
304
  'relative',
304
305
  'flex',
305
306
  'desktop:hidden',
307
+ !editActive && 'rounded-[32px]',
308
+ editActive && 'rounded-[24px]',
306
309
  ])}
307
310
  >
308
311
  <div
309
312
  className={`w-full ${
310
- editActive ? 'bg-[#55566b] ' : ''
313
+ editActive ? 'bg-[#545987] ' : ''
311
314
  } flex just items-center`}
312
315
  >
313
316
  <Preview
@@ -318,12 +321,12 @@ function ImagePreviewComponent({
318
321
  selection={regions[currentIndex] || DEFAULT_REGION}
319
322
  regions={detectedRegions[currentIndex] || []}
320
323
  minWidth={Math.min(
321
- 80 *
324
+ 40 *
322
325
  (requestImages[currentIndex]?.width /
323
326
  requestImages[currentIndex]?.height),
324
327
  200,
325
328
  )}
326
- minHeight={80}
329
+ minHeight={40}
327
330
  dotColor={editActive ? '#FBD914' : ''}
328
331
  minCropWidth={editActive ? 30 : 5}
329
332
  minCropHeight={editActive ? 30 : 5}
@@ -370,26 +373,38 @@ function ImagePreviewComponent({
370
373
  )}
371
374
  <div
372
375
  onClick={() => setEditActive(s => !s)}
373
- className={`absolute right-1 ${
374
- editActive ? 'bottom-1' : 'bottom-8'
375
- } flex justify-center items-center desktop:hidden p-1`}
376
+ className={twMerge(
377
+ `absolute right-1 ${
378
+ editActive ? 'bottom-1' : 'bottom-1'
379
+ } flex justify-center items-center desktop:hidden p-1`,
380
+ )}
376
381
  >
377
- <div className="rounded-full bg-white w-6 h-6 flex justify-center items-center desktop:hidden">
382
+ <div
383
+ className={twMerge(
384
+ 'rounded-full w-6 h-6 flex justify-center items-center desktop:hidden',
385
+ editActive ? 'w-8 h-8 bg-white' : 'w-10 h-10 bg-transparent',
386
+ )}
387
+ >
378
388
  {editActive && <Icon name="collapse" className="text-primary" />}
379
- {!editActive && <Icon name="crop" className="text-primary" />}
389
+ {!editActive && <Icon name="crop" className="text-white" />}
380
390
  </div>
381
391
  </div>
382
392
 
383
393
  <div
384
394
  onClick={() => onImageRemove()}
385
395
  className={`absolute left-1 ${
386
- editActive ? 'top-1' : 'top-8'
396
+ editActive ? 'top-1' : 'top-1'
387
397
  } flex justify-center items-center desktop:hidden p-1`}
388
398
  >
389
- <div className="rounded-full bg-white w-6 h-6 flex justify-center items-center desktop:hidden">
399
+ <div
400
+ className={twMerge(
401
+ 'rounded-full bg-[#FFE5EF] flex justify-center items-center desktop:hidden',
402
+ editActive ? 'w-8 h-8' : 'w-10 h-10',
403
+ )}
404
+ >
390
405
  <Icon
391
406
  name="trash"
392
- className="text-primary"
407
+ className="text-[#E31B5D]"
393
408
  width={14}
394
409
  height={14}
395
410
  />