@asaleh37/ui-base 25.9.1 → 25.9.3-1

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaleh37/ui-base",
3
- "version": "25.9.1",
3
+ "version": "25.9.3-1",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "Ahmed Saleh Mohamed",
package/public/bg.jpg ADDED
Binary file
@@ -1,11 +1,26 @@
1
1
  import { PublicClientApplication } from "@azure/msal-browser";
2
- import { Box, Button } from "@mui/material";
2
+ import {
3
+ Box,
4
+ Button,
5
+ CircularProgress,
6
+ createTheme,
7
+ Paper,
8
+ Typography,
9
+ } from "@mui/material";
3
10
  import { useDispatch, useSelector } from "react-redux";
4
11
  import { AppInfo } from "../../redux/features/common/AppInfoSlice";
5
12
  import { useAxios } from "../../hooks";
6
13
  import { UserSessionActions } from "../../redux/features/common/UserSessionSlice";
7
- import { useEffect } from "react";
14
+ import { useEffect, useState } from "react";
8
15
 
16
+ import { ThemeProvider } from "@emotion/react";
17
+ import {
18
+ DARK_THEME_INITIAL_MAIN_COLOR,
19
+ DARK_THEME_INITIAL_SECANDARY_COLOR,
20
+ LIGHT_THEME_INITIAL_MAIN_COLOR,
21
+ LIGHT_THEME_INITIAL_SECANDARY_COLOR,
22
+ } from "../../util";
23
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
9
24
  interface AzureLoginProps {
10
25
  msalInstance: PublicClientApplication;
11
26
  }
