@campxdev/shared 1.8.4 → 1.8.5-0.alpha-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 +1 -1
- package/src/components/ApplicationProfile/ApplicationProfile.tsx +342 -0
- package/src/components/ApplicationProfile/Service.ts +68 -0
- package/src/components/ApplicationProfile/UserProfileRelation.tsx +174 -0
- package/src/components/ApplicationProfile/index.tsx +1 -0
- package/src/components/DropDownButton/DropdownMenuItem.tsx +12 -0
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +8 -3
- package/src/components/ErrorBoundary/ErrorFallback.tsx +7 -2
- package/src/components/FloatingContainer.tsx +1 -1
- package/src/components/HookForm/MultiSelect.tsx +8 -0
- package/src/components/Input/DatePicker.tsx +11 -0
- package/src/components/Input/MultiSelect.tsx +11 -0
- package/src/components/Layout/Header/AppHeader.tsx +2 -1
- package/src/components/Layout/Header/AppsMenu.tsx +51 -23
- package/src/components/Layout/Header/HeaderActions/FreshChatButton.tsx +61 -0
- package/src/components/Layout/Header/HeaderActions/FreshDeskHelpButton.tsx +36 -7
- package/src/components/Layout/Header/HeaderActions/HeaderActions.tsx +2 -0
- package/src/components/Layout/Header/SchoolSwitch/SchoolSwitch.tsx +33 -0
- package/src/components/Layout/Header/applications.ts +8 -9
- package/src/components/Layout/Header/assets/chat_with_us.png +0 -0
- package/src/components/Layout/Header/assets/index.ts +2 -0
- package/src/components/Layout/Helmet.tsx +91 -32
- package/src/components/ModalButtons/PopoverButton.tsx +99 -0
- package/src/components/Tabs/TabsContainer.tsx +3 -0
- package/src/components/index.ts +4 -0
- package/src/config/axios.ts +8 -2
- package/src/constants/UIConstants.ts +27 -0
- package/src/contexts/LoginFormProvider.tsx +2 -7
- package/src/contexts/Providers.tsx +3 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAuth.ts +58 -2
- package/src/hooks/useExternalScript.ts +38 -0
- package/src/hooks/useFilters.ts +6 -3
- package/src/shared-state/PermissionsStore.ts +937 -130
- package/src/theme/muiTheme.ts +6 -4
- package/src/theme/theme.d.ts +2 -0
- package/tsconfig.json +19 -19
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Grow, Popover, PopoverProps } from '@mui/material'
|
|
2
|
+
import { TransitionProps } from '@mui/material/transitions'
|
|
3
|
+
import { ReactNode, forwardRef, useState } from 'react'
|
|
4
|
+
|
|
5
|
+
export const Transition = forwardRef(function Transition(
|
|
6
|
+
props: TransitionProps & {
|
|
7
|
+
children: React.ReactElement
|
|
8
|
+
},
|
|
9
|
+
ref: React.Ref<unknown>,
|
|
10
|
+
) {
|
|
11
|
+
return <Grow timeout={1000} ref={ref} {...props} />
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
interface PopoverButtonProps {
|
|
15
|
+
anchor: (props: { open: (e: any) => void }) => ReactNode
|
|
16
|
+
content: (props: { close: () => void }) => ReactNode
|
|
17
|
+
popoverProps?: Omit<PopoverProps, 'open'>
|
|
18
|
+
onDialogClose?: () => void
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function PopoverButton({
|
|
22
|
+
content,
|
|
23
|
+
popoverProps,
|
|
24
|
+
onDialogClose,
|
|
25
|
+
anchor,
|
|
26
|
+
}: PopoverButtonProps) {
|
|
27
|
+
const [popperAnchor, setPopperAnchor] = useState(null)
|
|
28
|
+
|
|
29
|
+
const onClose = () => {
|
|
30
|
+
onDialogClose && onDialogClose()
|
|
31
|
+
setPopperAnchor(null)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const onOpen = (e) => {
|
|
35
|
+
setPopperAnchor(e.currentTarget)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
{anchor({
|
|
41
|
+
open: onOpen,
|
|
42
|
+
})}
|
|
43
|
+
<CustomPopover
|
|
44
|
+
open={Boolean(popperAnchor)}
|
|
45
|
+
content={content}
|
|
46
|
+
popoverProps={popoverProps}
|
|
47
|
+
onClose={onClose}
|
|
48
|
+
popperAnchor={popperAnchor}
|
|
49
|
+
/>
|
|
50
|
+
</>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface CustomDialogProps {
|
|
55
|
+
content: (props: { close: () => void }) => ReactNode
|
|
56
|
+
onClose: () => void
|
|
57
|
+
open: boolean
|
|
58
|
+
popoverProps?: Omit<PopoverProps, 'open'>
|
|
59
|
+
popperAnchor: any
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const CustomPopover = ({
|
|
63
|
+
onClose,
|
|
64
|
+
popoverProps,
|
|
65
|
+
content,
|
|
66
|
+
open,
|
|
67
|
+
popperAnchor,
|
|
68
|
+
}: CustomDialogProps) => {
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
<Popover
|
|
72
|
+
onClose={onClose}
|
|
73
|
+
open={open}
|
|
74
|
+
transitionDuration={140}
|
|
75
|
+
TransitionComponent={Transition}
|
|
76
|
+
PaperProps={{
|
|
77
|
+
...popoverProps?.PaperProps,
|
|
78
|
+
elevation: 2,
|
|
79
|
+
sx: {
|
|
80
|
+
borderRadius: '10px',
|
|
81
|
+
border: '1px solid #1212121A',
|
|
82
|
+
boxShadow: '0px 4px 16px #0000000F',
|
|
83
|
+
},
|
|
84
|
+
}}
|
|
85
|
+
anchorEl={popperAnchor}
|
|
86
|
+
anchorOrigin={{
|
|
87
|
+
vertical: 'bottom',
|
|
88
|
+
horizontal: 'left',
|
|
89
|
+
}}
|
|
90
|
+
sx={{
|
|
91
|
+
...popoverProps?.sx,
|
|
92
|
+
}}
|
|
93
|
+
{...popoverProps}
|
|
94
|
+
>
|
|
95
|
+
{content({ close: onClose })}
|
|
96
|
+
</Popover>
|
|
97
|
+
</>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
@@ -10,17 +10,20 @@ export interface TabsContainerProps {
|
|
|
10
10
|
}[]
|
|
11
11
|
size?: 'small' | 'medium'
|
|
12
12
|
conatinerVariant?: 'box' | 'page'
|
|
13
|
+
onTabChange?: (tabKey: string) => void
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export default function TabsContainer({
|
|
16
17
|
tabs,
|
|
17
18
|
size = 'small',
|
|
18
19
|
conatinerVariant = 'box',
|
|
20
|
+
onTabChange,
|
|
19
21
|
}: TabsContainerProps) {
|
|
20
22
|
const [currentTab, setCurrentTab] = useState(tabs[0].key)
|
|
21
23
|
|
|
22
24
|
const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => {
|
|
23
25
|
setCurrentTab(value)
|
|
26
|
+
onTabChange && onTabChange(value)
|
|
24
27
|
}
|
|
25
28
|
useEffect(() => {
|
|
26
29
|
setCurrentTab(tabs[0].key)
|
package/src/components/index.ts
CHANGED
|
@@ -35,6 +35,8 @@ import { CustomDialog } from './ModalButtons/DialogButton'
|
|
|
35
35
|
import { CustomDrawer } from './ModalButtons/DrawerButton'
|
|
36
36
|
import ExcelJsonUpload from './ExcelToJsonInput/ExcelJsonUpload'
|
|
37
37
|
import ExcelToJsonInput from './ExcelToJsonInput'
|
|
38
|
+
import ApplicationProfile from './ApplicationProfile'
|
|
39
|
+
import PopoverButton from './ModalButtons/PopoverButton'
|
|
38
40
|
export { default as Image } from './Image'
|
|
39
41
|
export { default as PageHeader } from './PageHeader'
|
|
40
42
|
export { PageContent } from './PageContent'
|
|
@@ -98,6 +100,8 @@ export {
|
|
|
98
100
|
UserBox,
|
|
99
101
|
ExcelJsonUpload,
|
|
100
102
|
ExcelToJsonInput,
|
|
103
|
+
ApplicationProfile,
|
|
104
|
+
PopoverButton,
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
export * from './UploadButton/types'
|
package/src/config/axios.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import Axios from 'axios'
|
|
1
|
+
import Axios, { AxiosRequestConfig } from 'axios'
|
|
2
2
|
import _ from 'lodash'
|
|
3
3
|
import { toast } from 'react-toastify'
|
|
4
4
|
import Cookies from 'js-cookie'
|
|
5
5
|
import { NetworkStore } from '../components/ErrorBoundary/GlobalNetworkLoadingIndicator'
|
|
6
6
|
import { isDevelopment } from '../constants'
|
|
7
|
+
import { UserStore } from '../shared-state'
|
|
7
8
|
|
|
8
9
|
const sessionKey = Cookies.get('campx_session_key')
|
|
9
10
|
const clientId = window.location.pathname.split('/')[1] ?? 'campx_dev'
|
|
@@ -30,7 +31,12 @@ let axios = Axios.create({
|
|
|
30
31
|
})
|
|
31
32
|
|
|
32
33
|
axios.interceptors.request.use(
|
|
33
|
-
function (config) {
|
|
34
|
+
function (config: AxiosRequestConfig) {
|
|
35
|
+
const userState = UserStore.getRawState()
|
|
36
|
+
if (userState?.username) {
|
|
37
|
+
config.headers.test = userState.username
|
|
38
|
+
}
|
|
39
|
+
|
|
34
40
|
const params = formatParams(config?.params)
|
|
35
41
|
NetworkStore.update((s) => {
|
|
36
42
|
s.loading = true
|
|
@@ -95,3 +95,30 @@ export function getRandomColor(name) {
|
|
|
95
95
|
character: firstAlphabet?.toUpperCase(),
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
export const ProfileApplicationType = [
|
|
100
|
+
{
|
|
101
|
+
label: 'Square',
|
|
102
|
+
value: 'square',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
label: 'Exams',
|
|
106
|
+
value: 'exams',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
label: 'Payments',
|
|
110
|
+
value: 'payments',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
label: 'EnrollX',
|
|
114
|
+
value: 'enroll_x',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
label: 'Hostels',
|
|
118
|
+
value: 'hostels',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
label: 'Commute',
|
|
122
|
+
value: 'commute',
|
|
123
|
+
},
|
|
124
|
+
]
|
|
@@ -8,19 +8,14 @@ const LoginContext = createContext<{
|
|
|
8
8
|
openLoginForm: (loginUrl: string) => {},
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
export default function LoginFormProvider({ children
|
|
11
|
+
export default function LoginFormProvider({ children }) {
|
|
12
12
|
const modal = useModal()
|
|
13
13
|
|
|
14
14
|
const onLogin = (loginUrl: string) => {
|
|
15
15
|
modal({
|
|
16
16
|
title: 'Developer Login',
|
|
17
17
|
content({ close }) {
|
|
18
|
-
return
|
|
19
|
-
<LoginForm
|
|
20
|
-
loginUrl={loginUrl}
|
|
21
|
-
showSuperAdminForm={showSuperAdminForm}
|
|
22
|
-
/>
|
|
23
|
-
)
|
|
18
|
+
return <LoginForm loginUrl={loginUrl} />
|
|
24
19
|
},
|
|
25
20
|
})
|
|
26
21
|
}
|
|
@@ -9,6 +9,7 @@ import { ToastContainer } from '../components'
|
|
|
9
9
|
import DialogProvider from '../components/DrawerWrapper/DrawerWrapper'
|
|
10
10
|
import GlobalNetworkLoadingIndicator from '../components/ErrorBoundary/GlobalNetworkLoadingIndicator'
|
|
11
11
|
import LoginFormProvider from './LoginFormProvider'
|
|
12
|
+
import FreshChatButton from '../components/Layout/Header/HeaderActions/FreshChatButton'
|
|
12
13
|
|
|
13
14
|
export const campxTenantKey = Cookies.get('campx_tenant')
|
|
14
15
|
export const urlTenantKey = window.location.pathname.split('/')[1]
|
|
@@ -36,9 +37,10 @@ export default function Providers({
|
|
|
36
37
|
<MuiThemeProvider>
|
|
37
38
|
<ConfirmContextProvider>
|
|
38
39
|
<DialogProvider>
|
|
39
|
-
<LoginFormProvider
|
|
40
|
+
<LoginFormProvider>
|
|
40
41
|
{children}
|
|
41
42
|
<GlobalNetworkLoadingIndicator />
|
|
43
|
+
<FreshChatButton />
|
|
42
44
|
</LoginFormProvider>
|
|
43
45
|
<ToastContainer />
|
|
44
46
|
</DialogProvider>
|
package/src/hooks/index.ts
CHANGED
package/src/hooks/useAuth.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { toast } from 'react-toastify'
|
|
|
4
4
|
import axios from '../config/axios'
|
|
5
5
|
import { isDevelopment } from '../constants'
|
|
6
6
|
import { useLoginForm } from '../contexts/LoginFormProvider'
|
|
7
|
-
import { campxTenantKey, urlTenantKey } from '../contexts/Providers'
|
|
8
7
|
import { PermissionsStore, AssetsStore, UserStore } from '../shared-state'
|
|
9
8
|
|
|
10
9
|
const url = window.location.origin
|
|
@@ -28,6 +27,41 @@ type AuthResponse = {
|
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
|
|
30
|
+
const ApplicationObj = {
|
|
31
|
+
enroll: 'enroll_x',
|
|
32
|
+
ums: 'square',
|
|
33
|
+
payments: 'payments',
|
|
34
|
+
exams: 'exams',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const checkIsAdmin = (user) => {
|
|
38
|
+
let subDomain = window.location.host.split('.')?.slice(-3)[0]
|
|
39
|
+
const localSubDomain = process.env.REACT_APP_SUBDOMAIN
|
|
40
|
+
|
|
41
|
+
if (user?.isSuperuser) return 1
|
|
42
|
+
|
|
43
|
+
if (process.env.NODE_ENV === 'development') {
|
|
44
|
+
subDomain = localSubDomain
|
|
45
|
+
|
|
46
|
+
if (!localSubDomain) {
|
|
47
|
+
toast.warn('missing REACT_APP_SUBDOMAIN in .env')
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// eslint-disable-next-line no-console
|
|
52
|
+
console.log(
|
|
53
|
+
'Current App ->',
|
|
54
|
+
ApplicationObj[subDomain],
|
|
55
|
+
'; subdomain env ->',
|
|
56
|
+
subDomain,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
const profile = user?.profiles?.find(
|
|
60
|
+
(item) => item.application == ApplicationObj[subDomain],
|
|
61
|
+
)
|
|
62
|
+
return profile ? (profile.isAdmin == true ? 1 : 0) : 0
|
|
63
|
+
}
|
|
64
|
+
|
|
31
65
|
function useAuth({ permissionsEndpoint, loginUrl }: AuthParams): AuthResponse {
|
|
32
66
|
const { openLoginForm } = useLoginForm()
|
|
33
67
|
const [loading, setLoading] = useState<boolean>(false)
|
|
@@ -38,13 +72,32 @@ function useAuth({ permissionsEndpoint, loginUrl }: AuthParams): AuthResponse {
|
|
|
38
72
|
axios
|
|
39
73
|
.get(permissionsEndpoint)
|
|
40
74
|
.then((res) => {
|
|
75
|
+
const origin = window.location.origin
|
|
76
|
+
const originSubdomain =
|
|
77
|
+
window.location.host.split('.')?.slice(-3)[0] ?? 'ums'
|
|
78
|
+
|
|
79
|
+
const isStaging = origin.split('campx')[1] === '.dev'
|
|
80
|
+
|
|
81
|
+
if (isDevelopment == false && isStaging == false) {
|
|
82
|
+
if (
|
|
83
|
+
!res.data.applications.includes(ApplicationObj[originSubdomain])
|
|
84
|
+
) {
|
|
85
|
+
window.location.replace(
|
|
86
|
+
`https://www.id.campx.in/apps?redirect_to=${url}`,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
41
91
|
setLoading(false)
|
|
42
92
|
setData(res.data)
|
|
43
93
|
UserStore.update((s) => {
|
|
44
|
-
s.username = res.data?.username
|
|
94
|
+
s.username = res.data?.user?.username
|
|
45
95
|
s.user = res.data?.user
|
|
46
96
|
s.roles = res.data?.roles
|
|
47
97
|
})
|
|
98
|
+
const isAdmin = checkIsAdmin(res.data.user)
|
|
99
|
+
// eslint-disable-next-line no-console
|
|
100
|
+
console.log('Is Admin -> ', isAdmin)
|
|
48
101
|
|
|
49
102
|
PermissionsStore.update((s) => {
|
|
50
103
|
s.permissions = {
|
|
@@ -52,7 +105,10 @@ function useAuth({ permissionsEndpoint, loginUrl }: AuthParams): AuthResponse {
|
|
|
52
105
|
can_settings_view: 1,
|
|
53
106
|
can_dashboard_view: 1,
|
|
54
107
|
can_individual_pages_view: 1,
|
|
108
|
+
can_analatics_view: isAdmin,
|
|
109
|
+
can_admin_view: isAdmin,
|
|
55
110
|
} as any
|
|
111
|
+
s.applications = res.data?.applications ?? []
|
|
56
112
|
})
|
|
57
113
|
AssetsStore.update((s) => {
|
|
58
114
|
s.logo = res.data?.assets.logo
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
const useExternalScript = (url) => {
|
|
3
|
+
let [state, setState] = useState(url ? 'loading' : 'idle')
|
|
4
|
+
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
if (!url) {
|
|
7
|
+
setState('idle')
|
|
8
|
+
return
|
|
9
|
+
}
|
|
10
|
+
let script: any = document.querySelector(`script[src="${url}"]`)
|
|
11
|
+
|
|
12
|
+
const handleScript = (e) => {
|
|
13
|
+
setState(e.type === 'load' ? 'ready' : 'error')
|
|
14
|
+
}
|
|
15
|
+
if (!script) {
|
|
16
|
+
script = document.createElement('script')
|
|
17
|
+
script.type = 'application/javascript'
|
|
18
|
+
script.src = url
|
|
19
|
+
script.async = true
|
|
20
|
+
document.body.appendChild(script)
|
|
21
|
+
script.addEventListener('load', handleScript)
|
|
22
|
+
script.addEventListener('error', handleScript)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
script.addEventListener('load', handleScript)
|
|
26
|
+
script.addEventListener('error', handleScript)
|
|
27
|
+
|
|
28
|
+
return () => {
|
|
29
|
+
script.removeEventListener('load', handleScript)
|
|
30
|
+
script.removeEventListener('error', handleScript)
|
|
31
|
+
document.body.removeChild(script)
|
|
32
|
+
}
|
|
33
|
+
}, [url])
|
|
34
|
+
|
|
35
|
+
return state
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default useExternalScript
|
package/src/hooks/useFilters.ts
CHANGED
|
@@ -13,10 +13,10 @@ export default function useFilters(initialState, key?: any) {
|
|
|
13
13
|
}, [])
|
|
14
14
|
|
|
15
15
|
function onFilterChange(modified) {
|
|
16
|
-
setFilters({
|
|
17
|
-
...
|
|
16
|
+
setFilters((prev) => ({
|
|
17
|
+
...prev,
|
|
18
18
|
...modified,
|
|
19
|
-
})
|
|
19
|
+
}))
|
|
20
20
|
|
|
21
21
|
const filterData = {
|
|
22
22
|
...filters,
|
|
@@ -36,6 +36,9 @@ export default function useFilters(initialState, key?: any) {
|
|
|
36
36
|
if (filteredSessionArray?.length > 0) {
|
|
37
37
|
sessionStorage.setItem(key, JSON.stringify(filteredSessionArray))
|
|
38
38
|
setFiltersApplied(true)
|
|
39
|
+
} else {
|
|
40
|
+
sessionStorage.removeItem(key)
|
|
41
|
+
setFiltersApplied(false)
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|