@nyris/nyris-webapp 0.3.41 → 0.3.42

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 (31) hide show
  1. package/build/_redirects +1 -0
  2. package/build/asset-manifest.json +9 -9
  3. package/build/index.html +1 -1
  4. package/build/{precache-manifest.d9bae9c81b3a390a89a437be45e3a94b.js → precache-manifest.009e864ff0764cf3cf8a9b290c334099.js} +10 -10
  5. package/build/service-worker.js +1 -1
  6. package/build/static/js/2.1757789c.chunk.js +3 -0
  7. package/build/static/js/{2.1e5f374f.chunk.js.LICENSE.txt → 2.1757789c.chunk.js.LICENSE.txt} +2 -0
  8. package/build/static/js/2.1757789c.chunk.js.map +1 -0
  9. package/build/static/js/main.1d184393.chunk.js +3 -0
  10. package/build/static/js/main.1d184393.chunk.js.map +1 -0
  11. package/package.json +4 -3
  12. package/public/_redirects +1 -0
  13. package/src/App.tsx +0 -17
  14. package/src/Router.tsx +12 -36
  15. package/src/Store/constants.ts +1 -0
  16. package/src/components/AuthProvider.tsx +25 -0
  17. package/src/components/AuthenticatedRoute.tsx +35 -0
  18. package/src/components/CadenasWebViewer.tsx +5 -2
  19. package/src/components/Layout.tsx +7 -4
  20. package/src/components/ProductDetailView.tsx +5 -1
  21. package/src/components/carousel/ImagePreviewCarousel.tsx +6 -2
  22. package/src/components/rfq/RfqBanner.tsx +0 -1
  23. package/src/index.tsx +9 -6
  24. package/src/page/Login.tsx +21 -0
  25. package/src/page/Logout.tsx +23 -0
  26. package/src/types.ts +24 -15
  27. package/build/static/js/2.1e5f374f.chunk.js +0 -3
  28. package/build/static/js/2.1e5f374f.chunk.js.map +0 -1
  29. package/build/static/js/main.909efae2.chunk.js +0 -3
  30. package/build/static/js/main.909efae2.chunk.js.map +0 -1
  31. /package/build/static/js/{main.909efae2.chunk.js.LICENSE.txt → main.1d184393.chunk.js.LICENSE.txt} +0 -0
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@nyris/nyris-webapp",
3
- "version": "0.3.41",
3
+ "version": "0.3.42",
4
4
  "homepage": "./",
