mattermost-mobile/app/screens/user_profile/user_profile.tsx
Daniel Espino García af0a7525c8
Refactor Open Profile (#8746)
* Refactor Open Profile

* Add missing changes

* Fix tests

* Fix tests

* Address feedback
2025-05-13 17:07:13 +02:00

232 lines
7.9 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import moment from 'moment';
import mtz from 'moment-timezone';
import React, {useEffect, useMemo} from 'react';
import {defineMessages, useIntl} from 'react-intl';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {fetchTeamAndChannelMembership} from '@actions/remote/user';
import {Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {getLocaleFromLanguage} from '@i18n';
import BottomSheet from '@screens/bottom_sheet';
import {bottomSheetSnapPoint} from '@utils/helpers';
import {getUserCustomStatus, getUserTimezone, isCustomStatusExpired} from '@utils/user';
import ManageUserOptions, {DIVIDER_MARGIN} from './manage_user_options';
import UserProfileOptions, {type OptionsType} from './options';
import UserProfileTitle, {HEADER_TEXT_HEIGHT} from './title';
import UserInfo from './user_info';
import type UserModel from '@typings/database/models/servers/user';
import type {AvailableScreens} from '@typings/screens/navigation';
type Props = {
canChangeMemberRoles: boolean;
channelId?: string;
closeButtonId: string;
currentUserId: string;
enablePostIconOverride: boolean;
enablePostUsernameOverride: boolean;
isChannelAdmin: boolean;
canManageAndRemoveMembers?: boolean;
isCustomStatusEnabled: boolean;
isDirectMessage: boolean;
isDefaultChannel: boolean;
isMilitaryTime: boolean;
isSystemAdmin: boolean;
isTeamAdmin: boolean;
manageMode?: boolean;
location?: AvailableScreens;
teamId: string;
teammateDisplayName: string;
user: UserModel;
userIconOverride?: string;
usernameOverride?: string;
hideGuestTags: boolean;
enableCustomAttributes: boolean;
}
const TITLE_HEIGHT = 118;
const OPTIONS_HEIGHT = 82;
const SINGLE_OPTION_HEIGHT = 68;
const LABEL_HEIGHT = 58;
const EXTRA_HEIGHT = 60;
const MANAGE_ICON_HEIGHT = 72;
const messages = defineMessages({
manageMember: {
id: 'mobile.manage_members.manage_member',
defaultMessage: 'Manage member',
},
});
const channelContextScreens: AvailableScreens[] = [Screens.CHANNEL, Screens.THREAD];
const UserProfile = ({
canChangeMemberRoles,
canManageAndRemoveMembers,
channelId,
closeButtonId,
currentUserId,
enablePostIconOverride,
enablePostUsernameOverride,
isChannelAdmin,
isCustomStatusEnabled,
isDefaultChannel,
isDirectMessage,
isMilitaryTime,
isSystemAdmin,
isTeamAdmin,
location,
manageMode = false,
teamId,
teammateDisplayName,
user,
userIconOverride,
usernameOverride,
hideGuestTags,
enableCustomAttributes,
}: Props) => {
const {formatMessage, locale} = useIntl();
const serverUrl = useServerUrl();
const channelContext = location ? channelContextScreens.includes(location) : false;
const showOptions: OptionsType = channelContext && !user.isBot ? 'all' : 'message';
const override = Boolean(userIconOverride || usernameOverride);
const {bottom} = useSafeAreaInsets();
const timezone = getUserTimezone(user);
const customStatus = getUserCustomStatus(user);
let localTime: string|undefined;
if (timezone) {
moment.locale(getLocaleFromLanguage(locale).toLowerCase());
let format = 'H:mm';
if (!isMilitaryTime) {
const localeFormat = moment.localeData().longDateFormat('LT');
format = localeFormat?.includes('A') ? localeFormat : 'h:mm A';
}
localTime = mtz.tz(Date.now(), timezone).format(format);
}
const showCustomStatus = isCustomStatusEnabled && Boolean(customStatus) && !user.isBot && !isCustomStatusExpired(user);
const showUserProfileOptions = (!isDirectMessage || !channelContext) && !override && !manageMode;
const showNickname = Boolean(user.nickname) && !override && !user.isBot && !manageMode;
const showPosition = Boolean(user.position) && !override && !user.isBot && !manageMode;
const showLocalTime = Boolean(localTime) && !override && !user.isBot && !manageMode;
const headerText = manageMode ? formatMessage(messages.manageMember) : undefined;
const snapPoints = useMemo(() => {
let title = TITLE_HEIGHT;
if (headerText) {
title += HEADER_TEXT_HEIGHT;
}
if (showUserProfileOptions) {
title += showOptions === 'all' ? OPTIONS_HEIGHT : SINGLE_OPTION_HEIGHT;
}
const optionsCount = [
showCustomStatus,
showNickname,
showPosition,
showLocalTime,
].reduce((acc, v) => {
return v ? acc + 1 : acc;
}, 0);
if (manageMode) {
title += DIVIDER_MARGIN * 2;
if (canChangeMemberRoles) {
title += SINGLE_OPTION_HEIGHT; // roles button
}
if (canManageAndRemoveMembers) {
title += SINGLE_OPTION_HEIGHT; // roles button
}
}
const extraHeight = manageMode ? 0 : (EXTRA_HEIGHT - bottom);
return [
1,
bottomSheetSnapPoint(optionsCount, LABEL_HEIGHT) + title + extraHeight,
'90%',
];
}, [
headerText, showUserProfileOptions, showCustomStatus,
showNickname, showPosition, showLocalTime,
manageMode, bottom, showOptions,
canChangeMemberRoles, canManageAndRemoveMembers,
enableCustomAttributes,
]);
useEffect(() => {
if (currentUserId !== user.id) {
fetchTeamAndChannelMembership(serverUrl, user.id, teamId, channelId);
}
}, []);
const renderContent = () => {
return (
<>
<UserProfileTitle
enablePostIconOverride={enablePostIconOverride}
enablePostUsernameOverride={enablePostUsernameOverride}
headerText={headerText}
imageSize={manageMode ? MANAGE_ICON_HEIGHT : undefined}
isChannelAdmin={isChannelAdmin}
isSystemAdmin={isSystemAdmin}
isTeamAdmin={isTeamAdmin}
teammateDisplayName={teammateDisplayName}
user={user}
userIconOverride={userIconOverride}
usernameOverride={usernameOverride}
hideGuestTags={hideGuestTags}
/>
{showUserProfileOptions &&
<UserProfileOptions
location={location}
type={showOptions}
username={user.username}
userId={user.id}
/>
}
{!manageMode && (
<UserInfo
localTime={localTime}
showCustomStatus={showCustomStatus}
showNickname={showNickname}
showPosition={showPosition}
showLocalTime={showLocalTime}
user={user}
enableCustomAttributes={enableCustomAttributes}
/>
)}
{manageMode && channelId && (canManageAndRemoveMembers || canChangeMemberRoles) &&
<ManageUserOptions
canChangeMemberRoles={canChangeMemberRoles}
channelId={channelId}
isDefaultChannel={isDefaultChannel}
isChannelAdmin={isChannelAdmin}
userId={user.id}
/>
}
</>
);
};
return (
<BottomSheet
renderContent={renderContent}
closeButtonId={closeButtonId}
componentId={Screens.USER_PROFILE}
initialSnapIndex={1}
snapPoints={snapPoints}
testID='user_profile'
/>
);
};
export default UserProfile;