diff --git a/app/lib/hooks/index.ts b/app/lib/hooks/index.ts index e32a49c6b..4501efcd7 100644 --- a/app/lib/hooks/index.ts +++ b/app/lib/hooks/index.ts @@ -1 +1,2 @@ export * from './useAppSelector'; +export * from './usePermissions'; diff --git a/app/lib/hooks/usePermissions.ts b/app/lib/hooks/usePermissions.ts new file mode 100644 index 000000000..c15c29b68 --- /dev/null +++ b/app/lib/hooks/usePermissions.ts @@ -0,0 +1,53 @@ +import { useState, useEffect } from 'react'; +import { dequal } from 'dequal'; +import { Subscription } from 'rxjs'; +import { createSelector } from 'reselect'; +import { shallowEqual } from 'react-redux'; + +import { TSupportedPermissions } from '../../reducers/permissions'; +import { IApplicationState, TSubscriptionModel } from '../../definitions'; +import { getUserSelector } from '../../selectors/login'; +import { useAppSelector } from './useAppSelector'; +import { getSubscriptionByRoomId } from '../database/services/Subscription'; + +const getPermissionsSelector = createSelector( + [(state: IApplicationState) => state.permissions, (_state: any, permissionsArray: TSupportedPermissions[]) => permissionsArray], + (permissions, permissionsArray) => permissionsArray.map(p => permissions[p]) +); + +const useSubscriptionRoles = (rid?: string): TSubscriptionModel['roles'] => { + const [subscriptionRoles, setSubscriptionRoles] = useState([]); + + useEffect(() => { + if (!rid) { + return; + } + let subSubscription: Subscription; + getSubscriptionByRoomId(rid).then(sub => { + if (!sub) { + return; + } + const observable = sub.observe(); + subSubscription = observable.subscribe(s => { + if (!dequal(subscriptionRoles, s.roles)) { + setSubscriptionRoles(s.roles); + } + }); + }); + + return () => { + if (subSubscription && subSubscription?.unsubscribe) subSubscription.unsubscribe(); + }; + }, [subscriptionRoles]); + + return subscriptionRoles; +}; + +export function usePermissions(permissions: TSupportedPermissions[], rid?: string): boolean[] { + const userRoles = useAppSelector(state => getUserSelector(state).roles || [], shallowEqual); + const permissionsRedux = useAppSelector(state => getPermissionsSelector(state, permissions), shallowEqual); + const subscriptionRoles = useSubscriptionRoles(rid); + + const mergedRoles = [...new Set([...(subscriptionRoles || []), ...userRoles])]; + return permissionsRedux.map(permission => (permission ?? []).some(r => mergedRoles.includes(r))); +} diff --git a/app/views/LivechatEditView.tsx b/app/views/LivechatEditView.tsx index cbc473a4c..094896bed 100644 --- a/app/views/LivechatEditView.tsx +++ b/app/views/LivechatEditView.tsx @@ -21,8 +21,8 @@ import { ICustomFields, IInputsRefs, TParams, ITitle, ILivechat } from '../defin import { IApplicationState, IUser } from '../definitions'; import { ChatsStackParamList } from '../stacks/types'; import sharedStyles from './Styles'; -import { hasPermission } from '../lib/methods/helpers'; import { Services } from '../lib/services'; +import { usePermissions } from '../lib/hooks'; const styles = StyleSheet.create({ container: { @@ -55,17 +55,9 @@ interface ILivechatEditViewProps { const Title = ({ title, theme }: ITitle) => title ? {title} : null; -const LivechatEditView = ({ - user, - navigation, - route, - theme, - editOmnichannelContact, - editLivechatRoomCustomfields -}: ILivechatEditViewProps) => { +const LivechatEditView = ({ user, navigation, route, theme }: ILivechatEditViewProps) => { const [customFields, setCustomFields] = useState({}); const [availableUserTags, setAvailableUserTags] = useState([]); - const [permissions, setPermissions] = useState([]); const params = {} as TParams; const inputs = {} as IInputsRefs; @@ -73,6 +65,11 @@ const LivechatEditView = ({ const livechat = (route.params?.room ?? {}) as ILivechat; const visitor = route.params?.roomUser ?? {}; + const [editOmnichannelContactPermission, editLivechatRoomCustomFieldsPermission] = usePermissions( + ['edit-omnichannel-contact', 'edit-livechat-room-customfields'], + livechat.rid + ); + const getCustomFields = async () => { const result = await Services.getCustomFields(); if (result.success && result.customFields?.length) { @@ -171,18 +168,12 @@ const LivechatEditView = ({ params[key] = text; }; - const getPermissions = async () => { - const permissionsArray = await hasPermission([editOmnichannelContact, editLivechatRoomCustomfields], livechat.rid); - setPermissions(permissionsArray); - }; - useEffect(() => { navigation.setOptions({ title: I18n.t('Edit') }); handleGetAgentDepartments(); getCustomFields(); - getPermissions(); }, []); return ( @@ -201,7 +192,7 @@ const LivechatEditView = ({ inputs.name?.focus(); }} theme={theme} - editable={!!permissions[0]} + editable={!!editOmnichannelContactPermission} /> {Object.entries(customFields?.visitor || {}).map(([key, value], index, array) => ( ))} @@ -262,7 +253,7 @@ const LivechatEditView = ({ defaultValue={livechat?.topic} onChangeText={text => onChangeText('topic', text)} theme={theme} - editable={!!permissions[1]} + editable={!!editLivechatRoomCustomFieldsPermission} /> <Text style={[styles.label, { color: themes[theme].titleText }]}>{I18n.t('Tags')}</Text> @@ -275,7 +266,7 @@ const LivechatEditView = ({ value={tagParamSelected} context={BlockContext.FORM} multiselect - disabled={!permissions[1]} + disabled={!editLivechatRoomCustomFieldsPermission} inputStyle={styles.multiSelect} /> @@ -294,7 +285,7 @@ const LivechatEditView = ({ submit(); }} theme={theme} - editable={!!permissions[1]} + editable={!!editLivechatRoomCustomFieldsPermission} /> ))} @@ -307,9 +298,7 @@ const LivechatEditView = ({ const mapStateToProps = (state: IApplicationState) => ({ server: state.server.server, - user: getUserSelector(state), - editOmnichannelContact: state.permissions['edit-omnichannel-contact'], - editLivechatRoomCustomfields: state.permissions['edit-livechat-room-customfields'] + user: getUserSelector(state) }); export default connect(mapStateToProps)(withTheme(LivechatEditView));