@nyris/nyris-webapp 0.3.90 → 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.cede3ae1.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.cede3ae1.js +0 -3
  105. package/src/utils/addAssets.ts +0 -40
  106. /package/build/static/js/{main.cede3ae1.js.LICENSE.txt → main.36b77705.js.LICENSE.txt} +0 -0
@@ -12,7 +12,13 @@ import { useCadSearch } from 'hooks/useCadSearch';
12
12
  import { isCadFile } from '@nyris/nyris-api';
13
13
  import UploadDisclaimer from './UploadDisclaimer';
14
14
 
15
- function ImageUpload({ onCameraClick }: { onCameraClick?: () => void }) {
15
+ function ImageUpload({
16
+ onCameraClick,
17
+ disableDisclaimer,
18
+ }: {
19
+ onCameraClick?: () => void;
20
+ disableDisclaimer?: boolean;
21
+ }) {
16
22
  const settings = window.settings;
17
23
  const user = useAuth0().user;
18
24
 
@@ -66,12 +72,13 @@ function ImageUpload({ onCameraClick }: { onCameraClick?: () => void }) {
66
72
  ]);
67
73
 
68
74
  const showDisclaimerDisabled = useMemo(() => {
75
+ if (disableDisclaimer) return true;
69
76
  const disclaimer = localStorage.getItem('upload-disclaimer-suite');
70
77
  if (requestImages.length === 0) return true;
71
78
  if (!disclaimer) return false;
72
79
  return disclaimer === 'dont-show';
73
80
  // eslint-disable-next-line react-hooks/exhaustive-deps
74
- }, [showDisclaimer, requestImages]);
81
+ }, [showDisclaimer, requestImages, disableDisclaimer]);
75
82
 
76
83
  const { singleImageSearch } = useImageSearch();
77
84
  const { cadSearch } = useCadSearch();
