@campxdev/shared 1.10.41 → 1.10.46
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/components/ApplicationProfile/UserProfileRelation.tsx +42 -8
- package/src/components/ApplicationProfile/services.ts +5 -12
- package/src/components/Layout/Header/AppHeader.tsx +1 -1
- package/src/components/Layout/Header/HeaderActions/CogWheelMenu.tsx +5 -3
- package/src/components/Layout/Header/HeaderActions/HeaderActions.tsx +4 -8
- package/src/components/LoginForm.tsx +6 -3
- package/src/components/StudentCard/FeeCard.tsx +301 -0
- package/src/components/StudentCard/PrintStudentCard.tsx +39 -0
- package/src/components/StudentCard/index.tsx +1 -0
- package/src/components/StudentCard/styles.tsx +34 -0
- package/src/components/index.ts +2 -0
- package/src/shared-state/PermissionsStore.ts +5 -0
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { yupResolver } from '@hookform/resolvers/yup'
|
|
2
2
|
import { Stack } from '@mui/material'
|
|
3
|
+
import { useEffect } from 'react'
|
|
3
4
|
import { useForm } from 'react-hook-form'
|
|
4
|
-
import { useMutation, useQueryClient } from 'react-query'
|
|
5
|
+
import { useMutation, useQuery, useQueryClient } from 'react-query'
|
|
5
6
|
import { toast } from 'react-toastify'
|
|
6
7
|
import { useImmer } from 'use-immer'
|
|
7
|
-
import { axiosErrorToast } from '../../config/axios'
|
|
8
|
+
import axios, { axiosErrorToast } from '../../config/axios'
|
|
8
9
|
import ActionButton from '../ActionButton'
|
|
9
|
-
import { FormMultiSelect } from '../HookForm'
|
|
10
|
+
import { FormMultiSelect, FormSingleSelect } from '../HookForm'
|
|
11
|
+
import Spinner from '../Spinner'
|
|
10
12
|
import {
|
|
11
13
|
editUserProfileSchema,
|
|
12
14
|
fetchUsers,
|
|
@@ -20,20 +22,27 @@ interface UserProps {
|
|
|
20
22
|
}[]
|
|
21
23
|
inputValue: string
|
|
22
24
|
}
|
|
25
|
+
const getDepartments = () => {
|
|
26
|
+
return axios.get('/hrms/departments').then((res) => res?.data?.data)
|
|
27
|
+
}
|
|
23
28
|
function UserProfileRelation({ close, application, profiles, data }) {
|
|
24
29
|
const [state, setState] = useImmer<UserProps>({
|
|
25
30
|
options: [],
|
|
26
31
|
inputValue: '',
|
|
27
32
|
})
|
|
28
33
|
const queryClient = useQueryClient()
|
|
34
|
+
const { data: departments, isLoading } = useQuery('get-department', () =>
|
|
35
|
+
getDepartments(),
|
|
36
|
+
)
|
|
29
37
|
|
|
30
|
-
const { control, handleSubmit } = useForm({
|
|
38
|
+
const { control, handleSubmit, watch } = useForm({
|
|
31
39
|
defaultValues: {
|
|
32
40
|
profileIds:
|
|
33
41
|
data?.profiles?.map((profile) => ({
|
|
34
42
|
label: profile.name,
|
|
35
43
|
value: profile.id,
|
|
36
44
|
})) ?? [],
|
|
45
|
+
departmentId: null,
|
|
37
46
|
},
|
|
38
47
|
resolver: yupResolver(data ? editUserProfileSchema : userProfileSchema),
|
|
39
48
|
})
|
|
@@ -54,6 +63,15 @@ function UserProfileRelation({ close, application, profiles, data }) {
|
|
|
54
63
|
},
|
|
55
64
|
)
|
|
56
65
|
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (watch('departmentId')) {
|
|
68
|
+
fetchUsersFn({
|
|
69
|
+
application: application,
|
|
70
|
+
departmentId: watch('departmentId'),
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
}, [watch('departmentId')])
|
|
74
|
+
|
|
57
75
|
const { mutate: fetchUsersFn, isLoading: gettingUsers } = useMutation(
|
|
58
76
|
fetchUsers,
|
|
59
77
|
{
|
|
@@ -69,10 +87,10 @@ function UserProfileRelation({ close, application, profiles, data }) {
|
|
|
69
87
|
)
|
|
70
88
|
const onSubmit = (formData) => {
|
|
71
89
|
mutate({
|
|
72
|
-
|
|
90
|
+
userIds: formData?.userId?.map((userId) => +userId.value) ?? [],
|
|
73
91
|
application: application,
|
|
74
92
|
profileIds: formData.profileIds?.map((profile) => profile.value) ?? [],
|
|
75
|
-
|
|
93
|
+
...(data && { userId: data?.id }),
|
|
76
94
|
})
|
|
77
95
|
}
|
|
78
96
|
const onError = (err) => {
|
|
@@ -86,22 +104,38 @@ function UserProfileRelation({ close, application, profiles, data }) {
|
|
|
86
104
|
setState((s) => {
|
|
87
105
|
s.inputValue = e.target.value
|
|
88
106
|
})
|
|
89
|
-
if (e.target.value.length
|
|
107
|
+
if (e.target.value.length >= 3) {
|
|
90
108
|
fetchUsersFn({
|
|
91
109
|
application: application,
|
|
92
110
|
search: e.target.value,
|
|
111
|
+
departmentId: watch('departmentId') ?? null,
|
|
93
112
|
})
|
|
94
113
|
}
|
|
95
114
|
}
|
|
96
115
|
}
|
|
97
116
|
|
|
117
|
+
if (isLoading) {
|
|
118
|
+
return <Spinner />
|
|
119
|
+
}
|
|
120
|
+
|
|
98
121
|
return (
|
|
99
122
|
<>
|
|
100
123
|
<form onSubmit={handleSubmit(onSubmit, onError)}>
|
|
101
124
|
<Stack gap={4} sx={{ padding: '10px' }}>
|
|
125
|
+
{!data && (
|
|
126
|
+
<FormSingleSelect
|
|
127
|
+
control={control}
|
|
128
|
+
name="departmentId"
|
|
129
|
+
label="Department"
|
|
130
|
+
options={departments?.map((department) => ({
|
|
131
|
+
label: department.name,
|
|
132
|
+
value: department._id,
|
|
133
|
+
}))}
|
|
134
|
+
/>
|
|
135
|
+
)}
|
|
136
|
+
|
|
102
137
|
{!data && (
|
|
103
138
|
<FormMultiSelect
|
|
104
|
-
multiple={false}
|
|
105
139
|
label={'User'}
|
|
106
140
|
name={'userId'}
|
|
107
141
|
onInputChange={handleInputChange}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AxiosRequestConfig } from 'axios'
|
|
2
|
-
import { id } from 'date-fns/locale'
|
|
3
2
|
import * as yup from 'yup'
|
|
4
3
|
import axios from '../../config/axios'
|
|
5
4
|
export const defaultFilterObj = {
|
|
@@ -12,13 +11,7 @@ export const defaultFilterObj = {
|
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
export const userProfileSchema = yup.object().shape({
|
|
15
|
-
userId: yup
|
|
16
|
-
.object()
|
|
17
|
-
.shape({
|
|
18
|
-
label: yup.string().required('User is required'),
|
|
19
|
-
value: yup.string().required('User is required'),
|
|
20
|
-
})
|
|
21
|
-
.required('User is required'),
|
|
14
|
+
userId: yup.array().min(1).required('User is required'),
|
|
22
15
|
profileIds: yup.array().min(1).required('Profile is required'),
|
|
23
16
|
})
|
|
24
17
|
|
|
@@ -50,9 +43,9 @@ export const fetchProfiles = (application) => {
|
|
|
50
43
|
}
|
|
51
44
|
|
|
52
45
|
interface ApplicationUserProfile {
|
|
53
|
-
|
|
46
|
+
userId?: number
|
|
54
47
|
application: string
|
|
55
|
-
|
|
48
|
+
userIds: number[]
|
|
56
49
|
profileIds: number[]
|
|
57
50
|
}
|
|
58
51
|
export const createApplicationUserProfile = (
|
|
@@ -73,8 +66,8 @@ export const updateCreateUserApplicationProfile = (
|
|
|
73
66
|
postBody: ApplicationUserProfile,
|
|
74
67
|
) => {
|
|
75
68
|
const config: AxiosRequestConfig = {
|
|
76
|
-
method:
|
|
77
|
-
url:
|
|
69
|
+
method: postBody?.userId ? 'PUT' : 'POST',
|
|
70
|
+
url: postBody?.userId
|
|
78
71
|
? `/square/profile-permissions/edit-user-permissions`
|
|
79
72
|
: '/square/profile-permissions/add-user',
|
|
80
73
|
data: postBody,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { SettingsOutlined } from '@mui/icons-material'
|
|
2
2
|
import { IconButton } from '@mui/material'
|
|
3
|
-
import {
|
|
3
|
+
import { useNavigate } from 'react-router-dom'
|
|
4
4
|
import DropDownButton from '../../../DropDownButton/DropDownButton'
|
|
5
5
|
|
|
6
6
|
const CogWheelMenu = ({ menu }) => {
|
|
7
|
-
const
|
|
7
|
+
const navigate = useNavigate()
|
|
8
8
|
|
|
9
9
|
return (
|
|
10
10
|
<DropDownButton
|
|
@@ -16,7 +16,9 @@ const CogWheelMenu = ({ menu }) => {
|
|
|
16
16
|
menu={menu?.map((item) => ({
|
|
17
17
|
label: item?.label,
|
|
18
18
|
onClick: () => {
|
|
19
|
-
|
|
19
|
+
item?.openNewTab
|
|
20
|
+
? window.open(item?.path, '_blank')
|
|
21
|
+
: navigate(item?.path)
|
|
20
22
|
},
|
|
21
23
|
}))}
|
|
22
24
|
menuProps={{
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { Box, styled } from '@mui/material'
|
|
2
|
-
import UserBox from './UserBox'
|
|
3
|
-
import CogWheelMenu from './CogWheelMenu'
|
|
4
|
-
import FreshDeskHelpButton from './FreshDeskHelpButton'
|
|
5
2
|
import InstitutionsDropDown from '../../../Institutions/InstitutionsDropdown'
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import { useEffect } from 'react'
|
|
3
|
+
import CogWheelMenu from './CogWheelMenu'
|
|
4
|
+
import UserBox from './UserBox'
|
|
9
5
|
|
|
10
|
-
const
|
|
6
|
+
const StyledBeamedBox = styled(Box)(() => ({
|
|
11
7
|
width: '60px',
|
|
12
8
|
}))
|
|
13
9
|
|
|
@@ -21,7 +17,7 @@ export default function HeaderActions({
|
|
|
21
17
|
<InstitutionsDropDown />
|
|
22
18
|
{/* <SearchButton /> */}
|
|
23
19
|
{/* <FreshDeskHelpButton /> */}
|
|
24
|
-
<
|
|
20
|
+
<StyledBeamedBox></StyledBeamedBox>
|
|
25
21
|
{cogWheelMenu?.length ? <CogWheelMenu menu={cogWheelMenu} /> : null}
|
|
26
22
|
<UserBox fullName={fullName} actions={userBoxActions} />
|
|
27
23
|
</>
|
|
@@ -15,13 +15,13 @@ import Cookies from 'js-cookie'
|
|
|
15
15
|
import { useEffect, useState } from 'react'
|
|
16
16
|
import { useForm } from 'react-hook-form'
|
|
17
17
|
import { Link } from 'react-router-dom'
|
|
18
|
+
import { campxLogoPrimary } from '../assets/images'
|
|
18
19
|
import axios from '../config/axios'
|
|
19
20
|
import adminAxios from '../utils/adminAxios'
|
|
20
21
|
import ActionButton from './ActionButton'
|
|
21
22
|
import { FormTextField } from './HookForm'
|
|
22
|
-
import ResetPassword from './ResetPassword'
|
|
23
23
|
import Image from './Image/Image'
|
|
24
|
-
import
|
|
24
|
+
import ResetPassword from './ResetPassword'
|
|
25
25
|
|
|
26
26
|
export function LoginForm({
|
|
27
27
|
loginUrl,
|
|
@@ -43,7 +43,10 @@ export function LoginForm({
|
|
|
43
43
|
method: 'POST',
|
|
44
44
|
baseURL: process.env.REACT_APP_API_HOST,
|
|
45
45
|
url: loginUrl ? loginUrl : `/auth-server/auth/login`,
|
|
46
|
-
data:
|
|
46
|
+
data: {
|
|
47
|
+
...values,
|
|
48
|
+
type: 'WEB',
|
|
49
|
+
},
|
|
47
50
|
})
|
|
48
51
|
Cookies.set('campx_tenant', res?.data?.subDomain)
|
|
49
52
|
Cookies.set('campx_session_key', res.data?.token)
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Box,
|
|
3
|
+
Divider,
|
|
4
|
+
Table,
|
|
5
|
+
TableBody,
|
|
6
|
+
TableCell,
|
|
7
|
+
TableHead,
|
|
8
|
+
TableRow,
|
|
9
|
+
Typography,
|
|
10
|
+
} from '@mui/material'
|
|
11
|
+
import { StyledCardBorder } from './styles'
|
|
12
|
+
|
|
13
|
+
function FeeCard({ data, feeDetails }) {
|
|
14
|
+
const studentFirstPart = [
|
|
15
|
+
{ label: 'Roll.No', value: data?.admission?.rollNo ?? '-' },
|
|
16
|
+
{ label: 'Branch', value: data?.admission?.branchCode ?? '-' },
|
|
17
|
+
{ label: 'Seat', value: data?.admission?.quota?.name ?? '-' },
|
|
18
|
+
{ label: 'Student Mobile', value: data?.admission?.mobile ?? '-' },
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const studentSecondPart = [
|
|
22
|
+
{ label: 'Name', value: data?.admission?.fullName ?? '-' },
|
|
23
|
+
{
|
|
24
|
+
label: 'Semester',
|
|
25
|
+
value: data?.admission?.detained
|
|
26
|
+
? 'Detained'
|
|
27
|
+
: data?.admission?.discontinued
|
|
28
|
+
? 'Discontinued'
|
|
29
|
+
: data?.admission?.semNo ?? '-',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: 'ScholarShip',
|
|
33
|
+
value: data?.admission?.hasScholarship ? 'Yes' : 'No',
|
|
34
|
+
},
|
|
35
|
+
{ label: 'Parent Mobile', value: data?.admission?.parentMobile ?? '-' },
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
const totalLateFinesPaid = feeDetails?.map((row) => {
|
|
39
|
+
const latefines = row[1]?.map((latefee) => {
|
|
40
|
+
const fines = latefee?.debits?.reduce((acc, curr) => {
|
|
41
|
+
if (curr.isFine && curr.debit > 0) {
|
|
42
|
+
return acc + curr.debit
|
|
43
|
+
}
|
|
44
|
+
return acc
|
|
45
|
+
}, 0)
|
|
46
|
+
return fines
|
|
47
|
+
})
|
|
48
|
+
return latefines
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const lateFines = feeDetails?.map((row) => {
|
|
52
|
+
const latefine = row[1]?.map((latefee) => {
|
|
53
|
+
const fines = latefee?.credits?.reduce((acc, curr) => {
|
|
54
|
+
if (curr.isFine && curr.credit > 0) {
|
|
55
|
+
return acc + curr.credit
|
|
56
|
+
}
|
|
57
|
+
return acc
|
|
58
|
+
}, 0)
|
|
59
|
+
return fines
|
|
60
|
+
})
|
|
61
|
+
return latefine
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
function amountDue(row: any) {
|
|
65
|
+
const debitTotal = row?.debits?.reduce((acc, curr) => {
|
|
66
|
+
if (!curr.isFine) {
|
|
67
|
+
acc += curr.debit
|
|
68
|
+
}
|
|
69
|
+
return acc
|
|
70
|
+
}, 0)
|
|
71
|
+
|
|
72
|
+
const creditTotal = row?.credits?.reduce((acc, curr) => {
|
|
73
|
+
if (!curr.isFine) {
|
|
74
|
+
acc += curr.credit
|
|
75
|
+
}
|
|
76
|
+
return acc
|
|
77
|
+
}, 0)
|
|
78
|
+
|
|
79
|
+
const difference = Math.abs(creditTotal - debitTotal)
|
|
80
|
+
return difference
|
|
81
|
+
}
|
|
82
|
+
return (
|
|
83
|
+
<StyledCardBorder>
|
|
84
|
+
<Box
|
|
85
|
+
className='school-details'
|
|
86
|
+
sx={{
|
|
87
|
+
display: 'flex',
|
|
88
|
+
flexDirection: 'column',
|
|
89
|
+
padding: '20px',
|
|
90
|
+
alignItems: 'center',
|
|
91
|
+
gap: '10px',
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
<Box>
|
|
95
|
+
<img
|
|
96
|
+
src={data?.institution?.images?.url}
|
|
97
|
+
alt='school-logo'
|
|
98
|
+
width={'200px'}
|
|
99
|
+
/>
|
|
100
|
+
</Box>
|
|
101
|
+
|
|
102
|
+
<Typography variant='h6' sx={{ fontSize: '22px' }}>
|
|
103
|
+
{data?.institution?.name}
|
|
104
|
+
</Typography>
|
|
105
|
+
<Typography variant='h6' textAlign={'center'} sx={{ fontSize: '16px' }}>
|
|
106
|
+
{data?.institution?.recognitionDetails}
|
|
107
|
+
</Typography>
|
|
108
|
+
<Typography variant='h6' textAlign={'center'} sx={{ fontSize: '16px' }}>
|
|
109
|
+
{data?.institution?.address}
|
|
110
|
+
</Typography>
|
|
111
|
+
</Box>
|
|
112
|
+
<Divider />
|
|
113
|
+
<Typography
|
|
114
|
+
variant='h6'
|
|
115
|
+
textAlign={'center'}
|
|
116
|
+
sx={{ margin: '10px', fontSize: '22px' }}
|
|
117
|
+
>
|
|
118
|
+
STUDENT FEE CARD
|
|
119
|
+
</Typography>
|
|
120
|
+
<Divider />
|
|
121
|
+
<Box
|
|
122
|
+
className='student-details'
|
|
123
|
+
sx={{
|
|
124
|
+
display: 'flex',
|
|
125
|
+
padding: '10px',
|
|
126
|
+
gap: '30px',
|
|
127
|
+
justifyContent: 'space-around',
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
<Box sx={{ display: 'flex', gap: '22px' }}>
|
|
131
|
+
<Box>
|
|
132
|
+
{studentFirstPart?.map((item, index) => (
|
|
133
|
+
<Box key={index} sx={{ mt: '10px' }}>
|
|
134
|
+
<Typography variant='h6'>{item.label}</Typography>
|
|
135
|
+
</Box>
|
|
136
|
+
))}
|
|
137
|
+
</Box>
|
|
138
|
+
<Box>
|
|
139
|
+
{studentFirstPart?.map((item, index) => (
|
|
140
|
+
<Box key={index} sx={{ mt: '10px' }}>
|
|
141
|
+
<Typography variant='subtitle1'>{item.value}</Typography>
|
|
142
|
+
</Box>
|
|
143
|
+
))}
|
|
144
|
+
</Box>
|
|
145
|
+
</Box>
|
|
146
|
+
|
|
147
|
+
<Box sx={{ display: 'flex', gap: '12px' }}>
|
|
148
|
+
<Box>
|
|
149
|
+
{studentSecondPart?.map((item, index) => (
|
|
150
|
+
<Box key={index} sx={{ mt: '10px' }}>
|
|
151
|
+
<Typography variant='h6'>{item.label}</Typography>
|
|
152
|
+
</Box>
|
|
153
|
+
))}
|
|
154
|
+
</Box>
|
|
155
|
+
<Box>
|
|
156
|
+
{studentSecondPart?.map((item, index) => (
|
|
157
|
+
<Box key={index} sx={{ mt: '10px' }}>
|
|
158
|
+
<Typography variant='subtitle1'>{item.value}</Typography>
|
|
159
|
+
</Box>
|
|
160
|
+
))}
|
|
161
|
+
</Box>
|
|
162
|
+
</Box>
|
|
163
|
+
|
|
164
|
+
<img
|
|
165
|
+
src={data?.admission?.photo}
|
|
166
|
+
alt='student-photo'
|
|
167
|
+
width={'150px'}
|
|
168
|
+
height={'120px'}
|
|
169
|
+
/>
|
|
170
|
+
</Box>
|
|
171
|
+
|
|
172
|
+
<Divider />
|
|
173
|
+
|
|
174
|
+
<Box>
|
|
175
|
+
<Table>
|
|
176
|
+
<TableHead>
|
|
177
|
+
<TableRow>
|
|
178
|
+
<TableCell>SI.No</TableCell>
|
|
179
|
+
<TableCell>Fee</TableCell>
|
|
180
|
+
<TableCell>Payable</TableCell>
|
|
181
|
+
<TableCell>Paid</TableCell>
|
|
182
|
+
<TableCell>Rec.No(s)</TableCell>
|
|
183
|
+
<TableCell>Rec.Date(s)</TableCell>
|
|
184
|
+
<TableCell>Bank Details</TableCell>
|
|
185
|
+
<TableCell>Due</TableCell>
|
|
186
|
+
<TableCell>Excess paid</TableCell>
|
|
187
|
+
</TableRow>
|
|
188
|
+
</TableHead>
|
|
189
|
+
|
|
190
|
+
{feeDetails?.map((fee, index) => (
|
|
191
|
+
<>
|
|
192
|
+
<TableRow>
|
|
193
|
+
<TableCell colSpan={9}>{fee[0]} Year</TableCell>
|
|
194
|
+
</TableRow>
|
|
195
|
+
<>
|
|
196
|
+
{fee[1]?.map((item, i) => (
|
|
197
|
+
<TableBody key={i}>
|
|
198
|
+
<TableCell>{i + 1}</TableCell>
|
|
199
|
+
<TableCell>{item.feeName}</TableCell>
|
|
200
|
+
<TableCell>
|
|
201
|
+
{item?.credits?.reduce((acc, curr) => {
|
|
202
|
+
if (!curr.isFine) {
|
|
203
|
+
acc = acc + curr.credit
|
|
204
|
+
}
|
|
205
|
+
return acc
|
|
206
|
+
}, 0)}
|
|
207
|
+
</TableCell>
|
|
208
|
+
<TableCell>
|
|
209
|
+
{item?.debits?.reduce((acc, curr) => {
|
|
210
|
+
if (!curr.isFine) {
|
|
211
|
+
acc = acc + curr.debit
|
|
212
|
+
}
|
|
213
|
+
return acc
|
|
214
|
+
}, 0)}
|
|
215
|
+
</TableCell>
|
|
216
|
+
<TableCell>{item?.receipts.join(', ')}</TableCell>
|
|
217
|
+
<TableCell>{item?.receiptDates?.join(', ')}</TableCell>
|
|
218
|
+
<TableCell>{item.bankDetails?.join(' ')}</TableCell>
|
|
219
|
+
<TableCell>
|
|
220
|
+
{amountDue(item)}
|
|
221
|
+
{lateFines[index][i] > 0 &&
|
|
222
|
+
totalLateFinesPaid[index][i] == 0 && (
|
|
223
|
+
<Typography variant='caption' color={'red'}>
|
|
224
|
+
{'(+' +
|
|
225
|
+
`${
|
|
226
|
+
lateFines[index][i] -
|
|
227
|
+
totalLateFinesPaid[index][i]
|
|
228
|
+
}` +
|
|
229
|
+
' Late fee)'}
|
|
230
|
+
</Typography>
|
|
231
|
+
)}
|
|
232
|
+
</TableCell>
|
|
233
|
+
<TableCell>
|
|
234
|
+
{item?.debits?.reduce((acc, curr) => {
|
|
235
|
+
if (curr.isFine) {
|
|
236
|
+
acc = acc + curr.debit
|
|
237
|
+
}
|
|
238
|
+
return acc
|
|
239
|
+
}, 0)}
|
|
240
|
+
</TableCell>
|
|
241
|
+
</TableBody>
|
|
242
|
+
))}
|
|
243
|
+
</>
|
|
244
|
+
<TableHead>
|
|
245
|
+
<TableRow>
|
|
246
|
+
<TableCell colSpan={2}>
|
|
247
|
+
<Typography variant='h6'>{fee[0]} year total</Typography>
|
|
248
|
+
</TableCell>
|
|
249
|
+
<TableCell>
|
|
250
|
+
<Typography variant='h6'>
|
|
251
|
+
{data?.totalFeesByYear[index]?.amount}
|
|
252
|
+
</Typography>
|
|
253
|
+
</TableCell>
|
|
254
|
+
<TableCell colSpan={4}>
|
|
255
|
+
<Typography variant='h6'>
|
|
256
|
+
{data?.totalFeesPaidByYear[index]?.amount}{' '}
|
|
257
|
+
</Typography>
|
|
258
|
+
</TableCell>
|
|
259
|
+
<TableCell>
|
|
260
|
+
<Typography variant='h6'>
|
|
261
|
+
{data?.totalFeesDueByYear[index]?.amount}
|
|
262
|
+
</Typography>
|
|
263
|
+
</TableCell>
|
|
264
|
+
<TableCell>
|
|
265
|
+
<Typography variant='h6'>
|
|
266
|
+
{data?.totalFeesExcessiveByYear[index]?.amount}
|
|
267
|
+
</Typography>
|
|
268
|
+
</TableCell>
|
|
269
|
+
</TableRow>
|
|
270
|
+
</TableHead>
|
|
271
|
+
</>
|
|
272
|
+
))}
|
|
273
|
+
|
|
274
|
+
<TableHead>
|
|
275
|
+
<TableRow>
|
|
276
|
+
<TableCell colSpan={2}>
|
|
277
|
+
<Typography variant='h6'>Grand total</Typography>
|
|
278
|
+
</TableCell>
|
|
279
|
+
<TableCell>
|
|
280
|
+
<Typography variant='h6'>{data?.grandFeeTotal}</Typography>
|
|
281
|
+
</TableCell>
|
|
282
|
+
<TableCell colSpan={4}>
|
|
283
|
+
<Typography variant='h6'>{data?.grandFeePaidTotal} </Typography>
|
|
284
|
+
</TableCell>
|
|
285
|
+
<TableCell>
|
|
286
|
+
<Typography variant='h6'>{data?.grandFeeDueTotal}</Typography>
|
|
287
|
+
</TableCell>
|
|
288
|
+
<TableCell>
|
|
289
|
+
<Typography variant='h6'>
|
|
290
|
+
{data?.grandFeeExcessiveTotal}
|
|
291
|
+
</Typography>
|
|
292
|
+
</TableCell>
|
|
293
|
+
</TableRow>
|
|
294
|
+
</TableHead>
|
|
295
|
+
</Table>
|
|
296
|
+
</Box>
|
|
297
|
+
</StyledCardBorder>
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export default FeeCard
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Container } from '@mui/material'
|
|
2
|
+
import _ from 'lodash'
|
|
3
|
+
import { useQuery } from 'react-query'
|
|
4
|
+
import { useSearchParams } from 'react-router-dom'
|
|
5
|
+
import axios from '../../config/axios'
|
|
6
|
+
import Spinner from '../Spinner'
|
|
7
|
+
import FeeCard from './FeeCard'
|
|
8
|
+
|
|
9
|
+
function PrintStudentCard({ url }) {
|
|
10
|
+
const [search] = useSearchParams()
|
|
11
|
+
const { data, isLoading } = useQuery('print-student-card', () =>
|
|
12
|
+
axios
|
|
13
|
+
.get(url, {
|
|
14
|
+
params: {
|
|
15
|
+
id: search.get('id'),
|
|
16
|
+
idType: search.get('idType'),
|
|
17
|
+
},
|
|
18
|
+
})
|
|
19
|
+
.then((res) => res.data),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if (isLoading) return <Spinner />
|
|
23
|
+
|
|
24
|
+
const feeDetails = Object.entries(
|
|
25
|
+
_.groupBy(data?.feeDataResult, 'year'),
|
|
26
|
+
)?.map((item) => {
|
|
27
|
+
return item
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<>
|
|
32
|
+
<Container>
|
|
33
|
+
<FeeCard data={data} feeDetails={feeDetails} />
|
|
34
|
+
</Container>
|
|
35
|
+
</>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default PrintStudentCard
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './PrintStudentCard'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Box, Typography, styled } from '@mui/material'
|
|
2
|
+
|
|
3
|
+
export const StyledCardBorder = styled(Box)(({ theme }) => ({
|
|
4
|
+
border: theme.borders.grayLight,
|
|
5
|
+
display: 'inline-block',
|
|
6
|
+
width: '100%',
|
|
7
|
+
height: 'auto',
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
export const StyledSchoolHeader = styled(Box)(({ theme }) => ({
|
|
11
|
+
textAlign: 'center',
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
export const StyledMainBox = styled(Box)({
|
|
15
|
+
display: 'flex',
|
|
16
|
+
marginTop: '30px',
|
|
17
|
+
gap: '10px',
|
|
18
|
+
alignItems: 'flex-end',
|
|
19
|
+
marginBottom: '20px',
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export const StyledSearch = styled(Box)({
|
|
23
|
+
border: '1px solid #22222233 ',
|
|
24
|
+
padding: '7px',
|
|
25
|
+
maxHeight: '55px',
|
|
26
|
+
borderRadius: '10px',
|
|
27
|
+
width: '400px',
|
|
28
|
+
})
|
|
29
|
+
export const StyledSearchLabel = styled(Typography)({
|
|
30
|
+
fontSize: '14px',
|
|
31
|
+
fontWeight: 'bold',
|
|
32
|
+
margin: '0px 0px 3px 10px',
|
|
33
|
+
color: '#888888',
|
|
34
|
+
})
|
package/src/components/index.ts
CHANGED
|
@@ -36,6 +36,7 @@ import { CustomDrawer } from './ModalButtons/DrawerButton'
|
|
|
36
36
|
import ExcelJsonUpload from './ExcelToJsonInput/ExcelJsonUpload'
|
|
37
37
|
import ExcelToJsonInput from './ExcelToJsonInput'
|
|
38
38
|
import ApplicationProfile from './ApplicationProfile'
|
|
39
|
+
import PrintStudentCard from './StudentCard'
|
|
39
40
|
import PopoverButton from './ModalButtons/PopoverButton'
|
|
40
41
|
export { default as Image } from './Image'
|
|
41
42
|
export { default as PageHeader } from './PageHeader'
|
|
@@ -101,6 +102,7 @@ export {
|
|
|
101
102
|
ExcelJsonUpload,
|
|
102
103
|
ExcelToJsonInput,
|
|
103
104
|
ApplicationProfile,
|
|
105
|
+
PrintStudentCard,
|
|
104
106
|
PopoverButton,
|
|
105
107
|
}
|
|
106
108
|
|
|
@@ -685,6 +685,11 @@ export enum Permission {
|
|
|
685
685
|
CAN_HOSTEL_TICKETS_DELETE = 'can_hostel_tickets_delete',
|
|
686
686
|
CAN_HOSTEL_TICKETS_ADD = 'can_hostel_tickets_add',
|
|
687
687
|
|
|
688
|
+
// Hosteler attendence
|
|
689
|
+
CAN_HOSTELER_ATTENDANCE_VIEW = 'can_hosteler_attendance_view',
|
|
690
|
+
CAN_HOSTELER_ATTENDANCE_EDIT = 'can_hosteler_attendance_edit',
|
|
691
|
+
CAN_HOSTELER_ATTENDANCE_ADD = 'can_hosteler_attendance_add',
|
|
692
|
+
|
|
688
693
|
// Square
|
|
689
694
|
// manage
|
|
690
695
|
|