@asaleh37/ui-base 25.9.3 → 25.9.5-2

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.3",
3
+ "version": "25.9.5-2",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "Ahmed Saleh Mohamed",
package/public/bg.jpg ADDED
Binary file
@@ -23,7 +23,7 @@ const PersonGrid: React.FC = () => {
23
23
  );
24
24
  const [data, setData] = useState([]);
25
25
  const apiActions = useApiActions({
26
- findAll: "api/v1/public/person/all",
26
+ commonStoreKey: "persons",
27
27
  deleteById: "api/v1/admin/person",
28
28
  save: "api/v1/admin/person",
29
29
  findById: "api/v1/admin/person",
@@ -276,10 +276,10 @@ const PersonGrid: React.FC = () => {
276
276
  data={data}
277
277
  setData={setData}
278
278
  editMode={{
279
- editMode: "modal",
279
+ editMode: "modal",
280
280
  specs: {
281
281
  modalIcon: "user",
282
- modalTitle: "Person Profile",
282
+ modalTitle: "Person Profile",
283
283
  modalWidth: 300,
284
284
  },
285
285
  }}
@@ -320,7 +320,7 @@ const PersonGrid: React.FC = () => {
320
320
  ]}
321
321
  girdIcon="users"
322
322
  editAction={{
323
- isEnabled: true,
323
+ isEnabled: true,
324
324
  authority: "PERSON_EDIT",
325
325
  preActionValidation: (data) => {
326
326
  if (
@@ -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
 
@@ -140,39 +140,50 @@ const Login: React.FC = () => {
140
140
  }
141
141
  };
142
142
  useEffect(() => {
143
- console.log("checking usersession on reload", userSession);
144
- console.log("checking usersession app info", appInfo);
145
143
  checkUserSession();
146
144
  }, [appInfo, userSession.isAuthenticated]);
147
145
 
148
146
  return (
149
147
  <ThemeProvider theme={loginTheme}>
150
- <Box
151
- sx={{
152
- minHeight: "100vh", // full page height
153
- width: "100%",
154
- display: "flex",
155
- alignItems: "center",
156
- justifyContent: "center",
157
- background: appInfo?.loginScreenStyle?.backgroundColor,
158
- backgroundImage: `url('/${appInfo?.loginScreenStyle?.backgroundImageNameInPublicFolder}')`,
159
- backgroundRepeat: "no-repeat",
160
- backgroundSize: "cover", // 🔥 makes it responsive
161
- backgroundPosition: "center", // keeps it centered
162
- }}
163
- >
164
- <Paper
148
+ {UserSessionState.isAuthenticated == false ? (
149
+ <Box
165
150
  sx={{
151
+ // position: "relative",
166
152
  display: "flex",
167
- width: "fit-content",
168
- padding: 2,
169
- height: "fit-content",
170
- borderRadius: 5,
171
153
  alignItems: "center",
172
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
+ },
173
171
  }}
174
172
  >
175
- {UserSessionState.isAuthenticated == false ? (
173
+ <Paper
174
+ sx={{
175
+ display: "flex",
176
+ width: "fit-content",
177
+ padding: 2,
178
+ height: "fit-content",
179
+ borderRadius: 5,
180
+ alignItems: "center",
181
+ justifyContent: "center",
182
+ textAlign: "center",
183
+ zIndex: 1,
184
+ p: 4,
185
+ }}
186
+ >
176
187
  <Box
177
188
  sx={{
178
189
  display: "flex",
@@ -234,14 +245,22 @@ const Login: React.FC = () => {
234
245
  login
235
246
  </Button>
236
247
  </Box>
237
- ) : (
238
- <>
239
- <CircularProgress sx={{ marginRight: 1 }} />
240
- <div>You will be redirected shortly ... please wait</div>
241
- </>
242
- )}
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>
243
262
  </Paper>
244
- </Box>
263
+ )}
245
264
  </ThemeProvider>
246
265
  );
247
266
  };
@@ -30,7 +30,7 @@ const FormElementField: React.FC<FormElementFieldProps> = (
30
30
  return element?.fieldInfo?.fieldLabel;
31
31
  }
32
32
  };
33
- return !element.hiddenFields.includes(fieldName) ? (
33
+ return (
34
34
  <Grid2
35
35
  size={
36
36
  props?.formProps?.fieldSize || {
@@ -49,16 +49,7 @@ const FormElementField: React.FC<FormElementFieldProps> = (
49
49
  {...props.muiTextFieldProps}
50
50
  fullWidth
51
51
  type={fieldType}
52
- disabled={
53
- props?.disabled || element.disabledFields.includes(fieldName)
54
- ? true
55
- : false
56
- }
57
- // hidden={
58
- // props?.hidden || element.hiddenFields.includes(fieldName)
59
- // ? true
60
- // : false
61
- // }
52
+ disabled={element.disabledFields.includes(fieldName)}
62
53
  label={getFieldLabel()}
63
54
  value={formValues[fieldName]}
64
55
  onChange={(event) => {
@@ -89,6 +80,9 @@ const FormElementField: React.FC<FormElementFieldProps> = (
89
80
  height: "100% !important", // forces full height usage
90
81
  },
91
82
  ...props?.formProps?.style,
83
+ display: element.hiddenFields.includes(fieldName)
84
+ ? "none"
85
+ : undefined,
92
86
  }}
93
87
  error={formManager.formState.errors[fieldName] != undefined}
94
88
  helperText={formManager?.formState?.errors[
@@ -99,16 +93,8 @@ const FormElementField: React.FC<FormElementFieldProps> = (
99
93
  <Datefield
100
94
  format={props?.dateFormat || DATE_FORMAT}
101
95
  sx={props?.formProps?.style || { width: "100%" }}
102
- disabled={
103
- props?.disabled || element.disabledFields.includes(fieldName)
104
- ? true
105
- : false
106
- }
107
- // hidden={
108
- // props?.hidden || element.hiddenFields.includes(fieldName)
109
- // ? true
110
- // : false
111
- // }
96
+ disabled={element.disabledFields.includes(fieldName)}
97
+ hidden={element.hiddenFields.includes(fieldName)}
112
98
  label={getFieldLabel()}
113
99
  onChangeCallBack={(v: any) => {
114
100
  formManager.setValue(fieldName, v);
@@ -132,11 +118,8 @@ const FormElementField: React.FC<FormElementFieldProps> = (
132
118
  <DatetimeField
133
119
  format={props?.dateFormat || DATE_TIME_FORMAT}
134
120
  sx={props?.formProps?.style || { width: "100%" }}
135
- disabled={
136
- props?.disabled || element.disabledFields.includes(fieldName)
137
- ? true
138
- : false
139
- }
121
+ disabled={element.disabledFields.includes(fieldName)}
122
+ hidden={element.hiddenFields.includes(fieldName)}
140
123
  label={getFieldLabel()}
141
124
  onChangeCallBack={(v: any) => {
142
125
  formManager.setValue(fieldName, v);
@@ -150,11 +133,6 @@ const FormElementField: React.FC<FormElementFieldProps> = (
150
133
  );
151
134
  }
152
135
  }}
153
- // hidden={
154
- // props?.hidden || element.hiddenFields.includes(fieldName)
155
- // ? true
156
- // : false
157
- // }
158
136
  value={formValues[fieldName]}
159
137
  error={formManager.formState.errors[fieldName] != undefined}
160
138
  errorMessage={formManager?.formState?.errors[
@@ -176,35 +154,19 @@ const FormElementField: React.FC<FormElementFieldProps> = (
176
154
  );
177
155
  }
178
156
  }}
179
- // hidden={
180
- // props?.hidden || element.hiddenFields.includes(fieldName)
181
- // ? true
182
- // : false
183
- // }
184
157
  value={formValues[fieldName]}
185
158
  checkedValue={props?.checkedValue || true}
186
159
  unCheckedValue={props?.unCheckedValue || false}
187
- disabled={
188
- props?.disabled || element.disabledFields.includes(fieldName)
189
- ? true
190
- : false
191
- }
160
+ disabled={element.disabledFields.includes(fieldName)}
161
+ hidden={element.hiddenFields.includes(fieldName)}
192
162
  sx={props?.formProps?.style}
193
163
  />
194
164
  ) : props?.fieldType === "combobox" ? (
195
165
  <ComboBox
196
166
  sx={props?.formProps?.style || { width: "100%" }}
197
167
  label={getFieldLabel()}
198
- disabled={
199
- props?.disabled || element.disabledFields.includes(fieldName)
200
- ? true
201
- : false
202
- }
203
- // hidden={
204
- // props?.hidden || element.hiddenFields.includes(fieldName)
205
- // ? true
206
- // : false
207
- // }
168
+ disabled={element.disabledFields.includes(fieldName)}
169
+ hidden={element.hiddenFields.includes(fieldName)}
208
170
  onChangeCallBack={(v: any, selectedRecord: any) => {
209
171
  let newValue = null;
210
172
  if (v) {
@@ -234,16 +196,8 @@ const FormElementField: React.FC<FormElementFieldProps> = (
234
196
  <SystemLookupCombobox
235
197
  sx={props?.formProps?.style || { width: "100%" }}
236
198
  label={getFieldLabel()}
237
- disabled={
238
- props?.disabled || element.disabledFields.includes(fieldName)
239
- ? true
240
- : false
241
- }
242
- // hidden={
243
- // props?.hidden || element.hiddenFields.includes(fieldName)
244
- // ? true
245
- // : false
246
- // }
199
+ disabled={element.disabledFields.includes(fieldName)}
200
+ hidden={element.hiddenFields.includes(fieldName)}
247
201
  onChangeCallBack={(v: any, selectedRecord: any) => {
248
202
  let newValue = null;
249
203
  if (v) {
@@ -269,8 +223,6 @@ const FormElementField: React.FC<FormElementFieldProps> = (
269
223
  />
270
224
  ) : null}
271
225
  </Grid2>
272
- ) : (
273
- <></>
274
226
  );
275
227
  } else {
276
228
  return <></>;
@@ -8,6 +8,7 @@ const TemplateTextField: React.FC<Omit<TextFieldProps, "outlined">> = (
8
8
  return (
9
9
  <TextField
10
10
  {...props}
11
+ hidden={true}
11
12
  slotProps={{ inputLabel: { shrink: true, sx: { fontWeight: "bold" } } }}
12
13
  label={<>{props?.label ? t(props.label) : ""}</>}
13
14
  helperText={props?.helperText ? t(props.helperText) : undefined}
@@ -45,13 +45,20 @@ const TemplateForm: React.FC<TemplateFormProps> = (
45
45
  const [attachmentPanelEnabledForRecord, setAttachmentPanelEnabledForRecord] =
46
46
  useState<boolean>(true);
47
47
  const { t } = useTranslation();
48
- const fields = getAllFields(props.elements);
48
+ const fields = getAllFields(props.elements);
49
49
  const initiallyHiddenFields = [];
50
+ const initiallyDisabledFields = [];
50
51
  for (const field of fields) {
51
52
  if (field?.hidden) {
52
53
  initiallyHiddenFields.push(field.fieldName);
53
54
  }
55
+ if (field?.disabled) {
56
+ initiallyDisabledFields.push(field.fieldName);
57
+ }
54
58
  }
59
+ const [disabledFields, setDisabledFields] = useState<string[]>(
60
+ initiallyDisabledFields
61
+ );
55
62
  const [hiddenFields, setHiddenFields] = useState<string[]>(
56
63
  initiallyHiddenFields
57
64
  );
@@ -65,7 +72,7 @@ const TemplateForm: React.FC<TemplateFormProps> = (
65
72
  initialValues[element.props.fieldName] = element.props.defaultValue;
66
73
  }
67
74
  }
68
- const [disabledFields, setDisabledFields] = useState<string[]>([]);
75
+
69
76
  let formSchema = null;
70
77
  if (props?.validationSchema) {
71
78
  formSchema = props.validationSchema;
package/src/main.tsx CHANGED
@@ -8,11 +8,11 @@ createRoot(document.getElementById("root")!).render(
8
8
  appLogo={"/logo.png"}
9
9
  appName="UI Base Library"
10
10
  loginScreenStyle={{
11
- themeMode: "light",
11
+ themeMode: "dark",
12
12
  backgroundImageNameInPublicFolder: "bg.jpg",
13
13
  }}
14
14
  appVersion="0.0"
15
- authenticationMethod="APP"
15
+ authenticationMethod="AZURE"
16
16
  azureConfiguration={{
17
17
  frontEndClientId: "c3bbbdbd-f392-4459-b3dd-2351cb07f924",
18
18
  tenantId: "9f136fef-4529-475f-98e6-d271eb04eb00",
@@ -145,4 +145,9 @@ export const ADMINISTRATION_STORES: CommonStores = {
145
145
  authority: "SYSTEM_ADMIN",
146
146
  url: "api/v1/admin/systemapplicationrole/all",
147
147
  },
148
+ persons: {
149
+ autoLoad: true,
150
+ data: [],
151
+ url: "api/v1/public/person/all",
152
+ },
148
153
  };