@campxdev/shared 0.2.9 → 0.2.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/package.json +1 -1
- package/src/assets/images/campx_logo__full_primary.png +0 -0
- package/src/assets/images/index.ts +11 -9
- package/src/components/Layout/Header/AppHeader.tsx +70 -138
- package/src/components/Layout/Header/AppsMenu.tsx +85 -0
- package/src/components/Layout/Header/UserBox.tsx +80 -44
- package/src/components/Layout/Header/styles.tsx +81 -37
- package/src/components/ModalButtons/DialogButton.tsx +66 -65
- package/src/components/PopupConfirm/PopupConfirm.tsx +27 -26
- package/src/constants/isDevelopment.ts +3 -0
- package/src/pages/LoginPage/LoginPage.tsx +149 -148
- package/src/components/Layout/Header/MainAppHeader.tsx +0 -6
package/package.json
CHANGED
|
Binary file
|
|
@@ -5,15 +5,17 @@ const taskAttachmentImage = require('./taskAttachment.png')
|
|
|
5
5
|
const pdfImage = require('./pdf.png')
|
|
6
6
|
const NoPart = require('./NoPart.png')
|
|
7
7
|
const FileBundleImage = require('./Filebundle.png')
|
|
8
|
-
|
|
9
8
|
const resultProcessingImage = require('./ResultProcess.png')
|
|
9
|
+
const campxLogoPrimary = require('./campx_logo__full_primary.png')
|
|
10
|
+
|
|
10
11
|
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
attachmentImage,
|
|
13
|
+
avatarImage,
|
|
14
|
+
welcomeImage,
|
|
15
|
+
taskAttachmentImage,
|
|
16
|
+
pdfImage,
|
|
17
|
+
NoPart,
|
|
18
|
+
resultProcessingImage,
|
|
19
|
+
FileBundleImage,
|
|
20
|
+
campxLogoPrimary,
|
|
19
21
|
}
|
|
@@ -1,175 +1,107 @@
|
|
|
1
|
-
import {Box,
|
|
2
|
-
import {useState} from 'react'
|
|
1
|
+
import {Box, styled, Typography} from '@mui/material'
|
|
3
2
|
import {Link} from 'react-router-dom'
|
|
3
|
+
import {campxLogoPrimary} from '../../../assets/images'
|
|
4
4
|
import {applications} from './applications'
|
|
5
|
+
import AppsMenu from './AppsMenu'
|
|
5
6
|
import {collegex, enrollx, examx, payx, peoplex} from './assets'
|
|
6
7
|
import CogWheelMenu from './CogWheelMenu'
|
|
7
8
|
import FreshDeskHelpButton from './FreshDeskHelpButton'
|
|
8
|
-
import {AppsIcon} from './icons'
|
|
9
9
|
import Notification from './Notification'
|
|
10
10
|
import {StyledHeader, StyledImageWrapper} from './styles'
|
|
11
11
|
import UserBox from './UserBox'
|
|
12
12
|
|
|
13
|
+
const StyledLogosWrapper = styled(Box)(() => ({
|
|
14
|
+
display: 'flex',
|
|
15
|
+
alignItems: 'center',
|
|
16
|
+
gap: '10px',
|
|
17
|
+
padding: '10px',
|
|
18
|
+
transition: 'background ease 0.3s',
|
|
19
|
+
borderRadius: '5px',
|
|
20
|
+
'&:hover': {
|
|
21
|
+
background: 'rgba(0, 0, 0, 0.05)',
|
|
22
|
+
},
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
const StyledLink = styled(Link)(() => ({
|
|
26
|
+
textDecoration: 'none',
|
|
27
|
+
}))
|
|
28
|
+
|
|
13
29
|
const imageMap = {
|
|
14
30
|
ums: collegex,
|
|
15
31
|
enroll: enrollx,
|
|
16
32
|
exams: examx,
|
|
17
33
|
payments: payx,
|
|
18
34
|
peoplex: peoplex,
|
|
19
|
-
|
|
35
|
+
campx: campxLogoPrimary,
|
|
20
36
|
}
|
|
21
37
|
|
|
22
|
-
|
|
38
|
+
interface AppHeaderProps {
|
|
39
|
+
clientLogo: string
|
|
40
|
+
username: string
|
|
41
|
+
profileIcon: string
|
|
42
|
+
permissions: any
|
|
43
|
+
}
|
|
23
44
|
|
|
24
|
-
|
|
25
|
-
const originSubdomain = `https://www.exams.ums.in`.split('.')?.slice(-3)[0]
|
|
26
|
-
console.log(originSubdomain)
|
|
27
|
-
const currentApp =
|
|
28
|
-
applications.find((item) => item.key === originSubdomain)?.key ?? 'local'
|
|
45
|
+
const isDev = process.env.NODE_ENV === 'development'
|
|
29
46
|
|
|
47
|
+
export default function AppHeader({
|
|
48
|
+
clientLogo = imageMap.campx,
|
|
49
|
+
username,
|
|
50
|
+
profileIcon,
|
|
51
|
+
permissions,
|
|
52
|
+
}: AppHeaderProps) {
|
|
30
53
|
return (
|
|
31
54
|
<StyledHeader>
|
|
32
|
-
<Box sx={{display: 'flex', alignItems: 'center', gap: '
|
|
55
|
+
<Box sx={{display: 'flex', alignItems: 'center', gap: '10px'}}>
|
|
33
56
|
<AppsMenu />
|
|
34
|
-
|
|
35
|
-
<Link to={'/'}>
|
|
36
|
-
{title ? (
|
|
37
|
-
<Typography variant='h1'>{title}</Typography>
|
|
38
|
-
) : (
|
|
39
|
-
<StyledImageWrapper>
|
|
40
|
-
{isDev ? (
|
|
41
|
-
<Typography variant='h6'>CampX</Typography>
|
|
42
|
-
) : (
|
|
43
|
-
<img
|
|
44
|
-
src={imageMap[currentApp]}
|
|
45
|
-
style={{
|
|
46
|
-
width: '200px',
|
|
47
|
-
height: 'auto',
|
|
48
|
-
}}
|
|
49
|
-
/>
|
|
50
|
-
)}
|
|
51
|
-
</StyledImageWrapper>
|
|
52
|
-
)}
|
|
53
|
-
</Link>
|
|
57
|
+
<AppLogo clientLogo={clientLogo} />
|
|
54
58
|
</Box>
|
|
55
59
|
<Box className='actions'>
|
|
56
60
|
<FreshDeskHelpButton />
|
|
57
61
|
<Notification />
|
|
58
62
|
<CogWheelMenu />
|
|
59
|
-
<UserBox />
|
|
63
|
+
<UserBox username={username} profileIcon={profileIcon} />
|
|
60
64
|
</Box>
|
|
61
65
|
</StyledHeader>
|
|
62
66
|
)
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
setAnchorEl(event.currentTarget)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const handleClose = () => {
|
|
74
|
-
setAnchorEl(null)
|
|
75
|
-
}
|
|
69
|
+
const AppLogo = ({clientLogo}) => {
|
|
70
|
+
const originSubdomain =
|
|
71
|
+
window.location.origin.split('.')?.slice(-3)[0] ?? 'ums'
|
|
72
|
+
const currentApp =
|
|
73
|
+
applications.find((item) => item.key === originSubdomain)?.key ?? 'local'
|
|
76
74
|
|
|
77
75
|
return (
|
|
78
|
-
<
|
|
79
|
-
<
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}}
|
|
103
|
-
sx={{
|
|
104
|
-
'& .MuiPaper-root': {
|
|
105
|
-
left: '0px',
|
|
106
|
-
},
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
<Box sx={{padding: '1rem 1.5rem'}}>
|
|
110
|
-
<Typography variant='h6'>Switch to</Typography>
|
|
111
|
-
</Box>
|
|
112
|
-
<Box>
|
|
113
|
-
{applications.map((item, index) => (
|
|
114
|
-
<StyledMenuItemContainer
|
|
115
|
-
key={index}
|
|
116
|
-
onClick={() => {
|
|
117
|
-
window.location.href = item.path
|
|
118
|
-
handleClose()
|
|
76
|
+
<StyledLink to={'/'}>
|
|
77
|
+
<StyledLogosWrapper>
|
|
78
|
+
<StyledImageWrapper>
|
|
79
|
+
{isDev ? (
|
|
80
|
+
<img src={imageMap.campx} />
|
|
81
|
+
) : (
|
|
82
|
+
<img src={imageMap[currentApp]} />
|
|
83
|
+
)}
|
|
84
|
+
</StyledImageWrapper>
|
|
85
|
+
<Box
|
|
86
|
+
sx={{
|
|
87
|
+
height: '26px',
|
|
88
|
+
width: '2px',
|
|
89
|
+
background: 'gray',
|
|
90
|
+
}}
|
|
91
|
+
></Box>
|
|
92
|
+
<StyledImageWrapper>
|
|
93
|
+
{isDev ? (
|
|
94
|
+
<Typography variant='h1'>Developer</Typography>
|
|
95
|
+
) : (
|
|
96
|
+
<img
|
|
97
|
+
src={clientLogo}
|
|
98
|
+
onError={(e: any) => {
|
|
99
|
+
e.target.src = imageMap.campx
|
|
119
100
|
}}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
</Menu>
|
|
126
|
-
</Box>
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const StyledMenuItem = ({data}) => {
|
|
131
|
-
return (
|
|
132
|
-
<StyledMenuitem>
|
|
133
|
-
<Box>{data.icon}</Box>
|
|
134
|
-
<Box>
|
|
135
|
-
<Typography variant='h1'>{data?.title}</Typography>
|
|
136
|
-
<StyledDescription>{data?.description}</StyledDescription>
|
|
137
|
-
</Box>
|
|
138
|
-
</StyledMenuitem>
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
</StyledImageWrapper>
|
|
104
|
+
</StyledLogosWrapper>
|
|
105
|
+
</StyledLink>
|
|
139
106
|
)
|
|
140
107
|
}
|
|
141
|
-
|
|
142
|
-
const StyledIconButton = styled(IconButton)({
|
|
143
|
-
padding: '20px',
|
|
144
|
-
backgroundColor: 'black',
|
|
145
|
-
display: 'flex',
|
|
146
|
-
alignItems: 'center',
|
|
147
|
-
justifyContent: 'center',
|
|
148
|
-
borderRadius: '0px',
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
const StyledDescription = styled(Typography)(({theme}) => ({
|
|
152
|
-
fontSize: '15px',
|
|
153
|
-
fontWeight: 500,
|
|
154
|
-
color: theme?.palette?.secondary?.main,
|
|
155
|
-
}))
|
|
156
|
-
|
|
157
|
-
const StyledMenuitem = styled(Box)({
|
|
158
|
-
height: '72px',
|
|
159
|
-
width: '400px',
|
|
160
|
-
padding: '40px 20px',
|
|
161
|
-
'&:hover': {
|
|
162
|
-
background: 'rgba(0, 0, 0, 0.03)',
|
|
163
|
-
},
|
|
164
|
-
display: 'flex',
|
|
165
|
-
alignItems: 'center',
|
|
166
|
-
gap: '10px',
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
const StyledMenuItemContainer = styled(Box)(({theme}) => ({
|
|
170
|
-
cursor: 'pointer',
|
|
171
|
-
borderBottom: `1px solid ${theme?.palette?.secondary?.lighter}`,
|
|
172
|
-
'&:last-of-type': {
|
|
173
|
-
border: 'none',
|
|
174
|
-
},
|
|
175
|
-
}))
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {Box, Menu, Typography} from '@mui/material'
|
|
2
|
+
import {useState} from 'react'
|
|
3
|
+
import {applications} from './applications'
|
|
4
|
+
import {AppsIcon} from './icons'
|
|
5
|
+
import {
|
|
6
|
+
StyledDescription,
|
|
7
|
+
StyledIconButton,
|
|
8
|
+
StyledMenuItem,
|
|
9
|
+
StyledMenuItemContainer,
|
|
10
|
+
} from './styles'
|
|
11
|
+
|
|
12
|
+
const AppsMenu = () => {
|
|
13
|
+
const [anchorEl, setAnchorEl] = useState<any>(null)
|
|
14
|
+
const open = Boolean(anchorEl)
|
|
15
|
+
|
|
16
|
+
const handleClick = (event) => {
|
|
17
|
+
setAnchorEl(event.currentTarget)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const handleClose = () => {
|
|
21
|
+
setAnchorEl(null)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<StyledIconButton onClick={handleClick}>
|
|
27
|
+
<AppsIcon />
|
|
28
|
+
</StyledIconButton>
|
|
29
|
+
|
|
30
|
+
<Menu
|
|
31
|
+
transitionDuration={150}
|
|
32
|
+
elevation={3}
|
|
33
|
+
id='basic-menu'
|
|
34
|
+
anchorEl={anchorEl}
|
|
35
|
+
open={open}
|
|
36
|
+
onClose={handleClose}
|
|
37
|
+
anchorOrigin={{
|
|
38
|
+
vertical: 'bottom',
|
|
39
|
+
horizontal: 'left',
|
|
40
|
+
}}
|
|
41
|
+
transformOrigin={{
|
|
42
|
+
vertical: 'top',
|
|
43
|
+
horizontal: 'left',
|
|
44
|
+
}}
|
|
45
|
+
sx={{
|
|
46
|
+
'& .MuiPaper-root': {
|
|
47
|
+
left: '0 !important',
|
|
48
|
+
top: '65px !important',
|
|
49
|
+
},
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<Box sx={{padding: '0.3rem 1rem'}}>
|
|
53
|
+
<Typography variant='body2'>Switch to</Typography>
|
|
54
|
+
</Box>
|
|
55
|
+
<Box>
|
|
56
|
+
{applications.map((item, index) => (
|
|
57
|
+
<StyledMenuItemContainer
|
|
58
|
+
key={index}
|
|
59
|
+
onClick={() => {
|
|
60
|
+
window.location.href = item.path
|
|
61
|
+
handleClose()
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<MenuItem data={item} />
|
|
65
|
+
</StyledMenuItemContainer>
|
|
66
|
+
))}
|
|
67
|
+
</Box>
|
|
68
|
+
</Menu>
|
|
69
|
+
</>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default AppsMenu
|
|
74
|
+
|
|
75
|
+
const MenuItem = ({data}) => {
|
|
76
|
+
return (
|
|
77
|
+
<StyledMenuItem>
|
|
78
|
+
<Box height={'20px'}>{data.icon}</Box>
|
|
79
|
+
<Box>
|
|
80
|
+
<Typography variant='h1'>{data?.title}</Typography>
|
|
81
|
+
<StyledDescription>{data?.description}</StyledDescription>
|
|
82
|
+
</Box>
|
|
83
|
+
</StyledMenuItem>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
@@ -1,51 +1,87 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
ExitToAppOutlined,
|
|
3
|
+
HttpsOutlined,
|
|
4
|
+
PermIdentityOutlined,
|
|
5
5
|
} from '@mui/icons-material'
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { UserStore } from '../../../shared-state/UserStore'
|
|
6
|
+
import {Avatar, Box, CircularProgress, Typography} from '@mui/material'
|
|
7
|
+
import {useHistory} from '../../../hooks/useRouter'
|
|
8
|
+
import {avatarImage} from '../../../assets/images'
|
|
10
9
|
import MenuButton from '../../MenuButton'
|
|
11
|
-
import {
|
|
10
|
+
import {StyledUser} from './styles'
|
|
11
|
+
import axios from 'axios'
|
|
12
|
+
import {axiosErrorToast} from '../../../config/axios'
|
|
13
|
+
import {isDevelopment} from '../../../constants/isDevelopment'
|
|
14
|
+
import Cookies from 'js-cookie'
|
|
15
|
+
import {useState} from 'react'
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
+
export default function UserBox({
|
|
18
|
+
username,
|
|
19
|
+
profileIcon,
|
|
20
|
+
}: {
|
|
21
|
+
username: string
|
|
22
|
+
profileIcon: string
|
|
23
|
+
}) {
|
|
24
|
+
const history = useHistory()
|
|
25
|
+
const [posting, setPosting] = useState(false)
|
|
26
|
+
|
|
27
|
+
async function logout() {
|
|
28
|
+
if (isDevelopment) {
|
|
29
|
+
Cookies.remove('campx_session_key')
|
|
30
|
+
window.location.href = '/'
|
|
31
|
+
return
|
|
32
|
+
}
|
|
17
33
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
34
|
+
setPosting(true)
|
|
35
|
+
axios
|
|
36
|
+
.post(`${process.env.REACT_APP_API_HOST}/auth/logout`)
|
|
37
|
+
.then((res) => {
|
|
38
|
+
setPosting(false)
|
|
39
|
+
window.location.href = '/'
|
|
40
|
+
})
|
|
41
|
+
.catch((err) => {
|
|
42
|
+
setPosting(false)
|
|
43
|
+
axiosErrorToast('Unable To Logout.')
|
|
44
|
+
})
|
|
45
|
+
}
|
|
21
46
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
return (
|
|
48
|
+
<MenuButton
|
|
49
|
+
anchor={
|
|
50
|
+
<Box minWidth={'80px'} textAlign='center'>
|
|
51
|
+
{!posting ? (
|
|
52
|
+
<StyledUser>
|
|
53
|
+
<Avatar src={profileIcon ?? avatarImage} />
|
|
54
|
+
<Typography variant='h6'>{username}</Typography>
|
|
55
|
+
</StyledUser>
|
|
56
|
+
) : (
|
|
57
|
+
<CircularProgress
|
|
58
|
+
size={16}
|
|
59
|
+
sx={{
|
|
60
|
+
color: ({palette}) => palette.primary.main,
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
63
|
+
)}
|
|
64
|
+
</Box>
|
|
65
|
+
}
|
|
66
|
+
menu={[
|
|
67
|
+
{
|
|
68
|
+
label: 'Profile',
|
|
69
|
+
icon: <PermIdentityOutlined />,
|
|
70
|
+
onClick: () => {
|
|
71
|
+
history.push('/profile')
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: 'Change Password',
|
|
76
|
+
icon: <HttpsOutlined />,
|
|
77
|
+
onClick: () => {},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: 'Logout',
|
|
81
|
+
icon: <ExitToAppOutlined />,
|
|
82
|
+
onClick: logout,
|
|
83
|
+
},
|
|
84
|
+
]}
|
|
85
|
+
/>
|
|
86
|
+
)
|
|
51
87
|
}
|
|
@@ -1,48 +1,92 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AppBar,
|
|
3
|
+
Box,
|
|
4
|
+
IconButton,
|
|
5
|
+
ListItemText,
|
|
6
|
+
styled,
|
|
7
|
+
Typography,
|
|
8
|
+
} from '@mui/material'
|
|
2
9
|
|
|
3
10
|
export const StyledImageWrapper = styled('div')`
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
width: auto;
|
|
12
|
+
height: 20px;
|
|
13
|
+
& img {
|
|
14
|
+
width: 100%;
|
|
15
|
+
height: 100%;
|
|
16
|
+
object-fit: contain;
|
|
17
|
+
}
|
|
11
18
|
`
|
|
12
19
|
|
|
13
|
-
export const StyledItemText = styled(ListItemText)(({
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
export const StyledItemText = styled(ListItemText)(({theme}) => ({
|
|
21
|
+
color: theme.palette.text.primary,
|
|
22
|
+
transition: '0.2s ease',
|
|
16
23
|
}))
|
|
17
24
|
|
|
18
|
-
export const StyledAppBar = styled(AppBar)(({
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
export const StyledAppBar = styled(AppBar)(({theme}) => ({
|
|
26
|
+
backgroundColor: 'white',
|
|
27
|
+
boxShadow: '0px 8px 28px rgb(136,136,136, 0.3)',
|
|
21
28
|
}))
|
|
22
29
|
|
|
23
|
-
export const StyledHeader = styled(Box)(({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
export const StyledHeader = styled(Box)(({theme}) => ({
|
|
31
|
+
boxShadow: '0px 2px 10px #0000001a',
|
|
32
|
+
// padding: '0 1rem',
|
|
33
|
+
backgroundColor: 'white',
|
|
34
|
+
display: 'flex',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
justifyContent: 'space-between',
|
|
37
|
+
'& .actions': {
|
|
38
|
+
marginRight: '10px',
|
|
39
|
+
display: 'flex',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
gap: '14px',
|
|
42
|
+
},
|
|
35
43
|
}))
|
|
36
44
|
|
|
37
|
-
export const StyledUser = styled(Box)(({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
export const StyledUser = styled(Box)(({theme}) => ({
|
|
46
|
+
cursor: 'pointer',
|
|
47
|
+
borderRadius: '5px',
|
|
48
|
+
transition: 'background 0.2s ease',
|
|
49
|
+
padding: '5px 10px',
|
|
50
|
+
display: 'flex',
|
|
51
|
+
alignItems: 'center',
|
|
52
|
+
gap: '10px',
|
|
53
|
+
'&:hover': {
|
|
54
|
+
background: theme.palette.secondary.light,
|
|
55
|
+
},
|
|
56
|
+
}))
|
|
57
|
+
|
|
58
|
+
export const StyledIconButton = styled(IconButton)({
|
|
59
|
+
padding: '20px',
|
|
60
|
+
backgroundColor: 'black',
|
|
61
|
+
display: 'flex',
|
|
62
|
+
alignItems: 'center',
|
|
63
|
+
justifyContent: 'center',
|
|
64
|
+
borderRadius: '0px',
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
export const StyledDescription = styled(Typography)(({theme}) => ({
|
|
68
|
+
fontSize: '15px',
|
|
69
|
+
fontWeight: 500,
|
|
70
|
+
color: theme?.palette?.secondary?.main,
|
|
71
|
+
}))
|
|
72
|
+
|
|
73
|
+
export const StyledMenuItem = styled(Box)({
|
|
74
|
+
height: '64px',
|
|
75
|
+
width: '360px',
|
|
76
|
+
padding: '20px',
|
|
77
|
+
transition: 'background ease 0.3s',
|
|
78
|
+
'&:hover': {
|
|
79
|
+
background: 'rgba(0, 0, 0, 0.03)',
|
|
80
|
+
},
|
|
81
|
+
display: 'flex',
|
|
82
|
+
alignItems: 'center',
|
|
83
|
+
gap: '10px',
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
export const StyledMenuItemContainer = styled(Box)(({theme}) => ({
|
|
87
|
+
cursor: 'pointer',
|
|
88
|
+
borderBottom: `1px solid ${theme?.palette?.secondary?.lighter}`,
|
|
89
|
+
'&:last-of-type': {
|
|
90
|
+
border: 'none',
|
|
91
|
+
},
|
|
48
92
|
}))
|
|
@@ -1,84 +1,85 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {Close} from '@mui/icons-material'
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
alpha,
|
|
4
|
+
Box,
|
|
5
|
+
ButtonProps,
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogProps,
|
|
8
|
+
IconButton,
|
|
9
|
+
styled,
|
|
10
|
+
Typography,
|
|
11
11
|
} from '@mui/material'
|
|
12
|
-
import {
|
|
12
|
+
import {createElement, ReactNode, useState} from 'react'
|
|
13
13
|
|
|
14
|
-
const StyledDialogHeader = styled(Box)(({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
const StyledDialogHeader = styled(Box)(({theme}) => ({
|
|
15
|
+
height: '64px',
|
|
16
|
+
backgroundColor: alpha(theme.palette.text.secondary, 0.1),
|
|
17
|
+
display: 'flex',
|
|
18
|
+
justifyContent: 'space-between',
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
padding: '0.6rem 1rem',
|
|
21
21
|
}))
|
|
22
22
|
|
|
23
|
-
const StyledDialogContent = styled(Box)(({
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const StyledDialogContent = styled(Box)(({theme}) => ({
|
|
24
|
+
width: '100%',
|
|
25
|
+
padding: '1rem',
|
|
26
26
|
}))
|
|
27
27
|
|
|
28
28
|
type ContentProps = {
|
|
29
|
-
|
|
29
|
+
close: () => void
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
interface DrawerButtonProps {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
button: any
|
|
34
|
+
content: (props: ContentProps) => ReactNode
|
|
35
|
+
title: string | ReactNode
|
|
36
|
+
btnTxt?: string | ReactNode
|
|
37
|
+
btnProps?: ButtonProps
|
|
38
|
+
dialogProps?: Omit<DialogProps, 'open'>
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export default function DialogButton({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
button: Button,
|
|
43
|
+
content,
|
|
44
|
+
title,
|
|
45
|
+
btnTxt,
|
|
46
|
+
btnProps,
|
|
47
|
+
dialogProps,
|
|
48
48
|
}: DrawerButtonProps) {
|
|
49
|
-
|
|
49
|
+
const [open, setOpen] = useState(false)
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
const ButtonEl = (props) => (
|
|
52
|
+
<Button {...props} {...btnProps}>
|
|
53
|
+
{btnTxt}
|
|
54
|
+
</Button>
|
|
55
|
+
)
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
const MyButton = createElement(ButtonEl, {
|
|
58
|
+
onClick: () => setOpen(true),
|
|
59
|
+
})
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
61
|
+
const onClose = () => {
|
|
62
|
+
setOpen(false)
|
|
63
|
+
}
|
|
64
|
+
return (
|
|
65
|
+
<>
|
|
66
|
+
{MyButton}
|
|
67
|
+
<Dialog
|
|
68
|
+
PaperProps={{sx: {borderRadius: '10px'}}}
|
|
69
|
+
fullWidth
|
|
70
|
+
onClose={onClose}
|
|
71
|
+
open={open}
|
|
72
|
+
transitionDuration={200}
|
|
73
|
+
{...dialogProps}
|
|
74
|
+
>
|
|
75
|
+
<StyledDialogHeader>
|
|
76
|
+
<Typography fontWeight={600}>{title}</Typography>
|
|
77
|
+
<IconButton onClick={onClose}>
|
|
78
|
+
<Close />
|
|
79
|
+
</IconButton>
|
|
80
|
+
</StyledDialogHeader>
|
|
81
|
+
<StyledDialogContent>{content({close: onClose})}</StyledDialogContent>
|
|
82
|
+
</Dialog>
|
|
83
|
+
</>
|
|
84
|
+
)
|
|
84
85
|
}
|
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
Button,
|
|
3
|
+
Dialog,
|
|
4
|
+
DialogActions,
|
|
5
|
+
DialogContent,
|
|
6
|
+
DialogTitle,
|
|
7
7
|
} from '@mui/material'
|
|
8
8
|
import useConfirm from './useConfirm'
|
|
9
9
|
|
|
10
10
|
const PopupConfirm = () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
11
|
+
const {prompt = '', isOpen = false, proceed, cancel} = useConfirm()
|
|
12
|
+
return (
|
|
13
|
+
<Dialog
|
|
14
|
+
sx={{zIndex: 1600}}
|
|
15
|
+
keepMounted
|
|
16
|
+
maxWidth='sm'
|
|
17
|
+
fullWidth
|
|
18
|
+
open={isOpen}
|
|
19
|
+
transitionDuration={150}
|
|
20
|
+
>
|
|
21
|
+
<DialogTitle>Confirm</DialogTitle>
|
|
22
|
+
<DialogContent sx={{minHeight: '40px'}}>{prompt}</DialogContent>
|
|
23
|
+
<DialogActions>
|
|
24
|
+
<Button variant='contained' color='primary' onClick={proceed}>
|
|
25
|
+
Ok
|
|
26
|
+
</Button>
|
|
27
|
+
<Button color='secondary' variant='outlined' onClick={cancel}>
|
|
28
|
+
Cancel
|
|
29
|
+
</Button>
|
|
30
|
+
</DialogActions>
|
|
31
|
+
</Dialog>
|
|
32
|
+
)
|
|
32
33
|
}
|
|
33
34
|
export default PopupConfirm
|
|
@@ -1,166 +1,167 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { Visibility, VisibilityOff } from '@mui/icons-material'
|
|
1
|
+
import {Spinner} from '../../components'
|
|
2
|
+
import {useFetch} from '../../hooks'
|
|
3
|
+
import {Visibility, VisibilityOff} from '@mui/icons-material'
|
|
5
4
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
Alert,
|
|
6
|
+
Box,
|
|
7
|
+
IconButton,
|
|
8
|
+
InputAdornment,
|
|
9
|
+
Stack,
|
|
10
|
+
Typography,
|
|
12
11
|
} from '@mui/material'
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import {useState} from 'react'
|
|
13
|
+
import {useForm} from 'react-hook-form'
|
|
14
|
+
import {welcomeImage} from '../../assets/images'
|
|
16
15
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
StyledBanner,
|
|
17
|
+
StyledBannerFooter,
|
|
18
|
+
StyledBannerImage,
|
|
19
|
+
StyledButton,
|
|
20
|
+
StyledFormSection,
|
|
21
|
+
StyledLink,
|
|
22
|
+
StyledMain,
|
|
23
|
+
StyledTextField,
|
|
25
24
|
} from './styles'
|
|
26
|
-
import {
|
|
25
|
+
import {useNavigate} from 'react-router-dom'
|
|
27
26
|
import Cookies from 'js-cookie'
|
|
28
27
|
import axiosBase from 'axios'
|
|
29
28
|
|
|
30
29
|
const LoginPage = () => {
|
|
31
|
-
|
|
30
|
+
const {loading, data: assets} = useFetch('/assets')
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
if (loading) {
|
|
33
|
+
return <Spinner />
|
|
34
|
+
}
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<StyledMain>
|
|
39
|
+
<StyledBanner>
|
|
40
|
+
<StyledBannerImage>
|
|
41
|
+
<img src={welcomeImage} alt='login-banner' />
|
|
42
|
+
</StyledBannerImage>
|
|
43
|
+
<StyledBannerFooter>
|
|
44
|
+
<div className='logo'>
|
|
45
|
+
<Typography variant='body1'>Powered By</Typography>
|
|
46
|
+
<img
|
|
47
|
+
src={
|
|
48
|
+
'https://campx-logos.s3.ap-south-1.amazonaws.com/CampX.png'
|
|
49
|
+
}
|
|
50
|
+
alt='login-banner'
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
<div className='copyright'>
|
|
54
|
+
<Typography variant='subtitle1'>
|
|
55
|
+
© All Rights reserved to CampX Edutech Pvt. Ltd., 2022
|
|
56
|
+
</Typography>
|
|
57
|
+
</div>
|
|
58
|
+
</StyledBannerFooter>
|
|
59
|
+
</StyledBanner>
|
|
60
|
+
<StyledFormSection>
|
|
61
|
+
<Box width={'100%'}>
|
|
62
|
+
<Box
|
|
63
|
+
sx={{
|
|
64
|
+
display: 'flex',
|
|
65
|
+
justifyContent: 'center',
|
|
66
|
+
marginBottom: '54px',
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
<img
|
|
70
|
+
src={assets?.logo}
|
|
71
|
+
style={{
|
|
72
|
+
width: '200px',
|
|
73
|
+
}}
|
|
74
|
+
/>
|
|
75
|
+
</Box>
|
|
76
|
+
<LoginForm />
|
|
77
|
+
</Box>
|
|
78
|
+
</StyledFormSection>
|
|
79
|
+
</StyledMain>
|
|
80
|
+
<StyledLink
|
|
81
|
+
style={{
|
|
82
|
+
textAlign: 'right',
|
|
83
|
+
display: 'block',
|
|
84
|
+
position: 'absolute',
|
|
85
|
+
top: '20px',
|
|
86
|
+
right: '20px',
|
|
87
|
+
}}
|
|
88
|
+
href='/results/search'
|
|
89
|
+
>
|
|
90
|
+
Student Results
|
|
91
|
+
</StyledLink>
|
|
92
|
+
</>
|
|
93
|
+
)
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
export default LoginPage
|
|
98
97
|
|
|
99
98
|
export function LoginForm() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
const [showPassword, setShowPassword] = useState(false)
|
|
100
|
+
const {handleSubmit, control} = useForm()
|
|
101
|
+
const [error, setError] = useState('')
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
103
|
+
const onSubmit = async (values) => {
|
|
104
|
+
try {
|
|
105
|
+
const res = await axiosBase({
|
|
106
|
+
baseURL: process.env.REACT_APP_API_URL,
|
|
107
|
+
url: '/auth/login',
|
|
108
|
+
data: {
|
|
109
|
+
values,
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
Cookies.set('campx_session_key', res.data.cookie)
|
|
113
|
+
window.location.href = '/'
|
|
114
|
+
} catch (err) {
|
|
115
|
+
// eslint-disable-next-line no-console
|
|
116
|
+
console.log(err)
|
|
117
|
+
setError(err.response.data.message ?? 'Server Error')
|
|
118
|
+
}
|
|
119
|
+
}
|
|
118
120
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
121
|
+
return (
|
|
122
|
+
<Box sx={{maxWidth: '500px'}} margin='0 auto' padding={'0 1rem'}>
|
|
123
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
124
|
+
<Stack gap={'40px'}>
|
|
125
|
+
<Box>
|
|
126
|
+
<StyledTextField
|
|
127
|
+
size='medium'
|
|
128
|
+
control={control}
|
|
129
|
+
name='username'
|
|
130
|
+
label='User ID'
|
|
131
|
+
required
|
|
132
|
+
/>
|
|
133
|
+
</Box>
|
|
134
|
+
<Box>
|
|
135
|
+
<StyledTextField
|
|
136
|
+
control={control}
|
|
137
|
+
name='password'
|
|
138
|
+
label='Password'
|
|
139
|
+
type={showPassword ? 'text' : 'password'}
|
|
140
|
+
required
|
|
141
|
+
InputProps={{
|
|
142
|
+
endAdornment: (
|
|
143
|
+
<InputAdornment position='end'>
|
|
144
|
+
<IconButton
|
|
145
|
+
size='small'
|
|
146
|
+
aria-label='toggle password visibility'
|
|
147
|
+
onClick={() => setShowPassword((prev) => !prev)}
|
|
148
|
+
edge='end'
|
|
149
|
+
>
|
|
150
|
+
{showPassword ? <VisibilityOff /> : <Visibility />}
|
|
151
|
+
</IconButton>
|
|
152
|
+
</InputAdornment>
|
|
153
|
+
),
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
</Box>
|
|
157
|
+
<StyledButton type='submit'>Login</StyledButton>
|
|
158
|
+
</Stack>
|
|
159
|
+
</form>
|
|
160
|
+
{error && (
|
|
161
|
+
<Alert severity='error' sx={{marginTop: '20px'}}>
|
|
162
|
+
{error}
|
|
163
|
+
</Alert>
|
|
164
|
+
)}
|
|
165
|
+
</Box>
|
|
166
|
+
)
|
|
165
167
|
}
|
|
166
|
-
|