@campxdev/shared 1.8.21 → 1.8.23
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 +301 -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/HookForm/MultiSelect.tsx +8 -0
- package/src/components/Input/MultiSelect.tsx +8 -0
- package/src/components/Layout/Header/HeaderActions/FreshChatButton.tsx +22 -12
package/package.json
CHANGED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Avatar,
|
|
3
|
+
Box,
|
|
4
|
+
Button,
|
|
5
|
+
CircularProgress,
|
|
6
|
+
InputAdornment,
|
|
7
|
+
Typography,
|
|
8
|
+
styled,
|
|
9
|
+
} from '@mui/material'
|
|
10
|
+
import { useState } from 'react'
|
|
11
|
+
import { useMutation, useQuery } from 'react-query'
|
|
12
|
+
import { toast } from 'react-toastify'
|
|
13
|
+
import { useImmer } from 'use-immer'
|
|
14
|
+
import UserProfileRelation from './UserProfileRelation'
|
|
15
|
+
import {
|
|
16
|
+
defaultFilterObj,
|
|
17
|
+
fetchApplicationUsers,
|
|
18
|
+
fetchProfiles,
|
|
19
|
+
removeUserApplicationProfile,
|
|
20
|
+
updateUserApplicationProfile,
|
|
21
|
+
} from './Service'
|
|
22
|
+
import useConfirm from '../PopupConfirm/useConfirm'
|
|
23
|
+
import Spinner from '../Spinner'
|
|
24
|
+
import PageHeader from '../PageHeader'
|
|
25
|
+
import { PageContent } from '../PageContent'
|
|
26
|
+
|
|
27
|
+
import { SingleSelect } from '../Input'
|
|
28
|
+
import ActionButton from '../ActionButton'
|
|
29
|
+
import { axiosErrorToast } from '../../config/axios'
|
|
30
|
+
import { DialogButton } from '../ModalButtons'
|
|
31
|
+
import SearchBar from '../FilterComponents/SearchBar'
|
|
32
|
+
import Table from '../Tables/BasicTable/Table'
|
|
33
|
+
|
|
34
|
+
interface ApplicationProfileProps {
|
|
35
|
+
application: 'exams' | 'square' | 'payments' | 'enroll_x'
|
|
36
|
+
}
|
|
37
|
+
function ApplicationProfile({
|
|
38
|
+
application = 'exams',
|
|
39
|
+
}: ApplicationProfileProps) {
|
|
40
|
+
const { isConfirmed } = useConfirm()
|
|
41
|
+
const [filters, setFilters] = useImmer(defaultFilterObj)
|
|
42
|
+
const { data, isLoading, refetch } = useQuery(
|
|
43
|
+
['application-users', ...Object.keys(filters)?.map((key) => filters[key])],
|
|
44
|
+
() => fetchApplicationUsers({ application, ...filters }),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const { data: profiles, isLoading: profilesLoading } = useQuery(
|
|
48
|
+
'profiles',
|
|
49
|
+
() => fetchProfiles({ application }),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
const { mutate, isLoading: removingUserProfile } = useMutation(
|
|
53
|
+
removeUserApplicationProfile,
|
|
54
|
+
{
|
|
55
|
+
onSuccess: (res) => {
|
|
56
|
+
refetch()
|
|
57
|
+
toast.success('User profile removed from application')
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
const handleRemove = async (data) => {
|
|
63
|
+
const confirmed = await isConfirmed(
|
|
64
|
+
'Are you sure you want to remove the user profile?',
|
|
65
|
+
)
|
|
66
|
+
if (!confirmed) return
|
|
67
|
+
mutate({ userId: data.id, application: application })
|
|
68
|
+
}
|
|
69
|
+
const columns = [
|
|
70
|
+
{
|
|
71
|
+
title: 'User',
|
|
72
|
+
key: '',
|
|
73
|
+
dataIndex: '',
|
|
74
|
+
render: (_, row) => <UserComponent userData={row} />,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
title: 'Profile',
|
|
78
|
+
key: '',
|
|
79
|
+
dataIndex: '',
|
|
80
|
+
render: (_, row) => (
|
|
81
|
+
<RenderProfileDropDown
|
|
82
|
+
profiles={profiles?.profiles}
|
|
83
|
+
data={row}
|
|
84
|
+
application={application}
|
|
85
|
+
refetchFn={refetch}
|
|
86
|
+
/>
|
|
87
|
+
),
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
title: 'Actions',
|
|
91
|
+
key: '',
|
|
92
|
+
dataIndex: '',
|
|
93
|
+
render: (_, row) => (
|
|
94
|
+
<Button
|
|
95
|
+
variant="text"
|
|
96
|
+
onClick={() => handleRemove(row)}
|
|
97
|
+
sx={{ padding: '0px', margin: '0px' }}
|
|
98
|
+
>
|
|
99
|
+
Remove
|
|
100
|
+
</Button>
|
|
101
|
+
),
|
|
102
|
+
},
|
|
103
|
+
]
|
|
104
|
+
const handleLimitChange = (value: number) => {
|
|
105
|
+
setFilters((s) => {
|
|
106
|
+
s.limit = value
|
|
107
|
+
s.offset = 0
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const handlePagination = (value: number) => {
|
|
112
|
+
setFilters((s) => {
|
|
113
|
+
s.offset = value * s.limit - s.limit
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
if (profilesLoading) {
|
|
117
|
+
return <Spinner />
|
|
118
|
+
}
|
|
119
|
+
return (
|
|
120
|
+
<>
|
|
121
|
+
<PageHeader
|
|
122
|
+
title={'Profile Configuration'}
|
|
123
|
+
actions={[
|
|
124
|
+
<DialogButton
|
|
125
|
+
key={0}
|
|
126
|
+
title={'Add User Profile Relation'}
|
|
127
|
+
anchor={({ open }) => (
|
|
128
|
+
<ActionButton onClick={open}>
|
|
129
|
+
Add User Profile Relation
|
|
130
|
+
</ActionButton>
|
|
131
|
+
)}
|
|
132
|
+
content={({ close }) => (
|
|
133
|
+
<UserProfileRelation
|
|
134
|
+
close={close}
|
|
135
|
+
application={application}
|
|
136
|
+
profiles={profiles?.profiles}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
139
|
+
/>,
|
|
140
|
+
]}
|
|
141
|
+
/>
|
|
142
|
+
<PageContent sx={{ marginTop: '25px' }}>
|
|
143
|
+
<StyledTableContainer>
|
|
144
|
+
<SearchBar
|
|
145
|
+
onSearch={(value) => {
|
|
146
|
+
setFilters((s) => {
|
|
147
|
+
s.search = value
|
|
148
|
+
})
|
|
149
|
+
}}
|
|
150
|
+
textFieldProps={{
|
|
151
|
+
placeholder: 'Search by Name',
|
|
152
|
+
title: 'Search by Name',
|
|
153
|
+
sx: { width: '300px', marginBottom: '25px' },
|
|
154
|
+
size: 'small',
|
|
155
|
+
}}
|
|
156
|
+
/>
|
|
157
|
+
<Table
|
|
158
|
+
columns={columns}
|
|
159
|
+
dataSource={data?.users ?? []}
|
|
160
|
+
loading={isLoading || removingUserProfile}
|
|
161
|
+
pagination={{
|
|
162
|
+
limit: filters.limit,
|
|
163
|
+
onChangeLimit: handleLimitChange,
|
|
164
|
+
onChange: handlePagination,
|
|
165
|
+
totalCount: data?.count,
|
|
166
|
+
page: filters.offset / filters.limit,
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
</StyledTableContainer>
|
|
170
|
+
</PageContent>
|
|
171
|
+
</>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
export default ApplicationProfile
|
|
175
|
+
|
|
176
|
+
export const RenderProfileDropDown = ({
|
|
177
|
+
profiles,
|
|
178
|
+
data,
|
|
179
|
+
refetchFn,
|
|
180
|
+
application,
|
|
181
|
+
}) => {
|
|
182
|
+
const [state, setState] = useState({
|
|
183
|
+
userId: data.id,
|
|
184
|
+
profileId: data.profiles[0].id,
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
const { mutate, isLoading } = useMutation(updateUserApplicationProfile, {
|
|
188
|
+
onSuccess: (res) => {
|
|
189
|
+
refetchFn()
|
|
190
|
+
toast.success('User application profile updated successfully')
|
|
191
|
+
},
|
|
192
|
+
onError: (err) => {
|
|
193
|
+
// eslint-disable-next-line no-console
|
|
194
|
+
console.log(err)
|
|
195
|
+
axiosErrorToast(err)
|
|
196
|
+
},
|
|
197
|
+
})
|
|
198
|
+
const handleChange = (e) => {
|
|
199
|
+
setState({
|
|
200
|
+
userId: data.id,
|
|
201
|
+
profileId: e.target.value,
|
|
202
|
+
})
|
|
203
|
+
mutate({
|
|
204
|
+
userId: state.userId,
|
|
205
|
+
profileIds: [e.target.value],
|
|
206
|
+
application: application,
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
return (
|
|
210
|
+
<>
|
|
211
|
+
<StyledDropDownContainer>
|
|
212
|
+
<SingleSelect
|
|
213
|
+
label={'Profile'}
|
|
214
|
+
name={'profile'}
|
|
215
|
+
value={state?.profileId}
|
|
216
|
+
onChange={(e) => {
|
|
217
|
+
handleChange(e)
|
|
218
|
+
}}
|
|
219
|
+
endAdornment={
|
|
220
|
+
isLoading && (
|
|
221
|
+
<InputAdornment position="end">
|
|
222
|
+
<CircularProgress
|
|
223
|
+
size={20}
|
|
224
|
+
color={'secondary'}
|
|
225
|
+
sx={{ marginRight: '10px' }}
|
|
226
|
+
/>
|
|
227
|
+
</InputAdornment>
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
options={
|
|
231
|
+
profiles?.map((profile) => ({
|
|
232
|
+
label: profile.name,
|
|
233
|
+
value: profile.id,
|
|
234
|
+
})) ?? []
|
|
235
|
+
}
|
|
236
|
+
/>
|
|
237
|
+
</StyledDropDownContainer>
|
|
238
|
+
</>
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export const UserComponent = ({ userData }) => {
|
|
243
|
+
return (
|
|
244
|
+
<>
|
|
245
|
+
<Box
|
|
246
|
+
sx={{
|
|
247
|
+
width: '100%',
|
|
248
|
+
display: 'flex',
|
|
249
|
+
gap: '10px',
|
|
250
|
+
alignItems: 'center',
|
|
251
|
+
justifyContent: 'flex-start',
|
|
252
|
+
}}
|
|
253
|
+
>
|
|
254
|
+
<Avatar alt={userData?.fullName} />
|
|
255
|
+
<Typography variant="subtitle1">{userData?.fullName}</Typography>
|
|
256
|
+
</Box>
|
|
257
|
+
</>
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
export const StyledTableContainer = styled(Box)(({ theme }) => ({
|
|
261
|
+
width: '70%',
|
|
262
|
+
margin: 'auto',
|
|
263
|
+
'& .MuiTableHead-root': {
|
|
264
|
+
border: '1px solid white',
|
|
265
|
+
borderBottom: theme.borders.grayLight,
|
|
266
|
+
borderWidth: '2px',
|
|
267
|
+
|
|
268
|
+
backgroundColor: 'white',
|
|
269
|
+
'& th': {
|
|
270
|
+
textAlign: 'left',
|
|
271
|
+
padding: '5px',
|
|
272
|
+
},
|
|
273
|
+
'& .MuiBox-root': {
|
|
274
|
+
color: '#121212b3',
|
|
275
|
+
fontSize: '164x',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
'& tbody': {
|
|
279
|
+
border: '1px solid white',
|
|
280
|
+
borderBottom: theme.borders.grayLight,
|
|
281
|
+
borderWidth: '2px',
|
|
282
|
+
'& tr': {
|
|
283
|
+
border: '1px solid white',
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
'& td': {
|
|
287
|
+
textAlign: 'center',
|
|
288
|
+
border: '1px solid white',
|
|
289
|
+
padding: '15px 0px',
|
|
290
|
+
},
|
|
291
|
+
}))
|
|
292
|
+
|
|
293
|
+
export const StyledDropDownContainer = styled(Box)(({ theme }) => ({
|
|
294
|
+
width: '200px',
|
|
295
|
+
'& .MuiTypography-root': {
|
|
296
|
+
display: 'none',
|
|
297
|
+
},
|
|
298
|
+
'& .MuiInputBase-root': {
|
|
299
|
+
backgroundColor: '#f5f6f8',
|
|
300
|
+
},
|
|
301
|
+
}))
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as yup from 'yup'
|
|
2
|
+
import axios from '../../config/axios'
|
|
3
|
+
export const defaultFilterObj = {
|
|
4
|
+
search: null,
|
|
5
|
+
limit: 10,
|
|
6
|
+
offset: 0,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const userProfileSchema = yup.object().shape({
|
|
10
|
+
userId: yup
|
|
11
|
+
.object()
|
|
12
|
+
.shape({
|
|
13
|
+
label: yup.string().required('User is required'),
|
|
14
|
+
value: yup.string().required('User is required'),
|
|
15
|
+
})
|
|
16
|
+
.required('User is required'),
|
|
17
|
+
profileIds: yup.string().required('Profile is required'),
|
|
18
|
+
})
|
|
19
|
+
export const fetchUsers = (params) => {
|
|
20
|
+
return axios
|
|
21
|
+
.get(`/square/profile-permissions/new-users`, {
|
|
22
|
+
params: params,
|
|
23
|
+
})
|
|
24
|
+
.then((res) => res.data)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const fetchApplicationUsers = (params) => {
|
|
28
|
+
return axios
|
|
29
|
+
.get(`/square/profile-permissions/application-users`, {
|
|
30
|
+
params: params,
|
|
31
|
+
})
|
|
32
|
+
.then((res) => res.data)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const fetchProfiles = (application) => {
|
|
36
|
+
return axios
|
|
37
|
+
.get(`/square/profiles`, {
|
|
38
|
+
params: application,
|
|
39
|
+
})
|
|
40
|
+
.then((res) => res.data)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ApplicationUserProfile {
|
|
44
|
+
application: string
|
|
45
|
+
userId: number
|
|
46
|
+
profileIds: number[]
|
|
47
|
+
}
|
|
48
|
+
export const createApplicationUserProfile = (
|
|
49
|
+
postBody: ApplicationUserProfile,
|
|
50
|
+
) => {
|
|
51
|
+
return axios
|
|
52
|
+
.post(`/square/profile-permissions/add-user`, postBody)
|
|
53
|
+
.then((res) => res.data)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const removeUserApplicationProfile = (postBody) => {
|
|
57
|
+
return axios
|
|
58
|
+
.post(`/square/profile-permissions/remove-user`, postBody)
|
|
59
|
+
.then((res) => res.data)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const updateUserApplicationProfile = (
|
|
63
|
+
postBody: ApplicationUserProfile,
|
|
64
|
+
) => {
|
|
65
|
+
return axios
|
|
66
|
+
.put(`/square/profile-permissions/edit-user-permissions`, postBody)
|
|
67
|
+
.then((res) => res.data)
|
|
68
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { yupResolver } from '@hookform/resolvers/yup'
|
|
2
|
+
import {
|
|
3
|
+
Autocomplete,
|
|
4
|
+
CircularProgress,
|
|
5
|
+
Popper,
|
|
6
|
+
Stack,
|
|
7
|
+
styled,
|
|
8
|
+
} from '@mui/material'
|
|
9
|
+
import { useState } from 'react'
|
|
10
|
+
import { Controller, useForm } from 'react-hook-form'
|
|
11
|
+
import { useMutation, useQueryClient } from 'react-query'
|
|
12
|
+
import { toast } from 'react-toastify'
|
|
13
|
+
import {
|
|
14
|
+
createApplicationUserProfile,
|
|
15
|
+
fetchUsers,
|
|
16
|
+
userProfileSchema,
|
|
17
|
+
} from './Service'
|
|
18
|
+
import { useImmer } from 'use-immer'
|
|
19
|
+
import { axiosErrorToast } from '../../config/axios'
|
|
20
|
+
import { FormMultiSelect, FormSingleSelect } from '../HookForm'
|
|
21
|
+
import ActionButton from '../ActionButton'
|
|
22
|
+
interface UserProps {
|
|
23
|
+
options: {
|
|
24
|
+
label: any
|
|
25
|
+
value: any
|
|
26
|
+
}[]
|
|
27
|
+
inputValue: string
|
|
28
|
+
}
|
|
29
|
+
function UserProfileRelation({ close, application, profiles }) {
|
|
30
|
+
const [state, setState] = useImmer<UserProps>({
|
|
31
|
+
options: [],
|
|
32
|
+
inputValue: '',
|
|
33
|
+
})
|
|
34
|
+
const queryClient = useQueryClient()
|
|
35
|
+
|
|
36
|
+
const { control, handleSubmit, formState } = useForm({
|
|
37
|
+
defaultValues: {},
|
|
38
|
+
resolver: yupResolver(userProfileSchema),
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const { mutate, isLoading: creatingUserProfile } = useMutation(
|
|
42
|
+
createApplicationUserProfile,
|
|
43
|
+
{
|
|
44
|
+
onSuccess: (res) => {
|
|
45
|
+
queryClient.invalidateQueries(`application-users`)
|
|
46
|
+
toast.success('User profile added to application successfully')
|
|
47
|
+
close()
|
|
48
|
+
},
|
|
49
|
+
onError: (err) => {
|
|
50
|
+
// eslint-disable-next-line no-console
|
|
51
|
+
console.log(err)
|
|
52
|
+
axiosErrorToast(err)
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const { mutate: fetchUsersFn, isLoading: gettingUsers } = useMutation(
|
|
58
|
+
fetchUsers,
|
|
59
|
+
{
|
|
60
|
+
onSuccess: (res) => {
|
|
61
|
+
setState((s) => {
|
|
62
|
+
s.options = res.users?.map((item) => ({
|
|
63
|
+
label: item.fullName,
|
|
64
|
+
value: item.id,
|
|
65
|
+
}))
|
|
66
|
+
})
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
const onSubmit = (formData) => {
|
|
71
|
+
mutate({
|
|
72
|
+
application: application,
|
|
73
|
+
profileIds: [+formData.profileIds],
|
|
74
|
+
userId: +formData.userId?.value,
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
const onError = (err) => {
|
|
78
|
+
// eslint-disable-next-line no-console
|
|
79
|
+
console.log(err)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const handleInputChange = (e) => {
|
|
83
|
+
if (e) {
|
|
84
|
+
setState((s) => {
|
|
85
|
+
s.inputValue = e.target.value
|
|
86
|
+
})
|
|
87
|
+
if (e.target.value.length > 3) {
|
|
88
|
+
fetchUsersFn({
|
|
89
|
+
application: application,
|
|
90
|
+
search: e.target.value,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<>
|
|
98
|
+
<form onSubmit={handleSubmit(onSubmit, onError)}>
|
|
99
|
+
<Stack gap={4} sx={{ padding: '10px' }}>
|
|
100
|
+
<FormMultiSelect
|
|
101
|
+
multiple={false}
|
|
102
|
+
label={'User'}
|
|
103
|
+
name={'userId'}
|
|
104
|
+
onInputChange={handleInputChange}
|
|
105
|
+
loading={gettingUsers}
|
|
106
|
+
control={control}
|
|
107
|
+
options={state.options ?? []}
|
|
108
|
+
required
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
<FormSingleSelect
|
|
112
|
+
label={'Profile'}
|
|
113
|
+
name={'profileIds'}
|
|
114
|
+
control={control}
|
|
115
|
+
options={
|
|
116
|
+
profiles?.map((profile) => ({
|
|
117
|
+
label: profile.name,
|
|
118
|
+
value: profile.id,
|
|
119
|
+
})) ?? []
|
|
120
|
+
}
|
|
121
|
+
required
|
|
122
|
+
/>
|
|
123
|
+
<Stack gap={2} direction={'row'} sx={{ justifyContent: 'flex-end' }}>
|
|
124
|
+
<ActionButton variant="outlined" onClick={close}>
|
|
125
|
+
Cancel
|
|
126
|
+
</ActionButton>
|
|
127
|
+
<ActionButton type="submit" loading={creatingUserProfile}>
|
|
128
|
+
Confirm
|
|
129
|
+
</ActionButton>
|
|
130
|
+
</Stack>
|
|
131
|
+
</Stack>
|
|
132
|
+
</form>
|
|
133
|
+
</>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
export default UserProfileRelation
|
|
137
|
+
|
|
138
|
+
const StyledPopper = styled(Popper)(({ theme }) => ({
|
|
139
|
+
'& .MuiPaper-root': {
|
|
140
|
+
borderRadius: '10px',
|
|
141
|
+
borderTopRightRadius: 0,
|
|
142
|
+
borderTopLeftRadius: 0,
|
|
143
|
+
boxShadow: '0px 4px 16px #0000000F',
|
|
144
|
+
marginTop: '1px',
|
|
145
|
+
'& .MuiAutocomplete-listbox': {
|
|
146
|
+
minWidth: '240px',
|
|
147
|
+
padding: '10px',
|
|
148
|
+
'& .MuiAutocomplete-option': {
|
|
149
|
+
padding: '10px',
|
|
150
|
+
background: 'none',
|
|
151
|
+
'&.Mui-focused': {
|
|
152
|
+
background: 'none',
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
'& .MuiCheckbox-root': {
|
|
156
|
+
padding: 0,
|
|
157
|
+
marginRight: '10px',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
'&::-webkit-scrollbar': {
|
|
161
|
+
width: '0.5em',
|
|
162
|
+
height: '0.5em',
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
'&::-webkit-scrollbar-thumb': {
|
|
166
|
+
backgroundColor: 'rgba(0, 0, 0, 0.15)',
|
|
167
|
+
borderRadius: '3px',
|
|
168
|
+
|
|
169
|
+
'&:hover': {
|
|
170
|
+
background: 'rgba(0, 0, 0, 0.2)',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
}))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./ApplicationProfile";
|
|
@@ -2,6 +2,7 @@ import { ReactNode } from 'react'
|
|
|
2
2
|
import { Controller } from 'react-hook-form'
|
|
3
3
|
import { MultiSelect } from '../Input'
|
|
4
4
|
import { IOption } from '../Input/types'
|
|
5
|
+
import { AutocompleteInputChangeReason } from '@mui/material'
|
|
5
6
|
|
|
6
7
|
interface MultiSelectProps {
|
|
7
8
|
control: any
|
|
@@ -10,6 +11,11 @@ interface MultiSelectProps {
|
|
|
10
11
|
options: IOption[]
|
|
11
12
|
placeholder?: string
|
|
12
13
|
loading?: boolean
|
|
14
|
+
onInputChange?: (
|
|
15
|
+
event: React.SyntheticEvent,
|
|
16
|
+
value: string,
|
|
17
|
+
reason: AutocompleteInputChangeReason,
|
|
18
|
+
) => void
|
|
13
19
|
required?: boolean
|
|
14
20
|
value?: IOption[] | IOption
|
|
15
21
|
onChange?: (value: IOption[] | IOption) => void
|
|
@@ -24,6 +30,7 @@ export default function FormMultiSelect({
|
|
|
24
30
|
loading,
|
|
25
31
|
required,
|
|
26
32
|
multiple = true,
|
|
33
|
+
onInputChange,
|
|
27
34
|
...props
|
|
28
35
|
}: MultiSelectProps) {
|
|
29
36
|
return (
|
|
@@ -39,6 +46,7 @@ export default function FormMultiSelect({
|
|
|
39
46
|
onChange={(value) => {
|
|
40
47
|
field.onChange(value)
|
|
41
48
|
}}
|
|
49
|
+
onInputChange={onInputChange}
|
|
42
50
|
loading={loading}
|
|
43
51
|
options={options || []}
|
|
44
52
|
error={!!error}
|
|
@@ -2,6 +2,7 @@ import { Close, KeyboardArrowDown } from '@mui/icons-material'
|
|
|
2
2
|
import {
|
|
3
3
|
alpha,
|
|
4
4
|
Autocomplete,
|
|
5
|
+
AutocompleteInputChangeReason,
|
|
5
6
|
Checkbox,
|
|
6
7
|
CircularProgress,
|
|
7
8
|
Popper,
|
|
@@ -76,6 +77,11 @@ interface MultiSelectProps {
|
|
|
76
77
|
loading?: boolean
|
|
77
78
|
value: IOption[] | IOption
|
|
78
79
|
onChange: (value: IOption[] | IOption) => void
|
|
80
|
+
onInputChange?: (
|
|
81
|
+
event: React.SyntheticEvent,
|
|
82
|
+
value: string,
|
|
83
|
+
reason: AutocompleteInputChangeReason,
|
|
84
|
+
) => void
|
|
79
85
|
required?: boolean
|
|
80
86
|
error?: boolean
|
|
81
87
|
helperText?: string
|
|
@@ -90,6 +96,7 @@ export default function MultiSelect({
|
|
|
90
96
|
loading,
|
|
91
97
|
value,
|
|
92
98
|
onChange,
|
|
99
|
+
onInputChange,
|
|
93
100
|
required,
|
|
94
101
|
error,
|
|
95
102
|
helperText,
|
|
@@ -109,6 +116,7 @@ export default function MultiSelect({
|
|
|
109
116
|
if (!onChange) return
|
|
110
117
|
onChange(value)
|
|
111
118
|
}}
|
|
119
|
+
onInputChange={onInputChange}
|
|
112
120
|
limitTags={limitTags}
|
|
113
121
|
isOptionEqualToValue={(option: any, value: any) =>
|
|
114
122
|
option?.value === value?.value
|
|
@@ -2,24 +2,31 @@
|
|
|
2
2
|
import { useState } from 'react'
|
|
3
3
|
import { UserStore } from '../../../../shared-state'
|
|
4
4
|
import { chatWithUs } from '../assets'
|
|
5
|
-
import { Box } from '@mui/material'
|
|
5
|
+
import { Box, styled } from '@mui/material'
|
|
6
6
|
|
|
7
7
|
export default function FreshChatButton() {
|
|
8
8
|
const _window = window as any
|
|
9
|
-
const [show, setShow] = useState(false)
|
|
10
9
|
const { user } = UserStore.useState()
|
|
11
10
|
|
|
12
11
|
var openWidget = function () {
|
|
13
|
-
document.getElementById('fc_frame')
|
|
12
|
+
const el = document.getElementById('fc_frame')
|
|
13
|
+
if (el) {
|
|
14
|
+
el.style.visibility = 'visible'
|
|
15
|
+
}
|
|
14
16
|
_window.fcWidget.open()
|
|
15
17
|
initEvents()
|
|
16
18
|
}
|
|
17
19
|
var initEvents = function () {
|
|
20
|
+
const el = document.getElementById('custom_fc_button')
|
|
18
21
|
_window.fcWidget.on('widget:opened', function (resp) {
|
|
19
|
-
|
|
22
|
+
if (el) {
|
|
23
|
+
el.style.visibility = 'hidden'
|
|
24
|
+
}
|
|
20
25
|
})
|
|
21
26
|
_window.fcWidget.on('widget:closed', function (resp) {
|
|
22
|
-
|
|
27
|
+
if (el) {
|
|
28
|
+
el.style.visibility = 'visible'
|
|
29
|
+
}
|
|
23
30
|
})
|
|
24
31
|
}
|
|
25
32
|
|
|
@@ -38,14 +45,17 @@ export default function FreshChatButton() {
|
|
|
38
45
|
}}
|
|
39
46
|
>
|
|
40
47
|
<a id="open_fc_widget" onClick={openWidget} style={{ cursor: 'pointer' }}>
|
|
41
|
-
<
|
|
42
|
-
style={{
|
|
43
|
-
width: '40px',
|
|
44
|
-
height: 'auto',
|
|
45
|
-
}}
|
|
46
|
-
src={chatWithUs}
|
|
47
|
-
/>
|
|
48
|
+
<StyledImg src={chatWithUs} />
|
|
48
49
|
</a>
|
|
49
50
|
</Box>
|
|
50
51
|
)
|
|
51
52
|
}
|
|
53
|
+
|
|
54
|
+
const StyledImg = styled('img')(({ theme }) => ({
|
|
55
|
+
width: '35px',
|
|
56
|
+
height: 'auto',
|
|
57
|
+
'&:hover': {
|
|
58
|
+
width: '50px',
|
|
59
|
+
},
|
|
60
|
+
transition: 'width 0.3s',
|
|
61
|
+
}))
|