mattermost-mobile/app/utils/user/index.ts
Avinash Lingaloo 7f91a6a78a
Gekidou - Account Screen (#5708)
* Added DrawerItem component

* WIP Account Screen

* Added react-native-paper

* Added StatusLabel Component

* Extracted i18n

* TS fix DrawerItem component

* WIP Account Screen

* Added server name label under log out

* Updated translation

* WIP

* Fixes the Offline text style

* Added Metropolis fonts

* WIP

* Typo clean up

* WIP

* WIP

* WIP

* Added server display name

* Writing OpenSans properly

* WIP

* WIP

* Added OptionsModal

* Opening OptionsModal

* Added translation keys

* Writes status to local db

* Fix missing translation

* Fix OptionModal not dismissing

* Pushing status to server

* Refactored

* Added CustomStatusExpiry component

* Added sub components

* Added CustomLabel

* CustomStatus WIP

* Added Custom Status screen WIP

* WIP - unsetCustomStatus and CustomStatus constant

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Retrieving RecentCustomStatuses from Preferences table

* WIP

* WIP

* WIP

* Added Clear After Modal

* WIP - Transations

* WIP

* Done with showing modal cst

* wip

* Clear After Modal - DONE

* fix

* Added missing API calls

* wip

* Causing screen refresh

* wip

* WIP

* WIP

* WIP

* Code clean up

* Added OOO alert box

* Refactored Options-Item

* Refactored OptionsModalList component

* Opening 'status' in BottomSheet instead of OptionsModal

* AddReaction screen - WIP

* Add Reaction screen - WIP

* Added EmojiPickerRow

* Added @components/emoji_picker - WIP

* Emoji Picker - WIP

* WIP

* WIP

* WIP

* SectionList - WIP

* Installed react-native-section_list_get_item_layout

* Adding API calls - WIP

* WIP

* Search Bar component - WIP

* WIP

* WIP

* WIP

* Rendering Emoticons now - have to tackle some fixmes

* Code clean up

* Code clean up - WIP

* Code clean up

* WIP

* Major clean up

* wip

* WIP

* Fix rendering issue with SectionIcons and SearchBar

* Tackled the CustomEmojiPage

* Code clean up

* WIP

* Done with loading User Profiles for Custom Emoji

* Code clean up

* Code Clean up

* Fix screen Account

* Added missing sql file for IOS Pod

* Updated Podfile.lock

* Using queryConfig instead of queryCommonSystemValues

* Fix - Custom status

* Fix - Custom Status - Error

* Fix - Clear Pass Status - WIP

* Fix - Custom Status Clear

* Need to fix CST clear

* WIP

* Status clear - working

* Using catchError operator

* remove unnecessary prop

* Status  BottomSheet now has colored indicators

* Added KeyboardTrackingView from 'react-native-keyboard-tracking-view'

* Code clean up

* WIP

* code clean up

* Added a safety check

* Fix - Display suggestions

* Code clean up based on PR Review

* Code clean up

* Code clean up

* Code clean up

* Corrections

* Fix tsc

* TS fix

* Removed unnecessary prop

* Fix SearchBar Ts

* Updated tests

* Delete search_bar.test.js.snap

* Merge branch 'gekidou' into gekidou_account_screen

* Revert "Merge branch 'gekidou' into gekidou_account_screen"

This reverts commit 5defc313212478a55abf2f92cb4bd64dc7877342.

* Fix fonts

* Refactor home account screen

* fix theme provider

* refactor bottom sheet

* remove paper provider

* update drawer item snapshots

* Remove options modal screen

* remove react-native-ui-lib dependency

* Refactor & fix custom status & navigation (including tablet)

* Refactor emoji picker

Co-authored-by: Avinash Lingaloo <>
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2021-10-12 19:24:24 +04:00

240 lines
7.4 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import moment from 'moment-timezone';
import {Alert} from 'react-native';
import {General, Preferences} from '@constants';
import {CustomStatusDuration} from '@constants/custom_status';
import {UserModel} from '@database/models/server';
import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n';
import {toTitleCase} from '@utils/helpers';
import type GroupModel from '@typings/database/models/servers/group';
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
import type {UserMentionKey} from '@typings/global/markdown';
import type {IntlShape} from 'react-intl';
export function displayUsername(user?: UserProfile | UserModel, locale?: string, teammateDisplayNameSetting?: string, useFallbackUsername = true) {
let name = useFallbackUsername ? getLocalizedMessage(locale || DEFAULT_LOCALE, t('channel_loader.someone'), 'Someone') : '';
if (user) {
if (teammateDisplayNameSetting === Preferences.DISPLAY_PREFER_NICKNAME) {
name = user.nickname || getFullName(user);
} else if (teammateDisplayNameSetting === Preferences.DISPLAY_PREFER_FULL_NAME) {
name = getFullName(user);
} else {
name = user.username;
}
if (!name || name.trim().length === 0) {
name = user.username;
}
}
return name;
}
export function displayGroupMessageName(users: UserProfile[], locale?: string, teammateDisplayNameSetting?: string, excludeUserId?: string) {
const names: string[] = [];
const sortUsernames = (a: string, b: string) => {
return a.localeCompare(b, locale || DEFAULT_LOCALE, {numeric: true});
};
users.forEach((u) => {
if (u.id !== excludeUserId) {
names.push(displayUsername(u, locale, teammateDisplayNameSetting));
}
});
return names.sort(sortUsernames).join(', ');
}
export function getFullName(user: UserProfile | UserModel): string {
let firstName: string;
let lastName: string;
if (user instanceof UserModel) {
firstName = user.firstName;
lastName = user.lastName;
} else {
firstName = user.first_name;
lastName = user.last_name;
}
if (firstName && lastName) {
return `${firstName} ${lastName}`;
} else if (firstName) {
return firstName;
} else if (lastName) {
return lastName;
}
return '';
}
export function getUserIdFromChannelName(knownUserId: string, channelName: string): string {
const ids = channelName.split('__');
if (ids[0] === knownUserId) {
return ids[1];
}
return ids[0];
}
export function isRoleInRoles(roles: string, role: string): boolean {
const rolesArray = roles.split(' ');
return rolesArray.includes(role);
}
export function isGuest(roles: string): boolean {
return isRoleInRoles(roles, General.SYSTEM_GUEST_ROLE);
}
export function isSystemAdmin(roles: string): boolean {
return isRoleInRoles(roles, General.SYSTEM_ADMIN_ROLE);
}
export const getUsersByUsername = (users: UserModel[]) => {
const usersByUsername: Dictionary<UserModel> = {};
for (const user of users) {
usersByUsername[user.username] = user;
}
return usersByUsername;
};
export const getUserMentionKeys = (user: UserModel, groups: GroupModel[], userGroups: GroupMembershipModel[]) => {
const keys: UserMentionKey[] = [];
if (!user.notifyProps) {
return keys;
}
if (user.notifyProps.mention_keys) {
const mentions = user.notifyProps.mention_keys.split(',').map((key) => ({key}));
keys.push(...mentions);
}
if (user.notifyProps.first_name === 'true' && user.firstName) {
keys.push({key: user.firstName, caseSensitive: true});
}
if (user.notifyProps.channel === 'true') {
keys.push(
{key: '@channel'},
{key: '@all'},
{key: '@here'},
);
}
const usernameKey = `@${user.username}`;
if (keys.findIndex((item) => item.key === usernameKey) === -1) {
keys.push({key: usernameKey});
}
if (groups.length && userGroups.length) {
const groupMentions = userGroups.reduce((result: Array<{key: string}>, ug: GroupMembershipModel) => {
const group = groups.find((g) => ug.groupId === g.id);
if (group) {
result.push({key: `@${group.name}`});
}
return result;
}, []);
keys.push(...groupMentions);
}
return keys;
};
export const getUserTimezone = (user: UserModel) => {
return getTimezone(user.timezone);
};
export const getTimezone = (timezone: UserTimezone | null) => {
if (!timezone) {
return '';
}
const {useAutomaticTimezone} = timezone;
let useAutomatic = useAutomaticTimezone;
if (typeof useAutomaticTimezone === 'string') {
useAutomatic = useAutomaticTimezone === 'true';
}
if (useAutomatic) {
return timezone.automaticTimezone;
}
return timezone.manualTimezone;
};
export const getUserCustomStatus = (user: UserModel): UserCustomStatus | undefined => {
try {
if (typeof user.props?.customStatus === 'string') {
return JSON.parse(user.props.customStatus) as UserCustomStatus;
}
return user.props?.customStatus;
} catch {
return undefined;
}
};
export function isCustomStatusExpired(user: UserModel) {
const customStatus = getUserCustomStatus(user);
if (!customStatus) {
return true;
}
if (customStatus.duration === CustomStatusDuration.DONT_CLEAR || !customStatus.duration) {
return false;
}
const expiryTime = moment(customStatus.expires_at);
const timezone = getUserTimezone(user);
const currentTime = timezone ? moment.tz(timezone) : moment();
return currentTime.isSameOrAfter(expiryTime);
}
export function confirmOutOfOfficeDisabled(intl: IntlShape, status: string, updateStatus: (status: string) => void) {
const userStatusId = 'modal.manual_status.auto_responder.message_' + status;
t('modal.manual_status.auto_responder.message_');
t('modal.manual_status.auto_responder.message_away');
t('modal.manual_status.auto_responder.message_dnd');
t('modal.manual_status.auto_responder.message_offline');
t('modal.manual_status.auto_responder.message_online');
let translatedStatus;
if (status === 'dnd') {
translatedStatus = intl.formatMessage({
id: 'mobile.set_status.dnd',
defaultMessage: 'Do Not Disturb',
});
} else {
translatedStatus = intl.formatMessage({
id: `mobile.set_status.${status}`,
defaultMessage: toTitleCase(status),
});
}
Alert.alert(
intl.formatMessage({
id: 'mobile.reset_status.title_ooo',
defaultMessage: 'Disable "Out Of Office"?',
}),
intl.formatMessage({
id: userStatusId,
defaultMessage: 'Would you like to switch your status to "{status}" and disable Automatic Replies?',
}, {status: translatedStatus}),
[{
text: intl.formatMessage({id: 'mobile.reset_status.alert_cancel', defaultMessage: 'Cancel'}),
style: 'cancel',
}, {
text: intl.formatMessage({id: 'mobile.reset_status.alert_ok', defaultMessage: 'OK'}),
onPress: () => updateStatus(status),
}],
);
}