@campxdev/campx-web-utils 0.1.10 → 0.1.11
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/exports.ts +1 -0
- package/package.json +7 -3
- package/src/ErrorBoundary/ErrorBoundary.tsx +21 -7
- package/src/ErrorBoundary/Login.tsx +194 -0
package/exports.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@campxdev/campx-web-utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"main": "./exports.ts",
|
|
5
5
|
"private": false,
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@campxdev/react-blueprint": "^1.
|
|
7
|
+
"@campxdev/react-blueprint": "^1.1.2",
|
|
8
|
+
"@hookform/resolvers": "^3.9.0",
|
|
8
9
|
"@mui/x-date-pickers": "^7.11.0",
|
|
9
10
|
"@testing-library/jest-dom": "^5.14.1",
|
|
10
11
|
"@testing-library/react": "^13.0.0",
|
|
@@ -15,14 +16,17 @@
|
|
|
15
16
|
"@types/react-dom": "^18.0.0",
|
|
16
17
|
"axios": "^1.7.2",
|
|
17
18
|
"cookie-js": "^0.0.1",
|
|
19
|
+
"device-detector-js": "^3.0.3",
|
|
18
20
|
"pullstate": "^1.25.0",
|
|
19
21
|
"react": "^18.3.1",
|
|
20
22
|
"react-dom": "^18.3.1",
|
|
23
|
+
"react-hook-form": "^7.52.1",
|
|
21
24
|
"react-query": "^3.39.3",
|
|
22
25
|
"react-scripts": "5.0.1",
|
|
23
26
|
"react-toastify": "^9.0.1",
|
|
24
27
|
"typescript": "^4.4.2",
|
|
25
|
-
"web-vitals": "^2.1.0"
|
|
28
|
+
"web-vitals": "^2.1.0",
|
|
29
|
+
"yup": "^1.4.0"
|
|
26
30
|
},
|
|
27
31
|
"devDependencies": {
|
|
28
32
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Button,
|
|
3
|
+
CustomDialog,
|
|
3
4
|
InternalServerError,
|
|
4
5
|
NoInterneConnection,
|
|
6
|
+
PageNotFound,
|
|
5
7
|
UnAuthorized,
|
|
6
8
|
} from "@campxdev/react-blueprint";
|
|
7
9
|
import { Alert, Box, styled } from "@mui/material";
|
|
8
10
|
import Cookies from "js-cookie";
|
|
9
|
-
import { ReactNode } from "react";
|
|
11
|
+
import { ReactNode, useState } from "react";
|
|
10
12
|
import { ErrorBoundary as ReactErrorBoundary } from "react-error-boundary";
|
|
11
13
|
import { QueryErrorResetBoundary } from "react-query";
|
|
12
14
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
13
15
|
import { axios } from "../config/axios";
|
|
16
|
+
import { Login } from "./Login";
|
|
14
17
|
|
|
15
18
|
export type ErrorBoundaryProps = {
|
|
16
19
|
children: ReactNode;
|
|
@@ -55,14 +58,15 @@ export const ErrorBoundary = (props: ErrorBoundaryProps) => {
|
|
|
55
58
|
};
|
|
56
59
|
|
|
57
60
|
export const ErrorFallback = ({ error, resetErrorBoundary }: any) => {
|
|
58
|
-
console.log(error, "llll");
|
|
59
61
|
if (error?.response?.status) {
|
|
60
62
|
switch (error?.response?.status) {
|
|
61
63
|
case 401:
|
|
62
|
-
return <UnAuth
|
|
64
|
+
return <UnAuth />;
|
|
63
65
|
|
|
64
66
|
case 500:
|
|
65
67
|
return <InternalServerError resetBoundary={resetErrorBoundary} />;
|
|
68
|
+
case 404:
|
|
69
|
+
return <PageNotFound />;
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -88,8 +92,9 @@ export const ErrorFallback = ({ error, resetErrorBoundary }: any) => {
|
|
|
88
92
|
);
|
|
89
93
|
};
|
|
90
94
|
|
|
91
|
-
const UnAuth = (
|
|
95
|
+
const UnAuth = () => {
|
|
92
96
|
const navigate = useNavigate();
|
|
97
|
+
const [isModalOpen, setModalOpen] = useState(false);
|
|
93
98
|
|
|
94
99
|
const sessionCookie = Cookies.get("campx_session_key");
|
|
95
100
|
|
|
@@ -100,10 +105,14 @@ const UnAuth = ({ resetBoundary }: any) => {
|
|
|
100
105
|
};
|
|
101
106
|
|
|
102
107
|
const handleLoginClick = () => {
|
|
103
|
-
if (
|
|
104
|
-
|
|
108
|
+
if (window.location.hostname == "localhost") {
|
|
109
|
+
setModalOpen(true);
|
|
105
110
|
} else {
|
|
106
|
-
|
|
111
|
+
if (!sessionCookie) {
|
|
112
|
+
navigate("/auth/login");
|
|
113
|
+
} else {
|
|
114
|
+
appinit();
|
|
115
|
+
}
|
|
107
116
|
}
|
|
108
117
|
};
|
|
109
118
|
|
|
@@ -120,6 +129,11 @@ const UnAuth = ({ resetBoundary }: any) => {
|
|
|
120
129
|
>
|
|
121
130
|
Click Here To Login
|
|
122
131
|
</Button>
|
|
132
|
+
<CustomDialog
|
|
133
|
+
open={isModalOpen}
|
|
134
|
+
onClose={() => setModalOpen(false)}
|
|
135
|
+
content={({ close }) => <Login close={close} />}
|
|
136
|
+
/>
|
|
123
137
|
</>
|
|
124
138
|
}
|
|
125
139
|
/>
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { axios } from "@campxdev/campx-web-utils";
|
|
2
|
+
import { Button, Icons, TextField } from "@campxdev/react-blueprint";
|
|
3
|
+
import { yupResolver } from "@hookform/resolvers/yup";
|
|
4
|
+
import { Box, Stack } from "@mui/material";
|
|
5
|
+
import DeviceDetector from "device-detector-js";
|
|
6
|
+
import Cookies from "js-cookie";
|
|
7
|
+
import { useEffect, useState } from "react";
|
|
8
|
+
import { Controller, useForm } from "react-hook-form";
|
|
9
|
+
import { useMutation } from "react-query";
|
|
10
|
+
|
|
11
|
+
import * as Yup from "yup";
|
|
12
|
+
|
|
13
|
+
type DeviceInformation = {
|
|
14
|
+
deviceType: string;
|
|
15
|
+
clientName: string;
|
|
16
|
+
os: string;
|
|
17
|
+
osVersion: string;
|
|
18
|
+
latitude: number | null;
|
|
19
|
+
longitude: number | null;
|
|
20
|
+
tokenType: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type DeviceState = {
|
|
24
|
+
deviceInformation: DeviceInformation;
|
|
25
|
+
isLocationAllowed: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const performLogin = async (body: any) => {
|
|
29
|
+
if (!body.latitude || !body.longitude) {
|
|
30
|
+
const response = await fetch(
|
|
31
|
+
"https://www.googleapis.com/geolocation/v1/geolocate?key=AIzaSyB2YCpo1yi107RYj1LdZu2DCcpcO93reFY",
|
|
32
|
+
{
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify({
|
|
38
|
+
considerIp: "true",
|
|
39
|
+
}),
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
body.latitude = data.location.lat;
|
|
44
|
+
body.longitude = data.location.lng;
|
|
45
|
+
}
|
|
46
|
+
return axios.post(`/auth-server/auth/login`, body).then((res) => res.data);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const validationSchema = Yup.object().shape({
|
|
50
|
+
username: Yup.string().required("Username is required"),
|
|
51
|
+
password: Yup.string().required("Password is required"),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const Login = ({ close }: { close: () => void }) => {
|
|
55
|
+
const [deviceState, setDeviceState] = useState<DeviceState>({
|
|
56
|
+
deviceInformation: {
|
|
57
|
+
deviceType: "browser",
|
|
58
|
+
clientName: "unknown",
|
|
59
|
+
os: "unknown",
|
|
60
|
+
osVersion: "unknown",
|
|
61
|
+
latitude: null,
|
|
62
|
+
longitude: null,
|
|
63
|
+
tokenType: "WEB",
|
|
64
|
+
},
|
|
65
|
+
isLocationAllowed: true,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
navigator.geolocation.getCurrentPosition((position) => {
|
|
70
|
+
setDeviceState((s) => ({
|
|
71
|
+
...s,
|
|
72
|
+
deviceInformation: {
|
|
73
|
+
...s.deviceInformation,
|
|
74
|
+
latitude: position.coords.latitude,
|
|
75
|
+
longitude: position.coords.longitude,
|
|
76
|
+
},
|
|
77
|
+
}));
|
|
78
|
+
});
|
|
79
|
+
navigator.permissions
|
|
80
|
+
.query({ name: "geolocation" })
|
|
81
|
+
.then((permissionStatus) => {
|
|
82
|
+
if (permissionStatus.state === "denied") {
|
|
83
|
+
setDeviceState((s) => ({
|
|
84
|
+
...s,
|
|
85
|
+
isLocationAllowed: false,
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const detector = new DeviceDetector();
|
|
91
|
+
const deviceInfo = detector.parse(navigator.userAgent);
|
|
92
|
+
setDeviceState((s) => ({
|
|
93
|
+
...s,
|
|
94
|
+
deviceInformation: {
|
|
95
|
+
...s.deviceInformation,
|
|
96
|
+
clientName: deviceInfo.client?.name || s.deviceInformation.clientName,
|
|
97
|
+
os: deviceInfo.os?.name || s.deviceInformation.os,
|
|
98
|
+
osVersion: deviceInfo.os?.version || s.deviceInformation.osVersion,
|
|
99
|
+
},
|
|
100
|
+
}));
|
|
101
|
+
}, []);
|
|
102
|
+
|
|
103
|
+
const {
|
|
104
|
+
handleSubmit,
|
|
105
|
+
control,
|
|
106
|
+
formState: { errors },
|
|
107
|
+
} = useForm({ resolver: yupResolver(validationSchema) });
|
|
108
|
+
|
|
109
|
+
const { mutate, isLoading } = useMutation(performLogin, {
|
|
110
|
+
onSuccess(data) {
|
|
111
|
+
if (data.loginSuccessful) {
|
|
112
|
+
Cookies.remove("campx_session_key");
|
|
113
|
+
Cookies.remove("campx_tenant");
|
|
114
|
+
Cookies.remove("campx_institution");
|
|
115
|
+
Cookies.set("campx_session_key", data?.token);
|
|
116
|
+
Cookies.set("campx_tenant", data?.subDomain);
|
|
117
|
+
Cookies.set("campx_institution", data?.institutionCode);
|
|
118
|
+
close();
|
|
119
|
+
window.location.reload();
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
const onSubmit = async (body: any) => {
|
|
124
|
+
mutate({ ...body, ...deviceState.deviceInformation });
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<>
|
|
129
|
+
<Stack gap="16px" justifyContent="space-between" alignItems="center">
|
|
130
|
+
<Box height="36px" width="194.8px">
|
|
131
|
+
<Icons.CampxFullLogoIcon />
|
|
132
|
+
</Box>
|
|
133
|
+
<Stack gap="10px" justifyContent="center" alignItems="center">
|
|
134
|
+
<Controller
|
|
135
|
+
control={control}
|
|
136
|
+
render={({ field }: { field: any }) => {
|
|
137
|
+
return (
|
|
138
|
+
<TextField
|
|
139
|
+
size="medium"
|
|
140
|
+
name="username"
|
|
141
|
+
sx={{
|
|
142
|
+
width: "400px",
|
|
143
|
+
}}
|
|
144
|
+
placeholder="Enter Username or Email"
|
|
145
|
+
containerProps={{ my: "0" }}
|
|
146
|
+
onChange={field.onChange}
|
|
147
|
+
label="Username or Email"
|
|
148
|
+
error={!!errors.username}
|
|
149
|
+
required
|
|
150
|
+
/>
|
|
151
|
+
);
|
|
152
|
+
}}
|
|
153
|
+
name="username"
|
|
154
|
+
/>
|
|
155
|
+
<Controller
|
|
156
|
+
control={control}
|
|
157
|
+
render={({ field }: { field: any }) => {
|
|
158
|
+
return (
|
|
159
|
+
<TextField
|
|
160
|
+
size="medium"
|
|
161
|
+
name="password"
|
|
162
|
+
sx={{
|
|
163
|
+
width: "400px",
|
|
164
|
+
}}
|
|
165
|
+
placeholder="Enter password"
|
|
166
|
+
onChange={field.onChange}
|
|
167
|
+
containerProps={{ my: "0" }}
|
|
168
|
+
label="Password"
|
|
169
|
+
type="password"
|
|
170
|
+
error={!!errors.password}
|
|
171
|
+
required
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
}}
|
|
175
|
+
name="password"
|
|
176
|
+
/>
|
|
177
|
+
<Button
|
|
178
|
+
type="submit"
|
|
179
|
+
color="primary"
|
|
180
|
+
variant="contained"
|
|
181
|
+
sx={{
|
|
182
|
+
width: "400px",
|
|
183
|
+
}}
|
|
184
|
+
onClick={handleSubmit(onSubmit)}
|
|
185
|
+
disabled={isLoading}
|
|
186
|
+
loading={isLoading}
|
|
187
|
+
>
|
|
188
|
+
Login
|
|
189
|
+
</Button>
|
|
190
|
+
</Stack>
|
|
191
|
+
</Stack>
|
|
192
|
+
</>
|
|
193
|
+
);
|
|
194
|
+
};
|