@campxdev/shared 1.11.6 → 1.11.7-0.alpha-22
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/.vscode/settings.json +3 -0
- package/exports.ts +4 -0
- package/package.json +17 -9
- package/src/assets/images/X.png +0 -0
- package/src/assets/images/active_devices.svg +3 -0
- package/src/assets/images/animation.gif +0 -0
- package/src/assets/images/change_password.svg +6 -0
- package/src/assets/images/clog_wheel.svg +6 -0
- package/src/assets/images/index.ts +28 -3
- package/src/assets/images/location.svg +6 -0
- package/src/assets/images/logout_icon.svg +6 -0
- package/src/assets/images/lottery.svg +22 -0
- package/src/assets/images/mobile.svg +7 -0
- package/src/assets/images/no_devices.svg +734 -0
- package/src/assets/images/notifications.svg +3 -0
- package/src/assets/images/profile.svg +6 -0
- package/src/assets/images/web.svg +13 -0
- package/src/components/ActiveDevices/ActiveDevices.tsx +60 -0
- package/src/components/ActiveDevices/DeviceInformationCard.tsx +97 -0
- package/src/components/ActiveDevices/index.ts +1 -0
- package/src/components/ActivityLog/ActivityLog.tsx +268 -0
- package/src/components/ActivityLog/Styles.tsx +35 -0
- package/src/components/ActivityLog/index.ts +1 -0
- package/src/components/ApplicationProfile/ApplicationProfile.tsx +1 -0
- package/src/components/ApplicationProfile/UserProfileRelation.tsx +4 -1
- package/src/components/DatabaseConfiguration/DatabaseConfiguration.tsx +28 -0
- package/src/components/DatabaseConfiguration/DatabaseConfigurationForm.tsx +87 -0
- package/src/components/DatabaseConfiguration/components/AddConnectionDrawerButton.tsx +30 -0
- package/src/components/DatabaseConfiguration/components/ConnectionCard.tsx +79 -0
- package/src/components/DatabaseConfiguration/index.ts +5 -0
- package/src/components/DatabaseConfiguration/service.ts +6 -0
- package/src/components/DatabaseConfiguration/styles.ts +30 -0
- package/src/components/DrawerWrapper/DialogTemplate.tsx +58 -0
- package/src/components/DrawerWrapper/DrawerWrapper.tsx +23 -7
- package/src/components/DrawerWrapper/ErrorTemplate.tsx +77 -0
- package/src/components/ErrorModal.tsx +88 -0
- package/src/components/ErrorModalWrapper/ErrorModalTemplate.tsx +118 -0
- package/src/components/ErrorModalWrapper/ErrorModalWrapper.tsx +76 -0
- package/src/components/FilterComponents/SearchBar.tsx +5 -2
- package/src/components/Form/Form.tsx +4 -1
- package/src/components/HookForm/AutoCompleteSearch.tsx +3 -0
- package/src/components/HookForm/MultiSelect.tsx +1 -0
- package/src/components/HookForm/SingleSelect.tsx +2 -2
- package/src/components/ImageUpload.tsx +4 -1
- package/src/components/Input/MultiSelect.tsx +1 -0
- package/src/components/Input/SearchSingleSelect.tsx +1 -1
- package/src/components/Input/SingleSelect.tsx +7 -7
- package/src/components/Institutions/InsititutionsDialog.tsx +2 -2
- package/src/components/Layout/Header/AppHeader.tsx +23 -6
- package/src/components/Layout/Header/HeaderActions/CogWheelMenu.tsx +2 -2
- package/src/components/Layout/Header/HeaderActions/HeaderActions.tsx +41 -16
- package/src/components/Layout/Header/HeaderActions/UserBox.tsx +48 -6
- package/src/components/Layout/Header/applications.ts +43 -30
- package/src/components/Layout/LayoutWrapper.tsx +82 -4
- package/src/components/Layout/SideNav.tsx +42 -9
- package/src/components/LoginForm.tsx +53 -1
- package/src/components/MongoCharts/MongoDashboard.tsx +146 -0
- package/src/components/MongoCharts/index.tsx +1 -0
- package/src/components/MyProfile/MyProfile.tsx +1 -1
- package/src/components/ReportHeader.tsx +2 -2
- package/src/components/Selectors/ClassRoomSelector.tsx +2 -2
- package/src/components/Selectors/CourseSelector.tsx +2 -2
- package/src/components/Selectors/DepartmentSelector.tsx +2 -2
- package/src/components/Selectors/ExamGroupSelector.tsx +19 -10
- package/src/components/Selectors/FacultySelector.tsx +2 -2
- package/src/components/Selectors/FeeTypeSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormClassRoomSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormCourseSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormDepartmentSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormExamGroupSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormFacultySelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormFeeTypeSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormProgramSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/FormQuotaSelector.tsx +3 -3
- package/src/components/Selectors/FormSelectors/FormSemesterSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/MultiSelect/MultiFacultySelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/MultiSelect/MultiFeeTypeSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/MultiSelect/MultiProgramSelector.tsx +2 -2
- package/src/components/Selectors/FormSelectors/MultiSelect/MultiQuotaSelector.tsx +2 -2
- package/src/components/Selectors/ProgramSelector.tsx +3 -3
- package/src/components/Selectors/QuotaSelector.tsx +3 -3
- package/src/components/Selectors/SemesterSelector.tsx +2 -2
- package/src/components/SignatureFooter.tsx +35 -0
- package/src/components/SwitchButton.tsx +6 -1
- package/src/components/Tables/2DTable/Table.tsx +20 -23
- package/src/components/Tables/BasicTable/Table.tsx +22 -13
- package/src/components/Tables/BasicTable/TableFooter.tsx +35 -9
- package/src/components/Tables/BasicTable/styles.ts +1 -1
- package/src/components/Tables/ReactTable/ReactTable.tsx +42 -8
- package/src/components/Tables/common/types.ts +1 -0
- package/src/components/Tabs/TabsContainer.tsx +5 -5
- package/src/components/Tabs/styles.tsx +1 -0
- package/src/components/ToastContainer/ToastContainer.tsx +2 -3
- package/src/components/UploadButton/UploadButton.tsx +3 -1
- package/src/components/UploadButton/types.ts +2 -2
- package/src/components/UploadDocument.tsx +3 -0
- package/src/components/UploadFileDialog/UploadFileDialog.tsx +20 -9
- package/src/components/index.ts +5 -0
- package/src/config/axios.ts +5 -19
- package/src/constants/UIConstants.ts +65 -2
- package/src/constants/isDevelopment.ts +0 -1
- package/src/contexts/Providers.tsx +5 -43
- package/src/hooks/useAuth.ts +7 -0
- package/src/layouts/Components/styles.tsx +25 -7
- package/src/permissions/PermissionsStore.ts +658 -55
- package/src/permissions/ValidateAccess.tsx +37 -8
- package/src/shared-state/PermissionsStore.ts +779 -85
- package/src/theme/theme.d.ts +69 -35
- package/src/utils/debounce.ts +11 -0
- package/src/utils/getUrlParams.ts +13 -0
- package/src/utils/index.ts +6 -3
- package/src/utils/logout.ts +4 -8
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="18.125" height="20" viewBox="0 0 18.125 20">
|
|
2
|
+
<path id="bell_10_" data-name="bell (10)" d="M18.958,11.384l-1.583-5.7a7.767,7.767,0,0,0-15.064.395L1.085,11.595a4.166,4.166,0,0,0,4.067,5.07H6.08a4.166,4.166,0,0,0,8.166,0h.7a4.166,4.166,0,0,0,4.015-5.281Zm-8.795,6.948a2.5,2.5,0,0,1-2.346-1.666H12.51A2.5,2.5,0,0,1,10.163,18.332Zm6.771-4.32A2.481,2.481,0,0,1,14.944,15H5.152a2.5,2.5,0,0,1-2.44-3.042L3.937,6.444a6.1,6.1,0,0,1,11.832-.31l1.583,5.7a2.481,2.481,0,0,1-.418,2.181Z" transform="translate(-0.986 -0.002)" fill="#121212"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="17.049" height="22.632" viewBox="0 0 17.049 22.632">
|
|
2
|
+
<g id="user" transform="translate(-2.85 0.15)">
|
|
3
|
+
<path id="Path_38566" data-name="Path 38566" d="M11.583,11.166A5.583,5.583,0,1,0,6,5.583a5.583,5.583,0,0,0,5.583,5.583Zm0-9.305A3.722,3.722,0,1,1,7.861,5.583,3.722,3.722,0,0,1,11.583,1.861Z" transform="translate(-0.208 0)" stroke="#fff" stroke-width="0.3"/>
|
|
4
|
+
<path id="Path_38567" data-name="Path 38567" d="M11.375,14A8.384,8.384,0,0,0,3,22.375a.931.931,0,1,0,1.861,0,6.514,6.514,0,1,1,13.027,0,.931.931,0,0,0,1.861,0A8.384,8.384,0,0,0,11.375,14Z" transform="translate(0 -0.973)" stroke="#fff" stroke-width="0.3"/>
|
|
5
|
+
</g>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
|
2
|
+
<g id="Group_5289" data-name="Group 5289" transform="translate(-5577 -13602)">
|
|
3
|
+
<g id="Group_5288" data-name="Group 5288">
|
|
4
|
+
<g id="Group_5287" data-name="Group 5287">
|
|
5
|
+
<path id="Vector" d="M4.44,0H15.55C19.11,0,20,.89,20,4.44v6.33c0,3.56-.89,4.44-4.44,4.44H4.44C.89,15.22,0,14.33,0,10.78V4.44C0,.89.89,0,4.44,0Z" transform="translate(5579 13604)" fill="none" stroke="#292d32" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
|
|
6
|
+
<path id="Vector-2" data-name="Vector" d="M0,0V4.78" transform="translate(5589 13619.22)" fill="none" stroke="#292d32" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
|
|
7
|
+
<path id="Vector-3" data-name="Vector" d="M0,0H20" transform="translate(5579 13615)" fill="none" stroke="#292d32" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
|
|
8
|
+
<path id="Vector-4" data-name="Vector" d="M0,0H9" transform="translate(5584.5 13624)" fill="none" stroke="#292d32" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
|
|
9
|
+
<path id="Vector-5" data-name="Vector" d="M0,0H24V24H0Z" transform="translate(5577 13602)" fill="none" opacity="0"/>
|
|
10
|
+
</g>
|
|
11
|
+
</g>
|
|
12
|
+
</g>
|
|
13
|
+
</svg>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Button, Stack } from '@mui/material'
|
|
2
|
+
|
|
3
|
+
import { useMutation, useQuery } from 'react-query'
|
|
4
|
+
import { NoDataIllustration } from '..'
|
|
5
|
+
import { noDevices } from '../../assets/images'
|
|
6
|
+
import axios from '../../config/axios'
|
|
7
|
+
import useConfirm from '../PopupConfirm/useConfirm'
|
|
8
|
+
import Spinner from '../Spinner'
|
|
9
|
+
import { DeviceInformationCard } from './DeviceInformationCard'
|
|
10
|
+
|
|
11
|
+
const ActiveDevices = ({ close }) => {
|
|
12
|
+
const { isConfirmed } = useConfirm()
|
|
13
|
+
const {
|
|
14
|
+
data: activeSessions,
|
|
15
|
+
isLoading,
|
|
16
|
+
isRefetching,
|
|
17
|
+
refetch,
|
|
18
|
+
} = useQuery('activeDevices', () =>
|
|
19
|
+
axios.get('/auth-server/auth/active-sessions').then((res) => res?.data),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const { mutate: logoutAllOtherDevices } = useMutation(
|
|
23
|
+
() => axios.post('/auth-server/auth/logout-active-sessions'),
|
|
24
|
+
{
|
|
25
|
+
onSuccess: () => {
|
|
26
|
+
close()
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const handleLogoutAllOtherDevices = async () => {
|
|
32
|
+
const confirm = await isConfirmed(
|
|
33
|
+
'Are you sure you want to logout from all other devices?',
|
|
34
|
+
)
|
|
35
|
+
if (confirm) {
|
|
36
|
+
logoutAllOtherDevices()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (isLoading || isRefetching) return <Spinner />
|
|
40
|
+
if (activeSessions?.length == 0)
|
|
41
|
+
return (
|
|
42
|
+
<NoDataIllustration
|
|
43
|
+
height="60vh"
|
|
44
|
+
message="No active devices found"
|
|
45
|
+
imageSrc={noDevices.default}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
return (
|
|
49
|
+
<Stack height="60vh" padding="10px 50px" gap={3} alignItems="flex-end">
|
|
50
|
+
<Button onClick={handleLogoutAllOtherDevices} sx={{ width: '300px' }}>
|
|
51
|
+
Logout from All Other Devices
|
|
52
|
+
</Button>
|
|
53
|
+
{activeSessions?.map((sessionData) => (
|
|
54
|
+
<DeviceInformationCard sessionData={sessionData} refetch={refetch} />
|
|
55
|
+
))}
|
|
56
|
+
</Stack>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default ActiveDevices
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Box, Button, Stack, Typography, styled } from '@mui/material'
|
|
2
|
+
import { format } from 'date-fns-tz'
|
|
3
|
+
import { useMutation } from 'react-query'
|
|
4
|
+
import { toast } from 'react-toastify'
|
|
5
|
+
import { location, mobile, web } from '../../assets/images'
|
|
6
|
+
import axios from '../../config/axios'
|
|
7
|
+
import useConfirm from '../PopupConfirm/useConfirm'
|
|
8
|
+
|
|
9
|
+
const StyledIconContainer = styled(Box)(({ theme }) => ({
|
|
10
|
+
backgroundColor: '#ED90350F',
|
|
11
|
+
borderRadius: '10px',
|
|
12
|
+
border: '1px solid #ED903580',
|
|
13
|
+
width: '60px',
|
|
14
|
+
height: '60px',
|
|
15
|
+
padding: '17px 0px 0px 17px',
|
|
16
|
+
}))
|
|
17
|
+
|
|
18
|
+
const StyledTrustedContainer = styled(Box)(({ theme }) => ({
|
|
19
|
+
backgroundColor: '#F4A101',
|
|
20
|
+
borderRadius: '15px',
|
|
21
|
+
padding: '3px 15px',
|
|
22
|
+
}))
|
|
23
|
+
|
|
24
|
+
export const DeviceInformationCard = ({ sessionData, refetch }) => {
|
|
25
|
+
const { isConfirmed } = useConfirm()
|
|
26
|
+
|
|
27
|
+
const { mutate: logout } = useMutation(
|
|
28
|
+
() =>
|
|
29
|
+
axios.post('/auth-server/auth/logout-active-sessions', {
|
|
30
|
+
deviceInformationId: sessionData?.deviceInformation?._id,
|
|
31
|
+
}),
|
|
32
|
+
{
|
|
33
|
+
onSuccess: () => {
|
|
34
|
+
refetch()
|
|
35
|
+
},
|
|
36
|
+
onError: (error: any) => {
|
|
37
|
+
toast.error(error?.response?.data?.message)
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
const handleLogout = async () => {
|
|
42
|
+
const confirmed = await isConfirmed(
|
|
43
|
+
'Are you sure you want to logout from this device?',
|
|
44
|
+
)
|
|
45
|
+
if (confirmed) logout()
|
|
46
|
+
}
|
|
47
|
+
return (
|
|
48
|
+
<Box
|
|
49
|
+
width="100%"
|
|
50
|
+
border="1px solid #1212121A"
|
|
51
|
+
borderRadius="10px"
|
|
52
|
+
padding="20px 0px 20px 0px"
|
|
53
|
+
>
|
|
54
|
+
<Stack
|
|
55
|
+
direction="row"
|
|
56
|
+
gap={2}
|
|
57
|
+
alignItems="center"
|
|
58
|
+
justifyContent="space-around"
|
|
59
|
+
>
|
|
60
|
+
<Stack direction="row" alignItems="center" gap={2}>
|
|
61
|
+
<StyledIconContainer>
|
|
62
|
+
<img
|
|
63
|
+
src={(sessionData.type = 'WEB' ? web.default : mobile.default)}
|
|
64
|
+
/>
|
|
65
|
+
</StyledIconContainer>
|
|
66
|
+
<Stack>
|
|
67
|
+
<Stack direction="row" alignItems="center" gap={1}>
|
|
68
|
+
<Typography variant="h1" fontSize="15px">
|
|
69
|
+
{`${sessionData?.deviceInformation?.clientName} (${sessionData?.deviceInformation?.os})`}
|
|
70
|
+
</Typography>
|
|
71
|
+
{sessionData?.deviceInformation?.trusted && (
|
|
72
|
+
<StyledTrustedContainer>
|
|
73
|
+
<Typography variant="subtitle1" color="white" fontSize="12px">
|
|
74
|
+
Trusted
|
|
75
|
+
</Typography>
|
|
76
|
+
</StyledTrustedContainer>
|
|
77
|
+
)}
|
|
78
|
+
</Stack>
|
|
79
|
+
<Typography variant="caption">{`Last Active on ${format(
|
|
80
|
+
new Date(sessionData?.lastAccessedAt),
|
|
81
|
+
'dd MMM, yyyy hh:mm a',
|
|
82
|
+
)}`}</Typography>
|
|
83
|
+
</Stack>
|
|
84
|
+
</Stack>
|
|
85
|
+
<Stack direction="row" alignItems="center" gap={1}>
|
|
86
|
+
<img src={location.default} />
|
|
87
|
+
<Typography variant="caption">
|
|
88
|
+
{sessionData?.deviceInformation?.locationName}
|
|
89
|
+
</Typography>
|
|
90
|
+
</Stack>
|
|
91
|
+
<Button onClick={handleLogout} variant="outlined">
|
|
92
|
+
Logout
|
|
93
|
+
</Button>
|
|
94
|
+
</Stack>
|
|
95
|
+
</Box>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './ActiveDevices'
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Timeline,
|
|
3
|
+
TimelineContent,
|
|
4
|
+
TimelineItem,
|
|
5
|
+
TimelineSeparator,
|
|
6
|
+
} from '@mui/lab'
|
|
7
|
+
import { Box, SxProps, Typography } from '@mui/material'
|
|
8
|
+
import moment from 'moment'
|
|
9
|
+
import { useCallback, useRef } from 'react'
|
|
10
|
+
import { useInfiniteQuery } from 'react-query'
|
|
11
|
+
import { NoDataIllustration } from '..'
|
|
12
|
+
import axios from '../../config/axios'
|
|
13
|
+
import { useErrorModal } from '../ErrorModalWrapper/ErrorModalWrapper'
|
|
14
|
+
import Spinner from '../Spinner'
|
|
15
|
+
import Table from '../Tables/BasicTable/Table'
|
|
16
|
+
import {
|
|
17
|
+
StyledAvatar,
|
|
18
|
+
StyledCircleIcon,
|
|
19
|
+
StyledSpinnerBox,
|
|
20
|
+
StyledTimeLineDot,
|
|
21
|
+
} from './Styles'
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
endPoint: string
|
|
25
|
+
tableView: boolean
|
|
26
|
+
enableTitle?: boolean
|
|
27
|
+
params: any
|
|
28
|
+
sx?: SxProps
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default function ActivityLog({
|
|
32
|
+
endPoint,
|
|
33
|
+
tableView,
|
|
34
|
+
enableTitle,
|
|
35
|
+
params,
|
|
36
|
+
sx,
|
|
37
|
+
}: Props) {
|
|
38
|
+
const errorModal = useErrorModal()
|
|
39
|
+
const fetchActivities = async ({ pageParam = 0 }) => {
|
|
40
|
+
try {
|
|
41
|
+
const response = await axios.get(endPoint, { params: { ...params } })
|
|
42
|
+
return response?.data
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// eslint-disable-next-line no-console
|
|
45
|
+
console.log(error)
|
|
46
|
+
errorModal({ error: error })
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } =
|
|
51
|
+
useInfiniteQuery('activities', fetchActivities, {
|
|
52
|
+
getNextPageParam: (lastPage) => {
|
|
53
|
+
return lastPage?.length ? lastPage[lastPage?.length - 1].id : null
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const activitesData = data ? data?.pages?.flatMap((page) => page) : []
|
|
58
|
+
|
|
59
|
+
if (isLoading) return <Spinner />
|
|
60
|
+
|
|
61
|
+
if (data?.pages?.length === 0 || !activitesData?.length) {
|
|
62
|
+
return (
|
|
63
|
+
<NoDataIllustration
|
|
64
|
+
imageSrc=""
|
|
65
|
+
message={
|
|
66
|
+
<Typography
|
|
67
|
+
variant="h6"
|
|
68
|
+
style={{ textAlign: 'center', marginTop: '20px' }}
|
|
69
|
+
>
|
|
70
|
+
{'No data found'}
|
|
71
|
+
</Typography>
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Box>
|
|
79
|
+
{enableTitle && (
|
|
80
|
+
<Typography
|
|
81
|
+
variant="h1"
|
|
82
|
+
sx={{ fontSize: '18px', fontWeight: 700, margin: '20px' }}
|
|
83
|
+
>
|
|
84
|
+
Activity Log
|
|
85
|
+
</Typography>
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
{!tableView ? (
|
|
89
|
+
<Box
|
|
90
|
+
sx={{
|
|
91
|
+
overflowY: 'scroll',
|
|
92
|
+
'&::-webkit-scrollbar': {
|
|
93
|
+
display: 'none',
|
|
94
|
+
},
|
|
95
|
+
height: '380px',
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
<TimeLineComponent
|
|
99
|
+
activitesData={activitesData}
|
|
100
|
+
fetchNextPage={fetchNextPage}
|
|
101
|
+
isFetchingNextPage={isFetchingNextPage}
|
|
102
|
+
hasNextPage={hasNextPage}
|
|
103
|
+
sx={sx}
|
|
104
|
+
/>
|
|
105
|
+
</Box>
|
|
106
|
+
) : (
|
|
107
|
+
<Box sx={{ margin: '0 25px' }}>
|
|
108
|
+
<Table
|
|
109
|
+
columns={columns}
|
|
110
|
+
dataSource={activitesData}
|
|
111
|
+
loading={isLoading}
|
|
112
|
+
/>
|
|
113
|
+
</Box>
|
|
114
|
+
)}
|
|
115
|
+
</Box>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const columns = [
|
|
120
|
+
{
|
|
121
|
+
title: 'Date',
|
|
122
|
+
dataIndex: 'timestamp',
|
|
123
|
+
key: 'timestamp',
|
|
124
|
+
render: (timestamp) =>
|
|
125
|
+
moment.utc(timestamp)?.local().format('DD MMM YYYY - hh:mm A'),
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
title: 'Action',
|
|
129
|
+
dataIndex: 'action',
|
|
130
|
+
key: 'action',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
title: 'User Name',
|
|
134
|
+
dataIndex: 'userName',
|
|
135
|
+
key: 'userName',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
title: 'Message',
|
|
139
|
+
dataIndex: 'message',
|
|
140
|
+
key: 'message',
|
|
141
|
+
render: (message) => (
|
|
142
|
+
<Typography sx={{ fontSize: '16px' }} variant="subtitle1">
|
|
143
|
+
{message?.split("'")?.map((text: string, index: number) =>
|
|
144
|
+
index % 2 === 0 ? (
|
|
145
|
+
<span key={index}>{text}</span>
|
|
146
|
+
) : (
|
|
147
|
+
<Typography key={index} sx={{ display: 'inline', fontWeight: 900 }}>
|
|
148
|
+
{text}
|
|
149
|
+
</Typography>
|
|
150
|
+
),
|
|
151
|
+
)}
|
|
152
|
+
</Typography>
|
|
153
|
+
),
|
|
154
|
+
},
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
export const TimeLineComponent = ({
|
|
158
|
+
activitesData,
|
|
159
|
+
isFetchingNextPage,
|
|
160
|
+
hasNextPage,
|
|
161
|
+
fetchNextPage,
|
|
162
|
+
sx,
|
|
163
|
+
}) => {
|
|
164
|
+
const lastItemRef = useIntersectionObserver<HTMLDivElement>(() => {
|
|
165
|
+
if (!isFetchingNextPage && hasNextPage) fetchNextPage()
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<Timeline sx={{ padding: 0, margin: 0 }}>
|
|
170
|
+
{activitesData?.map((item, index, items) => (
|
|
171
|
+
<Box
|
|
172
|
+
key={index}
|
|
173
|
+
ref={items.length - 1 === index ? lastItemRef : null}
|
|
174
|
+
sx={{ maxWidth: '550px', ...sx }}
|
|
175
|
+
>
|
|
176
|
+
<TimelineItem
|
|
177
|
+
sx={{
|
|
178
|
+
margin: 2,
|
|
179
|
+
padding: 0,
|
|
180
|
+
'&:before': { display: 'none' },
|
|
181
|
+
}}
|
|
182
|
+
>
|
|
183
|
+
<TimelineSeparator>
|
|
184
|
+
<StyledTimeLineDot>
|
|
185
|
+
<StyledCircleIcon />
|
|
186
|
+
</StyledTimeLineDot>
|
|
187
|
+
{index < activitesData?.length - 1 && (
|
|
188
|
+
<Box
|
|
189
|
+
sx={{
|
|
190
|
+
width: '1px',
|
|
191
|
+
height: '115%',
|
|
192
|
+
bgcolor: '#12121233',
|
|
193
|
+
position: 'absolute',
|
|
194
|
+
top: '25px',
|
|
195
|
+
}}
|
|
196
|
+
/>
|
|
197
|
+
)}
|
|
198
|
+
</TimelineSeparator>
|
|
199
|
+
<TimelineContent sx={{ padding: '6px 8px' }}>
|
|
200
|
+
<Box>
|
|
201
|
+
<Typography variant="subtitle2" sx={{ fontSize: '14px' }}>
|
|
202
|
+
{moment
|
|
203
|
+
.utc(item?.timestamp)
|
|
204
|
+
.local()
|
|
205
|
+
.format('DD MMM YYYY - hh:mm A')}
|
|
206
|
+
</Typography>
|
|
207
|
+
<Typography sx={{ fontSize: '16px' }} variant="subtitle1">
|
|
208
|
+
{item?.message
|
|
209
|
+
?.split("'")
|
|
210
|
+
?.map((text: string, index: number) =>
|
|
211
|
+
index % 2 === 0 ? (
|
|
212
|
+
<span key={index}>{text}</span>
|
|
213
|
+
) : (
|
|
214
|
+
<Typography
|
|
215
|
+
key={index}
|
|
216
|
+
sx={{ display: 'inline', fontWeight: 900 }}
|
|
217
|
+
>
|
|
218
|
+
{text}
|
|
219
|
+
</Typography>
|
|
220
|
+
),
|
|
221
|
+
)}
|
|
222
|
+
</Typography>
|
|
223
|
+
<Typography
|
|
224
|
+
style={{
|
|
225
|
+
display: 'flex',
|
|
226
|
+
alignItems: 'center',
|
|
227
|
+
marginTop: '8px',
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
230
|
+
<StyledAvatar>
|
|
231
|
+
{item?.userName?.charAt(0)?.toUpperCase()}
|
|
232
|
+
</StyledAvatar>
|
|
233
|
+
<Typography sx={{ fontSize: '13px', fontWeight: 900 }}>
|
|
234
|
+
{item?.userName}
|
|
235
|
+
</Typography>
|
|
236
|
+
</Typography>
|
|
237
|
+
</Box>
|
|
238
|
+
</TimelineContent>
|
|
239
|
+
</TimelineItem>
|
|
240
|
+
{isFetchingNextPage && index === items?.length - 1 && hasNextPage && (
|
|
241
|
+
<StyledSpinnerBox>
|
|
242
|
+
<Spinner />
|
|
243
|
+
</StyledSpinnerBox>
|
|
244
|
+
)}
|
|
245
|
+
</Box>
|
|
246
|
+
))}
|
|
247
|
+
</Timeline>
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function useIntersectionObserver<T extends HTMLDivElement>(
|
|
252
|
+
callback: () => void,
|
|
253
|
+
) {
|
|
254
|
+
const observer = useRef<IntersectionObserver | null>(null)
|
|
255
|
+
|
|
256
|
+
const handleObserver = useCallback(
|
|
257
|
+
(node: T) => {
|
|
258
|
+
if (observer?.current) observer?.current?.disconnect()
|
|
259
|
+
observer.current = new IntersectionObserver((entries) => {
|
|
260
|
+
if (entries[0]?.isIntersecting) callback()
|
|
261
|
+
})
|
|
262
|
+
if (node) observer?.current?.observe(node)
|
|
263
|
+
},
|
|
264
|
+
[callback],
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
return handleObserver
|
|
268
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import CircleRoundedIcon from '@mui/icons-material/CircleRounded'
|
|
2
|
+
import { TimelineDot } from '@mui/lab'
|
|
3
|
+
import { Avatar, Box, styled } from '@mui/material'
|
|
4
|
+
|
|
5
|
+
export const StyledTimeLineDot = styled(TimelineDot)({
|
|
6
|
+
width: '20px',
|
|
7
|
+
height: '20px',
|
|
8
|
+
boxShadow: 'none',
|
|
9
|
+
backgroundColor: '#F5F5F5',
|
|
10
|
+
border: '1px solid #12121233',
|
|
11
|
+
borderRadius: '50%',
|
|
12
|
+
margin: '5.5px 0',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export const StyledCircleIcon = styled(CircleRoundedIcon)({
|
|
16
|
+
position: 'relative',
|
|
17
|
+
left: '1px',
|
|
18
|
+
top: '1px',
|
|
19
|
+
color: 'black',
|
|
20
|
+
width: '7px',
|
|
21
|
+
height: '7px',
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
|
25
|
+
width: 30,
|
|
26
|
+
height: 30,
|
|
27
|
+
marginRight: '8px',
|
|
28
|
+
fontSize: '14px',
|
|
29
|
+
}))
|
|
30
|
+
|
|
31
|
+
export const StyledSpinnerBox = styled(Box)({
|
|
32
|
+
display: 'flex',
|
|
33
|
+
justifyContent: 'center',
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './ActivityLog'
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
updateCreateUserApplicationProfile,
|
|
16
16
|
userProfileSchema,
|
|
17
17
|
} from './services'
|
|
18
|
+
import { useErrorModal } from '../ErrorModalWrapper/ErrorModalWrapper'
|
|
18
19
|
interface UserProps {
|
|
19
20
|
options: {
|
|
20
21
|
label: any
|
|
@@ -26,6 +27,7 @@ const getDepartments = () => {
|
|
|
26
27
|
return axios.get('/hrms/departments').then((res) => res?.data?.data)
|
|
27
28
|
}
|
|
28
29
|
function UserProfileRelation({ close, application, profiles, data }) {
|
|
30
|
+
const errorModal = useErrorModal()
|
|
29
31
|
const [state, setState] = useImmer<UserProps>({
|
|
30
32
|
options: [],
|
|
31
33
|
inputValue: '',
|
|
@@ -58,7 +60,8 @@ function UserProfileRelation({ close, application, profiles, data }) {
|
|
|
58
60
|
onError: (err) => {
|
|
59
61
|
// eslint-disable-next-line no-console
|
|
60
62
|
console.log(err)
|
|
61
|
-
axiosErrorToast(err)
|
|
63
|
+
// axiosErrorToast(err)
|
|
64
|
+
errorModal({ error: err })
|
|
62
65
|
},
|
|
63
66
|
},
|
|
64
67
|
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Stack } from '@mui/material'
|
|
2
|
+
import { useQuery } from 'react-query'
|
|
3
|
+
import PageHeader from '../PageHeader'
|
|
4
|
+
import Spinner from '../Spinner'
|
|
5
|
+
import { AddConnectionDrawerButton } from './components/AddConnectionDrawerButton'
|
|
6
|
+
import { ConnectionCard } from './components/ConnectionCard'
|
|
7
|
+
import { getPunchLogsDatabaseConfigByTenant } from './service'
|
|
8
|
+
|
|
9
|
+
const DatabaseConfiguration = ({ type }) => {
|
|
10
|
+
const { data: punchLogsDatabaseConfig, isLoading } = useQuery(
|
|
11
|
+
'punch-logs-database-config',
|
|
12
|
+
getPunchLogsDatabaseConfigByTenant,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if (isLoading) return <Spinner />
|
|
16
|
+
return (
|
|
17
|
+
<Stack>
|
|
18
|
+
<PageHeader title="Punch Logs Database Configuration" />
|
|
19
|
+
{!punchLogsDatabaseConfig ? (
|
|
20
|
+
<AddConnectionDrawerButton type={type} />
|
|
21
|
+
) : (
|
|
22
|
+
<ConnectionCard data={punchLogsDatabaseConfig} />
|
|
23
|
+
)}
|
|
24
|
+
</Stack>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default DatabaseConfiguration
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as yup from 'yup'
|
|
2
|
+
import { generateLabelValueOptions } from '../../constants'
|
|
3
|
+
import Form from '../Form/Form'
|
|
4
|
+
import { Field } from '../Form/RenderForm'
|
|
5
|
+
|
|
6
|
+
const fields: Field[] = [
|
|
7
|
+
{
|
|
8
|
+
name: 'host',
|
|
9
|
+
render: 'FormTextField',
|
|
10
|
+
required: true,
|
|
11
|
+
label: 'Host',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'username',
|
|
15
|
+
render: 'FormTextField',
|
|
16
|
+
required: true,
|
|
17
|
+
label: 'Username',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'password',
|
|
21
|
+
render: 'FormTextField',
|
|
22
|
+
required: true,
|
|
23
|
+
label: 'Password',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'port',
|
|
27
|
+
render: 'FormTextField',
|
|
28
|
+
required: true,
|
|
29
|
+
label: 'Port',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'database',
|
|
33
|
+
render: 'FormTextField',
|
|
34
|
+
required: true,
|
|
35
|
+
label: 'Database',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'timezone',
|
|
39
|
+
render: 'FormMultiSelect',
|
|
40
|
+
elementProps: {
|
|
41
|
+
multiple: false,
|
|
42
|
+
},
|
|
43
|
+
validation: yup.object().required('Select a Timezone'),
|
|
44
|
+
required: true,
|
|
45
|
+
label: 'Timezone',
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
export const DatabaseConfigurationForm = ({
|
|
50
|
+
data,
|
|
51
|
+
close,
|
|
52
|
+
successToastMessage,
|
|
53
|
+
type,
|
|
54
|
+
}) => {
|
|
55
|
+
const timezones = Intl.supportedValuesOf('timeZone')
|
|
56
|
+
return (
|
|
57
|
+
<Form
|
|
58
|
+
onCancel={close}
|
|
59
|
+
endPoint="/hrms/punch-logs-database-config"
|
|
60
|
+
fields={fields}
|
|
61
|
+
cols={1}
|
|
62
|
+
refetchKey="punch-logs-database-config"
|
|
63
|
+
dropdowns={{ timezone: generateLabelValueOptions(timezones) }}
|
|
64
|
+
submitBtn={{
|
|
65
|
+
label: 'Save',
|
|
66
|
+
}}
|
|
67
|
+
onSubmit={(originalFormData) => {
|
|
68
|
+
return {
|
|
69
|
+
...originalFormData,
|
|
70
|
+
timezone: originalFormData?.timezone?.value,
|
|
71
|
+
type,
|
|
72
|
+
}
|
|
73
|
+
}}
|
|
74
|
+
defaultValues={{
|
|
75
|
+
...data,
|
|
76
|
+
timezone: {
|
|
77
|
+
label: data?.timezone,
|
|
78
|
+
value: data?.timezone,
|
|
79
|
+
},
|
|
80
|
+
}}
|
|
81
|
+
successToastMessage={successToastMessage}
|
|
82
|
+
onSuccess={() => {
|
|
83
|
+
close()
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Add } from '@mui/icons-material'
|
|
2
|
+
import { Typography } from '@mui/material'
|
|
3
|
+
import { DrawerButton } from '../../ModalButtons'
|
|
4
|
+
import { DatabaseConfigurationForm } from '../DatabaseConfigurationForm'
|
|
5
|
+
import { StyledSelectAttachmentsContainer } from '../styles'
|
|
6
|
+
|
|
7
|
+
export const AddConnectionDrawerButton = ({ type }) => {
|
|
8
|
+
return (
|
|
9
|
+
<DrawerButton
|
|
10
|
+
key={'1'}
|
|
11
|
+
anchor={({ open }) => (
|
|
12
|
+
<StyledSelectAttachmentsContainer onClick={open}>
|
|
13
|
+
<Add />
|
|
14
|
+
<Typography sx={{ margin: '0px 10px', opacity: '0.6' }}>
|
|
15
|
+
Add Database Configuration
|
|
16
|
+
</Typography>
|
|
17
|
+
</StyledSelectAttachmentsContainer>
|
|
18
|
+
)}
|
|
19
|
+
content={({ close }) => (
|
|
20
|
+
<DatabaseConfigurationForm
|
|
21
|
+
type={type}
|
|
22
|
+
data={null}
|
|
23
|
+
close={close}
|
|
24
|
+
successToastMessage="Created Database Configuration"
|
|
25
|
+
/>
|
|
26
|
+
)}
|
|
27
|
+
title="Add Database Configuration"
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
}
|