@nyris/nyris-webapp 0.3.44 → 0.3.46

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 (39) hide show
  1. package/build/asset-manifest.json +14 -12
  2. package/build/index.html +1 -1
  3. package/build/{precache-manifest.c92406fe2e3b0feaf429c551125e2d95.js → precache-manifest.003c83b03ba38cefb9af2060ababe0b4.js} +18 -10
  4. package/build/service-worker.js +1 -1
  5. package/build/static/css/main.5b89f23f.chunk.css +2 -0
  6. package/build/static/css/main.5b89f23f.chunk.css.map +1 -0
  7. package/build/static/js/2.f3840c8e.chunk.js +3 -0
  8. package/build/static/js/2.f3840c8e.chunk.js.map +1 -0
  9. package/build/static/js/main.d68884f6.chunk.js +3 -0
  10. package/build/static/js/main.d68884f6.chunk.js.map +1 -0
  11. package/build/static/media/call.c3c23966.svg +3 -0
  12. package/build/static/media/icon_email.71b21005.svg +3 -0
  13. package/package.json +3 -3
  14. package/src/Store/constants.ts +0 -1
  15. package/src/common/assets/icons/call.svg +3 -0
  16. package/src/common/assets/icons/icon_email.svg +2 -2
  17. package/src/components/CadenasWebViewer.tsx +2 -2
  18. package/src/components/Feedback.tsx +36 -0
  19. package/src/components/Header.tsx +3 -4
  20. package/src/components/Inquiry/InquiryBanner.tsx +98 -33
  21. package/src/components/Inquiry/InquiryModal.tsx +7 -10
  22. package/src/components/Layout.tsx +5 -0
  23. package/src/components/ProductDetailView.tsx +32 -11
  24. package/src/components/common.scss +134 -0
  25. package/src/components/results/ItemResult.tsx +80 -15
  26. package/src/components/rfq/RfqModal.tsx +7 -5
  27. package/src/index.css +1 -1
  28. package/src/page/landingPage/common.scss +3 -4
  29. package/src/page/result/index.tsx +60 -3
  30. package/src/services/Feedback.ts +4 -13
  31. package/src/types.ts +22 -6
  32. package/build/static/css/main.1b40c5ff.chunk.css +0 -2
  33. package/build/static/css/main.1b40c5ff.chunk.css.map +0 -1
  34. package/build/static/js/2.82ef1cd4.chunk.js +0 -3
  35. package/build/static/js/2.82ef1cd4.chunk.js.map +0 -1
  36. package/build/static/js/main.7cdac2fb.chunk.js +0 -3
  37. package/build/static/js/main.7cdac2fb.chunk.js.map +0 -1
  38. /package/build/static/js/{2.82ef1cd4.chunk.js.LICENSE.txt → 2.f3840c8e.chunk.js.LICENSE.txt} +0 -0
  39. /package/build/static/js/{main.7cdac2fb.chunk.js.LICENSE.txt → main.d68884f6.chunk.js.LICENSE.txt} +0 -0
@@ -116,7 +116,7 @@ function ItemResult(props: Props) {
116
116
  dataItem,
117
117
  settings.field?.ctaLinkField ? settings.field?.ctaLinkField : 'links.main',
118
118
  );
119
-
119
+ const manufacturerNumber = get(dataItem, settings.field.manufacturerNumber);
120
120
  return (
121
121
  <Box className="wrap-main-item-result">
122
122
  <DefaultModal
@@ -174,7 +174,7 @@ function ItemResult(props: Props) {
174
174
  <IconSearchImage width={16} height={16} color={'#AAABB5'} />
175
175
  </Box>
176
176
  )}
