@campxdev/shared 1.10.72 → 1.10.74
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 +2 -1
- package/src/components/ApplicationProfile/ApplicationProfile.tsx +35 -1
- package/src/components/CurvedArrow.tsx +48 -0
- package/src/components/CustomJoyRideStyles.css +18 -0
- package/src/components/ReactJoyRide.tsx +77 -10
- package/src/components/Selectors/FormSelectors/MultiSelect/MultiFeeTypeSelector.tsx +81 -0
- package/src/components/Selectors/index.tsx +2 -0
- package/src/components/Tables/2DTable/Table.tsx +285 -0
- package/src/components/Tables/2DTable/TableFooter.tsx +86 -0
- package/src/components/Tables/2DTable/index.tsx +1 -0
- package/src/components/Tables/2DTable/interface.ts +19 -0
- package/src/components/Tables/2DTable/styles.ts +105 -0
- package/src/components/index.ts +1 -0
- package/src/shared-state/PermissionsStore.ts +25 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@campxdev/shared",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.74",
|
|
4
4
|
"main": "./exports.ts",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"start": "react-scripts start",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"moment": "^2.29.4",
|
|
42
42
|
"pullstate": "^1.24.0",
|
|
43
43
|
"react": "^18.2.0",
|
|
44
|
+
"react-arrows": "^1.2.0",
|
|
44
45
|
"react-dom": "^18.2.0",
|
|
45
46
|
"react-error-boundary": "^3.1.4",
|
|
46
47
|
"react-flatpickr": "^3.10.13",
|
|
@@ -22,6 +22,9 @@ import SearchBar from '../FilterComponents/SearchBar'
|
|
|
22
22
|
import { DialogButton, DrawerButton } from '../ModalButtons'
|
|
23
23
|
import Table from '../Tables/BasicTable/Table'
|
|
24
24
|
import DepartmentFilter from './DepartmentFilter'
|
|
25
|
+
import ReactJoyRide from '../ReactJoyRide'
|
|
26
|
+
// import Arrow, { DIRECTION } from 'react-arrows'
|
|
27
|
+
import '../CustomJoyRideStyles.css'
|
|
25
28
|
|
|
26
29
|
interface ApplicationProfileProps {
|
|
27
30
|
application:
|
|
@@ -40,6 +43,7 @@ interface ApplicationProfileProps {
|
|
|
40
43
|
delete: string
|
|
41
44
|
}
|
|
42
45
|
}
|
|
46
|
+
|
|
43
47
|
function ApplicationProfile({
|
|
44
48
|
application,
|
|
45
49
|
title,
|
|
@@ -160,9 +164,33 @@ function ApplicationProfile({
|
|
|
160
164
|
})
|
|
161
165
|
}
|
|
162
166
|
|
|
167
|
+
const tourSteps = [
|
|
168
|
+
{
|
|
169
|
+
target: '.test',
|
|
170
|
+
title: 'Adding User Profile Relation',
|
|
171
|
+
content: (
|
|
172
|
+
<Typography variant="subtitle1">
|
|
173
|
+
Choose your Profile Relation from the pre-given dropdowns
|
|
174
|
+
</Typography>
|
|
175
|
+
),
|
|
176
|
+
disableBeacon: true,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
target: '.test2',
|
|
180
|
+
title: 'Search By Name',
|
|
181
|
+
content: (
|
|
182
|
+
<Typography variant="subtitle1">
|
|
183
|
+
You can also find the person by just typing his name away!
|
|
184
|
+
</Typography>
|
|
185
|
+
),
|
|
186
|
+
},
|
|
187
|
+
]
|
|
188
|
+
|
|
163
189
|
if (profilesLoading) return <Spinner />
|
|
164
190
|
return (
|
|
165
191
|
<>
|
|
192
|
+
<ReactJoyRide steps={tourSteps} tourName="Application-Profile-Tour" />
|
|
193
|
+
|
|
166
194
|
<PageHeader
|
|
167
195
|
title={title}
|
|
168
196
|
actions={[
|
|
@@ -177,7 +205,11 @@ function ApplicationProfile({
|
|
|
177
205
|
<DialogButton
|
|
178
206
|
title={'Add User Profile Relation'}
|
|
179
207
|
anchor={({ open }) => (
|
|
180
|
-
<ActionButton
|
|
208
|
+
<ActionButton
|
|
209
|
+
onClick={open}
|
|
210
|
+
className="test"
|
|
211
|
+
sx={{ inset: 'auto' }}
|
|
212
|
+
>
|
|
181
213
|
Add User Profile Relation
|
|
182
214
|
</ActionButton>
|
|
183
215
|
)}
|
|
@@ -193,6 +225,7 @@ function ApplicationProfile({
|
|
|
193
225
|
</ValidateAccess>,
|
|
194
226
|
]}
|
|
195
227
|
/>
|
|
228
|
+
|
|
196
229
|
<PageContent sx={{ marginTop: '25px' }}>
|
|
197
230
|
<StyledTableContainer>
|
|
198
231
|
<Box
|
|
@@ -211,6 +244,7 @@ function ApplicationProfile({
|
|
|
211
244
|
})
|
|
212
245
|
}
|
|
213
246
|
textFieldProps={{
|
|
247
|
+
className: 'test2',
|
|
214
248
|
placeholder: 'Search by Name',
|
|
215
249
|
title: 'Search by Name',
|
|
216
250
|
sx: { width: '300px' },
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react'
|
|
2
|
+
import './CustomJoyRideStyles.css'
|
|
3
|
+
|
|
4
|
+
class Arrow {
|
|
5
|
+
constructor(w, h) {
|
|
6
|
+
if (!w) w = 300
|
|
7
|
+
if (!h) h = 150
|
|
8
|
+
|
|
9
|
+
const pad = Math.round(w / 6)
|
|
10
|
+
|
|
11
|
+
// container
|
|
12
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
|
13
|
+
svg.style.width = `${w}px`
|
|
14
|
+
svg.style.height = `${h}px`
|
|
15
|
+
svg.classList.add('arrow')
|
|
16
|
+
|
|
17
|
+
// line
|
|
18
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
|
19
|
+
path.setAttribute(
|
|
20
|
+
'd',
|
|
21
|
+
`M 0 0 C ${pad} ${h}, ${w - pad - 10} ${h - 10}, ${w - 8} 5`,
|
|
22
|
+
)
|
|
23
|
+
svg.appendChild(path)
|
|
24
|
+
|
|
25
|
+
// arrowhead
|
|
26
|
+
const polygon = document.createElementNS(
|
|
27
|
+
'http://www.w3.org/2000/svg',
|
|
28
|
+
'polygon',
|
|
29
|
+
)
|
|
30
|
+
polygon.setAttribute('points', `${w - 3} 0, ${w - 13} 3, ${w - 3} 9`)
|
|
31
|
+
svg.appendChild(polygon)
|
|
32
|
+
|
|
33
|
+
return svg
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const CurvedArrow = () => {
|
|
38
|
+
const arrowRef = useRef(null)
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
const arrow = new Arrow(100, 100)
|
|
42
|
+
arrowRef.current.appendChild(arrow)
|
|
43
|
+
}, [])
|
|
44
|
+
|
|
45
|
+
return <div ref={arrowRef}></div>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default CurvedArrow
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.react-joyride__tooltip {
|
|
2
|
+
background-color: 'rgb(255, 255, 255)';
|
|
3
|
+
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
div.react-joyride__tooltip > div:nth-child(1) {
|
|
7
|
+
text-align: left !important;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
div.react-joyride__tooltip > div:nth-child(1) div:nth-child(2) {
|
|
11
|
+
padding: 20px 0px !important;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
div.react-joyride__tooltip > div:nth-child(2) {
|
|
15
|
+
flex-direction: row-reverse !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
@@ -1,24 +1,55 @@
|
|
|
1
1
|
import TourIcon from '@mui/icons-material/Tour'
|
|
2
2
|
import { Box, IconButton } from '@mui/material'
|
|
3
|
-
import { ReactNode, useState } from 'react'
|
|
3
|
+
import { ReactNode, useEffect, useState } from 'react'
|
|
4
4
|
import ReactJoyride, { Step } from 'react-joyride'
|
|
5
|
+
import { useQuery } from 'react-query'
|
|
6
|
+
import axios from '../config/axios'
|
|
7
|
+
import './CustomJoyRideStyles.css'
|
|
5
8
|
|
|
6
9
|
function ReactJoyRide({
|
|
7
10
|
steps,
|
|
8
11
|
children,
|
|
12
|
+
tourName,
|
|
9
13
|
}: {
|
|
10
14
|
steps: Step[]
|
|
11
|
-
children
|
|
15
|
+
children?: ReactNode
|
|
16
|
+
tourName: string
|
|
12
17
|
}) {
|
|
13
18
|
const [run, setRun] = useState(false)
|
|
14
19
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
const fetchTours = (params) => {
|
|
21
|
+
return axios.get(`/square/tours`).then((res) => res.data)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { data: toursData, isLoading: toursLoading } = useQuery(
|
|
25
|
+
'tours',
|
|
26
|
+
fetchTours,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (toursData && !toursData.includes(tourName)) {
|
|
31
|
+
setRun(true)
|
|
32
|
+
}
|
|
33
|
+
}, [toursLoading])
|
|
34
|
+
|
|
35
|
+
const completeTour = async () => {
|
|
36
|
+
try {
|
|
37
|
+
await axios.post(`/square/tours/complete`, { tourName })
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// console.error('Error in Completing Tour:', error)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const handleJoyRideCallback = (data) => {
|
|
44
|
+
const { action, status } = data
|
|
45
|
+
|
|
46
|
+
if (action === 'skip') {
|
|
47
|
+
completeTour()
|
|
48
|
+
}
|
|
49
|
+
if (status === 'finished' || status === 'skip' || status === 'closed') {
|
|
21
50
|
setRun(false)
|
|
51
|
+
completeTour()
|
|
52
|
+
}
|
|
22
53
|
|
|
23
54
|
if (data.action == 'close' || data.action == 'skip') setRun(false)
|
|
24
55
|
}
|
|
@@ -27,17 +58,53 @@ function ReactJoyRide({
|
|
|
27
58
|
<>
|
|
28
59
|
<Box>
|
|
29
60
|
<ReactJoyride
|
|
30
|
-
callback={
|
|
61
|
+
callback={handleJoyRideCallback}
|
|
31
62
|
run={run}
|
|
32
63
|
steps={steps}
|
|
64
|
+
styles={{
|
|
65
|
+
buttonNext: {
|
|
66
|
+
backgroundColor: 'black',
|
|
67
|
+
color: 'yellow',
|
|
68
|
+
height: '28px',
|
|
69
|
+
width: '100px',
|
|
70
|
+
padding: '0px',
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
buttonBack: {
|
|
74
|
+
backgroundColor: 'cement',
|
|
75
|
+
color: 'black',
|
|
76
|
+
borderRadius: '4px',
|
|
77
|
+
height: '30px',
|
|
78
|
+
width: '100px',
|
|
79
|
+
gap: '10px',
|
|
80
|
+
marginLeft: '5px',
|
|
81
|
+
padding: '0px',
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
buttonSkip: {
|
|
85
|
+
backgroundColor: 'transparent',
|
|
86
|
+
color: 'cement',
|
|
87
|
+
borderRadius: '0px',
|
|
88
|
+
border: '0px',
|
|
89
|
+
fontSize: '13px',
|
|
90
|
+
padding: '21px 15px',
|
|
91
|
+
right: '0px',
|
|
92
|
+
top: '0px',
|
|
93
|
+
position: 'absolute',
|
|
94
|
+
lineHeight: 1,
|
|
95
|
+
},
|
|
96
|
+
}}
|
|
33
97
|
continuous
|
|
34
98
|
showSkipButton
|
|
35
|
-
showProgress
|
|
36
99
|
scrollToFirstStep
|
|
100
|
+
disableOverlay
|
|
37
101
|
disableOverlayClose
|
|
38
102
|
disableScrolling
|
|
103
|
+
hideCloseButton
|
|
39
104
|
/>
|
|
105
|
+
|
|
40
106
|
{children}
|
|
107
|
+
|
|
41
108
|
<IconButton
|
|
42
109
|
onClick={() => setRun(true)}
|
|
43
110
|
sx={{
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { SelectProps } from '@mui/material'
|
|
2
|
+
import { useEffect, useState } from 'react'
|
|
3
|
+
import { Controller } from 'react-hook-form'
|
|
4
|
+
import axios from '../../../../config/axios'
|
|
5
|
+
import { MultiSelect } from '../../../Input'
|
|
6
|
+
|
|
7
|
+
type MultiProgramSelectorProps = {
|
|
8
|
+
control: any
|
|
9
|
+
name?: string
|
|
10
|
+
label: string
|
|
11
|
+
required?: boolean
|
|
12
|
+
onChange?: (value: any) => void
|
|
13
|
+
allowAll?: boolean
|
|
14
|
+
error?: boolean
|
|
15
|
+
helperText?: string
|
|
16
|
+
} & SelectProps
|
|
17
|
+
const MultiFeeTypeSelector = (props: MultiProgramSelectorProps) => {
|
|
18
|
+
const {
|
|
19
|
+
control,
|
|
20
|
+
onChange,
|
|
21
|
+
name,
|
|
22
|
+
required = false,
|
|
23
|
+
label,
|
|
24
|
+
multiple = false,
|
|
25
|
+
value,
|
|
26
|
+
allowAll = true,
|
|
27
|
+
} = props
|
|
28
|
+
const [options, setOptions] = useState([])
|
|
29
|
+
const [prevCourseId, setPrevCourseId] = useState(null)
|
|
30
|
+
const handleOpen = () => {
|
|
31
|
+
if (options.length === 0) {
|
|
32
|
+
axios
|
|
33
|
+
.get('/paymentx/fee-types')
|
|
34
|
+
.then((response) => {
|
|
35
|
+
setOptions(response.data)
|
|
36
|
+
})
|
|
37
|
+
.catch((error) => {
|
|
38
|
+
console.error('Error fetching data from the API:', error)
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (props?.value && props.value != 'all') {
|
|
44
|
+
handleOpen()
|
|
45
|
+
}
|
|
46
|
+
}, [props.value])
|
|
47
|
+
|
|
48
|
+
const handleOptions =
|
|
49
|
+
options.length > 0
|
|
50
|
+
? [
|
|
51
|
+
...(allowAll ? [{ value: 'all', label: 'All' }] : []),
|
|
52
|
+
...options.map((item) => ({
|
|
53
|
+
label: `${item.name}`,
|
|
54
|
+
value: `${item.id}`,
|
|
55
|
+
})),
|
|
56
|
+
]
|
|
57
|
+
: allowAll
|
|
58
|
+
? [{ value: 'all', label: 'All' }]
|
|
59
|
+
: []
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Controller
|
|
63
|
+
name={name}
|
|
64
|
+
control={control}
|
|
65
|
+
render={({ field, fieldState: { error } }) => (
|
|
66
|
+
<MultiSelect
|
|
67
|
+
name={name}
|
|
68
|
+
label={label}
|
|
69
|
+
required={required}
|
|
70
|
+
options={handleOptions}
|
|
71
|
+
onOpen={handleOpen}
|
|
72
|
+
onChange={onChange ?? field.onChange}
|
|
73
|
+
value={value ?? field?.value}
|
|
74
|
+
error={!!error}
|
|
75
|
+
helperText={error?.message}
|
|
76
|
+
/>
|
|
77
|
+
)}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
export default MultiFeeTypeSelector
|
|
@@ -5,6 +5,7 @@ import FormFeeTypeSelector from './FormSelectors/FormFeeTypeSelector'
|
|
|
5
5
|
import FormProgramSelector from './FormSelectors/FormProgramSelector'
|
|
6
6
|
import FormQuotaSelector from './FormSelectors/FormQuotaSelector'
|
|
7
7
|
import FormSemseterSelector from './FormSelectors/FormSemesterSelector'
|
|
8
|
+
import MultiFeeTypeSelector from './FormSelectors/MultiSelect/MultiFeeTypeSelector'
|
|
8
9
|
import MultiProgramSelector from './FormSelectors/MultiSelect/MultiProgramSelector'
|
|
9
10
|
import MultiQuotaSelector from './FormSelectors/MultiSelect/MultiQuotaSelector'
|
|
10
11
|
import ProgramSelector from './ProgramSelector'
|
|
@@ -19,6 +20,7 @@ export {
|
|
|
19
20
|
FormProgramSelector,
|
|
20
21
|
FormQuotaSelector,
|
|
21
22
|
FormSemseterSelector,
|
|
23
|
+
MultiFeeTypeSelector,
|
|
22
24
|
MultiProgramSelector,
|
|
23
25
|
MultiQuotaSelector,
|
|
24
26
|
ProgramSelector,
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IconButton,
|
|
3
|
+
ListItemIcon,
|
|
4
|
+
TableBody,
|
|
5
|
+
TableHead,
|
|
6
|
+
TableRow,
|
|
7
|
+
Theme,
|
|
8
|
+
} from '@mui/material'
|
|
9
|
+
import { SxProps } from '@mui/system'
|
|
10
|
+
import _ from 'lodash'
|
|
11
|
+
import { useEffect, useState } from 'react'
|
|
12
|
+
import Spinner from '../../Spinner'
|
|
13
|
+
import NoRecordsFound from '../common/NoRecordsFound'
|
|
14
|
+
import { SortAscIcon, SortDescIcon, SortIcon } from '../common/icons'
|
|
15
|
+
import TableFooter from './TableFooter'
|
|
16
|
+
import {
|
|
17
|
+
StyledMuiTable,
|
|
18
|
+
StyledTableCell,
|
|
19
|
+
StyledTableContainer,
|
|
20
|
+
StyledTableRow,
|
|
21
|
+
} from './styles'
|
|
22
|
+
|
|
23
|
+
type Order = 'asc' | 'desc' | ''
|
|
24
|
+
type Sort = {}
|
|
25
|
+
type DataType = 'currency' | 'string' | 'number'
|
|
26
|
+
export interface TableColumn {
|
|
27
|
+
dataIndex: string
|
|
28
|
+
key: string
|
|
29
|
+
title?: any
|
|
30
|
+
render?: (cellData: any, row: any, index: number) => any
|
|
31
|
+
textColor?: string
|
|
32
|
+
sort?: boolean
|
|
33
|
+
width?: string //pixels
|
|
34
|
+
dataType?: DataType
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ColumnHeader {
|
|
38
|
+
title: any
|
|
39
|
+
colSpan: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface TableProps {
|
|
43
|
+
columns: Array<TableColumn>
|
|
44
|
+
rowKey?: string
|
|
45
|
+
dataSource?: any[]
|
|
46
|
+
loading?: boolean
|
|
47
|
+
onRowClick?: (row: any) => void
|
|
48
|
+
pagination?: {
|
|
49
|
+
page: number
|
|
50
|
+
limit: number
|
|
51
|
+
totalCount: number
|
|
52
|
+
onChange: (v: number) => void
|
|
53
|
+
onChangeLimit?: (v: number) => void
|
|
54
|
+
}
|
|
55
|
+
onSort?: (sort: any) => void
|
|
56
|
+
dense?: boolean
|
|
57
|
+
showTotal?: boolean
|
|
58
|
+
sx?: Record<string, SxProps<Theme>>
|
|
59
|
+
totalColumns?: number[]
|
|
60
|
+
showTotalInFirstCellOfTotalRow?: boolean
|
|
61
|
+
columnsHeader?: Array<ColumnHeader>
|
|
62
|
+
}
|
|
63
|
+
export default function Table({
|
|
64
|
+
columns,
|
|
65
|
+
dataSource,
|
|
66
|
+
onRowClick,
|
|
67
|
+
pagination,
|
|
68
|
+
loading,
|
|
69
|
+
columnsHeader,
|
|
70
|
+
onSort,
|
|
71
|
+
dense = false,
|
|
72
|
+
showTotal = false,
|
|
73
|
+
sx,
|
|
74
|
+
totalColumns,
|
|
75
|
+
showTotalInFirstCellOfTotalRow,
|
|
76
|
+
}: TableProps) {
|
|
77
|
+
const [sort, setSort] = useState<Sort>({})
|
|
78
|
+
let totalCount = []
|
|
79
|
+
let totalCols = []
|
|
80
|
+
if (showTotalInFirstCellOfTotalRow) {
|
|
81
|
+
totalCols = totalColumns ? [...totalColumns, 1] : [1]
|
|
82
|
+
} else {
|
|
83
|
+
totalCols = totalColumns ? [...totalColumns] : []
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const handleSortClick = (sortBykey) => {
|
|
87
|
+
setSort((prev) => {
|
|
88
|
+
if (prev[sortBykey]) {
|
|
89
|
+
if (prev[sortBykey] === 'desc') return { ...prev, [sortBykey]: 'asc' }
|
|
90
|
+
if (prev[sortBykey] === 'asc') {
|
|
91
|
+
delete prev[sortBykey]
|
|
92
|
+
return { ...prev }
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
return {
|
|
96
|
+
...prev,
|
|
97
|
+
[sortBykey]: 'desc',
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!onSort) return
|
|
105
|
+
|
|
106
|
+
onSort({
|
|
107
|
+
sortBy: Object.keys(sort).join(','),
|
|
108
|
+
sortOrder: Object.keys(sort)
|
|
109
|
+
.map((item) => sort[item])
|
|
110
|
+
.join(','),
|
|
111
|
+
})
|
|
112
|
+
}, [sort])
|
|
113
|
+
|
|
114
|
+
const calculateTotal = (row) => {
|
|
115
|
+
columns.forEach((col, colIndex) => {
|
|
116
|
+
const colValue = col?.render
|
|
117
|
+
? col.render(row[col.dataIndex], row, colIndex)
|
|
118
|
+
: _.get(row, col.dataIndex)
|
|
119
|
+
|
|
120
|
+
if (!totalCount[colIndex]) {
|
|
121
|
+
totalCount[colIndex] = 0
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (showTotalInFirstCellOfTotalRow && colIndex === 0) {
|
|
125
|
+
totalCount[colIndex] = 'Total'
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
totalCount[colIndex] += colValue
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const convertToAmount = (data) => {
|
|
134
|
+
return data.toLocaleString('en-IN', {
|
|
135
|
+
style: 'currency',
|
|
136
|
+
currency: 'INR',
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<StyledTableContainer sx={sx}>
|
|
142
|
+
<>
|
|
143
|
+
<StyledMuiTable sx={sx}>
|
|
144
|
+
<TableHead>
|
|
145
|
+
{columnsHeader && (
|
|
146
|
+
<TableRow>
|
|
147
|
+
{columnsHeader.map((col, columnIndex) => (
|
|
148
|
+
<StyledTableCell
|
|
149
|
+
key={columnIndex}
|
|
150
|
+
columnsLength={columns.length}
|
|
151
|
+
columnIndex={columnIndex + 1}
|
|
152
|
+
rowIndex={0}
|
|
153
|
+
col={col}
|
|
154
|
+
sx={sx}
|
|
155
|
+
isHeaderCell
|
|
156
|
+
align="center"
|
|
157
|
+
colSpan={col.colSpan}
|
|
158
|
+
>
|
|
159
|
+
{col.title}
|
|
160
|
+
</StyledTableCell>
|
|
161
|
+
))}
|
|
162
|
+
</TableRow>
|
|
163
|
+
)}
|
|
164
|
+
<TableRow>
|
|
165
|
+
{columns.map((col, columnIndex) => (
|
|
166
|
+
<StyledTableCell
|
|
167
|
+
key={columnIndex}
|
|
168
|
+
columnsLength={columns.length}
|
|
169
|
+
columnIndex={columnIndex + 1}
|
|
170
|
+
rowIndex={0}
|
|
171
|
+
col={col}
|
|
172
|
+
sx={sx}
|
|
173
|
+
align="center"
|
|
174
|
+
isHeaderCell
|
|
175
|
+
>
|
|
176
|
+
{col.title}
|
|
177
|
+
|
|
178
|
+
{col.sort && (
|
|
179
|
+
<IconButton onClick={() => handleSortClick(col.dataIndex)}>
|
|
180
|
+
<ListItemIcon>
|
|
181
|
+
{sort[col.dataIndex] === 'asc' ? (
|
|
182
|
+
<SortAscIcon />
|
|
183
|
+
) : sort[col.dataIndex] === 'desc' ? (
|
|
184
|
+
<SortDescIcon />
|
|
185
|
+
) : (
|
|
186
|
+
<SortIcon />
|
|
187
|
+
)}
|
|
188
|
+
</ListItemIcon>
|
|
189
|
+
</IconButton>
|
|
190
|
+
)}
|
|
191
|
+
</StyledTableCell>
|
|
192
|
+
))}
|
|
193
|
+
</TableRow>
|
|
194
|
+
</TableHead>
|
|
195
|
+
{!loading ? (
|
|
196
|
+
<>
|
|
197
|
+
{dataSource?.length ? (
|
|
198
|
+
<TableBody>
|
|
199
|
+
{dataSource?.map((row, rowIndex) => (
|
|
200
|
+
<StyledTableRow
|
|
201
|
+
canRowClick={!!onRowClick}
|
|
202
|
+
hover={!!onRowClick}
|
|
203
|
+
key={rowIndex}
|
|
204
|
+
onClick={() => {
|
|
205
|
+
return onRowClick && onRowClick(row)
|
|
206
|
+
}}
|
|
207
|
+
>
|
|
208
|
+
<> {showTotal && calculateTotal(row)}</>
|
|
209
|
+
{columns.map((col, colIndex) => (
|
|
210
|
+
<StyledTableCell
|
|
211
|
+
key={colIndex}
|
|
212
|
+
columnsLength={columns.length}
|
|
213
|
+
columnIndex={colIndex + 1}
|
|
214
|
+
rowIndex={rowIndex + 1}
|
|
215
|
+
col={col}
|
|
216
|
+
isBodyCell
|
|
217
|
+
sx={sx}
|
|
218
|
+
>
|
|
219
|
+
{col?.dataType && col?.dataType == 'currency' ? (
|
|
220
|
+
<>{convertToAmount(row[col.dataIndex])}</>
|
|
221
|
+
) : (
|
|
222
|
+
<>
|
|
223
|
+
{col?.render
|
|
224
|
+
? col.render(row[col.dataIndex], row, rowIndex)
|
|
225
|
+
: _.get(row, col.dataIndex)}
|
|
226
|
+
</>
|
|
227
|
+
)}
|
|
228
|
+
</StyledTableCell>
|
|
229
|
+
))}
|
|
230
|
+
</StyledTableRow>
|
|
231
|
+
))}
|
|
232
|
+
|
|
233
|
+
{showTotal && (
|
|
234
|
+
<StyledTableRow canRowClick={false}>
|
|
235
|
+
{columns.map((col, colIndex) => (
|
|
236
|
+
<>
|
|
237
|
+
<StyledTableCell
|
|
238
|
+
key={colIndex}
|
|
239
|
+
columnsLength={columns.length}
|
|
240
|
+
columnIndex={colIndex + 1}
|
|
241
|
+
rowIndex={dataSource.length + 1}
|
|
242
|
+
col={col}
|
|
243
|
+
isBodyCell
|
|
244
|
+
sx={sx}
|
|
245
|
+
>
|
|
246
|
+
{totalCols.includes(colIndex + 1) ? (
|
|
247
|
+
col?.dataType && col?.dataType == 'currency' ? (
|
|
248
|
+
<>{convertToAmount(totalCount[colIndex])}</>
|
|
249
|
+
) : (
|
|
250
|
+
<>{totalCount[colIndex]}</>
|
|
251
|
+
)
|
|
252
|
+
) : (
|
|
253
|
+
'---'
|
|
254
|
+
)}
|
|
255
|
+
</StyledTableCell>
|
|
256
|
+
</>
|
|
257
|
+
))}
|
|
258
|
+
</StyledTableRow>
|
|
259
|
+
)}
|
|
260
|
+
</TableBody>
|
|
261
|
+
) : (
|
|
262
|
+
<>
|
|
263
|
+
<NoRecordsFound colLength={columns?.length} />
|
|
264
|
+
</>
|
|
265
|
+
)}
|
|
266
|
+
</>
|
|
267
|
+
) : (
|
|
268
|
+
<Spinner />
|
|
269
|
+
)}
|
|
270
|
+
</StyledMuiTable>
|
|
271
|
+
</>
|
|
272
|
+
<>
|
|
273
|
+
{pagination && (
|
|
274
|
+
<TableFooter
|
|
275
|
+
page={pagination.page + 1}
|
|
276
|
+
limit={pagination.limit}
|
|
277
|
+
totalCount={pagination.totalCount ?? 0}
|
|
278
|
+
handlePagination={pagination.onChange}
|
|
279
|
+
handlePageLimit={pagination.onChangeLimit}
|
|
280
|
+
/>
|
|
281
|
+
)}
|
|
282
|
+
</>
|
|
283
|
+
</StyledTableContainer>
|
|
284
|
+
)
|
|
285
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Box, Typography } from '@mui/material'
|
|
2
|
+
import DropDownButton from '../../DropDownButton/DropDownButton'
|
|
3
|
+
import { StyledPagination, StyledTableFooter } from '../common/styles'
|
|
4
|
+
import TableStats from '../common/TableStats'
|
|
5
|
+
|
|
6
|
+
interface TableFooterProps {
|
|
7
|
+
totalCount: number
|
|
8
|
+
limit: number
|
|
9
|
+
handlePagination: (v: number) => void
|
|
10
|
+
page: number
|
|
11
|
+
handlePageLimit?: (v: number) => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function TableFooter({
|
|
15
|
+
totalCount,
|
|
16
|
+
limit,
|
|
17
|
+
handlePagination,
|
|
18
|
+
page,
|
|
19
|
+
handlePageLimit,
|
|
20
|
+
}: TableFooterProps) {
|
|
21
|
+
const onChange = (v: number) => {
|
|
22
|
+
handlePagination(v)
|
|
23
|
+
}
|
|
24
|
+
return (
|
|
25
|
+
<StyledTableFooter>
|
|
26
|
+
<TableStats limit={limit} totalCount={totalCount} page={page} />
|
|
27
|
+
<StyledPagination
|
|
28
|
+
page={page}
|
|
29
|
+
count={Math.ceil(totalCount / limit)}
|
|
30
|
+
onChange={(e, v) => onChange(v)}
|
|
31
|
+
variant="outlined"
|
|
32
|
+
shape="rounded"
|
|
33
|
+
/>
|
|
34
|
+
{handlePageLimit ? (
|
|
35
|
+
<LimitField handlePageLimit={handlePageLimit} limit={limit} />
|
|
36
|
+
) : (
|
|
37
|
+
<Box></Box>
|
|
38
|
+
)}
|
|
39
|
+
</StyledTableFooter>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const LimitField = ({ handlePageLimit, limit }) => {
|
|
44
|
+
return (
|
|
45
|
+
<Box>
|
|
46
|
+
<DropDownButton
|
|
47
|
+
button={{
|
|
48
|
+
buttonProps: {
|
|
49
|
+
variant: 'outlined',
|
|
50
|
+
color: 'secondary',
|
|
51
|
+
sx: {
|
|
52
|
+
padding: '0px 10px',
|
|
53
|
+
color: '#121212',
|
|
54
|
+
fontSize: '13px',
|
|
55
|
+
border: '1px solid #1212121A',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
label: `${limit} / page`,
|
|
59
|
+
}}
|
|
60
|
+
menu={[
|
|
61
|
+
{
|
|
62
|
+
label: 10,
|
|
63
|
+
onClick: () => handlePageLimit(10),
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
{
|
|
67
|
+
label: 20,
|
|
68
|
+
onClick: () => handlePageLimit(20),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
label: 30,
|
|
72
|
+
onClick: () => handlePageLimit(30),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: 50,
|
|
76
|
+
onClick: () => handlePageLimit(50),
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
label: 100,
|
|
80
|
+
onClick: () => handlePageLimit(100),
|
|
81
|
+
},
|
|
82
|
+
]}
|
|
83
|
+
/>
|
|
84
|
+
</Box>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Table'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Theme } from '@mui/material'
|
|
2
|
+
import { SxProps } from '@mui/system'
|
|
3
|
+
|
|
4
|
+
export interface StyledCellProps {
|
|
5
|
+
columnsLength: number
|
|
6
|
+
columnIndex: number
|
|
7
|
+
rowIndex: number
|
|
8
|
+
col: any
|
|
9
|
+
sx?: Record<string, SxProps<Theme>>
|
|
10
|
+
isBodyCell?: boolean
|
|
11
|
+
isHeaderCell?: boolean
|
|
12
|
+
}
|
|
13
|
+
export interface StyledTableContainerProps {
|
|
14
|
+
sx?: Record<string, SxProps<Theme>>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface StyledMuiTableProps {
|
|
18
|
+
sx?: Record<string, SxProps<Theme>>
|
|
19
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import styled, { CSSObject } from '@emotion/styled'
|
|
2
|
+
import {
|
|
3
|
+
Table,
|
|
4
|
+
TableCell,
|
|
5
|
+
TableContainer,
|
|
6
|
+
TableRow,
|
|
7
|
+
Theme,
|
|
8
|
+
alpha,
|
|
9
|
+
} from '@mui/material'
|
|
10
|
+
import { SxProps } from '@mui/system'
|
|
11
|
+
import _ from 'lodash'
|
|
12
|
+
import {
|
|
13
|
+
StyledCellProps,
|
|
14
|
+
StyledMuiTableProps,
|
|
15
|
+
StyledTableContainerProps,
|
|
16
|
+
} from './interface'
|
|
17
|
+
|
|
18
|
+
export const StyledTableCell = styled(TableCell)<StyledCellProps>(
|
|
19
|
+
({
|
|
20
|
+
theme,
|
|
21
|
+
columnsLength,
|
|
22
|
+
columnIndex,
|
|
23
|
+
rowIndex,
|
|
24
|
+
col,
|
|
25
|
+
sx,
|
|
26
|
+
isBodyCell = false,
|
|
27
|
+
isHeaderCell = false,
|
|
28
|
+
}) => {
|
|
29
|
+
const { rowkey, columnKey, cellKey, allKey } = getSxKeys(
|
|
30
|
+
rowIndex,
|
|
31
|
+
columnIndex,
|
|
32
|
+
)
|
|
33
|
+
const rowSx: SxProps<Theme> = _.get(sx, rowkey)
|
|
34
|
+
const columnSx: SxProps<Theme> = _.get(sx, columnKey)
|
|
35
|
+
const cellSx: SxProps<Theme> = _.get(sx, cellKey)
|
|
36
|
+
const allSx: SxProps<Theme> = _.get(sx, allKey)
|
|
37
|
+
return {
|
|
38
|
+
...(col?.width && {
|
|
39
|
+
width: col?.width,
|
|
40
|
+
}),
|
|
41
|
+
['@media(max-width: 680px)']: {
|
|
42
|
+
borderRightColor:
|
|
43
|
+
columnsLength - 1 !== columnIndex ? '#1212121A' : 'none',
|
|
44
|
+
borderRightStyle: columnsLength - 1 !== columnIndex ? 'solid' : 'none',
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
...(isBodyCell && {
|
|
48
|
+
color: col.textColor,
|
|
49
|
+
padding: '15px',
|
|
50
|
+
font: 'avenir',
|
|
51
|
+
fontSize: '14px',
|
|
52
|
+
}),
|
|
53
|
+
...(isHeaderCell && {
|
|
54
|
+
fontWeight: 600,
|
|
55
|
+
fontSize: '14px',
|
|
56
|
+
}),
|
|
57
|
+
|
|
58
|
+
...columnSx,
|
|
59
|
+
...rowSx,
|
|
60
|
+
...cellSx,
|
|
61
|
+
...allSx,
|
|
62
|
+
} as CSSObject
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export const StyledMuiTable = styled(Table)<StyledMuiTableProps>(
|
|
67
|
+
({ theme, sx }) => {
|
|
68
|
+
const containerSx: SxProps<Theme> = _.get(sx, 'MuiTable')
|
|
69
|
+
return {
|
|
70
|
+
...containerSx,
|
|
71
|
+
} as CSSObject
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
export const StyledTableRow = styled(TableRow, {
|
|
76
|
+
shouldForwardProp: (prop) => prop !== 'canRowClick',
|
|
77
|
+
})<{ canRowClick: boolean }>(({ canRowClick }) => ({
|
|
78
|
+
...(canRowClick && {
|
|
79
|
+
cursor: 'pointer',
|
|
80
|
+
'&.MuiTableRow-hover:hover': {
|
|
81
|
+
backgroundColor: alpha('#f2f2f2', 0.4),
|
|
82
|
+
},
|
|
83
|
+
}),
|
|
84
|
+
}))
|
|
85
|
+
|
|
86
|
+
export const StyledTableContainer = styled(
|
|
87
|
+
TableContainer,
|
|
88
|
+
)<StyledTableContainerProps>(({ theme, sx }) => {
|
|
89
|
+
const containerSx: SxProps<Theme> = _.get(sx, 'TableContainer')
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
width: '100%',
|
|
93
|
+
overflowX: 'auto',
|
|
94
|
+
...containerSx,
|
|
95
|
+
} as CSSObject
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const getSxKeys = (rowIndex, columnIndex) => {
|
|
99
|
+
return {
|
|
100
|
+
rowkey: `row:${rowIndex}`,
|
|
101
|
+
columnKey: `column:${columnIndex}`,
|
|
102
|
+
cellKey: `row:${rowIndex},column:${columnIndex}`,
|
|
103
|
+
allKey: 'Tablecell',
|
|
104
|
+
}
|
|
105
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -60,6 +60,7 @@ export { default as ReportPageHeader } from './ReportPageHeader'
|
|
|
60
60
|
export { default as Spinner } from './Spinner'
|
|
61
61
|
export { default as PaymentStepper } from './Stepper'
|
|
62
62
|
export { default as SwitchButton } from './SwitchButton'
|
|
63
|
+
export { default as Table2D } from './Tables/2DTable'
|
|
63
64
|
export { default as Table } from './Tables/BasicTable'
|
|
64
65
|
export { default as TableFooter } from './Tables/BasicTable/TableFooter'
|
|
65
66
|
export { default as ReactTable } from './Tables/ReactTable'
|
|
@@ -313,6 +313,13 @@ export enum SquarePermissions {
|
|
|
313
313
|
CAN_SURVEYS_EDIT = 'can_surveys_edit',
|
|
314
314
|
CAN_SURVEYS_ADD = 'can_surveys_add',
|
|
315
315
|
CAN_SURVEYS_DELETE = 'can_surveys_delete',
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
316
323
|
}
|
|
317
324
|
|
|
318
325
|
export enum EnrollPermissions {
|
|
@@ -949,6 +956,24 @@ export enum Permission {
|
|
|
949
956
|
CAN_SURVEYS_ADD = 'can_surveys_add',
|
|
950
957
|
CAN_SURVEYS_DELETE = 'can_surveys_delete',
|
|
951
958
|
|
|
959
|
+
//Configuration
|
|
960
|
+
|
|
961
|
+
CAN_CONFIGURATION_VIEW = 'can_configuration_view',
|
|
962
|
+
|
|
963
|
+
//Digital Notice Board
|
|
964
|
+
CAN_NOTICE_BOARD_VIEW = 'can_notice_board_view',
|
|
965
|
+
CAN_NOTICE_BOARD_EDIT = 'can_notice_board_edit',
|
|
966
|
+
CAN_NOTICE_BOARD_ADD = 'can_notice_board_add',
|
|
967
|
+
CAN_NOTICE_BOARD_DELETE = 'can_notice_board_delete',
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
//Research Projects
|
|
971
|
+
CAN_RESEARCH_PROJECT_VIEW = 'can_research_project_view',
|
|
972
|
+
CAN_RESEARCH_PROJECT_EDIT = 'can_research_project_edit',
|
|
973
|
+
CAN_RESEARCH_PROJECT_ADD = 'can_research_project_add',
|
|
974
|
+
CAN_RESEARCH_PROJECT_DELETE = 'can_research_project_delete',
|
|
975
|
+
|
|
976
|
+
|
|
952
977
|
// Enroll X
|
|
953
978
|
|
|
954
979
|
// manage exams profile_permissions
|