@@ -13,16 +28,17 @@ interface AzureLoginProps {
13
28
  const AzureLogin: React.FC<AzureLoginProps> = ({ msalInstance }) => {
14
29
  const appInfo: AppInfo = useSelector((state: any) => state.AppInfo.value);
15
30
  const userSession = useSelector((state: any) => state.UserSession.value);
31
+ const [isLoginInProcess, setIsLoginInProcess] = useState(false);
16
32
  const { handleGetRequest } = useAxios();
17
33
  const dispatch = useDispatch();
18
34
  const checkUserSession = async () => {
19
- if (appInfo?.apiBaseUrl) {
20
- if (userSession.isAuthenticated == null) {
21
- const token = localStorage.getItem("TOKEN");
35
+ if (localStorage.getItem("TOKEN")) {
36
+ if (appInfo?.apiBaseUrl) {
22
37
  handleGetRequest({
23
38
  endPointURI: "api/auth/userInfo",
24
39
  showMask: true,
25
40
  successCallBkFn: (response) => {
41
+ setIsLoginInProcess(false);
26
42
  if (response != null && response.data != null) {
27
43
  const UserSession = {
28
44
  ...response.data,
@@ -34,36 +50,172 @@ const AzureLogin: React.FC<AzureLoginProps> = ({ msalInstance }) => {
34
50
  localStorage.removeItem("TOKEN");
35
51
  }
36
52
  },
53
+ failureCallBkFn: () => {
54
+ setIsLoginInProcess(false);
55
+ },
37
56
  });
38
57
  }
58
+ } else {
59
+ dispatch(UserSessionActions.setUnAuthenticated());
60
+ setIsLoginInProcess(false);
39
61
  }
40
62
  };
41
63
  const handleLogin = async () => {
64
+ setIsLoginInProcess(true);
42
65
  const response = await msalInstance.acquireTokenPopup({
43
66
  scopes: appInfo?.azureConfiguration?.scopes,
44
67
  });
45
68
  if (response?.accessToken) {
46
69
  localStorage.setItem("TOKEN", response.accessToken);
47
70
  checkUserSession();
71
+ } else {
72
+ setIsLoginInProcess(false);
48
73
  }
49
74
  };
50
- const getUserInfo = async () => {
51
- const response = await handleGetRequest({
52
- endPointURI: "api/auth/userInfo",
53
- showMask: true,
54
- successCallBkFn: (response) => {
55
- console.log(response);
56
- },
57
- });
58
- };
75
+ const UserSessionState = useSelector((state: any) => state.UserSession.value);
59
76
 
60
- // useEffect(()=>{
61
- // handleLogin()
62
- // },[])
77
+ useEffect(() => {
78
+ checkUserSession();
79
+ }, [appInfo]);
80
+
81
+ const loginTheme = createTheme({
82
+ components: {
83
+ MuiCssBaseline: {
84
+ styleOverrides: `
85
+ /* Custom Scrollbar */
86
+ * {
87
+ scrollbar-width: thin;
88
+ scrollbar-color: ${
89
+ appInfo.appTheme?.dark?.primaryColor ||
90
+ DARK_THEME_INITIAL_MAIN_COLOR
91
+ } #121212;
92
+ }
93
+
94
+ /* Webkit Browsers */
95
+ *::-webkit-scrollbar {
96
+ width: 12px;
97
+ height: 10px;
98
+ }
99
+ `,
100
+ },
101
+ },
102
+ palette: {
103
+ mode: appInfo?.loginScreenStyle?.themeMode || "dark",
104
+ primary: {
105
+ main:
106
+ appInfo?.loginScreenStyle?.themeMode === "light"
107
+ ? appInfo.appTheme?.light?.primaryColor ||
108
+ LIGHT_THEME_INITIAL_MAIN_COLOR
109
+ : appInfo.appTheme?.dark?.primaryColor ||
110
+ DARK_THEME_INITIAL_MAIN_COLOR,
111
+ },
112
+ secondary: {
113
+ main:
114
+ appInfo?.loginScreenStyle?.themeMode === "light"
115
+ ? appInfo.appTheme?.light?.secondaryColor ||
116
+ LIGHT_THEME_INITIAL_SECANDARY_COLOR
117
+ : appInfo.appTheme?.dark?.secondaryColor ||
118
+ DARK_THEME_INITIAL_SECANDARY_COLOR,
119
+ },
120
+ },
121
+ });
63
122
  return (
64
- <Box>
65
- <Button onClick={handleLogin}>Azure Login </Button>
66
- </Box>
123
+ <ThemeProvider theme={loginTheme}>
124
+ {UserSessionState.isAuthenticated == false ? (
125
+ <Box
126
+ sx={{
127
+ // position: "relative",
128
+ display: "flex",
129
+ alignItems: "center",
130
+ justifyContent: "center",
131
+ minHeight: "100vh",
132
+ width: "100%",
133
+ backgroundImage: "url('/bg.jpg')",
134
+ backgroundRepeat: "no-repeat",
135
+ backgroundSize: "cover",
136
+ backgroundPosition: "center",
137
+ "&::before": {
138
+ content: '""',
139
+ position: "absolute",
140
+ top: 0,
141
+ left: 0,
142
+ right: 0,
143
+ bottom: 0,
144
+ backgroundColor: "rgba(0, 0, 0, 0.4)", // 👈 controls opacity
145
+ zIndex: 0,
146
+ },
147
+ }}
148
+ >
149
+ <Paper
150
+ sx={{
151
+ display: "flex",
152
+ width: "fit-content",
153
+ padding: 2,
154
+ height: "fit-content",
155
+ borderRadius: 5,
156
+ alignItems: "center",
157
+ justifyContent: "center",
158
+ textAlign: "center",
159
+ zIndex: 1,
160
+ p: 4,
161
+ }}
162
+ >
163
+ <Box
164
+ sx={{
165
+ display: "flex",
166
+ flexDirection: "column",
167
+ alignItems: "center",
168
+ justifyContent: "center",
169
+ }}
170
+ >
171
+ <img src={appInfo?.appLogo} width={150} height={150} />
172
+ <Typography sx={{ m: 1 }} variant="h4" color="textSecondary">
173
+ {appInfo?.appName}
174
+ </Typography>
175
+ <Typography
176
+ sx={{
177
+ paddingRight: 1,
178
+ width: "100%",
179
+ textAlign: "right",
180
+ fontSize: 10,
181
+ }}
182
+ variant="caption"
183
+ color="textSecondary"
184
+ >
185
+ V.{appInfo.appVersion}
186
+ </Typography>
187
+ <Button
188
+ loading={isLoginInProcess}
189
+ onClick={handleLogin}
190
+ variant="contained"
191
+ color="primary"
192
+ sx={{ m: 1 }}
193
+ startIcon={
194
+ <FontAwesomeIcon
195
+ icon={{ iconName: "microsoft", prefix: "fab" }}
196
+ />
197
+ }
198
+ >
199
+ login
200
+ </Button>
201
+ </Box>
202
+ </Paper>
203
+ </Box>
204
+ ) : (
205
+ <Paper
206
+ sx={{
207
+ width: "100%",
208
+ height: "100vh",
209
+ display: "flex",
210
+ alignItems: "center",
211
+ justifyContent: "center",
212
+ }}
213
+ >
214
+ <CircularProgress sx={{ marginRight: 1 }} />
215
+ <div>You will be redirected shortly ... please wait</div>
216
+ </Paper>
217
+ )}
218
+ </ThemeProvider>
67
219
  );
68
220
  };
69
221
 
@@ -16,10 +16,13 @@ import { UserSessionActions } from "../../redux/features/common/UserSessionSlice
16
16
  import {
17
17
  DARK_THEME_INITIAL_MAIN_COLOR,
18
18
  DARK_THEME_INITIAL_SECANDARY_COLOR,
19
+ LIGHT_THEME_INITIAL_MAIN_COLOR,
20
+ LIGHT_THEME_INITIAL_SECANDARY_COLOR,
19
21
  } from "../../util";
22
+ import { AppInfo } from "../../redux/features/common/AppInfoSlice";
20
23
 
21
24
  const Login: React.FC = () => {
22
- const appInfo = useSelector((state: any) => state.AppInfo.value);
25
+ const appInfo: AppInfo = useSelector((state: any) => state.AppInfo.value);
23
26
  const [username, setUsername] = useState("");
24
27
  const [password, setPassword] = useState("");
25
28
  const [isLoginInProcess, setIsLoginInProcess] = useState(false);
@@ -89,15 +92,22 @@ const Login: React.FC = () => {
89
92
  },
90
93
  },
91
94
  palette: {
92
- mode: "dark",
95
+ mode: appInfo?.loginScreenStyle?.themeMode || "dark",
93
96
  primary: {
94
97
  main:
95
- appInfo.appTheme?.dark?.primaryColor || DARK_THEME_INITIAL_MAIN_COLOR,
98
+ appInfo?.loginScreenStyle?.themeMode === "light"
99
+ ? appInfo.appTheme?.light?.primaryColor ||
100
+ LIGHT_THEME_INITIAL_MAIN_COLOR
101
+ : appInfo.appTheme?.dark?.primaryColor ||
102
+ DARK_THEME_INITIAL_MAIN_COLOR,
96
103
  },
97
104
  secondary: {
98
105
  main:
99
- appInfo.appTheme?.dark?.secondaryColor ||
100
- DARK_THEME_INITIAL_SECANDARY_COLOR,
106
+ appInfo?.loginScreenStyle?.themeMode === "light"
107
+ ? appInfo.appTheme?.light?.secondaryColor ||
108
+ LIGHT_THEME_INITIAL_SECANDARY_COLOR
109
+ : appInfo.appTheme?.dark?.secondaryColor ||
110
+ DARK_THEME_INITIAL_SECANDARY_COLOR,
101
111
  },
102
112
  },
103
113
  });
@@ -130,92 +140,127 @@ const Login: React.FC = () => {
130
140
  }
131
141
  };
132
142
  useEffect(() => {
133
- console.log("checking usersession on reload", userSession);
134
- console.log("checking usersession app info", appInfo);
135
143
  checkUserSession();
136
144
  }, [appInfo, userSession.isAuthenticated]);
137
145
 
138
146
  return (
139
147
  <ThemeProvider theme={loginTheme}>
140
- <Paper
141
- sx={{
142
- display: "flex",
143
- height: "100vh",
144
- width: "100%",
145
- borderRadius: 0,
146
- alignItems: "center",
147
- justifyContent: "center",
148
- }}
149
- >
150
- {UserSessionState.isAuthenticated == false ? (
151
- <Box
148
+ {UserSessionState.isAuthenticated == false ? (
149
+ <Box
150
+ sx={{
151
+ // position: "relative",
152
+ display: "flex",
153
+ alignItems: "center",
154
+ justifyContent: "center",
155
+ minHeight: "100vh",
156
+ width: "100%",
157
+ backgroundImage: "url('/bg.jpg')",
158
+ backgroundRepeat: "no-repeat",
159
+ backgroundSize: "cover",
160
+ backgroundPosition: "center",
161
+ "&::before": {
162
+ content: '""',
163
+ position: "absolute",
164
+ top: 0,
165
+ left: 0,
166
+ right: 0,
167
+ bottom: 0,
168
+ backgroundColor: "rgba(0, 0, 0, 0.4)", // 👈 controls opacity
169
+ zIndex: 0,
170
+ },
171
+ }}
172
+ >
173
+ <Paper
152
174
  sx={{
153
175
  display: "flex",
154
- flexDirection: "column",
176
+ width: "fit-content",
177
+ padding: 2,
178
+ height: "fit-content",
179
+ borderRadius: 5,
155
180
  alignItems: "center",
156
181
  justifyContent: "center",
182
+ textAlign: "center",
183
+ zIndex: 1,
184
+ p: 4,
157
185
  }}
158
186
  >
159
- <img src={appInfo?.appLogo} width={150} height={150} />
160
- <Typography sx={{ m: 1 }} variant="h4" color="textSecondary">
161
- {appInfo?.appName}
162
- </Typography>
163
- <Typography
187
+ <Box
164
188
  sx={{
165
- paddingRight: 1,
166
- width: "100%",
167
- textAlign: "right",
168
- fontSize: 10,
189
+ display: "flex",
190
+ flexDirection: "column",
191
+ alignItems: "center",
192
+ justifyContent: "center",
169
193
  }}
170
- variant="caption"
171
- color="textSecondary"
172
194
  >
173
- V.{appInfo.appVersion}
174
- </Typography>
175
- <TextField
176
- label="username"
177
- sx={{ width: 300, m: 1 }}
178
- value={username}
179
- onChange={(event) => {
180
- setUsername(event.target.value);
181
- }}
182
- onKeyDown={(event) => {
183
- if (event.key === "Enter") {
184
- handleLogin();
185
- }
186
- }}
187
- />
188
- <TextField
189
- label="password"
190
- sx={{ width: 300, m: 1 }}
191
- value={password}
192
- type="password"
193
- onChange={(event) => {
194
- setPassword(event.target.value);
195
- }}
196
- onKeyDown={(event) => {
197
- if (event.key === "Enter") {
198
- handleLogin();
199
- }
200
- }}
201
- />
202
- <Button
203
- loading={isLoginInProcess}
204
- onClick={handleLogin}
205
- variant="contained"
206
- color="primary"
207
- sx={{ m: 1 }}
208
- >
209
- login
210
- </Button>
211
- </Box>
212
- ) : (
213
- <>
214
- <CircularProgress sx={{ marginRight: 1 }} />
215
- <div>You will be redirected shortly ... please wait</div>
216
- </>
217
- )}
218
- </Paper>
195
+ <img src={appInfo?.appLogo} width={150} height={150} />
196
+ <Typography sx={{ m: 1 }} variant="h4" color="textSecondary">
197
+ {appInfo?.appName}
198
+ </Typography>
199
+ <Typography
200
+ sx={{
201
+ paddingRight: 1,
202
+ width: "100%",
203
+ textAlign: "right",
204
+ fontSize: 10,
205
+ }}
206
+ variant="caption"
207
+ color="textSecondary"
208
+ >
209
+ V.{appInfo.appVersion}
210
+ </Typography>
211
+ <TextField
212
+ label="username"
213
+ sx={{ width: 300, m: 1 }}
214
+ value={username}
215
+ onChange={(event) => {
216
+ setUsername(event.target.value);
217
+ }}
218
+ onKeyDown={(event) => {
219
+ if (event.key === "Enter") {
220
+ handleLogin();
221
+ }
222
+ }}
223
+ />
224
+ <TextField
225
+ label="password"
226
+ sx={{ width: 300, m: 1 }}
227
+ value={password}
228
+ type="password"
229
+ onChange={(event) => {
230
+ setPassword(event.target.value);
231
+ }}
232
+ onKeyDown={(event) => {
233
+ if (event.key === "Enter") {
234
+ handleLogin();
235
+ }
236
+ }}
237
+ />
238
+ <Button
239
+ loading={isLoginInProcess}
240
+ onClick={handleLogin}
241
+ variant="contained"
242
+ color="primary"
243
+ sx={{ m: 1 }}
244
+ >
245
+ login
246
+ </Button>
247
+ </Box>
248
+ </Paper>
249
+ </Box>
250
+ ) : (
251
+ <Paper
252
+ sx={{
253
+ width: "100%",
254
+ height: "100vh",
255
+ display: "flex",
256
+ alignItems: "center",
257
+ justifyContent: "center",
258
+ }}
259
+ >
260
+ <CircularProgress sx={{ marginRight: 1 }} />
261
+ <div>You will be redirected shortly ... please wait</div>
262
+ </Paper>
263
+ )}
219
264
  </ThemeProvider>
220
265
  );
221
266
  };
package/src/main.tsx CHANGED
@@ -7,6 +7,10 @@ createRoot(document.getElementById("root")!).render(
7
7
  enableUINotifications={false}
8
8
  appLogo={"/logo.png"}
9
9
  appName="UI Base Library"
10
+ loginScreenStyle={{
11
+ themeMode: "dark",
12
+ backgroundImageNameInPublicFolder: "bg.jpg",
13
+ }}
10
14
  appVersion="0.0"
11
15
  authenticationMethod="AZURE"
12
16
  azureConfiguration={{
@@ -19,6 +19,11 @@ export type AppInfo = {
19
19
  ar: { [key: string]: string };
20
20
  en: { [key: string]: string };
21
21
  };
22
+ loginScreenStyle?: {
23
+ themeMode: "dark" | "light";
24
+ backgroundImageNameInPublicFolder?: string;
25
+ backgroundColor?: string;
26
+ };
22
27
  authenticationMethod: "AZURE" | "APP";
23
28
  azureConfiguration?: {
24
29
  frontEndClientId: string;
@@ -48,6 +53,7 @@ const initialState: AppInfoProp = {
48
53
  value: {
49
54
  documentTitle: null,
50
55
  apiBaseUrl: null,
56
+ authenticationMethod: "APP",
51
57
  appName: null,
52
58
  appVersion: null,
53
59
  appLogo: null,