@campxdev/shared 1.9.0 → 1.9.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campxdev/shared",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "main": "./exports.ts",
5
5
  "scripts": {
6
6
  "start": "react-scripts start",
@@ -28,10 +28,12 @@ import { axiosErrorToast } from '../../config/axios'
28
28
  import { ValidateAccess } from '../../permissions'
29
29
  import { Permission, PermissionsStore } from '../../shared-state'
30
30
  import ActionButton from '../ActionButton'
31
+ import FilterButton from '../FilterComponents/FilterButton'
31
32
  import SearchBar from '../FilterComponents/SearchBar'
32
33
  import { SingleSelect } from '../Input'
33
- import { DialogButton } from '../ModalButtons'
34
+ import { DialogButton, DrawerButton } from '../ModalButtons'
34
35
  import Table from '../Tables/BasicTable/Table'
36
+ import DeprartmentFilter from './DepartmentFilter'
35
37
 
36
38
  interface ApplicationProfileProps {
37
39
  application: 'exams' | 'square' | 'payments' | 'enroll_x' | 'hostels'
@@ -49,10 +51,14 @@ function ApplicationProfile({
49
51
  permissions,
50
52
  }: ApplicationProfileProps) {
51
53
  const { isConfirmed } = useConfirm()
52
- const [filters, setFilters] = useImmer(defaultFilterObj)
54
+ const [state, setState] = useImmer(defaultFilterObj)
55
+
53
56
  const { data, isLoading, refetch } = useQuery(
54
- ['application-users', filters],
55
- () => fetchApplicationUsers({ application, ...filters }),
57
+ [
58
+ 'application-users',
59
+ ...Object.keys(state.filters).map((key) => state.filters[key]),
60
+ ],
61
+ () => fetchApplicationUsers({ application, ...state.filters }),
56
62
  )
57
63
 
58
64
  const { data: profiles, isLoading: profilesLoading } = useQuery(
@@ -63,7 +69,7 @@ function ApplicationProfile({
63
69
  const { mutate, isLoading: removingUserProfile } = useMutation(
64
70
  removeUserApplicationProfile,
65
71
  {
66
- onSuccess: (res) => {
72
+ onSuccess: () => {
67
73
  refetch()
68
74
  toast.success('User profile removed from application')
69
75
  },
@@ -77,6 +83,7 @@ function ApplicationProfile({
77
83
  if (!confirmed) return
78
84
  mutate({ userId: data.id, application: application })
79
85
  }
86
+
80
87
  const columns = [
81
88
  {
82
89
  title: 'User',
@@ -122,15 +129,15 @@ function ApplicationProfile({
122
129
  },
123
130
  ]
124
131
  const handleLimitChange = (value: number) => {
125
- setFilters((s) => {
126
- s.limit = value
127
- s.offset = 0
132
+ setState((s) => {
133
+ s.filters.limit = value
134
+ s.filters.offset = 0
128
135
  })
129
136
  }
130
137
 
131
138
  const handlePagination = (value: number) => {
132
- setFilters((s) => {
133
- s.offset = value * s.limit - s.limit
139
+ setState((s) => {
140
+ s.filters.offset = value * s.filters.limit - s.filters.limit
134
141
  })
135
142
  }
136
143
 
@@ -168,29 +175,56 @@ function ApplicationProfile({
168
175
  />
169
176
  <PageContent sx={{ marginTop: '25px' }}>
170
177
  <StyledTableContainer>
171
- <SearchBar
172
- onSearch={(value) => {
173
- setFilters((s) => {
174
- s.search = value
175
- })
178
+ <Box
179
+ sx={{
180
+ display: 'flex',
181
+ gap: '10px',
182
+ alignItems: 'center',
183
+ marginBottom: '10px',
176
184
  }}
177
- textFieldProps={{
178
- placeholder: 'Search by Name',
179
- title: 'Search by Name',
180
- sx: { width: '300px', marginBottom: '25px' },
181
- size: 'small',
182
- }}
183
- />
185
+ >
186
+ <Box>
187
+ <SearchBar
188
+ onSearch={(value) =>
189
+ setState((s) => {
190
+ s.filters.search = value
191
+ })
192
+ }
193
+ textFieldProps={{
194
+ placeholder: 'Search by Name',
195
+ title: 'Search by Name',
196
+ sx: { width: '300px' },
197
+ size: 'medium',
198
+ }}
199
+ />
200
+ </Box>
201
+ <DrawerButton
202
+ anchor={({ open }) => (
203
+ <FilterButton
204
+ onClick={open}
205
+ filtersApplied={state.filtersApplied}
206
+ />
207
+ )}
208
+ content={({ close }) => (
209
+ <DeprartmentFilter
210
+ close={close}
211
+ setAppliedFilters={setState}
212
+ appliedFilters={state}
213
+ />
214
+ )}
215
+ title="People Filters"
216
+ />
217
+ </Box>
184
218
  <Table
185
219
  columns={columns}
186
220
  dataSource={data?.result ?? []}
187
221
  loading={isLoading || removingUserProfile}
188
222
  pagination={{
189
- limit: filters.limit,
223
+ limit: state.filters.limit,
190
224
  onChangeLimit: handleLimitChange,
191
225
  onChange: handlePagination,
192
226
  totalCount: data?.count,
193
- page: filters.offset / filters.limit,
227
+ page: state.filters.offset / state.filters.limit,
194
228
  }}
195
229
  />
196
230
  </StyledTableContainer>
@@ -218,14 +252,14 @@ export const RenderProfileDropDown = ({
218
252
  })
219
253
 
220
254
  useEffect(() => {
221
- setState((pre) => ({
255
+ setState(() => ({
222
256
  userId: data.id,
223
257
  profileId: data?.profiles?.find((p) => p.application === application)?.id,
224
258
  }))
225
259
  }, [data])
226
260
 
227
261
  const { mutate, isLoading } = useMutation(updateUserApplicationProfile, {
228
- onSuccess: (res) => {
262
+ onSuccess: () => {
229
263
  refetchFn()
230
264
  toast.success('User application profile updated successfully')
231
265
  },
@@ -333,7 +367,7 @@ export const StyledTableContainer = styled(Box)(({ theme }) => ({
333
367
  },
334
368
  }))
335
369
 
336
- export const StyledDropDownContainer = styled(Box)(({ theme }) => ({
370
+ export const StyledDropDownContainer = styled(Box)(() => ({
337
371
  width: '200px',
338
372
  '& .MuiTypography-root': {
339
373
  display: 'none',
@@ -0,0 +1,77 @@
1
+ import { Button, Stack } from '@mui/material'
2
+ import { useEffect } from 'react'
3
+ import { useQuery } from 'react-query'
4
+ import { useImmer } from 'use-immer'
5
+ import axios from '../../config/axios'
6
+ import { SingleSelect } from '../Input'
7
+ import Spinner from '../Spinner'
8
+
9
+ const defaultState = {
10
+ departmentId: '',
11
+ }
12
+
13
+ const getDepartments = () => {
14
+ return axios.get('/square/departments').then((res) => res.data)
15
+ }
16
+
17
+ export default function DeprartmentFilter({
18
+ close,
19
+ appliedFilters,
20
+ setAppliedFilters,
21
+ }) {
22
+ const [filter, setFilter] = useImmer(defaultState)
23
+
24
+ const { data, isLoading } = useQuery('department', () => getDepartments())
25
+
26
+ useEffect(() => {
27
+ setFilter({ departmentId: appliedFilters.filters.departmentId })
28
+ }, [])
29
+
30
+ const applyFilter = () => {
31
+ close()
32
+ setAppliedFilters((s) => {
33
+ s.filters.departmentId = filter.departmentId
34
+ s.filtersApplied = filter.departmentId ? true : false
35
+ })
36
+ }
37
+ const clearFilter = () => {
38
+ setAppliedFilters((s) => {
39
+ s.filters.departmentId = ''
40
+ s.filtersApplied = false
41
+ })
42
+ close()
43
+ }
44
+
45
+ if (isLoading) return <Spinner />
46
+ return (
47
+ <>
48
+ <Stack gap={3}>
49
+ <SingleSelect
50
+ label="Select Program"
51
+ onChange={(e) => {
52
+ setFilter((s) => {
53
+ s.departmentId = e.target.value
54
+ })
55
+ }}
56
+ value={filter.departmentId}
57
+ options={
58
+ data &&
59
+ data?.map((item) => ({
60
+ label: item?.name,
61
+ value: item?.id,
62
+ }))
63
+ }
64
+ />
65
+
66
+ <Stack direction="row" gap={2} mt={0.5}>
67
+ <Button fullWidth onClick={applyFilter}>
68
+ Apply Filters
69
+ </Button>
70
+ <Button variant="outlined" fullWidth onClick={clearFilter}>
71
+ Clear Filters
72
+ </Button>
73
+ </Stack>
74
+ </Stack>
75
+ </>
76
+ )
77
+ }
@@ -1,9 +1,12 @@
1
1
  import * as yup from 'yup'
2
2
  import axios from '../../config/axios'
3
3
  export const defaultFilterObj = {
4
- search: null,
5
- limit: 10,
6
- offset: 0,
4
+ filters: {
5
+ search: null,
6
+ limit: 10,
7
+ offset: 0,
8
+ },
9
+ filtersApplied: false,
7
10
  }
8
11
 
9
12
  export const userProfileSchema = yup.object().shape({
@@ -1,4 +1,4 @@
1
- import { Box, Typography } from '@mui/material'
1
+ import { Box, Stack, Typography, styled } from '@mui/material'
2
2
  import { InsititutionsStore } from '../../shared-state/InstitutionsStore'
3
3
  import Image from '../Image/Image'
4
4
 
@@ -6,30 +6,23 @@ export default function InsititutionsDialog({ close }) {
6
6
  const { institutions } = InsititutionsStore.useState((s) => s)
7
7
 
8
8
  return (
9
- <Box
9
+ <Stack
10
+ gap={4}
10
11
  sx={{
11
12
  padding: '20px',
13
+ alignItems: 'center',
12
14
  }}
13
15
  >
14
16
  <Typography variant="h3" textAlign={'center'}>
15
17
  Select an Instituition
16
18
  </Typography>
17
- <Box>
18
- <Box
19
- sx={{
20
- marginTop: '30px',
21
- display: 'flex',
22
- gap: '30px',
23
- justifyContent: 'center',
24
- alignItems: 'center',
25
- }}
26
- >
27
- {institutions?.map((item, index) => (
28
- <InstitutionCard institution={item} key={index} />
29
- ))}
30
- </Box>
31
- </Box>
32
- </Box>
19
+
20
+ <StyledInstitutionContainer>
21
+ {institutions?.map((item, index) => (
22
+ <InstitutionCard institution={item} key={index} />
23
+ ))}
24
+ </StyledInstitutionContainer>
25
+ </Stack>
33
26
  )
34
27
  }
35
28
 
@@ -68,3 +61,26 @@ const InstitutionCard = ({ institution }) => {
68
61
  </Box>
69
62
  )
70
63
  }
64
+
65
+ export const StyledInstitutionContainer = styled(Box)(({ theme }) => ({
66
+ width: '87%',
67
+ overflowX: 'auto',
68
+ display: 'flex',
69
+ flex: 1,
70
+ justifyContent: 'flex-start',
71
+ padding: '20px',
72
+ gap: '20px',
73
+ '&::-webkit-scrollbar': {
74
+ width: '0.5em',
75
+ height: '0.5em',
76
+ backgroundColor: 'rgba(0, 0, 0, 0.1)',
77
+ },
78
+ '&::-webkit-scrollbar-thumb': {
79
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
80
+ borderRadius: '3px',
81
+
82
+ '&:hover': {
83
+ background: 'rgba(0, 0, 0, 0.3)',
84
+ },
85
+ },
86
+ }))
@@ -81,13 +81,13 @@ export const applications = [
81
81
  icon: hostelSmall,
82
82
  description: 'Manage Hostels in the Campus',
83
83
  },
84
- {
85
- title: 'CommuteX',
86
- key: 'commute',
87
- path: isDevelopment ? origins.commute.dev : origins.commute.prod,
88
- icon: commuteSmall,
89
- description: 'Manage Commute in the Campus',
90
- },
84
+ // {
85
+ // title: 'CommuteX',
86
+ // key: 'commute',
87
+ // path: isDevelopment ? origins.commute.dev : origins.commute.prod,
88
+ // icon: commuteSmall,
89
+ // description: 'Manage Commute in the Campus',
90
+ // },
91
91
  ...(isDevelopment
92
92
  ? [
93
93
  {
@@ -349,7 +349,10 @@ export enum EnrollPermissions {
349
349
  ADMISSIONS_CONFIRM = 'can_admissions_confirm',
350
350
  CAN_ADMISSION_REJECT = 'can_admissions_reject',
351
351
  CAN_ADMISSIONS_DASHBOARD_VIEW = 'can_admission_dashboard_view',
352
-
352
+ CAN_ADMISSIONS_GRAPH_VIEW = 'can_admission_graph_view',
353
+ CAN_ADMISSIONS_LEAD_REMARKS = 'can_admission_lead_remarks',
354
+ CAN_ENROLL_X_AUDIT_LOGS = 'can_enroll_x_view_audit_logs',
355
+ CAN_ADMISSION_APPROVAL = 'can_admission_approvals',
353
356
  // CET & PHD
354
357
  CAN_PHD_FORM_VIEW = 'can_admissions_view_phd_applications',
355
358
  CAN_PHD_FORM_DOWNLOAD = 'can_admissions_download_phd_applications',
@@ -850,6 +853,7 @@ export enum Permission {
850
853
  CAN_COUNSELLOR_VIEW = 'can_counsellor_view',
851
854
  CAN_COUNSELLOR_ADD = 'can_counsellor_add',
852
855
  CAN_COUNSELLOR_DELETE = 'can_counsellor_delete',
856
+ CAN_COUNSELLOR_REPORT_VIEW = 'can_counsellor_report_view',
853
857
 
854
858
  // Notifications
855
859
  CAN_NOTIFICATION_ADD = 'can_notification_add',
@@ -868,6 +872,10 @@ export enum Permission {
868
872
  ADMISSIONS_CONFIRM = 'can_admissions_confirm',
869
873
  CAN_ADMISSION_REJECT = 'can_admissions_reject',
870
874
  CAN_ADMISSIONS_DASHBOARD_VIEW = 'can_admission_dashboard_view',
875
+ CAN_ADMISSIONS_LEAD_REMARKS = 'can_admission_lead_remarks',
876
+ CAN_ADMISSIONS_GRAPH_VIEW = 'can_admission_graph_view',
877
+ CAN_ENROLL_X_AUDIT_LOGS = 'can_enroll_x_view_audit_logs',
878
+ CAN_ADMISSION_APPROVAL = 'can_admission_approvals',
871
879
 
872
880
  // CET & PHD
873
881
  CAN_PHD_FORM_VIEW = 'can_admissions_view_phd_applications',