5
5
  "dependencies": {
6
6
  "@algolia/autocomplete-js": "^1.7.1",
7
7
  "@algolia/autocomplete-plugin-query-suggestions": "^1.7.1",
8
8
  "@algolia/autocomplete-plugin-recent-searches": "^1.7.1",
9
9
  "@algolia/autocomplete-theme-classic": "^1.7.1",
10
+ "@auth0/auth0-react": "^2.2.1",
10
11
  "@babel/runtime": "^7.17.2",
11
12
  "@material-ui/core": "^4.3.3",
12
13
  "@material-ui/data-grid": "^4.0.0-alpha.37",
13
14
  "@material-ui/icons": "^4.4.1",
14
15
  "@material-ui/lab": "^4.0.0-alpha.60",
15
- "@nyris/nyris-api": "^0.3.41",
16
- "@nyris/nyris-react-components": "^0.3.41",
16
+ "@nyris/nyris-api": "^0.3.42",
17
+ "@nyris/nyris-react-components": "^0.3.42",
17
18
  "@reduxjs/toolkit": "^1.6.1",
18
19
  "@splidejs/react-splide": "^0.7.12",
19
20
  "@types/blueimp-load-image": "^2.23.4",
@@ -0,0 +1 @@
1
+ /* /index.html 200
package/src/App.tsx CHANGED
@@ -7,25 +7,8 @@ import 'index.css';
7
7
  import { useMediaQuery } from 'react-responsive';
8
8
  import AppMD from 'page/landingPage/AppMD';
9
9
  import AppMobile from 'page/landingPage/AppMobile';
10
- // import i18n from 'i18next';
11
- // import { initReactI18next } from 'react-i18next';
12
- // import { useAppSelector } from 'Store/Store';
13
- // import { translations } from 'translations';
14
-
15
- // i18n.use(initReactI18next).init({
16
- // resources: translations,
17
- // fallbackLng: 'en',
18
- // interpolation: {
19
- // escapeValue: false,
20
- // },
21
- // returnNull: false,
22
- // });
23
10
 
24
11
  function App(): JSX.Element {
25
- // const language = useAppSelector(state => state.settings.language);
26
-
27
- // i18n.changeLanguage(language);
28
-
29
12
  const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
30
13
  let SelectedApp: any = isMobile ? AppMobile : AppMD;
31
14
 
package/src/Router.tsx CHANGED
@@ -1,52 +1,28 @@
1
1
  import React, { memo } from 'react';
2
- import { Route, Switch, Redirect } from 'react-router-dom';
2
+ import { Route, Switch } from 'react-router-dom';
3
3
  import Layout from 'components/Layout';
4
- import { ReactNode } from 'components/common';
5
4
  import App from 'App';
6
5
  import ResultComponent from 'page/result';
7
-
8
- interface PrivateRouteProps {
9
- component: ReactNode;
10
- authed: boolean;
11
- [key: string]: any;
12
- }
13
-
14
- const PrivateRoute = ({
15
- component: Component,
16
- authed,
17
- ...rest
18
- }: PrivateRouteProps) => {
19
- return (
20
- <Route
21
- {...rest}
22
- render={() => (authed ? <Component /> : <Redirect to="/login" />)}
23
- />
24
- );
25
- };
6
+ import AuthenticatedRoute from 'components/AuthenticatedRoute';
7
+ import Login from 'page/Login';
8
+ import Logout from 'page/Logout';
26
9
 
27
10
  function Router(): JSX.Element {
28
- const accessToken = true;
29
-
30
11
  return (
31
12
  <Switch>
32
- <Layout>
33
- <Switch>
34
- <PrivateRoute
35
- authed={!!accessToken}
36
- exact
37
- strict
38
- path="/"
39
- component={App}
40
- />
41
- <PrivateRoute
42
- authed={!!accessToken}
13
+ <Switch>
14
+ <Route path={'/login'} exact component={Login} />
15
+ <Route path={'/logout'} exact component={Logout} />
16
+ <Layout>
17
+ <AuthenticatedRoute exact strict path="/" component={App} />
18
+ <AuthenticatedRoute
43
19
  exact
44
20
  strict
45
21
  path="/result"
46
22
  component={ResultComponent}
47
23
  />
48
- </Switch>
49
- </Layout>
24
+ </Layout>
25
+ </Switch>
50
26
  </Switch>
51
27
  );
52
28
  }
@@ -1,6 +1,7 @@
1
1
  import { AppSettings } from '../types';
2
2
 
3
3
  export const defaultSettings: AppSettings = {
4
+ auth0: {},
4
5
  xOptions: false,
5
6
  apiKey: 'UNSET',
6
7
  preview: true,
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { Auth0Provider } from '@auth0/auth0-react';
3
+ import { useAppSelector } from 'Store/Store';
4
+
5
+ const AuthProvider = ({ children }: any) => {
6
+ const settings = useAppSelector(state => state.settings);
7
+
8
+ if (!settings.auth0.enabled) {
9
+ return <>{children}</>;
10
+ }
11
+
12
+ return (
13
+ <Auth0Provider
14
+ domain={settings.auth0.domain || ''}
15
+ clientId={settings.auth0.clientId || ''}
16
+ authorizationParams={{
17
+ redirect_uri: window.location.origin,
18
+ }}
19
+ >
20
+ {children}
21
+ </Auth0Provider>
22
+ );
23
+ };
24
+
25
+ export default AuthProvider;
@@ -0,0 +1,35 @@
1
+ import React, { useEffect } from 'react';
2
+ import { useAuth0 } from '@auth0/auth0-react';
3
+ import { Route } from 'react-router-dom';
4
+ import { useAppSelector } from 'Store/Store';
5
+
6
+ const AuthenticatedRoute = ({ component, ...rest }: any) => {
7
+ const { auth0 } = useAppSelector(state => state.settings);
8
+
9
+ const { user, isAuthenticated, isLoading, loginWithRedirect } = useAuth0();
10
+
11
+ useEffect(() => {
12
+ if (!isLoading && !user && !isAuthenticated && auth0.enabled) {
13
+ loginWithRedirect();
14
+ }
15
+ }, [loginWithRedirect, isLoading, user, isAuthenticated, auth0]);
16
+
17
+ const Component = component;
18
+
19
+ return (
20
+ <Route
21
+ {...rest}
22
+ render={props => {
23
+ if (!auth0.enabled) {
24
+ return <Component {...props} />;
25
+ } else if (isAuthenticated) {
26
+ return <Component {...props} />;
27
+ } else {
28
+ return <div></div>;
29
+ }
30
+ }}
31
+ />
32
+ );
33
+ };
34
+
35
+ export default AuthenticatedRoute;
@@ -3,6 +3,7 @@ import React, { useEffect, useState } from 'react';
3
3
  import { useMediaQuery } from 'react-responsive';
4
4
  import { ReactComponent as DownloadIcon } from 'common/assets/icons/download.svg';
5
5
  import CadenasLoading from './CadenasLoading';
6
+ import { useAppSelector } from '../Store/Store';
6
7
 
7
8
  declare const psol: any;
8
9
 
@@ -27,6 +28,7 @@ function CadenasWebViewer({
27
28
  }) {
28
29
  const [mident, setMident] = useState('');
29
30
  const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
31
+ const { settings } = useAppSelector(state => state);
30
32
 
31
33
  useEffect(() => {
32
34
  // prepare 3d viewer settings.
@@ -72,13 +74,14 @@ function CadenasWebViewer({
72
74
 
73
75
  // initialize 3d viewer
74
76
  let webviewer3d = new psol.components.WebViewer3D(webViewer3DSettings);
77
+ psol.core.setApiKey(settings.cadenasAPIKey);
75
78
  setStatus3dView('loading');
76
79
  // run search and display result in 3D viewer.
77
80
  psol.core
78
81
  .ajaxGetOrPost({
79
82
  url: psol.core.getServiceBaseUrl() + '/service/reversemap',
80
83
  data: {
81
- catalog: 'ganter',
84
+ catalog: settings.catalog,
82
85
  part: sku,
83
86
  exact: '0',
84
87
  },
@@ -98,7 +101,7 @@ function CadenasWebViewer({
98
101
  });
99
102
  });
100
103
  });
101
- }, [sku, setStatus3dView]);
104
+ }, [sku, setStatus3dView, settings]);
102
105
 
103
106
  const showWebViewer = !is3dView || status3dView !== 'loaded';
104
107
 
@@ -26,11 +26,11 @@ import Loading from './Loading';
26
26
  import i18n from 'i18next';
27
27
  import { initReactI18next } from 'react-i18next';
28
28
  import { translations } from 'translations';
29
+ import { useAuth0 } from '@auth0/auth0-react';
29
30
 
30
31
  declare var psol: any;
31
32
 
32
33
  jQuery(document).ready(function () {
33
- psol.core.setApiKey('66c56a38010f4a81a82f6ed51c903399');
34
34
  psol.core.setUserInfo({
35
35
  server_type: 'oem_apps_cadenas_webcomponentsdemo',
36
36
  title: 'Herr',
@@ -69,7 +69,9 @@ function Layout({ children }: ReactNode): JSX.Element {
69
69
  (isMobile && history.location?.pathname === '/result') ||
70
70
  history.location?.pathname === '/';
71
71
  const language = useAppSelector(state => state.settings.language);
72
-
72
+ const { isAuthenticated } = useAuth0();
73
+ const { auth0 } = settings;
74
+ const showApp = !auth0.enabled || (auth0.enabled && isAuthenticated);
73
75
  i18n.changeLanguage(language);
74
76
 
75
77
  useEffect(() => {
@@ -165,8 +167,8 @@ function Layout({ children }: ReactNode): JSX.Element {
165
167
  }
166
168
  }}
167
169
  >
168
- {isMobile && <AppMobile>{children}</AppMobile>}
169
- {!isMobile && (
170
+ {isMobile && showApp && <AppMobile>{children}</AppMobile>}
171
+ {!isMobile && showApp && (
170
172
  <div className={`layout-main-${classNameBoxVersion}`}>
171
173
  <div
172
174
  className={
@@ -199,6 +201,7 @@ function Layout({ children }: ReactNode): JSX.Element {
199
201
  )}
200
202
  </div>
201
203
  )}
204
+ {!showApp && <> {children}</>}
202
205
  </InstantSearch>
203
206
  </div>
204
207
  );
@@ -159,7 +159,9 @@ function ProductDetailView(props: Props) {
159
159
  }}
160
160
  >
161
161
  {dataImageCarousel.length > 0 && (
162
- <ImagePreviewCarousel imgItem={dataImageCarousel} />
162
+ <ImagePreviewCarousel imgItem={dataImageCarousel} setSelectedImage={(url) => {
163
+ setUrlImage(url ? url : urlImage);
164
+ }} />
163
165
  )}
164
166
  {dataImageCarousel.length > 0 && (
165
167
  <Button
@@ -175,6 +177,7 @@ function ProductDetailView(props: Props) {
175
177
  justifyContent: 'center',
176
178
  alignItems: 'center',
177
179
  cursor: 'pointer',
180
+ bottom: isMobile ? '25px' : '4px',
178
181
  }}
179
182
  onClick={() => {
180
183
  if (urlImage.length > 1) {
@@ -212,6 +215,7 @@ function ProductDetailView(props: Props) {
212
215
  style={{
213
216
  position: 'absolute',
214
217
  left: '16px',
218
+ bottom: isMobile ? '25px' : '10px'
215
219
  }}
216
220
  >
217
221
  {!is3dView &&
@@ -9,17 +9,18 @@ interface Props {
9
9
  imgItem: any[];
10
10
  onSearchImage?: any;
11
11
  handlerCloseModal?: any;
12
+ setSelectedImage: (url: string) => void;
12
13
  }
13
14
 
14
15
  export const ImagePreviewCarousel = (props: Props) => {
15
- let { imgItem } = props;
16
+ let { imgItem, setSelectedImage } = props;
16
17
  const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
17
18
  const mainRef: any = useRef(null);
18
19
  const thumbsRef: any = useRef(null);
19
20
 
20
21
  const maxWidth = useMemo(() => {
21
22
  const contentWidth = 75 + 58 * imgItem.length;
22
- const modalWidth = isMobile ? 340 : 600;
23
+ const modalWidth = isMobile ? 240 : 460;
23
24
  return contentWidth < modalWidth ? contentWidth : modalWidth;
24
25
  }, [imgItem.length, isMobile]);
25
26
 
@@ -74,6 +75,9 @@ export const ImagePreviewCarousel = (props: Props) => {
74
75
  return (
75
76
  <>
76
77
  <Splide
78
+ onActive={(e: any) => {
79
+ setSelectedImage(e?.root?.querySelector('li.is-active')?.querySelector('img')?.src)
80
+ }}
77
81
  options={mainOptions}
78
82
  ref={mainRef}
79
83
  style={{ maxWidth: '100%', height: isMobile ? '80%' : '' }}
@@ -31,7 +31,6 @@ function RfqBanner({
31
31
  alignItems: 'center',
32
32
  }}
33
33
  className="rfq-box"
34
- // ref={rfqRef}
35
34
  >
36
35
  <Box
37
36
  style={{
package/src/index.tsx CHANGED
@@ -7,12 +7,13 @@ import * as serviceWorker from './serviceWorker';
7
7
  import { Provider } from 'react-redux';
8
8
  import { MuiThemeProvider } from '@material-ui/core';
9
9
  import 'typeface-roboto';
10
- import { HashRouter } from 'react-router-dom';
10
+ import { BrowserRouter } from 'react-router-dom';
11
11
  import Router from 'Router';
12
12
  import { store } from 'Store/Store';
13
13
  import 'react-responsive-carousel/lib/styles/carousel.min.css';
14
14
  import { createTheme } from '@material-ui/core/styles';
15
15
  import { Toaster } from 'components/Toaster';
16
+ import AuthProvider from 'components/AuthProvider';
16
17
 
17
18
  document.title = window.location.host;
18
19
 
@@ -33,11 +34,13 @@ ReactDOM.render(
33
34
  <Fragment>
34
35
  <Toaster />
35
36
  <Provider store={store}>
36
- <MuiThemeProvider theme={theme}>
37
- <HashRouter>
38
- <Router />
39
- </HashRouter>
40
- </MuiThemeProvider>
37
+ <AuthProvider>
38
+ <MuiThemeProvider theme={theme}>
39
+ <BrowserRouter>
40
+ <Router />
41
+ </BrowserRouter>
42
+ </MuiThemeProvider>
43
+ </AuthProvider>
41
44
  </Provider>
42
45
  </Fragment>,
43
46
  document.getElementById('root'),
@@ -0,0 +1,21 @@
1
+ import React, { useEffect } from 'react';
2
+ import { useAuth0 } from '@auth0/auth0-react';
3
+ import { useAppSelector } from 'Store/Store';
4
+
5
+ const Login = () => {
6
+ const { user, isAuthenticated, isLoading, loginWithRedirect } = useAuth0();
7
+ const { auth0 } = useAppSelector(state => state.settings);
8
+
9
+ useEffect(() => {
10
+ if (!isLoading && !user && !isAuthenticated && auth0.enabled) {
11
+ loginWithRedirect();
12
+ }
13
+ if (isAuthenticated || !auth0.enabled) {
14
+ window.location.href = '/';
15
+ }
16
+ }, [loginWithRedirect, isLoading, user, isAuthenticated, auth0]);
17
+
18
+ return <div></div>;
19
+ };
20
+
21
+ export default Login;
@@ -0,0 +1,23 @@
1
+ import React, { useEffect } from 'react';
2
+ import { useAuth0 } from '@auth0/auth0-react';
3
+ import { useAppSelector } from 'Store/Store';
4
+
5
+ const Logout = () => {
6
+ const { user, isAuthenticated, isLoading, loginWithRedirect, logout } =
7
+ useAuth0();
8
+ const { auth0 } = useAppSelector(state => state.settings);
9
+
10
+ useEffect(() => {
11
+ if (!isLoading && !user && !isAuthenticated && auth0.enabled) {
12
+ loginWithRedirect();
13
+ } else if (isAuthenticated) {
14
+ logout({ logoutParams: { returnTo: window.location.origin } });
15
+ } else if (!auth0.enabled) {
16
+ window.location.href = '/';
17
+ }
18
+ }, [loginWithRedirect, isAuthenticated, isLoading, user, logout, auth0]);
19
+
20
+ return <div></div>;
21
+ };
22
+
23
+ export default Logout;
package/src/types.ts CHANGED
@@ -8,6 +8,12 @@ export interface AlgoliaSettings {
8
8
  indexName: string;
9
9
  }
10
10
 
11
+ export interface Auth0Settings {
12
+ clientId?: string;
13
+ domain?: string;
14
+ enabled?: boolean;
15
+ }
16
+
11
17
  export interface Field {
12
18
  ctaLinkField: string;
13
19
  productName: string;
@@ -31,28 +37,31 @@ export interface AppSettings extends NyrisAPISettings {
31
37
  instantRedirectPatterns: string[];
32
38
  theme: SearchSuiteSettings;
33
39
  algolia?: AlgoliaSettings;
34
- productCtaText?: string;
40
+ alogoliaFilterField?: string;
35
41
  appTitle?: string;
36
- refinements?: any;
37
- showGroup?: boolean;
38
- preFilterOption?: boolean;
42
+ auth0: Auth0Settings;
43
+ brandName?: string;
39
44
  cadenas3dWebView?: boolean;
40
- rfq?: boolean;
45
+ catalog?: string;
46
+ cadenasAPIKey?: string;
47
+ field: Field;
48
+ headerText?: string;
41
49
  inquiry?: boolean;
42
- templateId?: string;
43
- warehouseVariant?: boolean;
44
- preFilterTitle?: string;
50
+ itemIdLabel?: string;
51
+ language?: string;
45
52
  postFilterOption?: boolean;
53
+ preFilterOption?: boolean;
54
+ preFilterTitle?: string;
55
+ productCtaText?: string;
56
+ refinements?: any;
57
+ rfq?: boolean;
58
+ shareOption?: boolean;
46
59
  showFeedbackAndShare?: boolean;
60
+ showGroup?: boolean;
47
61
  showMoreInfo?: boolean; // deprecated
62
+ templateId?: string;
48
63
  visualSearchFilterKey?: string;
49
- alogoliaFilterField?: string;
50
- headerText?: string;
51
- brandName?: string;
52
- shareOption?: boolean;
53
- language?: string;
54
- itemIdLabel?: string;
55
- field: Field;
64
+ warehouseVariant?: boolean;
56
65
  }
57
66
 
58
67
  export interface SearchSuiteSettings {