330 lines
10 KiB
TypeScript
330 lines
10 KiB
TypeScript
import { CompositeNavigationProp, RouteProp, useNavigation, useRoute } from '@react-navigation/native';
|
|
import { StackNavigationProp } from '@react-navigation/stack';
|
|
import { uniq } from 'lodash';
|
|
import isEmpty from 'lodash/isEmpty';
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
import { ScrollView, View } from 'react-native';
|
|
import { Subscription } from 'rxjs';
|
|
import UAParser from 'ua-parser-js';
|
|
|
|
import * as HeaderButton from '../../containers/HeaderButton';
|
|
import SafeAreaView from '../../containers/SafeAreaView';
|
|
import StatusBar from '../../containers/StatusBar';
|
|
import { LISTENER } from '../../containers/Toast';
|
|
import { ISubscription, IUser, SubscriptionType } from '../../definitions';
|
|
import I18n from '../../i18n';
|
|
import { getSubscriptionByRoomId } from '../../lib/database/services/Subscription';
|
|
import { useAppSelector } from '../../lib/hooks';
|
|
import { getRoomTitle, getUidDirectMessage, hasPermission } from '../../lib/methods/helpers';
|
|
import EventEmitter from '../../lib/methods/helpers/events';
|
|
import { goRoom } from '../../lib/methods/helpers/goRoom';
|
|
import { handleIgnore } from '../../lib/methods/helpers/handleIgnore';
|
|
import log, { events, logEvent } from '../../lib/methods/helpers/log';
|
|
import { Services } from '../../lib/services';
|
|
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
|
|
import { ChatsStackParamList } from '../../stacks/types';
|
|
import { useTheme } from '../../theme';
|
|
import RoomInfoButtons from './components/RoomInfoButtons';
|
|
import RoomInfoViewAvatar from './components/RoomInfoViewAvatar';
|
|
import RoomInfoViewBody from './components/RoomInfoViewBody';
|
|
import RoomInfoViewTitle from './components/RoomInfoViewTitle';
|
|
import styles from './styles';
|
|
|
|
type TRoomInfoViewNavigationProp = CompositeNavigationProp<
|
|
StackNavigationProp<ChatsStackParamList, 'RoomInfoView'>,
|
|
StackNavigationProp<MasterDetailInsideStackParamList>
|
|
>;
|
|
|
|
type TRoomInfoViewRouteProp = RouteProp<ChatsStackParamList, 'RoomInfoView'>;
|
|
|
|
const RoomInfoView = (): React.ReactElement => {
|
|
const {
|
|
params: { rid, t, fromRid, member, room: roomParam, showCloseModal, itsMe }
|
|
} = useRoute<TRoomInfoViewRouteProp>();
|
|
const { addListener, setOptions, navigate, goBack } = useNavigation<TRoomInfoViewNavigationProp>();
|
|
|
|
const [room, setRoom] = useState(roomParam || ({ rid, t } as ISubscription));
|
|
const [roomFromRid, setRoomFromRid] = useState<ISubscription | undefined>();
|
|
const [roomUser, setRoomUser] = useState(member || {});
|
|
const [showEdit, setShowEdit] = useState(false);
|
|
|
|
const roomType = room?.t || t;
|
|
const isDirect = roomType === SubscriptionType.DIRECT;
|
|
const isLivechat = roomType === SubscriptionType.OMNICHANNEL;
|
|
|
|
const subscription = useRef<Subscription | undefined>(undefined);
|
|
|
|
const {
|
|
isMasterDetail,
|
|
subscribedRoom,
|
|
usersRoles,
|
|
roles,
|
|
serverVersion,
|
|
// permissions
|
|
editRoomPermission,
|
|
editOmnichannelContact,
|
|
editLivechatRoomCustomfields
|
|
} = useAppSelector(state => ({
|
|
subscribedRoom: state.room.subscribedRoom,
|
|
isMasterDetail: state.app.isMasterDetail,
|
|
roles: state.roles,
|
|
usersRoles: state.usersRoles,
|
|
serverVersion: state.server.version,
|
|
// permissions
|
|
editRoomPermission: state.permissions['edit-room'],
|
|
editOmnichannelContact: state.permissions['edit-omnichannel-contact'],
|
|
editLivechatRoomCustomfields: state.permissions['edit-livechat-room-customfields']
|
|
}));
|
|
|
|
const { colors } = useTheme();
|
|
|
|
useEffect(() => {
|
|
const listener = addListener('focus', () => (isLivechat ? loadVisitor() : null));
|
|
return () => listener();
|
|
}, []);
|
|
|
|
useEffect(
|
|
() => () => {
|
|
subscription.current?.unsubscribe();
|
|
},
|
|
[]
|
|
);
|
|
|
|
useEffect(() => {
|
|
loadRoom();
|
|
if (isDirect) loadUser();
|
|
}, []);
|
|
|
|
const setHeader = (canEdit?: boolean) => {
|
|
const HeaderRight = () => (
|
|
<HeaderButton.Container>
|
|
<HeaderButton.Item
|
|
iconName='edit'
|
|
onPress={() => {
|
|
if (!room) return;
|
|
logEvent(events[`RI_GO_${isLivechat ? 'LIVECHAT' : 'RI'}_EDIT`]);
|
|
const navigationProps = { room, roomUser };
|
|
if (isLivechat) navigate('LivechatEditView', navigationProps);
|
|
else navigate('RoomInfoEditView', { rid, ...navigationProps });
|
|
}}
|
|
testID='room-info-view-edit-button'
|
|
/>
|
|
</HeaderButton.Container>
|
|
);
|
|
setOptions({
|
|
headerLeft: showCloseModal ? () => <HeaderButton.CloseModal /> : undefined,
|
|
title: isDirect ? I18n.t('User_Info') : I18n.t('Room_Info'),
|
|
headerRight: canEdit ? () => <HeaderRight /> : undefined
|
|
});
|
|
};
|
|
|
|
const loadVisitor = async () => {
|
|
try {
|
|
if (room?.visitor?._id) {
|
|
const result = await Services.getVisitorInfo(room.visitor._id);
|
|
if (result.success) {
|
|
const { visitor } = result;
|
|
const params: { os?: string; browser?: string } = {};
|
|
if (visitor.userAgent) {
|
|
const ua = new UAParser();
|
|
ua.setUA(visitor.userAgent);
|
|
params.os = `${ua.getOS().name} ${ua.getOS().version}`;
|
|
params.browser = `${ua.getBrowser().name} ${ua.getBrowser().version}`;
|
|
}
|
|
setRoomUser({ ...visitor, ...params });
|
|
setHeader();
|
|
}
|
|
}
|
|
} catch (error) {
|
|
// Do nothing
|
|
}
|
|
};
|
|
|
|
const parseRoles = (roleArray: string[]) => roleArray.map(role => roles[role]);
|
|
|
|
const handleRoles = (user: Pick<IUser, 'username' | 'roles'>) => {
|
|
const rrr = (() => {
|
|
const userRoles = usersRoles.find(u => u?.username === user.username);
|
|
let r: string[] = [];
|
|
if (userRoles?.roles?.length) r = userRoles.roles;
|
|
if (user.roles?.length) r = [...r, ...user.roles];
|
|
return uniq(r);
|
|
})();
|
|
if (rrr.length) {
|
|
const parsedRoles = parseRoles(rrr);
|
|
return parsedRoles;
|
|
}
|
|
};
|
|
|
|
const loadUser = async () => {
|
|
if (isEmpty(roomUser)) {
|
|
try {
|
|
const roomUserId = getUidDirectMessage(room || { rid, t, itsMe });
|
|
const result = await Services.getUserInfo(roomUserId);
|
|
if (result.success) {
|
|
const { user } = result;
|
|
const r = handleRoles(user);
|
|
setRoomUser({ ...user, roles: r });
|
|
}
|
|
} catch {
|
|
// do nothing
|
|
}
|
|
} else {
|
|
const r = handleRoles(roomUser);
|
|
if (r) setRoomUser({ ...roomUser, roles: r });
|
|
}
|
|
};
|
|
|
|
const loadRoom = async () => {
|
|
const permissionToEdit = isLivechat ? [editOmnichannelContact, editLivechatRoomCustomfields] : [editRoomPermission];
|
|
const permissions = await hasPermission(permissionToEdit, rid);
|
|
const canEdit = permissions.some(Boolean);
|
|
const subRoom = await getSubscriptionByRoomId(rid);
|
|
if (!subRoom && isDirect && fromRid) {
|
|
const roomFromRid = await getSubscriptionByRoomId(fromRid);
|
|
if (roomFromRid?.observe) {
|
|
const sub = roomFromRid.observe();
|
|
subscription.current = sub.subscribe(changes => {
|
|
setRoomFromRid(changes.asPlain());
|
|
});
|
|
}
|
|
} else if (subRoom?.observe) {
|
|
const sub = subRoom.observe();
|
|
subscription.current = sub.subscribe(changes => {
|
|
setRoom(changes.asPlain());
|
|
setHeader(canEdit);
|
|
});
|
|
} else {
|
|
try {
|
|
if (!isDirect) {
|
|
const result = await Services.getRoomInfo(rid);
|
|
if (result.success) setRoom({ ...room, ...(result.room as unknown as ISubscription) });
|
|
}
|
|
} catch (e) {
|
|
log(e);
|
|
}
|
|
}
|
|
setShowEdit(canEdit);
|
|
setHeader(canEdit);
|
|
};
|
|
|
|
const createDirect = () =>
|
|
new Promise<void | ISubscription>(async (resolve, reject) => {
|
|
// We don't need to create a direct
|
|
if (!isEmpty(member)) return resolve();
|
|
try {
|
|
const result = await Services.createDirectMessage(roomUser.username);
|
|
if (result.success) return resolve({ ...roomUser, rid: result.room.rid });
|
|
} catch {
|
|
reject();
|
|
}
|
|
});
|
|
|
|
const handleGoRoom = (r?: ISubscription) => {
|
|
logEvent(events.RI_GO_ROOM_USER);
|
|
const params = {
|
|
rid: r?.rid,
|
|
name: getRoomTitle(r),
|
|
t: roomType,
|
|
roomUserId: getUidDirectMessage(r)
|
|
};
|
|
|
|
if (r?.rid) {
|
|
if (r.rid === subscribedRoom) {
|
|
if (isMasterDetail) {
|
|
return navigate('DrawerNavigator');
|
|
}
|
|
goBack();
|
|
goBack();
|
|
return;
|
|
}
|
|
// if it's on master detail layout, we close the modal and replace RoomView
|
|
goRoom({ item: params, isMasterDetail, popToRoot: true });
|
|
}
|
|
};
|
|
|
|
const handleCreateDirectMessage = async () => {
|
|
try {
|
|
let r = room;
|
|
if (isDirect) {
|
|
const direct = await createDirect();
|
|
if (direct) r = direct;
|
|
}
|
|
handleGoRoom(r);
|
|
} catch {
|
|
EventEmitter.emit(LISTENER, {
|
|
message: I18n.t('error-action-not-allowed', { action: I18n.t('Create_Direct_Messages') })
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleBlockUser = async () => {
|
|
const r = roomFromRid || room;
|
|
const userBlocked = roomUser._id;
|
|
const blocker = r?.blocker;
|
|
if (!r?.rid) return;
|
|
logEvent(events.RI_TOGGLE_BLOCK_USER);
|
|
try {
|
|
await Services.toggleBlockUser(r.rid, userBlocked, !blocker);
|
|
} catch (e) {
|
|
log(e);
|
|
}
|
|
};
|
|
|
|
const handleIgnoreUser = () => {
|
|
const r = roomFromRid || room;
|
|
const isIgnored = r?.ignored?.includes?.(roomUser._id);
|
|
if (r?.rid) handleIgnore(roomUser._id, !isIgnored, r?.rid);
|
|
};
|
|
|
|
const handleReportUser = () => {
|
|
navigate('ReportUserView', {
|
|
name: roomUser?.name,
|
|
userId: roomUser?._id,
|
|
username: roomUser.username
|
|
});
|
|
};
|
|
|
|
return (
|
|
<ScrollView style={[styles.scroll, { backgroundColor: colors.backgroundColor }]}>
|
|
<StatusBar />
|
|
<SafeAreaView style={{ backgroundColor: colors.backgroundColor }} testID='room-info-view'>
|
|
<View style={[styles.avatarContainer, { backgroundColor: colors.auxiliaryBackground }]}>
|
|
<RoomInfoViewAvatar
|
|
username={room?.name || roomUser.username}
|
|
rid={room?.rid}
|
|
userId={roomUser?._id}
|
|
handleEditAvatar={() => navigate('ChangeAvatarView', { titleHeader: I18n.t('Room_Info'), room, t, context: 'room' })}
|
|
showEdit={showEdit}
|
|
type={t}
|
|
/>
|
|
<RoomInfoViewTitle
|
|
type={t}
|
|
room={room || roomUser}
|
|
name={roomUser?.name}
|
|
username={roomUser?.username}
|
|
statusText={roomUser?.statusText}
|
|
/>
|
|
<RoomInfoButtons
|
|
rid={room?.rid || rid}
|
|
fromRid={fromRid}
|
|
handleBlockUser={handleBlockUser}
|
|
handleCreateDirectMessage={handleCreateDirectMessage}
|
|
handleIgnoreUser={handleIgnoreUser}
|
|
handleReportUser={handleReportUser}
|
|
isDirect={isDirect}
|
|
room={room || roomUser}
|
|
roomUserId={roomUser?._id}
|
|
roomFromRid={roomFromRid}
|
|
serverVersion={serverVersion}
|
|
itsMe={itsMe}
|
|
/>
|
|
</View>
|
|
<RoomInfoViewBody isDirect={isDirect} room={room} roomUser={roomUser} />
|
|
</SafeAreaView>
|
|
</ScrollView>
|
|
);
|
|
};
|
|
|
|
export default RoomInfoView;
|