Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/containers/CallHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type TCallHeader = {
setCam: Function;
setMic: Function;
title: string;
avatar: string;
avatar?: string;
uid: string;
name: string;
direct: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ export interface INotifierComponent {
type: SubscriptionType;
} & Pick<ISubscription, '_id' | 'name' | 'rid' | 'prid'>;
title: string;
avatar: string;
avatar?: string;
};
isMasterDetail: boolean;
}

const BUTTON_HIT_SLOP = { top: 12, right: 12, bottom: 12, left: 12 };

const IncomingCallHeader = React.memo(
({ uid, callId, avatar, roomName }: { callId: string; avatar: string; uid: string; roomName: string }) => {
({ uid, callId, avatar, roomName }: { callId: string; avatar?: string; uid: string; roomName: string }) => {
const componentRef = useRef<View>(null);
const [mic, setMic] = useState(true);
const [cam, setCam] = useState(false);
Expand Down
2 changes: 1 addition & 1 deletion app/containers/InAppNotification/NotifierComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface INotifierComponent {
message?: { message?: string; msg?: string; t?: string };
} & Pick<ISubscription, '_id' | 'name' | 'rid' | 'prid'>;
title: string;
avatar: string;
avatar?: string;
};
isMasterDetail: boolean;
}
Expand Down
14 changes: 7 additions & 7 deletions app/containers/MessageActions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ const MessageActions = React.memo(
];
const result = await hasPermission(permission, room.rid);
permissions = {
hasEditPermission: result[0],
hasDeletePermission: result[1],
hasForceDeletePermission: result[2],
hasPinPermission: result[3],
hasDeleteOwnPermission: result[4],
hasCreateDirectMessagePermission: result[5],
hasCreateDiscussionOtherUserPermission: result[6]
hasEditPermission: result[0] || false,
hasDeletePermission: result[1] || false,
hasForceDeletePermission: result[2] || false,
hasPinPermission: result[3] || false,
hasDeleteOwnPermission: result[4] || false,
hasCreateDirectMessagePermission: result[5] || false,
hasCreateDiscussionOtherUserPermission: result[6] || false
};
} catch {
// Do nothing
Expand Down
2 changes: 1 addition & 1 deletion app/containers/RoomItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const RoomItemContainer = React.memo(

return (
<RoomItem
name={name}
name={name || ''}
avatar={avatar}
isGroupChat={isGroupChat(item)}
isRead={isRead}
Expand Down
10 changes: 5 additions & 5 deletions app/containers/RoomItem/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface IUpdatedAtProps {

export interface IWrapperProps {
accessibilityLabel: string;
avatar: string;
avatar?: string;
type: string;
userId: string | null;
rid: string;
Expand Down Expand Up @@ -93,8 +93,8 @@ interface IBaseRoomItem extends IRoomItemTouchables {
export interface IRoomItemContainerProps extends IBaseRoomItem {
item: any;
id?: string;
getRoomTitle: (item: any) => string;
getRoomAvatar: (item: any) => string;
getRoomTitle: (item: any) => string | undefined;
getRoomAvatar: (item: any) => string | undefined;
getIsRead?: (item: any) => boolean;
}

Expand All @@ -103,7 +103,7 @@ export interface IRoomItemProps extends IBaseRoomItem {
type: SubscriptionType;
prid: string;
name: string;
avatar: string;
avatar?: string;
testID: string;
status: TUserStatus;
isGroupChat: boolean;
Expand Down Expand Up @@ -149,7 +149,7 @@ export interface ITouchableProps extends IRoomItemTouchables {
}

export interface IIconOrAvatar {
avatar: string;
avatar?: string;
type: string;
rid: string;
userId: string | null;
Expand Down
8 changes: 7 additions & 1 deletion app/lib/hooks/useUserData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import { getUserInfo } from '../services/restApi';
import { useAppSelector } from './useAppSelector';

const useUserData = (rid: string) => {
const [user, setUser] = useState({ username: '', avatar: '', uid: '', type: '', direct: false });
const [user, setUser] = useState<{ username: string; avatar?: string; uid: string; type: string; direct: boolean }>({
username: '',
avatar: '',
uid: '',
type: '',
direct: false
});
const { useRealName } = useAppSelector(state => ({
useRealName: state.settings.UI_Use_Real_Name as boolean
}));
Expand Down
95 changes: 68 additions & 27 deletions app/lib/methods/helpers/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
// @ts-nocheck - TEMP
import log from './log';
import { store as reduxStore } from '../../store/auxStore';
import database from '../../database';

export function isGroupChat(room): boolean {
import { type IRoom, type ISubscription, type TSubscriptionModel } from '../../../definitions';
import { type IUserMessage } from '../../../definitions/IMessage';

// Helper type for room-like objects that can be either IRoom or ISubscription
type TRoomLike = Pick<IRoom | ISubscription, 'uids' | 'usernames' | 'prid' | 'fname' | 'name'> & {
t?: string;
rid?: string;
federated?: boolean;
};

/**
* Determines if a room is a group chat (more than 2 participants)
*/
export function isGroupChat(room: Partial<TRoomLike> | undefined): boolean {
return ((room?.uids && room.uids.length > 2) || (room?.usernames && room.usernames.length > 2)) ?? false;
}

export function getRoomAvatar(room) {
if (isGroupChat(room) && room.uids && room.usernames) {
/**
* Gets the avatar identifier for a room
*/
export function getRoomAvatar(room: Partial<TRoomLike> | undefined): string | undefined {
if (isGroupChat(room) && room?.uids && room?.usernames) {
return room.uids.length + room.usernames.join();
}
return room.prid ? room.fname : room.name;
return room?.prid ? room.fname : room?.name;
}

export function getUidDirectMessage(room) {
/**
* Gets the UID of the other participant in a direct message
*/
export function getUidDirectMessage(room: (Partial<TRoomLike> & { itsMe?: boolean }) | null): string | undefined {
const { id: userId } = reduxStore.getState().login.user;

if (!room) {
return null;
return undefined;
}

if (room.itsMe) {
return userId;
return userId || undefined;
}

// legacy method
Expand All @@ -31,40 +48,49 @@ export function getUidDirectMessage(room) {
}

if (isGroupChat(room)) {
return null;
return undefined;
}

const me = room.uids?.find(uid => uid === userId);
const other = room.uids?.filter(uid => uid !== userId);

return other && other.length ? other[0] : me;
return (other && other.length ? other[0] : me) || undefined;
}

export function getRoomTitle(room) {
/**
* Gets the display title for a room
*/
export function getRoomTitle(room: Partial<TRoomLike> | undefined): string | undefined {
const { UI_Use_Real_Name: useRealName, UI_Allow_room_names_with_special_chars: allowSpecialChars } =
reduxStore.getState().settings;
const { username } = reduxStore.getState().login.user;
if ('federated' in room && room.federated === true) {
if (room && 'federated' in room && room.federated === true) {
return room.fname;
}
if (isGroupChat(room) && !(room.name && room.name.length) && room.usernames) {
if (isGroupChat(room) && !(room?.name && room.name.length) && room?.usernames) {
return room.usernames
.filter(u => u !== username)
.sort((u1, u2) => u1.localeCompare(u2))
.join(', ');
}
if (allowSpecialChars && room.t !== 'd') {
return room.fname || room.name;
if (allowSpecialChars && room?.t !== 'd') {
return room?.fname || room?.name;
}
return ((room?.prid || useRealName) && room?.fname) || room?.name;
}

export function getSenderName(sender) {
/**
* Gets the sender name based on settings (real name or username)
*/
export function getSenderName(sender: IUserMessage): string {
const { UI_Use_Real_Name: useRealName } = reduxStore.getState().settings;
return useRealName ? sender.name : sender.username;
return (useRealName ? sender.name : sender.username) || '';
}

export function canAutoTranslate() {
/**
* Checks if the current user can use auto-translate feature
*/
export function canAutoTranslate(): boolean {
try {
const { AutoTranslate_Enabled } = reduxStore.getState().settings;
if (!AutoTranslate_Enabled) {
Expand All @@ -79,28 +105,42 @@ export function canAutoTranslate() {
}
}

export function isRead(item) {
/**
* Checks if a subscription/room item is read
*/
export function isRead(item: Partial<ISubscription>): boolean {
let isUnread = item.archived !== true && item.open === true; // item is not archived and not opened
isUnread = isUnread && (item.unread > 0 || item.alert === true); // either its unread count > 0 or its alert
isUnread = isUnread && ((item.unread ?? 0) > 0 || item.alert === true); // either its unread count > 0 or its alert
return !isUnread;
}

export function hasRole(role): boolean {
/**
* Checks if the current user has a specific role
*/
export function hasRole(role: string): boolean {
const loginUser = reduxStore.getState().login.user;
const userRoles = loginUser?.roles || [];
return userRoles.indexOf(role) > -1;
}

export async function hasPermission(permissions, rid?: any): Promise<boolean[]> {
let roomRoles = [];
/**
* Checks if the current user has specific permissions in a room
* @param permissions Array of permission role arrays to check
* @param rid Optional room ID to check room-specific roles
* @returns Array of boolean values indicating if each permission is granted
*/
export async function hasPermission(permissions: Array<string[] | undefined>, rid?: string): Promise<(boolean | undefined)[]> {
let roomRoles: string[] = [];
if (rid) {
const db = database.active;
const subsCollection = db.get('subscriptions');
const subsCollection = db.get<TSubscriptionModel>('subscriptions');
try {
// get the room from database
const room = await subsCollection.find(rid);
// get room roles
roomRoles = room.roles || [];
if (room.roles) {
roomRoles = room.roles;
}
} catch (error) {
console.log('hasPermission -> Room not found');
return permissions.map(() => false);
Expand All @@ -111,8 +151,9 @@ export async function hasPermission(permissions, rid?: any): Promise<boolean[]>
const loginUser = reduxStore.getState().login.user;
const userRoles = loginUser?.roles || [];
const mergedRoles = [...new Set([...roomRoles, ...userRoles])];
return permissions.map(permission => permission?.some(r => mergedRoles.includes(r) ?? false));
return permissions.map(permission => permission?.some(r => mergedRoles.includes(r)));
} catch (e) {
log(e);
return permissions.map(() => false);
}
}
4 changes: 2 additions & 2 deletions app/views/AddExistingChannelView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const AddExistingChannelView = () => {
}
} catch (e: any) {
logEvent(events.CT_ADD_ROOM_TO_TEAM_F);
showErrorAlert(I18n.t(e.data.error), I18n.t('Add_Existing_Channel'), () => {});
showErrorAlert(I18n.t(e.data.error), I18n.t('Add_Existing_Channel'), () => { });
sendLoadingEvent({ visible: false });
}
};
Expand All @@ -162,7 +162,7 @@ const AddExistingChannelView = () => {
const icon = item.t === SubscriptionType.GROUP && !item?.teamId ? 'channel-private' : 'channel-public';
return (
<List.Item
title={getRoomTitle(item)}
title={getRoomTitle(item) || ''}
translateTitle={false}
onPress={() => toggleChannel(item.rid)}
testID={`add-existing-channel-view-item-${item.name}`}
Expand Down
4 changes: 2 additions & 2 deletions app/views/CreateDiscussionView/SelectChannel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const SelectChannel = ({
setChannels(res);
return res.map(channel => ({
value: channel,
text: { text: getRoomTitle(channel) },
text: { text: getRoomTitle(channel) || '' },
imageUrl: getAvatar(channel)
}));
} catch {
Expand Down Expand Up @@ -67,7 +67,7 @@ const SelectChannel = ({
value={initial && [initial]}
options={channels.map(channel => ({
value: channel,
text: { text: getRoomTitle(channel) },
text: { text: getRoomTitle(channel) || '' },
imageUrl: getAvatar(channel)
}))}
onClose={() => getChannels('')}
Expand Down
4 changes: 2 additions & 2 deletions app/views/CreateDiscussionView/SelectUsers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const SelectUsers = ({
setUsers(items);
return items.map((user: IUser) => ({
value: user.name,
text: { text: getRoomTitle(user) },
text: { text: getRoomTitle(user) || '' },
imageUrl: getAvatar(user)
}));
} catch {
Expand Down Expand Up @@ -66,7 +66,7 @@ const SelectUsers = ({
onChange={onUserSelect}
options={users.map((user: IUser) => ({
value: user.name,
text: { text: getRoomTitle(user) },
text: { text: getRoomTitle(user) || '' },
imageUrl: getAvatar(user)
}))}
placeholder={{ text: I18n.t('Select_Users') }}
Expand Down
4 changes: 2 additions & 2 deletions app/views/ForwardMessageView/SelectPersonOrChannel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const SelectPersonOrChannel = ({
setRooms(res);
return res.map(item => ({
value: item.rid,
text: { text: getRoomTitle(item) },
text: { text: getRoomTitle(item) || '' },
imageUrl: getAvatar(item)
}));
} catch {
Expand Down Expand Up @@ -62,7 +62,7 @@ const SelectPersonOrChannel = ({
onChange={onRoomSelect}
options={rooms.map(room => ({
value: room.rid,
text: { text: getRoomTitle(room) },
text: { text: getRoomTitle(room) || '' },
imageUrl: getAvatar(room)
}))}
placeholder={{ text: `${I18n.t('Select')}` }}
Expand Down
Loading