177
- {settings.cadenas3dWebView && (
177
+ {settings.cadenas?.cadenas3dWebView && (
178
178
  <Box
179
179
  className="box-icon-modal-3d"
180
180
  onClick={() => {
@@ -237,11 +237,22 @@ function ItemResult(props: Props) {
237
237
  style={{ color: '#2B2C46' }}
238
238
  gridGap={8}
239
239
  >
240
+ {settings.CTAButtonText && (
241
+ <Typography
242
+ className="text-f12 max-line-1 fw-700"
243
+ style={{
244
+ color: '#2B2C46',
245
+ marginTop: 8,
246
+ }}
247
+ >
248
+ {truncateString(dataItem[settings.field.productName], 45)}
249
+ </Typography>
250
+ )}
240
251
  <Box
241
252
  display="flex"
242
253
  justifyContent={'space-between'}
243
254
  flexDirection={'row'}
244
- style={{ color: '#2B2C46', marginTop: 12 }}
255
+ style={{ color: '#2B2C46', marginTop: 8 }}
245
256
  gridGap={8}
246
257
  >
247
258
  <Tooltip
@@ -299,10 +310,10 @@ function ItemResult(props: Props) {
299
310
  />
300
311
  )}
301
312
 
302
- {dataItem[settings.field.manufacturerNumber] && (
313
+ {manufacturerNumber && (
303
314
  <ProductAttribute
304
315
  title={t('Mfr. No.')}
305
- value={dataItem[settings.field.manufacturerNumber]}
316
+ value={manufacturerNumber}
306
317
  padding="4px 8px"
307
318
  width={{ xs: '49%' }}
308
319
  />
@@ -339,14 +350,68 @@ function ItemResult(props: Props) {
339
350
  </Box>
340
351
  )}
341
352
  <div>
342
- <Tooltip
343
- title={dataItem[settings.field.productName]}
344
- placement="top"
345
- arrow={true}
346
- disableHoverListener={
347
- dataItem[settings.field.productName]?.length < 45
348
- }
349
- >
353
+ {!settings.CTAButtonText ? (
354
+ <Tooltip
355
+ title={dataItem[settings.field.productName]}
356
+ placement="top"
357
+ arrow={true}
358
+ disableHoverListener={
359
+ dataItem[settings.field.productName]?.length < 45
360
+ }
361
+ >
362
+ <Box
363
+ style={{
364
+ boxShadow: '-2px 2px 4px rgba(170, 171, 181, 0.5)',
365
+ // marginBottom: 22,
366
+ height: 40,
367
+ background: settings.theme?.primaryColor,
368
+ borderRadius: 4,
369
+ padding: '0px 8px',
370
+ marginTop: '8px',
371
+ }}
372
+ display={'flex'}
373
+ justifyItems={'center'}
374
+ alignItems={'center'}
375
+ justifyContent={'space-between'}
376
+ >
377
+ <Box
378
+ style={{
379
+ display: 'flex',
380
+ justifyContent: 'space-between',
381
+ width: '100%',
382
+ padding: 0,
383
+ cursor: ctaLink ? 'pointer' : 'normal',
384
+ }}
385
+ onClick={() => {
386
+ if (ctaLink) {
387
+ feedbackConversionEpic(state, indexItem, dataItem.sku);
388
+ window.open(`${ctaLink}`, '_blank');
389
+ }
390
+ }}
391
+ >
392
+ <Typography
393
+ className="text-white max-line-2"
394
+ style={{
395
+ overflow: 'hidden',
396
+ textOverflow: 'ellipsis',
397
+ fontWeight: 500,
398
+ fontSize: '12px',
399
+ letterSpacing: '0.27px',
400
+ wordBreak: 'break-all',
401
+ maxWidth: !isMobile && ctaLink ? '136px' : '164x',
402
+ paddingRight: '8px',
403
+ }}
404
+ align="left"
405
+ >
406
+ {truncateString(dataItem[settings.field.productName], 45)}
407
+ </Typography>
408
+ {!isMobile && ctaLink && (
409
+ <img src={IconOpenLink} alt="more-info" width={16} />
410
+ )}
411
+ </Box>
412
+ </Box>
413
+ </Tooltip>
414
+ ) : (
350
415
  <Box
351
416
  style={{
352
417
  boxShadow: '-2px 2px 4px rgba(170, 171, 181, 0.5)',
@@ -391,14 +456,14 @@ function ItemResult(props: Props) {
391
456
  }}
392
457
  align="left"
393
458
  >
394
- {truncateString(dataItem[settings.field.productName], 45)}
459
+ {settings.CTAButtonText}
395
460
  </Typography>
396
461
  {!isMobile && ctaLink && (
397
462
  <img src={IconOpenLink} alt="more-info" width={16} />
398
463
  )}
399
464
  </Box>
400
465
  </Box>
401
- </Tooltip>
466
+ )}
402
467
 
403
468
  {settings.showFeedbackAndShare && (
404
469
  <Box
@@ -65,10 +65,12 @@ export default function RfqModal({
65
65
  const croppedImage = getCroppedCanvas(canvas, selectedRegion);
66
66
  const serviceId = 'service_zfsxshi';
67
67
  setIsRfqModalOpen(false);
68
- if (settings.templateId) {
68
+ const templateId = settings.rfq?.emailTemplateId;
69
+
70
+ if (templateId) {
69
71
  try {
70
72
  setRfqStatus('loading');
71
- await emailjs.send(serviceId, settings.templateId, {
73
+ await emailjs.send(serviceId, templateId, {
72
74
  email_id: email.trim(),
73
75
  information_text: information,
74
76
  request_image: croppedImage?.toDataURL(),
@@ -89,7 +91,7 @@ export default function RfqModal({
89
91
  width: '294px',
90
92
  }}
91
93
  >
92
- <span style={{fontWeight: 'bold'}}>Email not sent</span>
94
+ <span style={{ fontWeight: 'bold' }}>Email not sent</span>
93
95
  <span>{getErrorMessage(error)}</span>
94
96
  <a
95
97
  href={`mailto:support@nyris.io?subject=Request for quotation&body=${information}`}
@@ -116,8 +118,8 @@ export default function RfqModal({
116
118
  maxWidth: '400px',
117
119
  },
118
120
  icon: (
119
- <div style={{minWidth: '20px', minHeight: '20px'}}>
120
- <ErrorIcon/>
121
+ <div style={{ minWidth: '20px', minHeight: '20px' }}>
122
+ <ErrorIcon />
121
123
  </div>
122
124
  ),
123
125
  },
package/src/index.css CHANGED
@@ -427,7 +427,7 @@ strong {
427
427
  }
428
428
 
429
429
  body {
430
- background: #e7eaee;
430
+ background: #fafafa;
431
431
  }
432
432
 
433
433
  h1,
@@ -21,9 +21,7 @@
21
21
  }
22
22
  a {
23
23
  text-decoration: none !important;
24
- &:hover {
25
- color: #3e36dc !important;
26
- }
24
+
27
25
  }
28
26
  .text-gray2 {
29
27
  color: #55566b !important;
@@ -599,7 +597,7 @@ button {
599
597
  background-color: #e9e9ec;
600
598
  padding-left: 8px;
601
599
  padding-right: 8px;
602
- padding-bottom: 8px;
600
+ padding-bottom: 12px;
603
601
  min-height: 82px;
604
602
  justify-content: space-between;
605
603
  .box-top {
@@ -1082,6 +1080,7 @@ button {
1082
1080
  border-left: 1px solid #e9e9ec;
1083
1081
  }
1084
1082
  .box-change-hit-items {
1083
+ z-index: 500;
1085
1084
  font-family: 'Source Sans 3';
1086
1085
  font-style: normal;
1087
1086
  font-weight: 500;
@@ -49,6 +49,7 @@ import RfqBanner from 'components/rfq/RfqBanner';
49
49
  import InquiryBanner from 'components/Inquiry/InquiryBanner';
50
50
  import { useQuery } from 'hooks/useQuery';
51
51
  import { ReactComponent as PoweredByNyrisImage } from 'common/assets/images/powered_by_nyris.svg';
52
+ import Feedback from 'components/Feedback';
52
53
 
53
54
  interface Props {
54
55
  allSearchResults: any;
@@ -89,6 +90,11 @@ function ResultComponent(props: Props) {
89
90
  'not-scrolled' | 'scrolled' | 'user-scrolled'
90
91
  >('not-scrolled');
91
92
 
93
+ const [showFeedback, setShowFeedback] = useState<
94
+ 'not-scrolled' | 'scrolled' | 'user-scrolled'
95
+ >('not-scrolled');
96
+
97
+ const [showFeedbackSuccess, setShowFeedbackSuccess] = useState(false);
92
98
  const query = useQuery();
93
99
  const searchQuery = query.get('query') || search.valueTextSearch.query;
94
100
  const isAlgoliaEnabled = settings.algolia?.enabled;
@@ -118,12 +124,14 @@ function ResultComponent(props: Props) {
118
124
  setImageSelection(selectedRegion);
119
125
  setRfqStatus('inactive');
120
126
  setIsScrolled('not-scrolled');
127
+ setShowFeedback('not-scrolled');
121
128
  }
122
129
  }, [selectedRegion]);
123
130
 
124
131
  useEffect(() => {
125
132
  if (requestImage) {
126
133
  setIsScrolled('not-scrolled');
134
+ setShowFeedback('not-scrolled');
127
135
  executeScroll();
128
136
  setImageSelection(DEFAULT_REGION);
129
137
  }
@@ -330,6 +338,35 @@ function ResultComponent(props: Props) {
330
338
  };
331
339
  }, [requestImage]);
332
340
 
341
+ useEffect(() => {
342
+ if (!requestImage || !settings.showFeedback) return;
343
+
344
+ setTimeout(() => {
345
+ setShowFeedback(s => (s === 'not-scrolled' ? 'scrolled' : s));
346
+ }, 5000);
347
+
348
+ const handleScroll = () => {
349
+ setTimeout(() => {
350
+ setShowFeedback(s => (s === 'not-scrolled' ? 'scrolled' : s));
351
+ }, 100);
352
+ };
353
+
354
+ window.addEventListener('scroll', handleScroll, { capture: true });
355
+
356
+ return () => {
357
+ window.removeEventListener('scroll', handleScroll);
358
+ };
359
+ }, [requestImage, selectedRegion, settings.showFeedback]);
360
+
361
+ const submitFeedback = async (data: boolean) => {
362
+ setShowFeedbackSuccess(true);
363
+ setTimeout(() => {
364
+ setShowFeedbackSuccess(false);
365
+ }, 3000);
366
+ setShowFeedback('user-scrolled');
367
+ feedbackSuccessEpic(stateGlobal, data);
368
+ };
369
+
333
370
  return (
334
371
  <>
335
372
  <div
@@ -428,6 +465,23 @@ function ResultComponent(props: Props) {
428
465
  className={'box-item-result ml-auto mr-auto'}
429
466
  style={{ height: '100%', paddingLeft: isMobile ? 0 : 16 }}
430
467
  >
468
+ {showFeedbackSuccess && (
469
+ <div className={'box-item-result feedback-floating'}>
470
+ <div className="feedback-success">
471
+ Thanks for your feedback!
472
+ </div>
473
+ </div>
474
+ )}
475
+ {showFeedback === 'scrolled' && !showFeedbackSuccess && (
476
+ <div className={'box-item-result feedback-floating'}>
477
+ <Feedback
478
+ submitFeedback={submitFeedback}
479
+ onFeedbackClose={() => {
480
+ setShowFeedback('user-scrolled');
481
+ }}
482
+ />
483
+ </div>
484
+ )}
431
485
  <ProductList
432
486
  getUrlToCanvasFile={getUrlToCanvasFile}
433
487
  setLoading={false}
@@ -466,7 +520,8 @@ function ResultComponent(props: Props) {
466
520
  {requestImage &&
467
521
  !loadingSearchAlgolia &&
468
522
  !props.isSearchStalled &&
469
- settings.rfq && (
523
+ settings.rfq &&
524
+ settings.rfq.enabled && (
470
525
  <RfqBanner
471
526
  rfqRef={rfqRef}
472
527
  rfqStatus={rfqStatus}
@@ -477,7 +532,8 @@ function ResultComponent(props: Props) {
477
532
  )}
478
533
  {!loadingSearchAlgolia &&
479
534
  !props.isSearchStalled &&
480
- settings.inquiry &&
535
+ settings.support &&
536
+ settings.support.enabled &&
481
537
  (searchQuery || requestImage) && (
482
538
  <InquiryBanner
483
539
  requestImage={requestImage}
@@ -537,7 +593,8 @@ function ResultComponent(props: Props) {
537
593
  requestImage &&
538
594
  isMobile &&
539
595
  props.allSearchResults.hits.length > 0 &&
540
- settings.rfq && (
596
+ settings.rfq &&
597
+ settings.rfq.enabled && (
541
598
  <div
542
599
  style={{
543
600
  fontSize: '14px',
@@ -4,8 +4,6 @@ import NyrisAPI, {
4
4
  RectCoords,
5
5
  } from '@nyris/nyris-api';
6
6
  import { RootState } from '../Store/Store';
7
- import { ToastHelper } from '../helpers/ToastHelper';
8
- import { toast } from 'react-hot-toast';
9
7
 
10
8
  export const feedbackSuccessEpic = async (
11
9
  state: RootState,
@@ -15,17 +13,10 @@ export const feedbackSuccessEpic = async (
15
13
  const sessionId = search.sessionId;
16
14
  const requestId = search.requestId || search.sessionId;
17
15
 
18
- try {
19
- const res = await sendFeedbackByApi(settings, sessionId, requestId, {
20
- event: 'feedback',
21
- data: { success },
22
- });
23
- toast.dismiss();
24
- ToastHelper.success('Thank you for your feedback.');
25
- return res;
26
- } catch (err: any) {
27
- console.log(err);
28
- }
16
+ return await sendFeedbackByApi(settings, sessionId, requestId, {
17
+ event: 'feedback',
18
+ data: { success },
19
+ });
29
20
  };
30
21
 
31
22
  export const feedbackClickEpic = async (
package/src/types.ts CHANGED
@@ -15,6 +15,23 @@ export interface Auth0Settings {
15
15
  supportEmail?: string;
16
16
  }
17
17
 
18
+ export interface Support {
19
+ enabled?: boolean;
20
+ description?: string;
21
+ emailInquiry?: boolean;
22
+ supportNumber?: string;
23
+ emailTemplateId?: string;
24
+ }
25
+
26
+ export interface Rfq {
27
+ enabled?: boolean;
28
+ emailTemplateId?: string;
29
+ }
30
+ export interface Cadenas {
31
+ cadenas3dWebView?: boolean;
32
+ cadenasAPIKey?: string;
33
+ catalog?: string;
34
+ }
18
35
  export interface Field {
19
36
  ctaLinkField: string;
20
37
  productName: string;
@@ -35,14 +52,11 @@ export interface AppSettings extends NyrisAPISettings {
35
52
  appTitle?: string;
36
53
  auth0: Auth0Settings;
37
54
  brandName?: string;
38
- cadenas3dWebView?: boolean;
39
- cadenasAPIKey?: string;
55
+ cadenas?: Cadenas;
40
56
  cadSearch?: boolean;
41
- catalog?: string;
42
57
  exampleImages?: string[]; // deprecated
43
58
  field: Field;
44
59
  headerText?: string;
45
- inquiry?: boolean;
46
60
  instantRedirectPatterns: string[];
47
61
  itemIdLabel?: string;
48
62
  language?: string;
@@ -54,16 +68,18 @@ export interface AppSettings extends NyrisAPISettings {
54
68
  productCtaText?: string;
55
69
  refinements?: any;
56
70
  regions: boolean;
57
- rfq?: boolean;
71
+ rfq?: Rfq;
58
72
  shareOption?: boolean;
73
+ showFeedback?: boolean;
59
74
  showFeedbackAndShare?: boolean;
60
75
  showGroup?: boolean;
61
76
  showMoreInfo?: boolean; // deprecated
62
77
  showPoweredByNyris?: boolean;
63
- templateId?: string;
78
+ support?: Support;
64
79
  theme: SearchSuiteSettings;
65
80
  visualSearchFilterKey?: string;
66
81
  warehouseVariant?: boolean;
82
+ CTAButtonText?: string;
67
83
  }
68
84
 
69
85
  export interface SearchSuiteSettings {