wcz-layout 5.2.2 → 5.4.0

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
@@ -2,7 +2,7 @@
2
2
  "name": "wcz-layout",
3
3
  "license": "MIT",
4
4
  "author": "Dalibor Homola",
5
- "version": "5.2.2",
5
+ "version": "5.4.0",
6
6
  "main": "dist/src/index.js",
7
7
  "module": "dist/src/index.js",
8
8
  "exports": {
@@ -55,6 +55,8 @@ const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open'
55
55
  }),
56
56
  );
57
57
 
58
+ const isExternalUrl = (url: string) => url.startsWith('http://') || url.startsWith('https://');
59
+
58
60
  interface LeftDrawerProps {
59
61
  appVersion: string,
60
62
  drawerOpen: boolean,
@@ -73,25 +75,32 @@ export default function LeftDrawer(props: LeftDrawerProps) {
73
75
  const closeDrawer = useCallback(() => setDrawerOpen(false), []);
74
76
 
75
77
  const handleMenuItemClick = useCallback((path: string) => () => {
76
- navigate(path);
78
+ setDrawerOpen(false);
77
79
 
78
80
  if (location.pathname === path)
79
81
  return window.location.reload();
80
82
 
81
- setDrawerOpen(false);
83
+ if (isExternalUrl(path))
84
+ return window.open(path, '_blank');
85
+
86
+ navigate(path);
82
87
  }, [location.pathname]);
83
88
 
84
89
  const menuItems = (
85
90
  <List>
86
91
  {items.filter(item => !item.hidden).map(item =>
87
- <ListItem key={item.path} disablePadding sx={{ display: 'block' }} onClick={handleMenuItemClick(item.path)}>
88
- <ListItemButton selected={location.pathname === item.path} >
89
- <ListItemIcon>
90
- {item.icon}
91
- </ListItemIcon>
92
- <ListItemText primary={t(item.title)} />
93
- </ListItemButton>
94
- </ListItem>
92
+ <Fragment key={item.path}>
93
+ <ListItem disablePadding sx={{ display: 'block' }} onClick={handleMenuItemClick(item.path)}>
94
+ <ListItemButton selected={location.pathname === item.path}>
95
+ <ListItemIcon>
96
+ {item.icon}
97
+ </ListItemIcon>
98
+ <ListItemText primary={t(item.title)} />
99
+ </ListItemButton>
100
+ </ListItem>
101
+
102
+ {item.divider && <Divider sx={{ my: 1 }} />}
103
+ </Fragment>
95
104
  )}
96
105
  </List>
97
106
  );
@@ -6,14 +6,15 @@ import I18NextHttpBackend from 'i18next-http-backend';
6
6
  import moment from 'moment';
7
7
  import { createContext, ReactNode, SyntheticEvent, useCallback, useEffect, useMemo, useState } from 'react';
8
8
  import { initReactI18next, useTranslation } from 'react-i18next';
9
- import Layout from '../components/Layout';
10
9
  import CenteredBox from '../components/common/CenteredBox';
10
+ import Layout from '../components/Layout';
11
11
  import KeycloakExtendedConfig from '../models/KeycloakExtendedConfig';
12
12
  import { LeftDrawerItem } from '../models/LeftDrawerItem';
13
13
  import SnackbarModel from '../models/SnackbarModel';
14
- import { ExtendedUser, User } from '../models/User';
14
+ import { User } from '../models/User';
15
15
  import { persistStorage } from '../utils/PersistStorage';
16
- import { doLogin, doLogout, initKeycloak, loggedIn } from '../utils/UserService';
16
+ import { initKeycloak } from '../utils/UserService';
17
+ import { useUser } from '../utils/UseUser';
17
18
 
18
19
  interface LayoutContextInterface {
19
20
  changeTitle: (title: string) => void,
@@ -27,7 +28,6 @@ export const LayoutContext = createContext({} as LayoutContextInterface);
27
28
 
28
29
  //User
29
30
  initKeycloak();
30
- const initialUser: ExtendedUser = { login: doLogin, logout: doLogout, loggedIn: loggedIn(), department: "", id: "", name: "" };
31
31
 
32
32
  //QueryClient
33
33
  const queryClient = new QueryClient({ defaultOptions: { queries: { enabled: false } } });
@@ -39,7 +39,6 @@ i18next
39
39
  .use(I18NextHttpBackend)
40
40
  .init({ fallbackLng: 'en' });
41
41
 
42
- //Moment
43
42
  moment.defaultFormat = 'YYYY-MM-DD';
44
43
 
45
44
  declare module "moment" {
@@ -69,28 +68,11 @@ interface LayoutProviderProps {
69
68
  }
70
69
 
71
70
  export function LayoutProvider(props: LayoutProviderProps) {
72
- const [user, setUser] = useState<ExtendedUser>(initialUser);
73
71
  const [title, setTitle] = useState(props.title);
74
72
  const [snackbar, setSnackbar] = useState({} as SnackbarModel);
75
73
  const [initialized, setInitialized] = useState<boolean>(false);
76
74
  const { t, i18n } = useTranslation();
77
-
78
- useEffect(() => {
79
- window.addEventListener('user', initUserInfo);
80
- return () => window.removeEventListener('user', initUserInfo);
81
- }, []);
82
-
83
- const initUserInfo = () => {
84
- const userInfo: User | null = persistStorage.getObject<User>("user");
85
- if (userInfo)
86
- setUser({
87
- ...user,
88
- id: userInfo.id,
89
- department: userInfo.department,
90
- name: userInfo.name,
91
- loggedIn: loggedIn()
92
- });
93
- };
75
+ const user = useUser();
94
76
 
95
77
  useEffect(() => setQueryClientDefaultOptions(), [user.loggedIn]);
96
78
 
@@ -103,10 +85,11 @@ export function LayoutProvider(props: LayoutProviderProps) {
103
85
  queries: {
104
86
  enabled: enabled,
105
87
  refetchOnWindowFocus: false,
106
- onError: message => setSnackbar({ message: String(message), severity: "error" })
88
+ onError: message => setSnackbar({ message: String(message), severity: "error" }),
89
+ retry: false
107
90
  },
108
91
  mutations: {
109
- onError: message => setSnackbar({ message: String(message), severity: "error" })
92
+ onError: message => setSnackbar({ message: String(message), severity: "error" }),
110
93
  }
111
94
  });
112
95
  };
@@ -1,12 +1,12 @@
1
- export default interface KeycloakExtendedConfig {
2
- autoLogin?: boolean,
3
- confidential?: Confidential,
4
- realm: string,
5
- "auth-server-url": string,
6
- idpHint?: string
7
- }
8
-
9
- export interface Confidential {
10
- client: string,
11
- secret: string
1
+ export default interface KeycloakExtendedConfig {
2
+ autoLogin?: boolean,
3
+ confidential?: Confidential,
4
+ realm: string,
5
+ "auth-server-url": string,
6
+ idpHint?: string
7
+ }
8
+
9
+ export interface Confidential {
10
+ client: string,
11
+ secret: string
12
12
  }
@@ -2,5 +2,6 @@ export interface LeftDrawerItem {
2
2
  title: string,
3
3
  path: string,
4
4
  icon: React.ReactNode,
5
- hidden?: boolean
5
+ hidden?: boolean,
6
+ divider?: boolean,
6
7
  }
@@ -1,6 +1,6 @@
1
- import { AlertColor } from "@mui/material";
2
-
3
- export default interface SnackbarModel {
4
- message: string,
5
- severity?: AlertColor
1
+ import { AlertColor } from "@mui/material";
2
+
3
+ export default interface SnackbarModel {
4
+ message: string,
5
+ severity?: AlertColor
6
6
  }
@@ -1,92 +1,92 @@
1
- import { getToken } from "./UserService";
2
-
3
- export const fetchGet = async (url: string, signal: AbortSignal | undefined): Promise<any> => {
4
- const initReq: RequestInit = await getRequestInit("GET", null, signal);
5
-
6
- const response: Response = await fetch(url, initReq);
7
- if (!response.ok)
8
- throw await getQueryErrorMessage(response);
9
-
10
- return response.json();
11
- };
12
-
13
- export const fetchFileGet = async (url: string, signal: AbortSignal | undefined): Promise<Blob> => {
14
- const initReq: RequestInit = await getRequestInit("GET", null, signal);
15
-
16
- const response: Response = await fetch(url, initReq);
17
- if (!response.ok)
18
- throw await getQueryErrorMessage(response);
19
-
20
- return response.blob();
21
- };
22
-
23
- export const fetchPost = async (url: string, data: unknown): Promise<any> => {
24
- const initReq: RequestInit = await getRequestInit("POST", data);
25
-
26
- const response: Response = await fetch(url, initReq);
27
- if (!response.ok)
28
- throw await getQueryErrorMessage(response);
29
-
30
- return response.json();
31
- };
32
-
33
- export const fetchPut = async (url: string, data: unknown): Promise<Response> => {
34
- const initReq: RequestInit = await getRequestInit("PUT", data);
35
-
36
- const response: Response = await fetch(url, initReq);
37
- if (!response.ok)
38
- throw await getQueryErrorMessage(response);
39
-
40
- return response;
41
- };
42
-
43
- export const fetchDelete = async (url: string): Promise<Response> => {
44
- const initReq: RequestInit = await getRequestInit("DELETE");
45
-
46
- const response: Response = await fetch(url, initReq);
47
- if (!response.ok)
48
- throw await getQueryErrorMessage(response);
49
-
50
- return response;
51
- };
52
-
53
- const getRequestInit = async (method: string, data?: unknown, signal?: AbortSignal): Promise<RequestInit> => {
54
- const request: RequestInit = {
55
- method: method,
56
- signal: signal,
57
- credentials: 'include'
58
- };
59
-
60
- if (data) {
61
- if (data instanceof FormData)
62
- request.body = data;
63
- else
64
- request.body = JSON.stringify(data);
65
- }
66
-
67
- if (data instanceof FormData)
68
- request.headers = {
69
- 'Authorization': `Bearer ${await getToken()}`
70
- };
71
- else {
72
- request.headers = {
73
- 'Content-Type': 'application/json',
74
- 'Authorization': `Bearer ${await getToken()}`
75
- };
76
- }
77
-
78
- return request;
79
- };
80
-
81
- const getQueryErrorMessage = async (response: Response): Promise<string> => {
82
- let message: string = `Error connecting to server`;
83
-
84
- const detailMessage: string | undefined = await response.json()
85
- .then(data => data.message ?? data.title)
86
- .catch(() => (message));
87
-
88
- if (detailMessage)
89
- message = detailMessage;
90
-
91
- return message;
1
+ import { getToken } from "./UserService";
2
+
3
+ export const fetchGet = async (url: string, signal: AbortSignal | undefined): Promise<any> => {
4
+ const initReq: RequestInit = await getRequestInit("GET", null, signal);
5
+
6
+ const response: Response = await fetch(url, initReq);
7
+ if (!response.ok)
8
+ throw await getQueryErrorMessage(response);
9
+
10
+ return response.json();
11
+ };
12
+
13
+ export const fetchFileGet = async (url: string, signal: AbortSignal | undefined): Promise<Blob> => {
14
+ const initReq: RequestInit = await getRequestInit("GET", null, signal);
15
+
16
+ const response: Response = await fetch(url, initReq);
17
+ if (!response.ok)
18
+ throw await getQueryErrorMessage(response);
19
+
20
+ return response.blob();
21
+ };
22
+
23
+ export const fetchPost = async (url: string, data: unknown): Promise<any> => {
24
+ const initReq: RequestInit = await getRequestInit("POST", data);
25
+
26
+ const response: Response = await fetch(url, initReq);
27
+ if (!response.ok)
28
+ throw await getQueryErrorMessage(response);
29
+
30
+ return response.json();
31
+ };
32
+
33
+ export const fetchPut = async (url: string, data: unknown): Promise<Response> => {
34
+ const initReq: RequestInit = await getRequestInit("PUT", data);
35
+
36
+ const response: Response = await fetch(url, initReq);
37
+ if (!response.ok)
38
+ throw await getQueryErrorMessage(response);
39
+
40
+ return response;
41
+ };
42
+
43
+ export const fetchDelete = async (url: string): Promise<Response> => {
44
+ const initReq: RequestInit = await getRequestInit("DELETE");
45
+
46
+ const response: Response = await fetch(url, initReq);
47
+ if (!response.ok)
48
+ throw await getQueryErrorMessage(response);
49
+
50
+ return response;
51
+ };
52
+
53
+ const getRequestInit = async (method: string, data?: unknown, signal?: AbortSignal): Promise<RequestInit> => {
54
+ const request: RequestInit = {
55
+ method: method,
56
+ signal: signal,
57
+ credentials: 'include'
58
+ };
59
+
60
+ if (data) {
61
+ if (data instanceof FormData)
62
+ request.body = data;
63
+ else
64
+ request.body = JSON.stringify(data);
65
+ }
66
+
67
+ if (data instanceof FormData)
68
+ request.headers = {
69
+ 'Authorization': `Bearer ${await getToken()}`
70
+ };
71
+ else {
72
+ request.headers = {
73
+ 'Content-Type': 'application/json',
74
+ 'Authorization': `Bearer ${await getToken()}`
75
+ };
76
+ }
77
+
78
+ return request;
79
+ };
80
+
81
+ const getQueryErrorMessage = async (response: Response): Promise<string> => {
82
+ let message: string = `[${response.status}] ${response.statusText}`;
83
+
84
+ const detailMessage: string | undefined = await response.json()
85
+ .then(data => `[${response.status}] ${data.message}`)
86
+ .catch(() => (message));
87
+
88
+ if (detailMessage)
89
+ message = detailMessage;
90
+
91
+ return message;
92
92
  };
@@ -1,8 +1,8 @@
1
- import { Guid } from "guid-ts";
2
-
3
- export const isAndroid: boolean = /(android)/i.test(navigator.userAgent);
4
- export const isMobile: boolean = /(android|iphone)/i.test(navigator.userAgent);
5
-
6
- export const isDevelopment: boolean = window.location.href.includes(".dev") || window.location.href.includes("localhost");
7
-
8
- export const newGuid = (): string => Guid.newGuid().toString();
1
+ import { Guid } from "guid-ts";
2
+
3
+ export const isAndroid: boolean = /(android)/i.test(navigator.userAgent);
4
+ export const isMobile: boolean = /(android|iphone)/i.test(navigator.userAgent);
5
+
6
+ export const isDevelopment: boolean = window.location.href.includes(".dev") || window.location.href.includes("localhost");
7
+
8
+ export const newGuid = (): string => Guid.newGuid().toString();
@@ -1,10 +1,13 @@
1
1
  import { useEffect, useState } from "react";
2
- import { User } from "../models/User";
2
+ import { ExtendedUser, User } from "../models/User";
3
3
  import { persistStorage } from "./PersistStorage";
4
+ import { doLogin, doLogout, loggedIn } from "./UserService";
5
+
6
+ const initialUser: ExtendedUser = { login: doLogin, logout: doLogout, loggedIn: loggedIn(), department: "", id: "", name: "" };
4
7
 
5
8
  export const useUser = () => {
6
- const [user, setUser] = useState<User>({ id: "", name: "", department: "" });
7
-
9
+ const [user, setUser] = useState<ExtendedUser>(initialUser);
10
+
8
11
  useEffect(() => {
9
12
  window.addEventListener('user', initUser);
10
13
  return () => window.removeEventListener('user', initUser);
@@ -13,7 +16,13 @@ export const useUser = () => {
13
16
  const initUser = () => {
14
17
  const storedUser: User | null = persistStorage.getObject<User>("user");
15
18
  if (storedUser)
16
- setUser(storedUser);
19
+ setUser({
20
+ ...user,
21
+ id: storedUser.id,
22
+ department: storedUser.department,
23
+ name: storedUser.name,
24
+ loggedIn: loggedIn()
25
+ });
17
26
  };
18
27
 
19
28
  return user;