@@ -81,7 +88,7 @@ function ImageUpload({ onCameraClick }: { onCameraClick?: () => void }) {
81
88
  setQuery('');
82
89
 
83
90
  if (isCadFile(files[0])) {
84
- cadSearch({ file: files[0], settings, newSearch: true }).then(res => {});
91
+ cadSearch({ file: files[0], settings, newSearch: true }).then(() => {});
85
92
 
86
93
  return;
87
94
  }
@@ -191,14 +198,15 @@ function ImageUpload({ onCameraClick }: { onCameraClick?: () => void }) {
191
198
  <Tooltip content={t('Search with an image')}>
192
199
  <label
193
200
  className={twMerge(
194
- 'mr-2 desktop:mr-1',
195
- 'w-10 h-10 flex justify-center items-center cursor-pointer rounded-full bg-gray-100 desktop:bg-transparent hover:bg-gray-100',
201
+ 'min-w-10 min-h-10 flex justify-center items-center cursor-pointer rounded-full bg-gray-100 desktop:bg-transparent hover:bg-gray-100',
196
202
  location.pathname === '/result' && 'desktop:w-8 desktop:h-8',
203
+ location.pathname !== '/result' &&
204
+ 'desktop:bg-[#FAFAFA] desktop:hover:bg-[#FAFAFA]',
197
205
  )}
198
206
  htmlFor={
199
207
  showDisclaimerDisabled && !onCameraClick ? 'icon-button-file' : ''
200
208
  }
201
- onClick={e => {
209
+ onClick={() => {
202
210
  if (!showDisclaimerDisabled) {
203
211
  // disclaimer
204
212
  setShowDisclaimer(true);
@@ -207,12 +215,12 @@ function ImageUpload({ onCameraClick }: { onCameraClick?: () => void }) {
207
215
  }
208
216
  }}
209
217
  >
210
- <Icon name="camera_simple" width={16} height={16} fill="#2B2C46" />
218
+ <Icon name="camera_ai" width={16} height={16} fill="#3B3E5F" />
211
219
  </label>
212
220
  </Tooltip>
213
221
  </div>
214
222
 
215
- {showDisclaimer && (
223
+ {showDisclaimer && !disableDisclaimer && (
216
224
  <UploadDisclaimer
217
225
  onClose={() => {
218
226
  setShowDisclaimer(false);
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
  import { useMediaQuery } from 'react-responsive';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { Icon } from '@nyris/nyris-react-components';
@@ -66,20 +66,22 @@ export default function InquiryModal({
66
66
  useEffect(() => {
67
67
  function omitKeys(obj: any, keys: string[]) {
68
68
  return Object.fromEntries(
69
- Object.entries(obj).filter(([key]) => !keys.includes(key))
69
+ Object.entries(obj).filter(([key]) => !keys.includes(key)),
70
70
  );
71
71
  }
72
- const omittedSpecification = omitKeys(specifications, ['is_nameplate', 'prefilter_value']);
72
+ const omittedSpecification = omitKeys(specifications, [
73
+ 'is_nameplate',
74
+ 'prefilter_value',
75
+ ]);
73
76
  setInformation(
74
- Object
75
- .entries(omittedSpecification)
76
- .reduce((acc, [k, v]) =>
77
- v == null || (typeof v === 'string' && v.trim() === '')
78
- ? acc
79
- : `${acc}${k}: ${v}\n`,
80
- ''
81
- )
82
- );
77
+ Object.entries(omittedSpecification).reduce(
78
+ (acc, [k, v]) =>
79
+ v == null || (typeof v === 'string' && v.trim() === '')
80
+ ? acc
81
+ : `${acc}${k}: ${v}\n`,
82
+ '',
83
+ ),
84
+ );
83
85
  }, [specifications]);
84
86
 
85
87
  useEffect(() => emailjs.init('SMGihPnuEGcYLm0V4'), []);
@@ -94,32 +96,36 @@ export default function InquiryModal({
94
96
  const croppedImage = requestImage
95
97
  ? getCroppedCanvas(requestImage, selectedRegion)
96
98
  : null;
97
- const nameplateImageCanvas = nameplateImage ? await createImage(nameplateImage) : null;
98
-
99
+ const nameplateImageCanvas = nameplateImage
100
+ ? await createImage(nameplateImage)
101
+ : null;
102
+
99
103
  const serviceId = 'service_zfsxshi';
100
104
  setIsInquiryModalOpen(false);
101
105
  const templateId = settings.support?.emailTemplateId;
102
106
  if (templateId) {
103
- const body = !specifications?.is_nameplate ? {
104
- email_id: email.trim(),
105
- information_text: information ? information : '<not specified>',
106
- request_image: croppedImage?.toDataURL(),
107
- prefilter_values: preFilterValues?.length
108
- ? preFilterValues.join(', ')
109
- : '<not specified>',
110
- } : {
111
- email_id: email.trim(),
112
- information_text: information,
113
- request_image: croppedImage?.toDataURL() || '',
114
- typeplate_image: nameplateImageCanvas?.toDataURL() || '',
115
- prefilter_values: specifications.prefilter_value,
116
- };
107
+ const body = !specifications?.is_nameplate
108
+ ? {
109
+ email_id: email.trim(),
110
+ information_text: information ? information : '<not specified>',
111
+ request_image: croppedImage?.toDataURL(),
112
+ prefilter_values: preFilterValues?.length
113
+ ? preFilterValues.join(', ')
114
+ : '<not specified>',
115
+ }
116
+ : {
117
+ email_id: email.trim(),
118
+ information_text: information,
119
+ request_image: croppedImage?.toDataURL() || '',
120
+ typeplate_image: nameplateImageCanvas?.toDataURL() || '',
121
+ prefilter_values: specifications.prefilter_value,
122
+ };
117
123
  try {
118
124
  await emailjs.send(serviceId, templateId, body);
119
125
  ToastHelper.success(t('Request sent successfully'));
120
126
  } catch (error) {
121
127
  toast(
122
- t => {
128
+ () => {
123
129
  return (
124
130
  <div
125
131
  style={{
@@ -174,7 +180,7 @@ export default function InquiryModal({
174
180
  return (
175
181
  <Dialog
176
182
  open={isInquiryModalOpen}
177
- onOpenChange={(e: any) => {
183
+ onOpenChange={() => {
178
184
  setIsInquiryModalOpen(false);
179
185
  }}
180
186
  >
@@ -4,7 +4,6 @@ import { twMerge } from 'tailwind-merge';
4
4
  import useRequestStore from '../stores/request/requestStore';
5
5
  import useResultStore from '../stores/result/resultStore';
6
6
  import { Icon } from '@nyris/nyris-react-components';
7
- import { useMediaQuery } from 'react-responsive';
8
7
 
9
8
  const ItemSpecification = ({
10
9
  attr,
@@ -16,7 +15,6 @@ const ItemSpecification = ({
16
15
  return ref.header.toLocaleLowerCase() === attr.toLocaleLowerCase();
17
16
  });
18
17
  const attribute = refinement?.length ? refinement[0].attribute : 'none';
19
- const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
20
18
  const { refine } = useRefinementList({
21
19
  attribute,
22
20
  operator: 'or',
@@ -24,140 +22,74 @@ const ItemSpecification = ({
24
22
  limit: 1,
25
23
  });
26
24
 
27
- return isMobile ? (
28
- <>
25
+ return (
26
+ <Tooltip
27
+ content={
28
+ specificationFilter[attr]
29
+ ? 'Filter applied. Clear to choose a different value.'
30
+ : 'Click to apply as a search filter.'
31
+ }
32
+ delayDuration={1000}
33
+ disabled={!value}
34
+ >
29
35
  <div
30
- className="inline-flex flex-col justify-center items-start "
31
- key={attr}
36
+ className={twMerge(
37
+ `px-3.5 py-2 bg-[#E7E8F1] rounded-lg flex justify-center items-center gap-1.5`,
38
+ 'border border-solid border-transparent hover:border-[#E7E8F1]',
39
+ 'cursor-pointer',
40
+ 'w-fit',
41
+ specificationFilter[attr]
42
+ ? ' bg-[#545987] '
43
+ : 'hover:shadow-[0_0_6px_0_#DDDEE7]',
44
+ )}
45
+ onClick={() => {
46
+ if (!value) {
47
+ return;
48
+ }
49
+ if (attribute !== 'none') {
50
+ refine(value);
51
+ } else {
52
+ const setSpecificationFilter =
53
+ useRequestStore.getState().setSpecificationFilter;
54
+
55
+ const setSpecificationFilteredProducts =
56
+ useResultStore.getState().setSpecificationFilteredProducts;
57
+
58
+ if (specificationFilter[attr]) {
59
+ setSpecificationFilter({});
60
+ setSpecificationFilteredProducts([]);
61
+ // setProducts(results);
62
+ } else {
63
+ setSpecificationFilter({
64
+ [attr]: value,
65
+ });
66
+ }
67
+ }
68
+ }}
32
69
  >
33
- <div className="pl-1 inline-flex justify-center items-center gap-2.5">
34
- <div className="justify-start text-[#3B3E5F] text-sm font-semibold">
35
- {attr}
36
- </div>
37
- </div>
38
70
  <div
39
71
  className={twMerge(
40
- `p-3 bg-[#e4e3ff] rounded-lg inline-flex justify-center items-center gap-1.5`,
41
- 'text-[#3e36dc]',
72
+ 'justify-start text-[#767A9F] text-sm leading-none px-0.5',
73
+ 'font-normal',
42
74
  specificationFilter[attr]
43
- ? 'border-[#3E36DC] bg-[#3E36DC] text-white'
44
- : '',
75
+ ? 'text-white hover:px-0.5'
76
+ : 'hover:font-semibold',
77
+ 'leading-4',
78
+ 'flex gap-2 items-center',
45
79
  )}
46
- onClick={() => {
47
- if (!value) {
48
- return;
49
- }
50
- if (attribute !== 'none') {
51
- refine(value);
52
- } else {
53
- const setSpecificationFilter =
54
- useRequestStore.getState().setSpecificationFilter;
55
-
56
- const setSpecificationFilteredProducts =
57
- useResultStore.getState().setSpecificationFilteredProducts;
58
-
59
- if (specificationFilter[attr]) {
60
- setSpecificationFilter({});
61
- setSpecificationFilteredProducts([]);
62
- // setProducts(results);
63
- } else {
64
- setSpecificationFilter({
65
- [attr]: value,
66
- });
67
- }
68
- }
69
- }}
70
80
  >
71
- <div className="justify-start text-sm font-medium leading-none flex gap-2">
72
- {imageAnalysis?.specification[attr] || 'N/A'}
73
- <div>
74
- <Icon
75
- name="close"
76
- className={twMerge(
77
- 'w-3 h-3 text-white',
78
- specificationFilter[attr] ? 'block' : 'hidden',
79
- )}
80
- />
81
- </div>
82
- </div>
83
- </div>
84
- </div>
85
- </>
86
- ) : (
87
- <div key={attr} className="flex justify-between w-full gap-2 items-center">
88
- <div className="self-stretch inline-flex justify-start items-center gap-1.5">
89
- <div className="justify-start text-[#3B3E5F] text-xs font-semibold">
90
- {attr}:
91
- </div>
92
- <Tooltip
93
- content={
94
- specificationFilter[attr]
95
- ? 'Filter applied. Clear to choose a different value.'
96
- : 'Click to apply as a search filter.'
97
- }
98
- delayDuration={1000}
99
- disabled={!value}
100
- >
101
- <div
81
+ {imageAnalysis?.specification[attr] || 'N/A'}
82
+
83
+ <Icon
84
+ name="close"
102
85
  className={twMerge(
103
- `px-1 py-1 bg-[#e4e3ff] rounded-[1px] flex justify-center items-center gap-1.5`,
104
- 'border border-solid border-transparent hover:border-[#3E36DC]',
105
- 'cursor-pointer',
106
- specificationFilter[attr] ? 'border-[#3E36DC] bg-[#3E36DC] ' : '',
86
+ 'w-[10px] h-[10px] text-white',
87
+ specificationFilter[attr] ? 'block' : 'hidden',
107
88
  )}
108
- onClick={() => {
109
- if (!value) {
110
- return;
111
- }
112
- if (attribute !== 'none') {
113
- refine(value);
114
- } else {
115
- const setSpecificationFilter =
116
- useRequestStore.getState().setSpecificationFilter;
117
-
118
- const setSpecificationFilteredProducts =
119
- useResultStore.getState().setSpecificationFilteredProducts;
120
-
121
- if (specificationFilter[attr]) {
122
- setSpecificationFilter({});
123
- setSpecificationFilteredProducts([]);
124
- // setProducts(results);
125
- } else {
126
- setSpecificationFilter({
127
- [attr]: value,
128
- });
129
- }
130
- }
131
- }}
132
- >
133
- <div
134
- className={twMerge(
135
- 'justify-start text-[#3e36dc] text-[10px] leading-none px-0.5',
136
- 'font-normal hover:font-bold hover:px-0',
137
- specificationFilter[attr]
138
- ? 'font-bold text-white hover:px-0.5'
139
- : '',
140
- 'max-line-1',
141
- )}
142
- >
143
- {imageAnalysis?.specification[attr] || 'N/A'}
144
- </div>
145
- </div>
146
- </Tooltip>
147
- </div>
148
- <div
149
- onClick={() => {
150
- navigator.clipboard.writeText(
151
- imageAnalysis?.specification[attr] || '',
152
- );
153
- }}
154
- >
155
- <Icon
156
- name="copy"
157
- className="text-[#AAABB5] w-[12px] h-[12px] hover:text-[#3E36DC] cursor-pointer"
158
- />
89
+ />
90
+ </div>
159
91
  </div>
160
- </div>
92
+ </Tooltip>
161
93
  );
162
94
  };
163
95
 
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { createPortal } from 'react-dom';
4
4
 
@@ -10,49 +10,49 @@ const LocationInfoPopup = () => {
10
10
  const shown = sessionStorage.getItem('locationNoticeShown');
11
11
  if (shown) return;
12
12
 
13
- navigator.permissions
14
- .query({ name: 'geolocation' })
15
- .then((result) => {
16
- if (result.state === 'prompt') {
17
- setShowPopup(true);
18
- } else if (result.state === 'granted') {
19
- navigator.geolocation.getCurrentPosition(console.log, console.error);
20
- sessionStorage.setItem('locationNoticeShown', 'true');
21
- } else {
22
- sessionStorage.setItem('locationNoticeShown', 'true');
23
- }
24
- });
13
+ navigator.permissions.query({ name: 'geolocation' }).then(result => {
14
+ if (result.state === 'prompt') {
15
+ setShowPopup(true);
16
+ } else if (result.state === 'granted') {
17
+ navigator.geolocation.getCurrentPosition(console.log, console.error);
18
+ sessionStorage.setItem('locationNoticeShown', 'true');
19
+ } else {
20
+ sessionStorage.setItem('locationNoticeShown', 'true');
21
+ }
22
+ });
25
23
  }, []);
26
24
 
27
25
  const closePopup = () => {
28
26
  navigator.geolocation.getCurrentPosition(console.log, console.error);
29
27
  sessionStorage.setItem('locationNoticeShown', 'true');
30
28
  setShowPopup(false);
31
- }
32
-
29
+ };
30
+
33
31
  return (
34
32
  <div>
35
- {showPopup && createPortal(
36
- <div
37
- className="custom-modal"
38
- onClick={closePopup}
39
- >
40
- <div
41
- className="custom-modal-body geolocation"
42
- onClick={(e) => {
33
+ {showPopup &&
34
+ createPortal(
35
+ <div className="custom-modal" onClick={closePopup}>
36
+ <div
37
+ className="custom-modal-body geolocation"
38
+ onClick={e => {
43
39
  e.preventDefault();
44
40
  e.stopPropagation();
45
- }}
46
- >
47
- <div className="geolocation-title">{t('Please enable location services when prompted.')}</div>
41
+ }}
42
+ >
43
+ <div className="geolocation-title">
44
+ {t('Please enable location services when prompted.')}
45
+ </div>
48
46
  <div>{window.settings.geoLocationMessage}</div>
49
- <button type="button" onClick={closePopup}>{t('I understand')}</button>
50
- </div>
51
- </div>,
52
- document.body
53
- )}
47
+ <button type="button" onClick={closePopup}>
48
+ {t('I understand')}
49
+ </button>
50
+ </div>
51
+ </div>,
52
+ document.body,
53
+ )}
54
54
  </div>
55
- )
56
- }
55
+ );
56
+ };
57
57
 
58
58
  export default LocationInfoPopup;