@asaleh37/ui-base 25.8.31 → 25.9.3
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/dist/index.d.ts +15 -1
- package/dist/index.js +134 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +134 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
- package/src/components/App.tsx +16 -1
- package/src/components/common/AzureLogin.tsx +70 -0
- package/src/components/common/Login.tsx +102 -75
- package/src/components/msalConfig.ts +11 -0
- package/src/hooks/useAxios.tsx +1 -0
- package/src/layout/Layout.tsx +14 -3
- package/src/layout/MainContent.tsx +0 -5
- package/src/layout/TopBar.tsx +2 -1
- package/src/main.tsx +11 -0
- package/src/navigationItems/index.tsx +1 -8
- package/src/redux/features/common/AppInfoSlice.ts +13 -0
- package/src/routes/index.ts +2 -6
- package/src/util/AppUtils.ts +18 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asaleh37/ui-base",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.9.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Ahmed Saleh Mohamed",
|
|
@@ -113,7 +113,9 @@
|
|
|
113
113
|
"stylis-plugin-rtl": "^2.1.1",
|
|
114
114
|
"zod": "^3.24.2"
|
|
115
115
|
},
|
|
116
|
-
"dependencies": {
|
|
116
|
+
"dependencies": {
|
|
117
|
+
"@azure/msal-browser": "^4.21.1",
|
|
118
|
+
"@azure/msal-react": "^3.0.19",
|
|
117
119
|
"@rollup/plugin-json": "^6.1.0",
|
|
118
120
|
"rollup-plugin-terser": "^7.0.2"
|
|
119
121
|
}
|
package/src/components/App.tsx
CHANGED
|
@@ -13,9 +13,18 @@ import {
|
|
|
13
13
|
} from "../util";
|
|
14
14
|
import { setStoresMetaData } from "../redux/features/common/CommonStoreSlice";
|
|
15
15
|
import { ADMINISTRATION_STORES } from "../redux/features/administration/AdministrationStoresMetaData";
|
|
16
|
+
import { PublicClientApplication } from "@azure/msal-browser";
|
|
17
|
+
import { MsalProvider } from "@azure/msal-react";
|
|
16
18
|
|
|
17
19
|
const App: React.FC<AppInfo> = (props: AppInfo) => {
|
|
18
20
|
const dispatch = useDispatch();
|
|
21
|
+
const msalInstance = new PublicClientApplication({
|
|
22
|
+
auth: {
|
|
23
|
+
clientId: props?.azureConfiguration?.frontEndClientId,
|
|
24
|
+
authority: `https://login.microsoftonline.com/${props?.azureConfiguration?.tenantId}`,
|
|
25
|
+
redirectUri: props?.azureConfiguration?.redirectURL,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
19
28
|
LicenseInfo.setLicenseKey(props.muiPremiumKey);
|
|
20
29
|
const LightThemeOptions: ThemeOptions = {
|
|
21
30
|
components: {
|
|
@@ -115,7 +124,13 @@ const App: React.FC<AppInfo> = (props: AppInfo) => {
|
|
|
115
124
|
}, [props]);
|
|
116
125
|
return (
|
|
117
126
|
<ThemeProvider theme={theme}>
|
|
118
|
-
|
|
127
|
+
{props?.authenticationMethod === "AZURE" ? (
|
|
128
|
+
<MsalProvider instance={msalInstance}>
|
|
129
|
+
<Layout msalInstance={msalInstance} />
|
|
130
|
+
</MsalProvider>
|
|
131
|
+
) : (
|
|
132
|
+
<Layout msalInstance={msalInstance} />
|
|
133
|
+
)}
|
|
119
134
|
</ThemeProvider>
|
|
120
135
|
);
|
|
121
136
|
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { PublicClientApplication } from "@azure/msal-browser";
|
|
2
|
+
import { Box, Button } from "@mui/material";
|
|
3
|
+
import { useDispatch, useSelector } from "react-redux";
|
|
4
|
+
import { AppInfo } from "../../redux/features/common/AppInfoSlice";
|
|
5
|
+
import { useAxios } from "../../hooks";
|
|
6
|
+
import { UserSessionActions } from "../../redux/features/common/UserSessionSlice";
|
|
7
|
+
import { useEffect } from "react";
|
|
8
|
+
|
|
9
|
+
interface AzureLoginProps {
|
|
10
|
+
msalInstance: PublicClientApplication;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const AzureLogin: React.FC<AzureLoginProps> = ({ msalInstance }) => {
|
|
14
|
+
const appInfo: AppInfo = useSelector((state: any) => state.AppInfo.value);
|
|
15
|
+
const userSession = useSelector((state: any) => state.UserSession.value);
|
|
16
|
+
const { handleGetRequest } = useAxios();
|
|
17
|
+
const dispatch = useDispatch();
|
|
18
|
+
const checkUserSession = async () => {
|
|
19
|
+
if (appInfo?.apiBaseUrl) {
|
|
20
|
+
if (userSession.isAuthenticated == null) {
|
|
21
|
+
const token = localStorage.getItem("TOKEN");
|
|
22
|
+
handleGetRequest({
|
|
23
|
+
endPointURI: "api/auth/userInfo",
|
|
24
|
+
showMask: true,
|
|
25
|
+
successCallBkFn: (response) => {
|
|
26
|
+
if (response != null && response.data != null) {
|
|
27
|
+
const UserSession = {
|
|
28
|
+
...response.data,
|
|
29
|
+
isAuthenticated: true,
|
|
30
|
+
};
|
|
31
|
+
dispatch(UserSessionActions.setAuthenticated(UserSession));
|
|
32
|
+
} else {
|
|
33
|
+
dispatch(UserSessionActions.setUnAuthenticated());
|
|
34
|
+
localStorage.removeItem("TOKEN");
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const handleLogin = async () => {
|
|
42
|
+
const response = await msalInstance.acquireTokenPopup({
|
|
43
|
+
scopes: appInfo?.azureConfiguration?.scopes,
|
|
44
|
+
});
|
|
45
|
+
if (response?.accessToken) {
|
|
46
|
+
localStorage.setItem("TOKEN", response.accessToken);
|
|
47
|
+
checkUserSession();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
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
|
+
};
|
|
59
|
+
|
|
60
|
+
// useEffect(()=>{
|
|
61
|
+
// handleLogin()
|
|
62
|
+
// },[])
|
|
63
|
+
return (
|
|
64
|
+
<Box>
|
|
65
|
+
<Button onClick={handleLogin}>Azure Login </Button>
|
|
66
|
+
</Box>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default AzureLogin;
|
|
@@ -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
|
|
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
|
|
100
|
-
|
|
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
|
});
|
|
@@ -121,6 +131,7 @@ const Login: React.FC = () => {
|
|
|
121
131
|
dispatch(UserSessionActions.setAuthenticated(UserSession));
|
|
122
132
|
} else {
|
|
123
133
|
dispatch(UserSessionActions.setUnAuthenticated());
|
|
134
|
+
localStorage.removeItem("TOKEN");
|
|
124
135
|
}
|
|
125
136
|
} catch (error) {
|
|
126
137
|
dispatch(UserSessionActions.setUnAuthenticated());
|
|
@@ -136,85 +147,101 @@ const Login: React.FC = () => {
|
|
|
136
147
|
|
|
137
148
|
return (
|
|
138
149
|
<ThemeProvider theme={loginTheme}>
|
|
139
|
-
<
|
|
150
|
+
<Box
|
|
140
151
|
sx={{
|
|
141
|
-
|
|
142
|
-
height: "100vh",
|
|
152
|
+
minHeight: "100vh", // full page height
|
|
143
153
|
width: "100%",
|
|
144
|
-
|
|
154
|
+
display: "flex",
|
|
145
155
|
alignItems: "center",
|
|
146
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
|
|
147
162
|
}}
|
|
148
163
|
>
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
<Typography
|
|
164
|
+
<Paper
|
|
165
|
+
sx={{
|
|
166
|
+
display: "flex",
|
|
167
|
+
width: "fit-content",
|
|
168
|
+
padding: 2,
|
|
169
|
+
height: "fit-content",
|
|
170
|
+
borderRadius: 5,
|
|
171
|
+
alignItems: "center",
|
|
172
|
+
justifyContent: "center",
|
|
173
|
+
}}
|
|
174
|
+
>
|
|
175
|
+
{UserSessionState.isAuthenticated == false ? (
|
|
176
|
+
<Box
|
|
163
177
|
sx={{
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}}
|
|
169
|
-
variant="caption"
|
|
170
|
-
color="textSecondary"
|
|
171
|
-
>
|
|
172
|
-
V.{appInfo.appVersion}
|
|
173
|
-
</Typography>
|
|
174
|
-
<TextField
|
|
175
|
-
label="username"
|
|
176
|
-
sx={{ width: 300, m: 1 }}
|
|
177
|
-
value={username}
|
|
178
|
-
onChange={(event) => {
|
|
179
|
-
setUsername(event.target.value);
|
|
180
|
-
}}
|
|
181
|
-
onKeyDown={(event) => {
|
|
182
|
-
if (event.key === "Enter") {
|
|
183
|
-
handleLogin();
|
|
184
|
-
}
|
|
185
|
-
}}
|
|
186
|
-
/>
|
|
187
|
-
<TextField
|
|
188
|
-
label="password"
|
|
189
|
-
sx={{ width: 300, m: 1 }}
|
|
190
|
-
value={password}
|
|
191
|
-
type="password"
|
|
192
|
-
onChange={(event) => {
|
|
193
|
-
setPassword(event.target.value);
|
|
194
|
-
}}
|
|
195
|
-
onKeyDown={(event) => {
|
|
196
|
-
if (event.key === "Enter") {
|
|
197
|
-
handleLogin();
|
|
198
|
-
}
|
|
178
|
+
display: "flex",
|
|
179
|
+
flexDirection: "column",
|
|
180
|
+
alignItems: "center",
|
|
181
|
+
justifyContent: "center",
|
|
199
182
|
}}
|
|
200
|
-
/>
|
|
201
|
-
<Button
|
|
202
|
-
loading={isLoginInProcess}
|
|
203
|
-
onClick={handleLogin}
|
|
204
|
-
variant="contained"
|
|
205
|
-
color="primary"
|
|
206
|
-
sx={{ m: 1 }}
|
|
207
183
|
>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
184
|
+
<img src={appInfo?.appLogo} width={150} height={150} />
|
|
185
|
+
<Typography sx={{ m: 1 }} variant="h4" color="textSecondary">
|
|
186
|
+
{appInfo?.appName}
|
|
187
|
+
</Typography>
|
|
188
|
+
<Typography
|
|
189
|
+
sx={{
|
|
190
|
+
paddingRight: 1,
|
|
191
|
+
width: "100%",
|
|
192
|
+
textAlign: "right",
|
|
193
|
+
fontSize: 10,
|
|
194
|
+
}}
|
|
195
|
+
variant="caption"
|
|
196
|
+
color="textSecondary"
|
|
197
|
+
>
|
|
198
|
+
V.{appInfo.appVersion}
|
|
199
|
+
</Typography>
|
|
200
|
+
<TextField
|
|
201
|
+
label="username"
|
|
202
|
+
sx={{ width: 300, m: 1 }}
|
|
203
|
+
value={username}
|
|
204
|
+
onChange={(event) => {
|
|
205
|
+
setUsername(event.target.value);
|
|
206
|
+
}}
|
|
207
|
+
onKeyDown={(event) => {
|
|
208
|
+
if (event.key === "Enter") {
|
|
209
|
+
handleLogin();
|
|
210
|
+
}
|
|
211
|
+
}}
|
|
212
|
+
/>
|
|
213
|
+
<TextField
|
|
214
|
+
label="password"
|
|
215
|
+
sx={{ width: 300, m: 1 }}
|
|
216
|
+
value={password}
|
|
217
|
+
type="password"
|
|
218
|
+
onChange={(event) => {
|
|
219
|
+
setPassword(event.target.value);
|
|
220
|
+
}}
|
|
221
|
+
onKeyDown={(event) => {
|
|
222
|
+
if (event.key === "Enter") {
|
|
223
|
+
handleLogin();
|
|
224
|
+
}
|
|
225
|
+
}}
|
|
226
|
+
/>
|
|
227
|
+
<Button
|
|
228
|
+
loading={isLoginInProcess}
|
|
229
|
+
onClick={handleLogin}
|
|
230
|
+
variant="contained"
|
|
231
|
+
color="primary"
|
|
232
|
+
sx={{ m: 1 }}
|
|
233
|
+
>
|
|
234
|
+
login
|
|
235
|
+
</Button>
|
|
236
|
+
</Box>
|
|
237
|
+
) : (
|
|
238
|
+
<>
|
|
239
|
+
<CircularProgress sx={{ marginRight: 1 }} />
|
|
240
|
+
<div>You will be redirected shortly ... please wait</div>
|
|
241
|
+
</>
|
|
242
|
+
)}
|
|
243
|
+
</Paper>
|
|
244
|
+
</Box>
|
|
218
245
|
</ThemeProvider>
|
|
219
246
|
);
|
|
220
247
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PublicClientApplication } from "@azure/msal-browser";
|
|
2
|
+
|
|
3
|
+
export const msalConfig = {
|
|
4
|
+
auth: {
|
|
5
|
+
clientId: "your-frontend-client-id",
|
|
6
|
+
authority: "https://login.microsoftonline.com/<tenant-id>",
|
|
7
|
+
redirectUri: "http://localhost:3000"
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const msalInstance = new PublicClientApplication(msalConfig);
|
package/src/hooks/useAxios.tsx
CHANGED
package/src/layout/Layout.tsx
CHANGED
|
@@ -14,6 +14,9 @@ import { UserSessionProps } from "../redux/features/common/UserSessionSlice";
|
|
|
14
14
|
import LoadingMask from "../components/common/LoadingMask";
|
|
15
15
|
import Login from "../components/common/Login";
|
|
16
16
|
import NoLicenseComponent from "../components/common/NoLicenseComponent";
|
|
17
|
+
import { msalInstance } from "../components/msalConfig";
|
|
18
|
+
import { PublicClientApplication } from "@azure/msal-browser";
|
|
19
|
+
import AzureLogin from "../components/common/AzureLogin";
|
|
17
20
|
|
|
18
21
|
const Main = styled("main", {
|
|
19
22
|
shouldForwardProp: (prop) => prop !== "open",
|
|
@@ -53,9 +56,13 @@ const Main = styled("main", {
|
|
|
53
56
|
};
|
|
54
57
|
});
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
interface LayoutProps {
|
|
60
|
+
msalInstance: PublicClientApplication;
|
|
61
|
+
}
|
|
58
62
|
|
|
63
|
+
const Layout: React.FC<LayoutProps> = ({ msalInstance }) => {
|
|
64
|
+
const SideBarState = useSelector((state: any) => state.SideBar);
|
|
65
|
+
const appInfo = useSelector((state: any) => state.AppInfo.value);
|
|
59
66
|
const isMobile = useIsMobile();
|
|
60
67
|
const UserSession: UserSessionProps = useSelector(
|
|
61
68
|
(state: any) => state.UserSession
|
|
@@ -80,9 +87,13 @@ export default function Layout() {
|
|
|
80
87
|
<MainContent />
|
|
81
88
|
<NoLicenseComponent />
|
|
82
89
|
</Main>
|
|
90
|
+
) : appInfo.authenticationMethod === "AZURE" ? (
|
|
91
|
+
<AzureLogin msalInstance={msalInstance} />
|
|
83
92
|
) : (
|
|
84
93
|
<Login />
|
|
85
94
|
)}
|
|
86
95
|
</BrowserRouter>
|
|
87
96
|
);
|
|
88
|
-
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export default Layout;
|
package/src/layout/TopBar.tsx
CHANGED
|
@@ -102,6 +102,7 @@ const TopBar: React.FC = () => {
|
|
|
102
102
|
await handleGetRequest({ endPointURI: "api/auth/logout" });
|
|
103
103
|
} catch (error) {}
|
|
104
104
|
dispatch(UserSessionActions.setUnAuthenticated());
|
|
105
|
+
localStorage.removeItem("TOKEN");
|
|
105
106
|
};
|
|
106
107
|
const toggleSideBar = () => {
|
|
107
108
|
dispatch(toggleSideBarState());
|
|
@@ -169,7 +170,7 @@ const TopBar: React.FC = () => {
|
|
|
169
170
|
<AttachmentImageViewer
|
|
170
171
|
showAsAvatar={true}
|
|
171
172
|
attachmentCode="ORGANIZATION_LOGOS"
|
|
172
|
-
refKey={UserSession
|
|
173
|
+
refKey={UserSession?.value?.currentOrganization?.id + ""}
|
|
173
174
|
onErrorImage="/logo.png"
|
|
174
175
|
style={{
|
|
175
176
|
marginRight: 1,
|
package/src/main.tsx
CHANGED
|
@@ -7,7 +7,18 @@ createRoot(document.getElementById("root")!).render(
|
|
|
7
7
|
enableUINotifications={false}
|
|
8
8
|
appLogo={"/logo.png"}
|
|
9
9
|
appName="UI Base Library"
|
|
10
|
+
loginScreenStyle={{
|
|
11
|
+
themeMode: "light",
|
|
12
|
+
backgroundImageNameInPublicFolder: "bg.jpg",
|
|
13
|
+
}}
|
|
10
14
|
appVersion="0.0"
|
|
15
|
+
authenticationMethod="APP"
|
|
16
|
+
azureConfiguration={{
|
|
17
|
+
frontEndClientId: "c3bbbdbd-f392-4459-b3dd-2351cb07f924",
|
|
18
|
+
tenantId: "9f136fef-4529-475f-98e6-d271eb04eb00",
|
|
19
|
+
redirectURL: "http://localhost:3000",
|
|
20
|
+
scopes: ["api://6008a934-2a32-4776-a3df-1842ac9371da/access_as_user"],
|
|
21
|
+
}}
|
|
11
22
|
businessCommonStoresMetaData={{}}
|
|
12
23
|
businessNavigationItems={[]}
|
|
13
24
|
businessReduxReducers={{}}
|
|
@@ -31,12 +31,5 @@ export const findNavigationItemById = (
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export const NavigationItems: TreeViewBaseItem<ExtendedTreeItemProps>[] = [
|
|
34
|
-
...AdministrationItems
|
|
35
|
-
{
|
|
36
|
-
icon: "user",
|
|
37
|
-
label: "Example Grid",
|
|
38
|
-
id: "example",
|
|
39
|
-
action: "NAVIGATION",
|
|
40
|
-
actionPayload: { path: "example" },
|
|
41
|
-
},
|
|
34
|
+
...AdministrationItems
|
|
42
35
|
];
|
|
@@ -19,6 +19,18 @@ 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
|
+
};
|
|
27
|
+
authenticationMethod: "AZURE" | "APP";
|
|
28
|
+
azureConfiguration?: {
|
|
29
|
+
frontEndClientId: string;
|
|
30
|
+
tenantId: string;
|
|
31
|
+
redirectURL: string;
|
|
32
|
+
scopes: Array<string>;
|
|
33
|
+
};
|
|
22
34
|
businessRoutes?: Array<SystemRoute>;
|
|
23
35
|
businessNavigationItems?: Array<ExtendedTreeItemProps>;
|
|
24
36
|
businessReduxReducers?: { [key: string]: Reducer<any> };
|
|
@@ -41,6 +53,7 @@ const initialState: AppInfoProp = {
|
|
|
41
53
|
value: {
|
|
42
54
|
documentTitle: null,
|
|
43
55
|
apiBaseUrl: null,
|
|
56
|
+
authenticationMethod: "APP",
|
|
44
57
|
appName: null,
|
|
45
58
|
appVersion: null,
|
|
46
59
|
appLogo: null,
|
package/src/routes/index.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import ExampleGrid from "../examples/ExampleGrid";
|
|
1
|
+
|
|
3
2
|
import { ADMINISTRATION_ROUTES } from "./administration";
|
|
4
3
|
import { SystemRoute } from "./types";
|
|
5
4
|
|
|
6
|
-
export const SYSTEM_ROUTES: Array<SystemRoute> = [
|
|
7
|
-
...ADMINISTRATION_ROUTES,
|
|
8
|
-
{ path: "example", component: ExampleGrid },
|
|
9
|
-
];
|
|
5
|
+
export const SYSTEM_ROUTES: Array<SystemRoute> = [...ADMINISTRATION_ROUTES];
|
package/src/util/AppUtils.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import moment from "moment";
|
|
1
2
|
import { FormElementProps } from "../components";
|
|
3
|
+
import { DATE_FORMAT } from "./constants";
|
|
2
4
|
|
|
3
5
|
export function hasDigitsOnly(str: string) {
|
|
4
6
|
return /^\d+$/.test(str);
|
|
@@ -53,3 +55,19 @@ export function timeAgo(dateInput, appDirection: "ltr" | "rtl") {
|
|
|
53
55
|
|
|
54
56
|
return locale === "ar" ? "الآن" : "just now";
|
|
55
57
|
}
|
|
58
|
+
|
|
59
|
+
export const formatDate = (date, format) => {
|
|
60
|
+
if (format) {
|
|
61
|
+
return moment(date).format(format);
|
|
62
|
+
} else {
|
|
63
|
+
return moment(date).format(DATE_FORMAT);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const parseStringToDate = (dateString, format) => {
|
|
68
|
+
if (format) {
|
|
69
|
+
return moment(dateString, format).toDate();
|
|
70
|
+
} else {
|
|
71
|
+
return moment(dateString, DATE_FORMAT).toDate();
|
|
72
|
+
}
|
|
73
|
+
};
|