@nyris/nyris-webapp 0.3.69 → 0.3.70

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/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@nyris/nyris-webapp",
3
- "version": "0.3.69",
3
+ "version": "0.3.70",
4
4
  "dependencies": {
5
5
  "@auth0/auth0-react": "^2.2.4",
6
6
  "@emailjs/browser": "^4.3.3",
7
7
  "@material-ui/core": "^4.12.4",
8
8
  "@material-ui/icons": "^4.11.3",
9
9
  "@material-ui/lab": "^4.0.0-alpha.61",
10
- "@nyris/nyris-api": "^0.3.69",
11
- "@nyris/nyris-react-components": "^0.3.69",
10
+ "@nyris/nyris-api": "^0.3.70",
11
+ "@nyris/nyris-react-components": "^0.3.70",
12
12
  "@reduxjs/toolkit": "^2.2.1",
13
13
  "@splidejs/react-splide": "^0.7.12",
14
14
  "@testing-library/jest-dom": "^5.17.0",
15
15
  "@testing-library/react": "^13.4.0",
16
16
  "@testing-library/user-event": "^13.5.0",
17
+ "@types/heic-convert": "^2.1.0",
17
18
  "@types/jest": "^27.5.2",
18
19
  "@types/node": "^16.18.88",
19
20
  "@types/react": "^18.2.65",
@@ -23,7 +24,9 @@
23
24
  "blueimp-load-image": "^5.16.0",
24
25
  "classnames": "^2.5.1",
25
26
  "compressorjs": "^1.2.1",
27
+ "env": "^0.0.2",
26
28
  "framer-motion": "^11.0.12",
29
+ "heic-convert": "^2.1.0",
27
30
  "i18next": "^23.10.1",
28
31
  "jotai": "^1.4.7",
29
32
  "jquery": "^3.7.1",
@@ -71,6 +71,13 @@ var settings = {
71
71
  CTALinkField: '',
72
72
  },
73
73
  language: 'en',
74
+ // productDetailsAttribute
75
+ productDetailsAttribute: [
76
+ {
77
+ propertyName: '',
78
+ value: '',
79
+ }
80
+ ],
74
81
  // features
75
82
  showPoweredByNyris: '',
76
83
  postFilterOption: '',
@@ -95,9 +95,7 @@ function DragDropFile(props: Props) {
95
95
  className="inputFile"
96
96
  placeholder="Choose photo"
97
97
  style={{ display: 'block', cursor: 'pointer' }}
98
- accept={`${
99
- isCadSearch ? '.stp,.step,.stl,.obj,.glb,.gltf,' : ''
100
- }image/*`}
98
+ accept={'.stp,.step,.stl,.obj,.glb,.gltf,.heic,.heif,image/*'}
101
99
  />
102
100
  </div>
103
101
  </div>
@@ -1,7 +1,6 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
2
- import { Button, Collapse, Grid, Typography, Tooltip } from '@material-ui/core';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { Button, Grid, Typography, Tooltip } from '@material-ui/core';
3
3
  import CloseOutlinedIcon from '@material-ui/icons/CloseOutlined';
4
- import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
5
4
  import { Icon } from '@nyris/nyris-react-components';
6
5
  import NoImage from '../common/assets/images/no-image.svg';
7
6
  import { useMediaQuery } from 'react-responsive';
@@ -9,7 +8,6 @@ import { ImagePreviewCarousel } from './carousel/ImagePreviewCarousel';
9
8
  import { AppState } from 'types';
10
9
  import { useAppSelector } from 'Store/Store';
11
10
  import { prepareImageList } from '../helpers/CommonHelper';
12
- import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
13
11
  import { useTranslation } from 'react-i18next';
14
12
  import ProductAttribute from './ProductAttribute';
15
13
  import CadenasWebViewer from './CadenasWebViewer';
@@ -56,6 +54,9 @@ function ProductDetailView(props: Props) {
56
54
  >();
57
55
  const { t } = useTranslation();
58
56
  const classes = useStyles(props?.show3dView);
57
+ const modal = useRef<any>(null);
58
+ const extraDetailPropertyLength = isMobile ? 15 : 30;
59
+ const extraDetailValueLength = isMobile ? 35 : 60;
59
60
 
60
61
  useEffect(() => {
61
62
  if (dataItem) {
@@ -92,17 +93,10 @@ function ProductDetailView(props: Props) {
92
93
 
93
94
  setDataImageCarouSel(valueKey);
94
95
  };
95
- const productDetails = useMemo(() => {
96
- const details = get(dataItem, settings.productDetails);
97
- try {
98
- return details.join(', ');
99
- } catch (e) {
100
- return details;
101
- }
102
- }, [dataItem, settings.productDetails]);
103
96
 
104
97
  return (
105
98
  <div
99
+ ref={modal}
106
100
  className="box-modal-default"
107
101
  style={{
108
102
  margin: isMobile ? 0 : '',
@@ -591,8 +585,8 @@ function ProductDetailView(props: Props) {
591
585
  </div>
592
586
  )}
593
587
  </div>
594
-
595
- {productDetails && (
588
+
589
+ {settings.productDetailsAttribute?.length ? (
596
590
  <div className="w-100">
597
591
  <Button
598
592
  className="w-100 button-hover"
@@ -607,34 +601,98 @@ function ProductDetailView(props: Props) {
607
601
  paddingRight: '15px',
608
602
  textTransform: 'initial',
609
603
  }}
610
- onClick={() => setCollapseDescription(e => !e)}
604
+ onClick={(e) => {
605
+ setCollapseDescription(prev => !prev);
606
+ if (modal && modal.current) {
607
+ setTimeout(() => {
608
+ const top = (settings.productDetailsAttribute?.length || 0) * 30 + 20;
609
+ modal.current.parentElement.scrollTo({ top });
610
+ });
611
+ }
612
+ }}
611
613
  >
612
614
  {t('View details')}
613
- {collapseDescription ? (
614
- <KeyboardArrowUpIcon
615
- htmlColor={settings.theme?.secondaryColor}
616
- />
617
- ) : (
618
- <KeyboardArrowDownIcon
619
- htmlColor={settings.theme?.secondaryColor}
620
- />
621
- )}
615
+ <span
616
+ style={{
617
+ fontSize: 20,
618
+ }}
619
+ >
620
+ {collapseDescription ? '—' : '+'}
621
+ </span>
622
622
  </Button>
623
- <Collapse in={collapseDescription}>
624
- <Typography
623
+ {collapseDescription ? (
624
+ <div
625
625
  style={{
626
- fontSize: 14,
627
- padding: 5,
628
- paddingLeft: 15,
629
- paddingRight: 15,
630
- color: '#2b2c46',
626
+ background: '#E9E9EC',
627
+ borderRadius: 2,
628
+ display: 'flex',
629
+ flexDirection: 'column',
630
+ gap: 6,
631
+ padding: '6px 15px 10px',
631
632
  }}
632
633
  >
633
- {productDetails}
634
- </Typography>
635
- </Collapse>
634
+ {settings.productDetailsAttribute.map((detail) =>
635
+ get(dataItem, detail.value)?.length
636
+ ? (
637
+ <div
638
+ style={{
639
+ height: 14,
640
+ display: 'flex',
641
+ flexDirection: 'row',
642
+ alignItems: 'center'
643
+ }}
644
+ >
645
+ <Tooltip
646
+ title={detail.propertyName}
647
+ placement="top"
648
+ arrow={true}
649
+ disableHoverListener={detail.propertyName.length < extraDetailPropertyLength}
650
+ >
651
+ <span
652
+ style={{
653
+ fontFamily: 'Source Sans 3',
654
+ fontSize: 12,
655
+ fontWeight: 600,
656
+ marginRight: 8,
657
+ height: 14,
658
+ }}
659
+ >
660
+ {detail.propertyName.length < extraDetailPropertyLength
661
+ ? detail.propertyName
662
+ : detail.propertyName.substring(0, extraDetailPropertyLength).concat('...')
663
+ }
664
+ </span>
665
+ </Tooltip>
666
+ <Tooltip
667
+ title={get(dataItem, detail.value)}
668
+ placement="top"
669
+ arrow={true}
670
+ disableHoverListener={get(dataItem, detail.value)?.length <= extraDetailValueLength}
671
+ >
672
+ <Typography
673
+ style={{
674
+ fontFamily: 'Source Sans 3',
675
+ fontSize: 12,
676
+ fontWeight: 400,
677
+ height: 14,
678
+ }}
679
+ >
680
+ {get(dataItem, detail.value).length <= extraDetailValueLength
681
+ ? get(dataItem, detail.value)
682
+ : get(dataItem, detail.value).substring(0, extraDetailValueLength).concat('...')
683
+ }
684
+ </Typography>
685
+ </Tooltip>
686
+ </div>
687
+ )
688
+ : (
689
+ ''
690
+ )
691
+ )}
692
+ </div>
693
+ ) : ('')}
636
694
  </div>
637
- )}
695
+ ) : ('')}
638
696
  </Grid>
639
697
  </Grid>
640
698
  </div>
@@ -13,7 +13,6 @@ function UploadDisclaimer({
13
13
  isMobile: boolean;
14
14
  }) {
15
15
  const [dontShowAgain, setDontShowAgain] = useState(false);
16
- const isCadSearch = window.settings.cadSearch;
17
16
 
18
17
  return (
19
18
  <>
@@ -68,9 +67,9 @@ function UploadDisclaimer({
68
67
  type="file"
69
68
  name="take-picture"
70
69
  id="nyris__upload-photo"
71
- accept={`${
72
- isCadSearch ? '.stp,.step,.stl,.obj,.glb,.gltf,' : ''
73
- }image/jpeg,image/png,image/webp`}
70
+ accept={
71
+ '.stp,.step,.stl,.obj,.glb,.gltf,.heic,.heif,image/jpeg,image/png,image/webp'
72
+ }
74
73
  onChange={makeFileHandler(file =>
75
74
  onContinue({ file, dontShowAgain }),
76
75
  )}
@@ -257,11 +257,9 @@ function CameraCustom(props: Props) {
257
257
  handlerFindImage(file);
258
258
  }
259
259
  }}
260
- accept={`${
261
- isCadSearch
262
- ? '.stp,.step,.stl,.obj,.glb,.gltf,'
263
- : ''
264
- }image/jpeg,image/png,image/webp`}
260
+ accept={
261
+ '.stp,.step,.stl,.obj,.glb,.gltf,.heic,.heif,image/jpeg,image/png,image/webp'
262
+ }
265
263
  onClick={event => {
266
264
  // @ts-ignore
267
265
  event.target.value = '';
@@ -322,8 +322,10 @@ const SearchBox = (props: any) => {
322
322
  <div className="wrap-box-input-mobile d-flex">
323
323
  <input
324
324
  accept={`${
325
- isCadSearch ? '.stp,.step,.stl,.obj,.glb,.gltf,' : ''
326
- }image/*`}
325
+ isCadSearch
326
+ ? '.stp,.step,.stl,.obj,.glb,.gltf,.heic,.heif,image/*'
327
+ : ''
328
+ }`}
327
329
  id="icon-button-file"
328
330
  type="file"
329
331
  style={{ display: 'none' }}
@@ -1,3 +1,5 @@
1
+ // @ts-nocheck
2
+
1
3
  import { RectCoords } from '@nyris/nyris-api';
2
4
  import { isEmpty } from 'lodash';
3
5
  import { useCallback } from 'react';
@@ -61,15 +63,34 @@ export const useImageSearch = () => {
61
63
  let res: any;
62
64
  let compressedBase64;
63
65
 
66
+ let blob = image;
67
+
68
+ if (['.heic', '.heif'].some(ex => image?.name?.endsWith(ex))) {
69
+ const blobTemp = new Blob([image], { type: 'image/heif' });
70
+ const buffer = new Uint8Array(await blobTemp.arrayBuffer());
71
+
72
+ try {
73
+ const convert = await import('heic-convert/browser');
74
+
75
+ let outputBuffer = await convert.default({
76
+ buffer: buffer, // the HEIC file buffer
77
+ format: 'JPEG', // output format
78
+ });
79
+ blob = new Blob([outputBuffer], { type: 'image/jpeg' });
80
+ } catch (error) {
81
+ console.log('HEIC conversion error:', error);
82
+ }
83
+ }
84
+
64
85
  if (compress) {
65
86
  try {
66
- compressedBase64 = await compressImage(image);
87
+ compressedBase64 = await compressImage(blob);
67
88
  } catch (error) {}
68
89
  }
69
90
 
70
- let canvasImage = await createImage(compressedBase64 || image);
91
+ let canvasImage = await createImage(compressedBase64 || blob);
71
92
 
72
- let requestImage = await createImage(image);
93
+ let requestImage = await createImage(blob);
73
94
 
74
95
  if (!imageRegion) {
75
96
  dispatch(setRequestImage(canvasImage));
@@ -84,7 +105,9 @@ export const useImageSearch = () => {
84
105
  region = res.selectedRegion;
85
106
  dispatch(setSelectedRegion(region));
86
107
  setImageRegions([region]);
87
- } catch (error) {}
108
+ } catch (error) {
109
+ console.log('Error finding regions', error);
110
+ }
88
111
  }
89
112
 
90
113
  const preFilterValues = [
@@ -14,7 +14,7 @@ export const translations = {
14
14
  'Items per page': 'Items per page',
15
15
  'Search with an image': 'Search with an image',
16
16
  'Clear text search': 'Clear text search',
17
- 'View details': 'View details description',
17
+ 'View details': 'View details',
18
18
  'Clear image search': 'Clear image search ',
19
19
  'Add or change pre-filter': 'Add or change pre-filter',
20
20
  'Expand all': 'Expand all',
package/src/types.ts CHANGED
@@ -65,6 +65,11 @@ interface Attributes {
65
65
  attributeFourValue?: string;
66
66
  }
67
67
 
68
+ interface ProductDetailsAttribute {
69
+ propertyName: string;
70
+ value: string;
71
+ }
72
+
68
73
  export interface AppSettings extends NyrisAPISettings {
69
74
  algolia: AlgoliaSettings;
70
75
  alogoliaFilterField?: string;
@@ -75,6 +80,7 @@ export interface AppSettings extends NyrisAPISettings {
75
80
  clarityId?: string;
76
81
  mainTitle: string;
77
82
  productDetails: string;
83
+ productDetailsAttribute?: ProductDetailsAttribute[];
78
84
  secondaryTitle: string;
79
85
  CTAButton?: CTAButtonSettings;
80
86
  secondaryCTAButton?: SecondaryCTAButton;