Refactor Open Profile (#8746)
* Refactor Open Profile * Add missing changes * Fix tests * Fix tests * Address feedback
This commit is contained in:
parent
305fbee513
commit
af0a7525c8
89 changed files with 509 additions and 270 deletions
|
|
@ -23,6 +23,7 @@ import {secureGetFromRecord} from '@utils/types';
|
||||||
import {displayUsername} from '@utils/user';
|
import {displayUsername} from '@utils/user';
|
||||||
|
|
||||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Selection = DialogOption | Channel | UserProfile | DialogOption[] | Channel[] | UserProfile[];
|
type Selection = DialogOption | Channel | UserProfile | DialogOption[] | Channel[] | UserProfile[];
|
||||||
|
|
||||||
|
|
@ -43,6 +44,7 @@ type AutoCompleteSelectorProps = {
|
||||||
teammateNameDisplay: string;
|
teammateNameDisplay: string;
|
||||||
isMultiselect?: boolean;
|
isMultiselect?: boolean;
|
||||||
testID: string;
|
testID: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
|
|
@ -131,8 +133,22 @@ function getTextAndValueFromSelectedItem(item: Selection, teammateNameDisplay: s
|
||||||
}
|
}
|
||||||
|
|
||||||
function AutoCompleteSelector({
|
function AutoCompleteSelector({
|
||||||
dataSource, disabled = false, errorText, getDynamicOptions, helpText, label, onSelected, optional = false,
|
dataSource,
|
||||||
options, placeholder, roundedBorders = true, selected, teammateNameDisplay, isMultiselect = false, testID,
|
disabled = false,
|
||||||
|
errorText,
|
||||||
|
getDynamicOptions,
|
||||||
|
helpText,
|
||||||
|
label,
|
||||||
|
onSelected,
|
||||||
|
optional = false,
|
||||||
|
options,
|
||||||
|
placeholder,
|
||||||
|
roundedBorders = true,
|
||||||
|
selected,
|
||||||
|
teammateNameDisplay,
|
||||||
|
isMultiselect = false,
|
||||||
|
testID,
|
||||||
|
location,
|
||||||
}: AutoCompleteSelectorProps) {
|
}: AutoCompleteSelectorProps) {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
@ -221,6 +237,7 @@ function AutoCompleteSelector({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
errorText={errorText}
|
errorText={errorText}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,11 @@ import type ChannelModel from '@typings/database/models/servers/channel';
|
||||||
import type DraftModel from '@typings/database/models/servers/draft';
|
import type DraftModel from '@typings/database/models/servers/draft';
|
||||||
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channel: ChannelModel;
|
channel: ChannelModel;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
postReceiverUser?: UserModel;
|
postReceiverUser?: UserModel;
|
||||||
post: DraftModel | ScheduledPostModel;
|
post: DraftModel | ScheduledPostModel;
|
||||||
layoutWidth: number;
|
layoutWidth: number;
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,12 @@ import {typography} from '@utils/typography';
|
||||||
import type DraftModel from '@typings/database/models/servers/draft';
|
import type DraftModel from '@typings/database/models/servers/draft';
|
||||||
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
||||||
import type {UserMentionKey} from '@typings/global/markdown';
|
import type {UserMentionKey} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
post: DraftModel | ScheduledPostModel;
|
post: DraftModel | ScheduledPostModel;
|
||||||
layoutWidth: number;
|
layoutWidth: number;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EMPTY_MENTION_KEYS: UserMentionKey[] = [];
|
const EMPTY_MENTION_KEYS: UserMentionKey[] = [];
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,11 @@ import DraftAndScheduledPostMessage from './draft_and_scheduled_post_message';
|
||||||
|
|
||||||
import type DraftModel from '@typings/database/models/servers/draft';
|
import type DraftModel from '@typings/database/models/servers/draft';
|
||||||
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
post: DraftModel | ScheduledPostModel;
|
post: DraftModel | ScheduledPostModel;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
layoutWidth: number;
|
layoutWidth: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import {logWarning} from '@utils/log';
|
||||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||||
import {concatStyles, changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {concatStyles, changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
import type {PrimitiveType} from 'intl-messageformat';
|
import type {PrimitiveType} from 'intl-messageformat';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -21,7 +22,7 @@ type Props = {
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
defaultMessage: string;
|
defaultMessage: string;
|
||||||
id: string;
|
id: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
onPostPress?: (e: GestureResponderEvent) => void;
|
onPostPress?: (e: GestureResponderEvent) => void;
|
||||||
style?: StyleProp<TextStyle>;
|
style?: StyleProp<TextStyle>;
|
||||||
values?: Record<string, PrimitiveType>;
|
values?: Record<string, PrimitiveType>;
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,28 @@ import {useManagedConfig} from '@mattermost/react-native-emm';
|
||||||
import Clipboard from '@react-native-clipboard/clipboard';
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import React, {useCallback, useEffect, useMemo} from 'react';
|
import React, {useCallback, useEffect, useMemo} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {type GestureResponderEvent, Keyboard, type StyleProp, StyleSheet, Text, type TextStyle, View} from 'react-native';
|
import {type GestureResponderEvent, type StyleProp, StyleSheet, Text, type TextStyle, View} from 'react-native';
|
||||||
|
|
||||||
import {fetchUserOrGroupsByMentionsInBatch} from '@actions/remote/user';
|
import {fetchUserOrGroupsByMentionsInBatch} from '@actions/remote/user';
|
||||||
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
|
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
|
||||||
import {Screens} from '@constants';
|
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import GroupModel from '@database/models/server/group';
|
import GroupModel from '@database/models/server/group';
|
||||||
import {useMemoMentionedGroup, useMemoMentionedUser} from '@hooks/markdown';
|
import {useMemoMentionedGroup, useMemoMentionedUser} from '@hooks/markdown';
|
||||||
import {bottomSheet, dismissBottomSheet, openAsBottomSheet} from '@screens/navigation';
|
import {bottomSheet, dismissBottomSheet, openUserProfileModal} from '@screens/navigation';
|
||||||
import {bottomSheetSnapPoint} from '@utils/helpers';
|
import {bottomSheetSnapPoint} from '@utils/helpers';
|
||||||
import {displayUsername} from '@utils/user';
|
import {displayUsername} from '@utils/user';
|
||||||
|
|
||||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||||
import type UserModelType from '@typings/database/models/servers/user';
|
import type UserModelType from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type AtMentionProps = {
|
type AtMentionProps = {
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
currentUserId: string;
|
currentUserId: string;
|
||||||
disableAtChannelMentionHighlight?: boolean;
|
disableAtChannelMentionHighlight?: boolean;
|
||||||
isSearchResult?: boolean;
|
isSearchResult?: boolean;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
mentionKeys?: Array<{key: string }>;
|
mentionKeys?: Array<{key: string }>;
|
||||||
mentionName: string;
|
mentionName: string;
|
||||||
mentionStyle: StyleProp<TextStyle>;
|
mentionStyle: StyleProp<TextStyle>;
|
||||||
|
|
@ -95,13 +95,11 @@ const AtMention = ({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const screen = Screens.USER_PROFILE;
|
openUserProfileModal(intl, theme, {
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
location,
|
||||||
const closeButtonId = 'close-user-profile';
|
userId: user.id,
|
||||||
const props = {closeButtonId, location, userId: user.id, channelId};
|
channelId,
|
||||||
|
});
|
||||||
Keyboard.dismiss();
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLongPress = useCallback(() => {
|
const handleLongPress = useCallback(() => {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ describe('Markdown', () => {
|
||||||
baseTextStyle: {},
|
baseTextStyle: {},
|
||||||
enableInlineLatex: true,
|
enableInlineLatex: true,
|
||||||
enableLatex: true,
|
enableLatex: true,
|
||||||
location: 'somewhere?',
|
location: 'Channel',
|
||||||
maxNodes: 2000,
|
maxNodes: 2000,
|
||||||
theme: Preferences.THEMES.denim,
|
theme: Preferences.THEMES.denim,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import type {
|
||||||
MarkdownAtMentionRenderer, MarkdownBaseRenderer, MarkdownBlockStyles, MarkdownChannelMentionRenderer,
|
MarkdownAtMentionRenderer, MarkdownBaseRenderer, MarkdownBlockStyles, MarkdownChannelMentionRenderer,
|
||||||
MarkdownEmojiRenderer, MarkdownImageRenderer, MarkdownLatexRenderer, MarkdownTextStyles, SearchPattern, UserMentionKey, HighlightWithoutNotificationKey,
|
MarkdownEmojiRenderer, MarkdownImageRenderer, MarkdownLatexRenderer, MarkdownTextStyles, SearchPattern, UserMentionKey, HighlightWithoutNotificationKey,
|
||||||
} from '@typings/global/markdown';
|
} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type MarkdownProps = {
|
type MarkdownProps = {
|
||||||
autolinkedUrlSchemes?: string[];
|
autolinkedUrlSchemes?: string[];
|
||||||
|
|
@ -65,7 +66,7 @@ type MarkdownProps = {
|
||||||
isSearchResult?: boolean;
|
isSearchResult?: boolean;
|
||||||
layoutHeight?: number;
|
layoutHeight?: number;
|
||||||
layoutWidth?: number;
|
layoutWidth?: number;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
maxNodes: number;
|
maxNodes: number;
|
||||||
mentionKeys?: UserMentionKey[];
|
mentionKeys?: UserMentionKey[];
|
||||||
minimumHashtagLength?: number;
|
minimumHashtagLength?: number;
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,12 @@ import {popToRoot} from '@screens/navigation';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
testID?: string;
|
testID?: string;
|
||||||
deactivated?: boolean;
|
deactivated?: boolean;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
|
const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
|
||||||
|
|
@ -57,6 +60,7 @@ const edges: Edge[] = ['bottom'];
|
||||||
export default function Archived({
|
export default function Archived({
|
||||||
testID,
|
testID,
|
||||||
deactivated,
|
deactivated,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
|
|
@ -94,7 +98,7 @@ export default function Archived({
|
||||||
{...message}
|
{...message}
|
||||||
style={style.archivedText}
|
style={style.archivedText}
|
||||||
baseTextStyle={style.baseTextStyle}
|
baseTextStyle={style.baseTextStyle}
|
||||||
location=''
|
location={location}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
buttonStyle={style.closeButton}
|
buttonStyle={style.closeButton}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import Archived from './archived';
|
||||||
import DraftHandler from './draft_handler';
|
import DraftHandler from './draft_handler';
|
||||||
import ReadOnly from './read_only';
|
import ReadOnly from './read_only';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
const AUTOCOMPLETE_ADJUST = -5;
|
const AUTOCOMPLETE_ADJUST = -5;
|
||||||
type Props = {
|
type Props = {
|
||||||
testID?: string;
|
testID?: string;
|
||||||
|
|
@ -30,6 +32,7 @@ type Props = {
|
||||||
containerHeight: number;
|
containerHeight: number;
|
||||||
isChannelScreen: boolean;
|
isChannelScreen: boolean;
|
||||||
canShowPostPriority?: boolean;
|
canShowPostPriority?: boolean;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
function PostDraft({
|
function PostDraft({
|
||||||
|
|
@ -46,6 +49,7 @@ function PostDraft({
|
||||||
containerHeight,
|
containerHeight,
|
||||||
isChannelScreen,
|
isChannelScreen,
|
||||||
canShowPostPriority,
|
canShowPostPriority,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [value, setValue] = useState(message);
|
const [value, setValue] = useState(message);
|
||||||
const [cursorPosition, setCursorPosition] = useState(message.length);
|
const [cursorPosition, setCursorPosition] = useState(message.length);
|
||||||
|
|
@ -73,6 +77,7 @@ function PostDraft({
|
||||||
<Archived
|
<Archived
|
||||||
testID={archivedTestID}
|
testID={archivedTestID}
|
||||||
deactivated={deactivatedChannel}
|
deactivated={deactivatedChannel}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,13 @@ import {secureGetFromRecord} from '@utils/types';
|
||||||
import LastUsers from './last_users';
|
import LastUsers from './last_users';
|
||||||
import {postTypeMessages} from './messages';
|
import {postTypeMessages} from './messages';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
canDelete: boolean;
|
canDelete: boolean;
|
||||||
currentUserId?: string;
|
currentUserId?: string;
|
||||||
currentUsername?: string;
|
currentUsername?: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: Post | null;
|
post: Post | null;
|
||||||
showJoinLeave: boolean;
|
showJoinLeave: boolean;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@ import {secureGetFromRecord} from '@utils/types';
|
||||||
|
|
||||||
import {postTypeMessages, systemMessages} from './messages';
|
import {postTypeMessages, systemMessages} from './messages';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type LastUsersProps = {
|
type LastUsersProps = {
|
||||||
actor: string;
|
actor: string;
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
postType: string;
|
postType: string;
|
||||||
usernames: string[];
|
usernames: string[];
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,27 @@
|
||||||
import {Image} from 'expo-image';
|
import {Image} from 'expo-image';
|
||||||
import React, {type ReactNode} from 'react';
|
import React, {type ReactNode} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard, Platform, StyleSheet, TouchableOpacity, View} from 'react-native';
|
import {Platform, StyleSheet, TouchableOpacity, View} from 'react-native';
|
||||||
|
|
||||||
import {buildAbsoluteUrl} from '@actions/remote/file';
|
import {buildAbsoluteUrl} from '@actions/remote/file';
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
import ProfilePicture from '@components/profile_picture';
|
import ProfilePicture from '@components/profile_picture';
|
||||||
import {Screens, View as ViewConstant} from '@constants';
|
import {View as ViewConstant} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal} from '@screens/navigation';
|
||||||
import {preventDoubleTap} from '@utils/tap';
|
import {preventDoubleTap} from '@utils/tap';
|
||||||
import {ensureString} from '@utils/types';
|
import {ensureString} from '@utils/types';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type AvatarProps = {
|
type AvatarProps = {
|
||||||
author?: UserModel;
|
author?: UserModel;
|
||||||
enablePostIconOverride?: boolean;
|
enablePostIconOverride?: boolean;
|
||||||
isAutoReponse: boolean;
|
isAutoReponse: boolean;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,20 +92,13 @@ const Avatar = ({author, enablePostIconOverride, isAutoReponse, location, post}:
|
||||||
if (!author) {
|
if (!author) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const screen = Screens.USER_PROFILE;
|
openUserProfileModal(intl, theme, {
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
location,
|
||||||
const closeButtonId = 'close-user-profile';
|
|
||||||
const props = {
|
|
||||||
closeButtonId,
|
|
||||||
userId: author.id,
|
userId: author.id,
|
||||||
channelId: post.channelId,
|
channelId: post.channelId,
|
||||||
location,
|
|
||||||
userIconOverride: propsIconUrl,
|
userIconOverride: propsIconUrl,
|
||||||
usernameOverride: propsUsername,
|
usernameOverride: propsUsername,
|
||||||
};
|
});
|
||||||
|
|
||||||
Keyboard.dismiss();
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let component = (
|
let component = (
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,13 @@ import {USER_ROW_HEIGHT} from './users_list/user_list_item';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentUserId: UserModel['id'];
|
currentUserId: UserModel['id'];
|
||||||
currentUserTimezone: UserModel['timezone'];
|
currentUserTimezone: UserModel['timezone'];
|
||||||
hasReactions: boolean;
|
hasReactions: boolean;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,17 @@
|
||||||
|
|
||||||
import React, {useCallback} from 'react';
|
import React, {useCallback} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard} from 'react-native';
|
|
||||||
|
|
||||||
import FormattedRelativeTime from '@components/formatted_relative_time';
|
import FormattedRelativeTime from '@components/formatted_relative_time';
|
||||||
import UserItem from '@components/user_item';
|
import UserItem from '@components/user_item';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {dismissBottomSheet, openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal as openUserProfileBottomSheet} from '@screens/navigation';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
export const USER_ROW_HEIGHT = 60;
|
export const USER_ROW_HEIGHT = 60;
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
user: UserModel;
|
user: UserModel;
|
||||||
userAcknowledgement: number;
|
userAcknowledgement: number;
|
||||||
timezone?: UserTimezone;
|
timezone?: UserTimezone;
|
||||||
|
|
@ -53,14 +53,11 @@ const UserListItem = ({
|
||||||
|
|
||||||
const handleUserPress = useCallback(async (userProfile: UserProfile) => {
|
const handleUserPress = useCallback(async (userProfile: UserProfile) => {
|
||||||
if (userProfile) {
|
if (userProfile) {
|
||||||
await dismissBottomSheet(Screens.BOTTOM_SHEET);
|
await openUserProfileBottomSheet(intl, theme, {
|
||||||
const screen = Screens.USER_PROFILE;
|
userId: userProfile.id,
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
channelId,
|
||||||
const closeButtonId = 'close-user-profile';
|
location,
|
||||||
const props = {closeButtonId, location, userId: userProfile.id, channelId};
|
}, Screens.BOTTOM_SHEET);
|
||||||
|
|
||||||
Keyboard.dismiss();
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
|
||||||
}
|
}
|
||||||
}, [channelId, intl, location, theme]);
|
}, [channelId, intl, location, theme]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,12 @@ import {useIsTablet} from '@hooks/device';
|
||||||
import UserListItem from './user_list_item';
|
import UserListItem from './user_list_item';
|
||||||
|
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
import type {ListRenderItemInfo} from 'react-native';
|
import type {ListRenderItemInfo} from 'react-native';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
users: UserModel[];
|
users: UserModel[];
|
||||||
userAcknowledgements: Record<string, number>;
|
userAcknowledgements: Record<string, number>;
|
||||||
timezone?: UserTimezone;
|
timezone?: UserTimezone;
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,12 @@ import {isStringArray} from '@utils/types';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type AddMembersProps = {
|
type AddMembersProps = {
|
||||||
channelType: string | null;
|
channelType: string | null;
|
||||||
currentUser?: UserModel;
|
currentUser?: UserModel;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,11 @@ import {useShowMoreAnimatedStyle} from '@hooks/show_more';
|
||||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ import {View} from 'react-native';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,11 @@ import EmbedTitle from './embed_title';
|
||||||
import EmbedSubBindings from './embedded_sub_bindings';
|
import EmbedSubBindings from './embedded_sub_bindings';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
embed: AppBinding;
|
embed: AppBinding;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +73,7 @@ const EmbeddedBinding = ({embed, location, post, theme}: Props) => {
|
||||||
bindings={cleanedBindings}
|
bindings={cleanedBindings}
|
||||||
post={post}
|
post={post}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,21 @@ import ButtonBinding from './button_binding';
|
||||||
import BindingMenu from './menu_binding';
|
import BindingMenu from './menu_binding';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
bindings: AppBinding[];
|
bindings: AppBinding[];
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EmbeddedSubBindings = ({bindings, post, theme}: Props) => {
|
const EmbeddedSubBindings = ({
|
||||||
|
bindings,
|
||||||
|
post,
|
||||||
|
theme,
|
||||||
|
location,
|
||||||
|
}: Props) => {
|
||||||
const content: React.ReactNode[] = [];
|
const content: React.ReactNode[] = [];
|
||||||
|
|
||||||
bindings.forEach((binding) => {
|
bindings.forEach((binding) => {
|
||||||
|
|
@ -28,6 +35,7 @@ const EmbeddedSubBindings = ({bindings, post, theme}: Props) => {
|
||||||
key={binding.location}
|
key={binding.location}
|
||||||
binding={binding}
|
binding={binding}
|
||||||
post={post}
|
post={post}
|
||||||
|
location={location}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,10 @@ import {isArrayOf} from '@utils/types';
|
||||||
import EmbeddedBinding from './embedded_binding';
|
import EmbeddedBinding from './embedded_binding';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,23 @@ import {logDebug} from '@utils/log';
|
||||||
|
|
||||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
binding: AppBinding;
|
binding: AppBinding;
|
||||||
currentTeamId: string;
|
currentTeamId: string;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
teamID?: string;
|
teamID?: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuBinding = ({binding, currentTeamId, post, teamID}: Props) => {
|
const MenuBinding = ({
|
||||||
|
binding,
|
||||||
|
currentTeamId,
|
||||||
|
post,
|
||||||
|
teamID,
|
||||||
|
location,
|
||||||
|
}: Props) => {
|
||||||
const [selected, setSelected] = useState<string>();
|
const [selected, setSelected] = useState<string>();
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
|
|
||||||
|
|
@ -73,6 +81,7 @@ const MenuBinding = ({binding, currentTeamId, post, teamID}: Props) => {
|
||||||
selected={selected}
|
selected={selected}
|
||||||
onSelected={onSelect}
|
onSelected={onSelect}
|
||||||
testID={`embedded_binding.${binding.location}`}
|
testID={`embedded_binding.${binding.location}`}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,12 @@ import Opengraph from './opengraph';
|
||||||
import YouTube from './youtube';
|
import YouTube from './youtube';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type ContentProps = {
|
type ContentProps = {
|
||||||
isReplyPost: boolean;
|
isReplyPost: boolean;
|
||||||
layoutWidth?: number;
|
layoutWidth?: number;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import AutocompleteSelector from '@components/autocomplete_selector';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {filterOptions} from '@utils/message_attachment';
|
import {filterOptions} from '@utils/message_attachment';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
dataSource?: string;
|
dataSource?: string;
|
||||||
defaultOption?: string;
|
defaultOption?: string;
|
||||||
|
|
@ -16,9 +18,19 @@ type Props = {
|
||||||
name: string;
|
name: string;
|
||||||
options?: PostActionOption[];
|
options?: PostActionOption[];
|
||||||
postId: string;
|
postId: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActionMenu = ({dataSource, defaultOption, disabled, id, name, options, postId}: Props) => {
|
const ActionMenu = ({
|
||||||
|
dataSource,
|
||||||
|
defaultOption,
|
||||||
|
disabled,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
options,
|
||||||
|
postId,
|
||||||
|
location,
|
||||||
|
}: Props) => {
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
|
|
||||||
const filteredOptions = useMemo(() => {
|
const filteredOptions = useMemo(() => {
|
||||||
|
|
@ -53,6 +65,7 @@ const ActionMenu = ({dataSource, defaultOption, disabled, id, name, options, pos
|
||||||
onSelected={handleSelect}
|
onSelected={handleSelect}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
testID={`message_attachment.${name}`}
|
testID={`message_attachment.${name}`}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,20 @@ import React from 'react';
|
||||||
import ActionButton from './action_button';
|
import ActionButton from './action_button';
|
||||||
import ActionMenu from './action_menu';
|
import ActionMenu from './action_menu';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
actions: PostAction[];
|
actions: PostAction[];
|
||||||
postId: string;
|
postId: string;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
const AttachmentActions = ({actions, postId, theme}: Props) => {
|
const AttachmentActions = ({
|
||||||
|
actions,
|
||||||
|
postId,
|
||||||
|
theme,
|
||||||
|
location,
|
||||||
|
}: Props) => {
|
||||||
const content: React.ReactNode[] = [];
|
const content: React.ReactNode[] = [];
|
||||||
|
|
||||||
actions.forEach((action) => {
|
actions.forEach((action) => {
|
||||||
|
|
@ -31,6 +39,7 @@ const AttachmentActions = ({actions, postId, theme}: Props) => {
|
||||||
options={action.options}
|
options={action.options}
|
||||||
postId={postId}
|
postId={postId}
|
||||||
disabled={action.disabled}
|
disabled={action.disabled}
|
||||||
|
location={location}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,14 @@ import Markdown from '@components/markdown';
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
||||||
import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown';
|
import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
baseTextStyle: StyleProp<TextStyle>;
|
baseTextStyle: StyleProp<TextStyle>;
|
||||||
blockStyles?: MarkdownBlockStyles;
|
blockStyles?: MarkdownBlockStyles;
|
||||||
channelId: string;
|
channelId: string;
|
||||||
fields: MessageAttachmentField[];
|
fields: MessageAttachmentField[];
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
metadata?: PostMetadata | null;
|
metadata?: PostMetadata | null;
|
||||||
textStyles?: MarkdownTextStyles;
|
textStyles?: MarkdownTextStyles;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@ import {type StyleProp, StyleSheet, type TextStyle, View} from 'react-native';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
|
|
||||||
import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown';
|
import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
baseTextStyle: StyleProp<TextStyle>;
|
baseTextStyle: StyleProp<TextStyle>;
|
||||||
blockStyles?: MarkdownBlockStyles;
|
blockStyles?: MarkdownBlockStyles;
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
metadata?: PostMetadata | null;
|
metadata?: PostMetadata | null;
|
||||||
textStyles?: MarkdownTextStyles;
|
textStyles?: MarkdownTextStyles;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,14 @@ import ShowMoreButton from '@components/post_list/post/body/message/show_more_bu
|
||||||
import {useShowMoreAnimatedStyle} from '@hooks/show_more';
|
import {useShowMoreAnimatedStyle} from '@hooks/show_more';
|
||||||
|
|
||||||
import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown';
|
import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
baseTextStyle: StyleProp<TextStyle>;
|
baseTextStyle: StyleProp<TextStyle>;
|
||||||
blockStyles?: MarkdownBlockStyles;
|
blockStyles?: MarkdownBlockStyles;
|
||||||
channelId: string;
|
channelId: string;
|
||||||
hasThumbnail?: boolean;
|
hasThumbnail?: boolean;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
metadata?: PostMetadata | null;
|
metadata?: PostMetadata | null;
|
||||||
textStyles?: MarkdownTextStyles;
|
textStyles?: MarkdownTextStyles;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ import Markdown from '@components/markdown';
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {tryOpenURL} from '@utils/url';
|
import {tryOpenURL} from '@utils/url';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
link?: string;
|
link?: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ import {StyleSheet, View} from 'react-native';
|
||||||
|
|
||||||
import MessageAttachment from './message_attachment';
|
import MessageAttachment from './message_attachment';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
attachments: MessageAttachment[];
|
attachments: MessageAttachment[];
|
||||||
channelId: string;
|
channelId: string;
|
||||||
layoutWidth?: number;
|
layoutWidth?: number;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
metadata?: PostMetadata | undefined | null;
|
metadata?: PostMetadata | undefined | null;
|
||||||
postId: string;
|
postId: string;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {render} from '@testing-library/react-native';
|
import {render} from '@testing-library/react-native';
|
||||||
import React from 'react';
|
import React, {type ComponentProps} from 'react';
|
||||||
|
|
||||||
import Preferences from '@constants/preferences';
|
import Preferences from '@constants/preferences';
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ describe('MessageAttachment', () => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseProps = {
|
const baseProps: ComponentProps<typeof MessageAttachment> = {
|
||||||
attachment: {
|
attachment: {
|
||||||
id: 1,
|
id: 1,
|
||||||
text: 'This is the text of an attachment',
|
text: 'This is the text of an attachment',
|
||||||
|
|
@ -113,7 +113,7 @@ describe('MessageAttachment', () => {
|
||||||
},
|
},
|
||||||
channelId: 'channel-id',
|
channelId: 'channel-id',
|
||||||
postId: 'post-id',
|
postId: 'post-id',
|
||||||
location: 'CENTER',
|
location: 'Channel',
|
||||||
theme: Preferences.THEMES.denim,
|
theme: Preferences.THEMES.denim,
|
||||||
metadata: {
|
metadata: {
|
||||||
images: {
|
images: {
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ import AttachmentText from './attachment_text';
|
||||||
import AttachmentThumbnail from './attachment_thumbnail';
|
import AttachmentThumbnail from './attachment_thumbnail';
|
||||||
import AttachmentTitle from './attachment_title';
|
import AttachmentTitle from './attachment_title';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
attachment: MessageAttachment;
|
attachment: MessageAttachment;
|
||||||
channelId: string;
|
channelId: string;
|
||||||
layoutWidth?: number;
|
layoutWidth?: number;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
metadata?: PostMetadata | null;
|
metadata?: PostMetadata | null;
|
||||||
postId: string;
|
postId: string;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
@ -138,6 +140,7 @@ export default function MessageAttachment({attachment, channelId, layoutWidth, l
|
||||||
actions={attachment.actions!}
|
actions={attachment.actions!}
|
||||||
postId={postId}
|
postId={postId}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{attachment.image_url && Boolean(metadata?.images?.[attachment.image_url]) &&
|
{attachment.image_url && Boolean(metadata?.images?.[attachment.image_url]) &&
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import Reactions from './reactions';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type {SearchPattern} from '@typings/global/markdown';
|
import type {SearchPattern} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type BodyProps = {
|
type BodyProps = {
|
||||||
appsEnabled: boolean;
|
appsEnabled: boolean;
|
||||||
|
|
@ -36,7 +37,7 @@ type BodyProps = {
|
||||||
isPendingOrFailed: boolean;
|
isPendingOrFailed: boolean;
|
||||||
isPostAcknowledgementEnabled?: boolean;
|
isPostAcknowledgementEnabled?: boolean;
|
||||||
isPostAddChannelMember: boolean;
|
isPostAddChannelMember: boolean;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
searchPatterns?: SearchPattern[];
|
searchPatterns?: SearchPattern[];
|
||||||
showAddReaction?: boolean;
|
showAddReaction?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import ShowMoreButton from './show_more_button';
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
import type {HighlightWithoutNotificationKey, SearchPattern, UserMentionKey} from '@typings/global/markdown';
|
import type {HighlightWithoutNotificationKey, SearchPattern, UserMentionKey} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type MessageProps = {
|
type MessageProps = {
|
||||||
currentUser?: UserModel;
|
currentUser?: UserModel;
|
||||||
|
|
@ -27,7 +28,7 @@ type MessageProps = {
|
||||||
isPendingOrFailed: boolean;
|
isPendingOrFailed: boolean;
|
||||||
isReplyPost: boolean;
|
isReplyPost: boolean;
|
||||||
layoutWidth?: number;
|
layoutWidth?: number;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
searchPatterns?: SearchPattern[];
|
searchPatterns?: SearchPattern[];
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,11 @@ import {typography} from '@utils/typography';
|
||||||
|
|
||||||
import type ThreadModel from '@typings/database/models/servers/thread';
|
import type ThreadModel from '@typings/database/models/servers/thread';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
participants: UserModel[];
|
participants: UserModel[];
|
||||||
teamId?: string;
|
teamId?: string;
|
||||||
thread: ThreadModel;
|
thread: ThreadModel;
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,22 @@
|
||||||
|
|
||||||
import React, {useCallback} from 'react';
|
import React, {useCallback} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard, Text, TouchableOpacity, useWindowDimensions, View} from 'react-native';
|
import {Text, TouchableOpacity, useWindowDimensions, View} from 'react-native';
|
||||||
|
|
||||||
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
|
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import {Screens} from '@constants';
|
import {usePreventDoubleTap} from '@hooks/utils';
|
||||||
import {openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal} from '@screens/navigation';
|
||||||
import {preventDoubleTap} from '@utils/tap';
|
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type HeaderDisplayNameProps = {
|
type HeaderDisplayNameProps = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
commentCount: number;
|
commentCount: number;
|
||||||
displayName?: string;
|
displayName?: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
rootPostAuthor?: string;
|
rootPostAuthor?: string;
|
||||||
shouldRenderReplyButton?: boolean;
|
shouldRenderReplyButton?: boolean;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
|
@ -71,15 +72,15 @@ const HeaderDisplayName = ({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
|
|
||||||
const onPress = useCallback(preventDoubleTap(() => {
|
const onPress = usePreventDoubleTap(useCallback(() => {
|
||||||
const screen = Screens.USER_PROFILE;
|
openUserProfileModal(intl, theme, {
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
location,
|
||||||
const closeButtonId = 'close-user-profile';
|
userId,
|
||||||
const props = {closeButtonId, userId, channelId, location, userIconOverride, usernameOverride};
|
channelId,
|
||||||
|
userIconOverride,
|
||||||
Keyboard.dismiss();
|
usernameOverride,
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
});
|
||||||
}), [intl.locale, channelId, userIconOverride, userId, usernameOverride, theme]);
|
}, [intl, userId, channelId, location, userIconOverride, usernameOverride, theme]));
|
||||||
|
|
||||||
const calcNameWidth = () => {
|
const calcNameWidth = () => {
|
||||||
const isLandscape = dimensions.width > dimensions.height;
|
const isLandscape = dimensions.width > dimensions.height;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import HeaderTag from './tag';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type HeaderProps = {
|
type HeaderProps = {
|
||||||
author?: UserModel;
|
author?: UserModel;
|
||||||
|
|
@ -37,7 +38,7 @@ type HeaderProps = {
|
||||||
isPendingOrFailed: boolean;
|
isPendingOrFailed: boolean;
|
||||||
isSystemPost: boolean;
|
isSystemPost: boolean;
|
||||||
isWebHook: boolean;
|
isWebHook: boolean;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
rootPostAuthor?: UserModel;
|
rootPostAuthor?: UserModel;
|
||||||
showPostPriority: boolean;
|
showPostPriority: boolean;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type ThreadModel from '@typings/database/models/servers/thread';
|
import type ThreadModel from '@typings/database/models/servers/thread';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
import type {SearchPattern} from '@typings/global/markdown';
|
import type {SearchPattern} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type PostProps = {
|
type PostProps = {
|
||||||
appsEnabled: boolean;
|
appsEnabled: boolean;
|
||||||
|
|
@ -57,7 +58,7 @@ type PostProps = {
|
||||||
isLastReply?: boolean;
|
isLastReply?: boolean;
|
||||||
isPostAddChannelMember: boolean;
|
isPostAddChannelMember: boolean;
|
||||||
isPostPriorityEnabled: boolean;
|
isPostPriorityEnabled: boolean;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
rootId?: string;
|
rootId?: string;
|
||||||
previousPost?: PostModel;
|
previousPost?: PostModel;
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,12 @@ import {typography} from '@utils/typography';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
import type {PrimitiveType} from 'intl-messageformat';
|
import type {PrimitiveType} from 'intl-messageformat';
|
||||||
|
|
||||||
type SystemMessageProps = {
|
type SystemMessageProps = {
|
||||||
author?: UserModel;
|
author?: UserModel;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import ScrollToEndView from './scroll_to_end_view';
|
||||||
|
|
||||||
import type {PostListItem, PostListOtherItem, ViewableItemsChanged, ViewableItemsChangedListenerEvent} from '@typings/components/post_list';
|
import type {PostListItem, PostListOtherItem, ViewableItemsChanged, ViewableItemsChangedListenerEvent} from '@typings/components/post_list';
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appsEnabled: boolean;
|
appsEnabled: boolean;
|
||||||
|
|
@ -40,7 +41,7 @@ type Props = {
|
||||||
isCRTEnabled?: boolean;
|
isCRTEnabled?: boolean;
|
||||||
isPostAcknowledgementEnabled?: boolean;
|
isPostAcknowledgementEnabled?: boolean;
|
||||||
lastViewedAt: number;
|
lastViewedAt: number;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
nativeID: string;
|
nativeID: string;
|
||||||
onEndReached?: () => void;
|
onEndReached?: () => void;
|
||||||
posts: PostModel[];
|
posts: PostModel[];
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,14 @@ import ChannelInfo from './channel_info';
|
||||||
|
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type {SearchPattern} from '@typings/global/markdown';
|
import type {SearchPattern} from '@typings/global/markdown';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appsEnabled: boolean;
|
appsEnabled: boolean;
|
||||||
customEmojiNames: string[];
|
customEmojiNames: string[];
|
||||||
isCRTEnabled: boolean;
|
isCRTEnabled: boolean;
|
||||||
post: PostModel;
|
post: PostModel;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
searchPatterns?: SearchPattern[];
|
searchPatterns?: SearchPattern[];
|
||||||
skipSavedPostsHighlight?: boolean;
|
skipSavedPostsHighlight?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
import React, {type ComponentProps} from 'react';
|
import React, {type ComponentProps} from 'react';
|
||||||
|
|
||||||
|
import {Screens} from '@constants';
|
||||||
import {fireEvent, renderWithEverything} from '@test/intl-test-helper';
|
import {fireEvent, renderWithEverything} from '@test/intl-test-helper';
|
||||||
import TestHelper from '@test/test_helper';
|
import TestHelper from '@test/test_helper';
|
||||||
|
|
||||||
|
|
@ -38,6 +39,7 @@ function getBaseProps(): ComponentProps<typeof SectionNotice> {
|
||||||
loading: true,
|
loading: true,
|
||||||
},
|
},
|
||||||
onDismissClick: jest.fn(),
|
onDismissClick: jest.fn(),
|
||||||
|
location: Screens.SETTINGS_NOTIFICATION_PUSH,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import Markdown from '../markdown';
|
||||||
|
|
||||||
import SectionNoticeButton from './section_notice_button';
|
import SectionNoticeButton from './section_notice_button';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
|
|
@ -22,6 +24,7 @@ type Props = {
|
||||||
type?: 'info' | 'success' | 'danger' | 'welcome' | 'warning' | 'hint';
|
type?: 'info' | 'success' | 'danger' | 'welcome' | 'warning' | 'hint';
|
||||||
isDismissable?: boolean;
|
isDismissable?: boolean;
|
||||||
onDismissClick?: () => void;
|
onDismissClick?: () => void;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const iconByType = {
|
const iconByType = {
|
||||||
|
|
@ -150,6 +153,7 @@ const SectionNotice = ({
|
||||||
secondaryButton,
|
secondaryButton,
|
||||||
text,
|
text,
|
||||||
type = 'info',
|
type = 'info',
|
||||||
|
location,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const styles = getStyleFromTheme(theme);
|
const styles = getStyleFromTheme(theme);
|
||||||
|
|
@ -179,7 +183,7 @@ const SectionNotice = ({
|
||||||
{text && (
|
{text && (
|
||||||
<Markdown
|
<Markdown
|
||||||
theme={theme}
|
theme={theme}
|
||||||
location=''
|
location={location}
|
||||||
baseTextStyle={styles.baseText}
|
baseTextStyle={styles.baseText}
|
||||||
value={text}
|
value={text}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import {useServerUrl} from '@context/server';
|
||||||
import {debounce} from '@helpers/api/general';
|
import {debounce} from '@helpers/api/general';
|
||||||
import {filterProfilesMatchingTerm} from '@utils/user';
|
import {filterProfilesMatchingTerm} from '@utils/user';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentUserId: string;
|
currentUserId: string;
|
||||||
tutorialWatched: boolean;
|
tutorialWatched: boolean;
|
||||||
|
|
@ -19,6 +21,7 @@ type Props = {
|
||||||
searchFunction: (term: string) => Promise<UserProfile[]>;
|
searchFunction: (term: string) => Promise<UserProfile[]>;
|
||||||
createFilter: (exactMatches: UserProfile[], term: string) => ((p: UserProfile) => boolean);
|
createFilter: (exactMatches: UserProfile[], term: string) => ((p: UserProfile) => boolean);
|
||||||
testID: string;
|
testID: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ServerUserList({
|
export default function ServerUserList({
|
||||||
|
|
@ -31,6 +34,7 @@ export default function ServerUserList({
|
||||||
searchFunction,
|
searchFunction,
|
||||||
createFilter,
|
createFilter,
|
||||||
testID,
|
testID,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
|
|
||||||
|
|
@ -124,6 +128,7 @@ export default function ServerUserList({
|
||||||
testID={testID}
|
testID={testID}
|
||||||
tutorialWatched={tutorialWatched}
|
tutorialWatched={tutorialWatched}
|
||||||
includeUserMargin={true}
|
includeUserMargin={true}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import Footer from './footer';
|
import Footer from './footer';
|
||||||
import Label from './label';
|
import Label from './label';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
label?: string;
|
label?: string;
|
||||||
value?: boolean;
|
value?: boolean;
|
||||||
|
|
@ -21,6 +23,7 @@ type Props = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onChange: (value: boolean) => void;
|
onChange: (value: boolean) => void;
|
||||||
testID: string;
|
testID: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
|
|
@ -62,6 +65,7 @@ function BoolSetting({
|
||||||
disabled = false,
|
disabled = false,
|
||||||
onChange,
|
onChange,
|
||||||
testID,
|
testID,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
|
|
@ -98,6 +102,7 @@ function BoolSetting({
|
||||||
disabledText={disabledText}
|
disabledText={disabledText}
|
||||||
errorText={errorText}
|
errorText={errorText}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import {useTheme} from '@context/theme';
|
||||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
return {
|
return {
|
||||||
helpTextContainer: {
|
helpTextContainer: {
|
||||||
|
|
@ -35,12 +37,14 @@ type Props = {
|
||||||
disabledText?: string;
|
disabledText?: string;
|
||||||
helpText?: string;
|
helpText?: string;
|
||||||
errorText?: string;
|
errorText?: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
function Footer({
|
function Footer({
|
||||||
disabled,
|
disabled,
|
||||||
disabledText,
|
disabledText,
|
||||||
helpText,
|
helpText,
|
||||||
errorText,
|
errorText,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
|
|
@ -55,7 +59,7 @@ function Footer({
|
||||||
baseTextStyle={style.helpText}
|
baseTextStyle={style.helpText}
|
||||||
textStyles={textStyles}
|
textStyles={textStyles}
|
||||||
disableAtMentions={true}
|
disableAtMentions={true}
|
||||||
location=''
|
location={location}
|
||||||
blockStyles={blockStyles}
|
blockStyles={blockStyles}
|
||||||
value={disabledText}
|
value={disabledText}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
|
@ -69,7 +73,7 @@ function Footer({
|
||||||
textStyles={textStyles}
|
textStyles={textStyles}
|
||||||
blockStyles={blockStyles}
|
blockStyles={blockStyles}
|
||||||
disableAtMentions={true}
|
disableAtMentions={true}
|
||||||
location=''
|
location={location}
|
||||||
value={helpText}
|
value={helpText}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
|
|
@ -82,7 +86,7 @@ function Footer({
|
||||||
textStyles={textStyles}
|
textStyles={textStyles}
|
||||||
blockStyles={blockStyles}
|
blockStyles={blockStyles}
|
||||||
disableAtMentions={true}
|
disableAtMentions={true}
|
||||||
location=''
|
location={location}
|
||||||
value={errorText}
|
value={errorText}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import Label from '../label';
|
||||||
|
|
||||||
import RadioEntry from './radio_entry';
|
import RadioEntry from './radio_entry';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||||
return {
|
return {
|
||||||
items: {
|
items: {
|
||||||
|
|
@ -32,6 +34,7 @@ type Props = {
|
||||||
errorText?: string;
|
errorText?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
testID: string;
|
testID: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
function RadioSetting({
|
function RadioSetting({
|
||||||
label,
|
label,
|
||||||
|
|
@ -41,6 +44,7 @@ function RadioSetting({
|
||||||
errorText = '',
|
errorText = '',
|
||||||
testID,
|
testID,
|
||||||
value,
|
value,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
|
|
@ -80,6 +84,7 @@ function RadioSetting({
|
||||||
disabled={false}
|
disabled={false}
|
||||||
errorText={errorText}
|
errorText={errorText}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import {
|
||||||
import Footer from './footer';
|
import Footer from './footer';
|
||||||
import Label from './label';
|
import Label from './label';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||||
const input = {
|
const input = {
|
||||||
color: theme.centerChannelColor,
|
color: theme.centerChannelColor,
|
||||||
|
|
@ -60,6 +62,7 @@ type Props = {
|
||||||
keyboardType: KeyboardTypeOptions;
|
keyboardType: KeyboardTypeOptions;
|
||||||
secureTextEntry: boolean;
|
secureTextEntry: boolean;
|
||||||
testID: string;
|
testID: string;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
function TextSetting({
|
function TextSetting({
|
||||||
label,
|
label,
|
||||||
|
|
@ -76,6 +79,7 @@ function TextSetting({
|
||||||
keyboardType,
|
keyboardType,
|
||||||
secureTextEntry,
|
secureTextEntry,
|
||||||
testID,
|
testID,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
|
|
@ -123,6 +127,7 @@ function TextSetting({
|
||||||
disabledText={disabledText}
|
disabledText={disabledText}
|
||||||
errorText={errorText}
|
errorText={errorText}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
|
location={location}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,14 @@ import UserAvatar from './user_avatar';
|
||||||
import UsersList from './users_list';
|
import UsersList from './users_list';
|
||||||
|
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
const OVERFLOW_DISPLAY_LIMIT = 99;
|
const OVERFLOW_DISPLAY_LIMIT = 99;
|
||||||
const USER_ROW_HEIGHT = 40;
|
const USER_ROW_HEIGHT = 40;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
users: UserModel[];
|
users: UserModel[];
|
||||||
breakAt?: number;
|
breakAt?: number;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
|
|
|
||||||
|
|
@ -4,27 +4,28 @@
|
||||||
import {BottomSheetFlatList} from '@gorhom/bottom-sheet';
|
import {BottomSheetFlatList} from '@gorhom/bottom-sheet';
|
||||||
import React, {useCallback, useRef} from 'react';
|
import React, {useCallback, useRef} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard, type ListRenderItemInfo, type NativeScrollEvent, type NativeSyntheticEvent} from 'react-native';
|
import {type ListRenderItemInfo, type NativeScrollEvent, type NativeSyntheticEvent} from 'react-native';
|
||||||
import {FlatList} from 'react-native-gesture-handler';
|
import {FlatList} from 'react-native-gesture-handler';
|
||||||
|
|
||||||
import UserItem from '@components/user_item';
|
import UserItem from '@components/user_item';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {useBottomSheetListsFix} from '@hooks/bottom_sheet_lists_fix';
|
import {useBottomSheetListsFix} from '@hooks/bottom_sheet_lists_fix';
|
||||||
import {dismissBottomSheet, openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal} from '@screens/navigation';
|
||||||
|
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
type?: BottomSheetList;
|
type?: BottomSheetList;
|
||||||
users: UserModel[];
|
users: UserModel[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type ItemProps = {
|
type ItemProps = {
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
user: UserModel;
|
user: UserModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,14 +34,11 @@ const Item = ({channelId, location, user}: ItemProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const openUserProfile = useCallback(async (u: UserModel | UserProfile) => {
|
const openUserProfile = useCallback(async (u: UserModel | UserProfile) => {
|
||||||
await dismissBottomSheet(Screens.BOTTOM_SHEET);
|
openUserProfileModal(intl, theme, {
|
||||||
const screen = Screens.USER_PROFILE;
|
userId: u.id,
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
channelId,
|
||||||
const closeButtonId = 'close-user-profile';
|
location,
|
||||||
const props = {closeButtonId, location, userId: u.id, channelId};
|
}, Screens.BOTTOM_SHEET);
|
||||||
|
|
||||||
Keyboard.dismiss();
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
|
||||||
}, [location, channelId, theme, intl]);
|
}, [location, channelId, theme, intl]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -629,7 +629,7 @@ exports[`components/channel_list_row should show results and tutorial 1`] = `
|
||||||
keyboardShouldPersistTaps="always"
|
keyboardShouldPersistTaps="always"
|
||||||
maxToRenderPerBatch={16}
|
maxToRenderPerBatch={16}
|
||||||
onContentSizeChange={[Function]}
|
onContentSizeChange={[Function]}
|
||||||
onEndReached={[Function]}
|
onEndReached={[MockFunction]}
|
||||||
onLayout={[Function]}
|
onLayout={[Function]}
|
||||||
onMomentumScrollBegin={[Function]}
|
onMomentumScrollBegin={[Function]}
|
||||||
onMomentumScrollEnd={[Function]}
|
onMomentumScrollEnd={[Function]}
|
||||||
|
|
@ -949,7 +949,7 @@ exports[`components/channel_list_row should show results no tutorial 1`] = `
|
||||||
keyboardShouldPersistTaps="always"
|
keyboardShouldPersistTaps="always"
|
||||||
maxToRenderPerBatch={16}
|
maxToRenderPerBatch={16}
|
||||||
onContentSizeChange={[Function]}
|
onContentSizeChange={[Function]}
|
||||||
onEndReached={[Function]}
|
onEndReached={[MockFunction]}
|
||||||
onLayout={[Function]}
|
onLayout={[Function]}
|
||||||
onMomentumScrollBegin={[Function]}
|
onMomentumScrollBegin={[Function]}
|
||||||
onMomentumScrollEnd={[Function]}
|
onMomentumScrollEnd={[Function]}
|
||||||
|
|
@ -1307,7 +1307,7 @@ exports[`components/channel_list_row should show results no tutorial 2 users 1`]
|
||||||
keyboardShouldPersistTaps="always"
|
keyboardShouldPersistTaps="always"
|
||||||
maxToRenderPerBatch={16}
|
maxToRenderPerBatch={16}
|
||||||
onContentSizeChange={[Function]}
|
onContentSizeChange={[Function]}
|
||||||
onEndReached={[Function]}
|
onEndReached={[MockFunction]}
|
||||||
onLayout={[Function]}
|
onLayout={[Function]}
|
||||||
onMomentumScrollBegin={[Function]}
|
onMomentumScrollBegin={[Function]}
|
||||||
onMomentumScrollEnd={[Function]}
|
onMomentumScrollEnd={[Function]}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React, {type ComponentProps} from 'react';
|
||||||
import {Image} from 'react-native';
|
import {Image} from 'react-native';
|
||||||
|
|
||||||
|
import {Screens} from '@constants';
|
||||||
import {Ringtone} from '@constants/calls';
|
import {Ringtone} from '@constants/calls';
|
||||||
import {renderWithEverything} from '@test/intl-test-helper';
|
import {renderWithEverything} from '@test/intl-test-helper';
|
||||||
import TestHelper from '@test/test_helper';
|
import TestHelper from '@test/test_helper';
|
||||||
|
|
@ -108,24 +109,26 @@ describe('components/channel_list_row', () => {
|
||||||
Image.resolveAssetSource = originalResolveAssetSource;
|
Image.resolveAssetSource = originalResolveAssetSource;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getBaseProps(): ComponentProps<typeof UserList> {
|
||||||
|
return {
|
||||||
|
profiles: [],
|
||||||
|
testID: 'UserListRow',
|
||||||
|
currentUserId: '1',
|
||||||
|
handleSelectProfile: jest.fn(),
|
||||||
|
fetchMore: jest.fn(),
|
||||||
|
loading: true,
|
||||||
|
selectedIds: {},
|
||||||
|
showNoResults: true,
|
||||||
|
tutorialWatched: true,
|
||||||
|
term: 'some term',
|
||||||
|
location: Screens.CHANNEL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
it('should show no results', () => {
|
it('should show no results', () => {
|
||||||
|
const props = getBaseProps();
|
||||||
const wrapper = renderWithEverything(
|
const wrapper = renderWithEverything(
|
||||||
<UserList
|
<UserList {...props}/>,
|
||||||
profiles={[]}
|
|
||||||
testID='UserListRow'
|
|
||||||
currentUserId={'1'}
|
|
||||||
handleSelectProfile={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
fetchMore={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
loading={true}
|
|
||||||
selectedIds={{}}
|
|
||||||
term={'some term'}
|
|
||||||
showNoResults={true}
|
|
||||||
tutorialWatched={true}
|
|
||||||
/>,
|
|
||||||
{database},
|
{database},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -133,22 +136,12 @@ describe('components/channel_list_row', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show results no tutorial', () => {
|
it('should show results no tutorial', () => {
|
||||||
|
const props = getBaseProps();
|
||||||
|
props.profiles = [user];
|
||||||
|
props.term = '';
|
||||||
|
|
||||||
const wrapper = renderWithEverything(
|
const wrapper = renderWithEverything(
|
||||||
<UserList
|
<UserList {...props}/>,
|
||||||
profiles={[user]}
|
|
||||||
testID='UserListRow'
|
|
||||||
currentUserId={'1'}
|
|
||||||
handleSelectProfile={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
fetchMore={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
loading={true}
|
|
||||||
selectedIds={{}}
|
|
||||||
showNoResults={true}
|
|
||||||
tutorialWatched={true}
|
|
||||||
/>,
|
|
||||||
{database},
|
{database},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -156,22 +149,11 @@ describe('components/channel_list_row', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show results no tutorial 2 users', () => {
|
it('should show results no tutorial 2 users', () => {
|
||||||
|
const props = getBaseProps();
|
||||||
|
props.profiles = [user, user2];
|
||||||
|
props.term = '';
|
||||||
const wrapper = renderWithEverything(
|
const wrapper = renderWithEverything(
|
||||||
<UserList
|
<UserList {...props}/>,
|
||||||
profiles={[user, user2]}
|
|
||||||
testID='UserListRow'
|
|
||||||
currentUserId={'1'}
|
|
||||||
handleSelectProfile={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
fetchMore={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
loading={true}
|
|
||||||
selectedIds={{}}
|
|
||||||
showNoResults={true}
|
|
||||||
tutorialWatched={true}
|
|
||||||
/>,
|
|
||||||
{database},
|
{database},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -179,22 +161,13 @@ describe('components/channel_list_row', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show results and tutorial', () => {
|
it('should show results and tutorial', () => {
|
||||||
|
const props = getBaseProps();
|
||||||
|
props.profiles = [user];
|
||||||
|
props.showNoResults = false;
|
||||||
|
props.tutorialWatched = false;
|
||||||
|
props.term = '';
|
||||||
const wrapper = renderWithEverything(
|
const wrapper = renderWithEverything(
|
||||||
<UserList
|
<UserList {...props}/>,
|
||||||
profiles={[user]}
|
|
||||||
testID='UserListRow'
|
|
||||||
currentUserId={'1'}
|
|
||||||
handleSelectProfile={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
fetchMore={() => {
|
|
||||||
// noop
|
|
||||||
}}
|
|
||||||
loading={true}
|
|
||||||
selectedIds={{}}
|
|
||||||
showNoResults={false}
|
|
||||||
tutorialWatched={false}
|
|
||||||
/>,
|
|
||||||
{database},
|
{database},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ import {storeProfile} from '@actions/local/user';
|
||||||
import Loading from '@components/loading';
|
import Loading from '@components/loading';
|
||||||
import NoResultsWithTerm from '@components/no_results_with_term';
|
import NoResultsWithTerm from '@components/no_results_with_term';
|
||||||
import UserListRow from '@components/user_list_row';
|
import UserListRow from '@components/user_list_row';
|
||||||
import {General, Screens} from '@constants';
|
import {General} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {useKeyboardHeight} from '@hooks/device';
|
import {useKeyboardHeight} from '@hooks/device';
|
||||||
import {openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal} from '@screens/navigation';
|
||||||
import {
|
import {
|
||||||
changeOpacity,
|
changeOpacity,
|
||||||
makeStyleSheetFromTheme,
|
makeStyleSheetFromTheme,
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
import {typography} from '@utils/typography';
|
import {typography} from '@utils/typography';
|
||||||
|
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type UserProfileWithChannelAdmin = UserProfile & {scheme_admin?: boolean}
|
type UserProfileWithChannelAdmin = UserProfile & {scheme_admin?: boolean}
|
||||||
type RenderItemType = ListRenderItemInfo<UserProfileWithChannelAdmin> & {section?: SectionListData<UserProfileWithChannelAdmin>}
|
type RenderItemType = ListRenderItemInfo<UserProfileWithChannelAdmin> & {section?: SectionListData<UserProfileWithChannelAdmin>}
|
||||||
|
|
@ -183,6 +184,7 @@ type Props = {
|
||||||
term?: string;
|
term?: string;
|
||||||
tutorialWatched: boolean;
|
tutorialWatched: boolean;
|
||||||
includeUserMargin?: boolean;
|
includeUserMargin?: boolean;
|
||||||
|
location: AvailableScreens;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function UserList({
|
export default function UserList({
|
||||||
|
|
@ -200,6 +202,7 @@ export default function UserList({
|
||||||
testID,
|
testID,
|
||||||
tutorialWatched,
|
tutorialWatched,
|
||||||
includeUserMargin,
|
includeUserMargin,
|
||||||
|
location,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
@ -235,18 +238,11 @@ export default function UserList({
|
||||||
user = profile;
|
user = profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
const screen = Screens.USER_PROFILE;
|
openUserProfileModal(intl, theme, {
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
|
||||||
const closeButtonId = 'close-user-profile';
|
|
||||||
const props = {
|
|
||||||
closeButtonId,
|
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
location: Screens.USER_PROFILE,
|
location,
|
||||||
};
|
});
|
||||||
|
}, [intl, location, serverUrl, theme]);
|
||||||
Keyboard.dismiss();
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
|
||||||
}, [intl, serverUrl, theme]);
|
|
||||||
|
|
||||||
const renderItem = useCallback(({item, index, section}: RenderItemType) => {
|
const renderItem = useCallback(({item, index, section}: RenderItemType) => {
|
||||||
// The list will re-render when the selection changes because it's passed into the list as extraData
|
// The list will re-render when the selection changes because it's passed into the list as extraData
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ jest.mock('react-native-navigation', () => ({
|
||||||
pop: jest.fn(() => Promise.resolve({
|
pop: jest.fn(() => Promise.resolve({
|
||||||
catch: jest.fn(),
|
catch: jest.fn(),
|
||||||
})),
|
})),
|
||||||
|
setDefaultOptions: jest.fn(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import DatabaseManager from '@database/manager';
|
||||||
import NetworkManager from '@managers/network_manager';
|
import NetworkManager from '@managers/network_manager';
|
||||||
import {queryAllActiveServers} from '@queries/app/servers';
|
import {queryAllActiveServers} from '@queries/app/servers';
|
||||||
import {getCurrentUser} from '@queries/servers/user';
|
import {getCurrentUser} from '@queries/servers/user';
|
||||||
import {openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal, openAsBottomSheet} from '@screens/navigation';
|
||||||
|
|
||||||
import {useTryCallsFunction, usePermissionsChecker, useCallsAdjustment, useHostControlsAvailable, useHostMenus} from './hooks';
|
import {useTryCallsFunction, usePermissionsChecker, useCallsAdjustment, useHostControlsAvailable, useHostMenus} from './hooks';
|
||||||
|
|
||||||
|
|
@ -74,6 +74,7 @@ jest.mock('@queries/servers/user', () => ({
|
||||||
|
|
||||||
jest.mock('@screens/navigation', () => ({
|
jest.mock('@screens/navigation', () => ({
|
||||||
openAsBottomSheet: jest.fn(),
|
openAsBottomSheet: jest.fn(),
|
||||||
|
openUserProfileModal: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('Calls Hooks', () => {
|
describe('Calls Hooks', () => {
|
||||||
|
|
@ -267,9 +268,13 @@ describe('Calls Hooks', () => {
|
||||||
await result.current.onPress(mockSession)();
|
await result.current.onPress(mockSession)();
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(openAsBottomSheet).toHaveBeenCalledWith(expect.objectContaining({
|
expect(openUserProfileModal).toHaveBeenCalledWith(
|
||||||
screen: Screens.USER_PROFILE,
|
expect.any(Object),
|
||||||
}));
|
expect.any(Object),
|
||||||
|
expect.objectContaining({
|
||||||
|
userId: mockSession.userId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import {useAppState} from '@hooks/device';
|
||||||
import NetworkManager from '@managers/network_manager';
|
import NetworkManager from '@managers/network_manager';
|
||||||
import {queryAllActiveServers} from '@queries/app/servers';
|
import {queryAllActiveServers} from '@queries/app/servers';
|
||||||
import {getCurrentUser} from '@queries/servers/user';
|
import {getCurrentUser} from '@queries/servers/user';
|
||||||
import {openAsBottomSheet} from '@screens/navigation';
|
import {openAsBottomSheet, openUserProfileModal} from '@screens/navigation';
|
||||||
import {getFullErrorMessage} from '@utils/errors';
|
import {getFullErrorMessage} from '@utils/errors';
|
||||||
import {isSystemAdmin} from '@utils/user';
|
import {isSystemAdmin} from '@utils/user';
|
||||||
|
|
||||||
|
|
@ -211,12 +211,9 @@ export const useHostMenus = () => {
|
||||||
}, [intl, theme]);
|
}, [intl, theme]);
|
||||||
|
|
||||||
const openUserProfile = useCallback(async (session: CallSession) => {
|
const openUserProfile = useCallback(async (session: CallSession) => {
|
||||||
const screen = Screens.USER_PROFILE;
|
openUserProfileModal(intl, theme, {
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
userId: session.userId,
|
||||||
const closeUserProfile = 'close-user-profile';
|
});
|
||||||
const props = {closeButtonId: closeUserProfile, location: '', userId: session.userId};
|
|
||||||
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId: closeUserProfile, props});
|
|
||||||
}, [intl, theme]);
|
}, [intl, theme]);
|
||||||
|
|
||||||
const onPress = useCallback((session: CallSession) => () => {
|
const onPress = useCallback((session: CallSession) => () => {
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ jest.mock('react-native-navigation', () => ({
|
||||||
pop: jest.fn(() => Promise.resolve({
|
pop: jest.fn(() => Promise.resolve({
|
||||||
catch: jest.fn(),
|
catch: jest.fn(),
|
||||||
})),
|
})),
|
||||||
|
setDefaultOptions: jest.fn(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import {SafeAreaView} from 'react-native-safe-area-context';
|
||||||
import {handleGotoLocation} from '@actions/remote/command';
|
import {handleGotoLocation} from '@actions/remote/command';
|
||||||
import CompassIcon from '@components/compass_icon';
|
import CompassIcon from '@components/compass_icon';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
|
import {Screens} from '@constants';
|
||||||
import {AppCallResponseTypes} from '@constants/apps';
|
import {AppCallResponseTypes} from '@constants/apps';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
|
|
@ -401,7 +402,7 @@ function AppsFormComponent({
|
||||||
baseTextStyle={style.errorLabel}
|
baseTextStyle={style.errorLabel}
|
||||||
textStyles={getMarkdownTextStyles(theme)}
|
textStyles={getMarkdownTextStyles(theme)}
|
||||||
blockStyles={getMarkdownBlockStyles(theme)}
|
blockStyles={getMarkdownBlockStyles(theme)}
|
||||||
location=''
|
location={Screens.APPS_FORM}
|
||||||
disableAtMentions={true}
|
disableAtMentions={true}
|
||||||
value={error}
|
value={error}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import AutocompleteSelector from '@components/autocomplete_selector';
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
import BoolSetting from '@components/settings/bool_setting';
|
import BoolSetting from '@components/settings/bool_setting';
|
||||||
import TextSetting from '@components/settings/text_setting';
|
import TextSetting from '@components/settings/text_setting';
|
||||||
import {View as ViewConstants} from '@constants';
|
import {Screens, View as ViewConstants} from '@constants';
|
||||||
import {AppFieldTypes, SelectableAppFieldTypes} from '@constants/apps';
|
import {AppFieldTypes, SelectableAppFieldTypes} from '@constants/apps';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {selectKeyboardType} from '@utils/integrations';
|
import {selectKeyboardType} from '@utils/integrations';
|
||||||
|
|
@ -161,6 +161,7 @@ function AppsFormField({
|
||||||
secureTextEntry={field.subtype === 'password'}
|
secureTextEntry={field.subtype === 'password'}
|
||||||
disabled={Boolean(field.readonly)}
|
disabled={Boolean(field.readonly)}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
|
location={Screens.APPS_FORM}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -185,6 +186,7 @@ function AppsFormField({
|
||||||
disabled={field.readonly}
|
disabled={field.readonly}
|
||||||
isMultiselect={field.multiselect}
|
isMultiselect={field.multiselect}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
|
location={Screens.APPS_FORM}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -200,6 +202,7 @@ function AppsFormField({
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
disabled={field.readonly}
|
disabled={field.readonly}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
|
location={Screens.APPS_FORM}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +219,7 @@ function AppsFormField({
|
||||||
value={field.description}
|
value={field.description}
|
||||||
mentionKeys={[]}
|
mentionKeys={[]}
|
||||||
disableAtMentions={true}
|
disableAtMentions={true}
|
||||||
location=''
|
location={Screens.APPS_FORM}
|
||||||
blockStyles={getMarkdownBlockStyles(theme)}
|
blockStyles={getMarkdownBlockStyles(theme)}
|
||||||
textStyles={getMarkdownTextStyles(theme)}
|
textStyles={getMarkdownTextStyles(theme)}
|
||||||
baseTextStyle={style.markdownFieldText}
|
baseTextStyle={style.markdownFieldText}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import FloatingCallContainer from '@calls/components/floating_call_container';
|
||||||
import FreezeScreen from '@components/freeze_screen';
|
import FreezeScreen from '@components/freeze_screen';
|
||||||
import PostDraft from '@components/post_draft';
|
import PostDraft from '@components/post_draft';
|
||||||
import ScheduledPostIndicator from '@components/scheduled_post_indicator';
|
import ScheduledPostIndicator from '@components/scheduled_post_indicator';
|
||||||
|
import {Screens} from '@constants';
|
||||||
import {ExtraKeyboardProvider} from '@context/extra_keyboard';
|
import {ExtraKeyboardProvider} from '@context/extra_keyboard';
|
||||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||||
import {useChannelSwitch} from '@hooks/channel_switch';
|
import {useChannelSwitch} from '@hooks/channel_switch';
|
||||||
|
|
@ -152,6 +153,7 @@ const Channel = ({
|
||||||
containerHeight={containerHeight}
|
containerHeight={containerHeight}
|
||||||
isChannelScreen={true}
|
isChannelScreen={true}
|
||||||
canShowPostPriority={true}
|
canShowPostPriority={true}
|
||||||
|
location={Screens.CHANNEL}
|
||||||
/>
|
/>
|
||||||
</ExtraKeyboardProvider>
|
</ExtraKeyboardProvider>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
|
|
||||||
import React, {useCallback} from 'react';
|
import React, {useCallback} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard, type StyleProp, StyleSheet, type ViewStyle} from 'react-native';
|
import {type StyleProp, StyleSheet, type ViewStyle} from 'react-native';
|
||||||
|
|
||||||
import ProfilePicture from '@components/profile_picture';
|
import ProfilePicture from '@components/profile_picture';
|
||||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
import {openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal} from '@screens/navigation';
|
||||||
|
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
|
||||||
|
|
@ -32,13 +32,11 @@ const styles = StyleSheet.create({
|
||||||
const Member = ({channelId, containerStyle, size = 72, showStatus = true, theme, user}: Props) => {
|
const Member = ({channelId, containerStyle, size = 72, showStatus = true, theme, user}: Props) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const onPress = useCallback(() => {
|
const onPress = useCallback(() => {
|
||||||
const screen = Screens.USER_PROFILE;
|
openUserProfileModal(intl, theme, {
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
userId: user.id,
|
||||||
const closeButtonId = 'close-user-profile';
|
channelId,
|
||||||
const props = {closeButtonId, userId: user.id, channelId, location: Screens.CHANNEL};
|
location: Screens.CHANNEL,
|
||||||
|
});
|
||||||
Keyboard.dismiss();
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
|
||||||
}, [intl, user.id, channelId, theme]);
|
}, [intl, user.id, channelId, theme]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import Loading from '@components/loading';
|
||||||
import Search from '@components/search';
|
import Search from '@components/search';
|
||||||
import SelectedUsers from '@components/selected_users';
|
import SelectedUsers from '@components/selected_users';
|
||||||
import ServerUserList from '@components/server_user_list';
|
import ServerUserList from '@components/server_user_list';
|
||||||
import {General} from '@constants';
|
import {General, Screens} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||||
|
|
@ -281,6 +281,7 @@ export default function ChannelAddMembers({
|
||||||
fetchFunction={userFetchFunction}
|
fetchFunction={userFetchFunction}
|
||||||
searchFunction={userSearchFunction}
|
searchFunction={userSearchFunction}
|
||||||
createFilter={createUserFilter}
|
createFilter={createUserFilter}
|
||||||
|
location={Screens.CHANNEL_ADD_MEMBERS}
|
||||||
/>
|
/>
|
||||||
<SelectedUsers
|
<SelectedUsers
|
||||||
keyboardOverlap={keyboardOverlap}
|
keyboardOverlap={keyboardOverlap}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import React, {useCallback, useMemo, useState} from 'react';
|
||||||
import AutocompleteSelector from '@components/autocomplete_selector';
|
import AutocompleteSelector from '@components/autocomplete_selector';
|
||||||
import BoolSetting from '@components/settings/bool_setting';
|
import BoolSetting from '@components/settings/bool_setting';
|
||||||
import TextSetting from '@components/settings/text_setting';
|
import TextSetting from '@components/settings/text_setting';
|
||||||
|
import {Screens} from '@constants';
|
||||||
|
|
||||||
type HookResult<T> = [
|
type HookResult<T> = [
|
||||||
{[x: string]: T},
|
{[x: string]: T},
|
||||||
|
|
@ -28,6 +29,7 @@ export const useStringProp = (
|
||||||
secureTextEntry={false}
|
secureTextEntry={false}
|
||||||
testID={`${propName}.input`}
|
testID={`${propName}.input`}
|
||||||
value={value}
|
value={value}
|
||||||
|
location={Screens.COMPONENT_LIBRARY}
|
||||||
/>
|
/>
|
||||||
), [value, propName, isTextarea]);
|
), [value, propName, isTextarea]);
|
||||||
const preparedProp = useMemo(() => ({[propName]: value}), [propName, value]);
|
const preparedProp = useMemo(() => ({[propName]: value}), [propName, value]);
|
||||||
|
|
@ -46,6 +48,7 @@ export const useBooleanProp = (
|
||||||
testID={`${propName}.input`}
|
testID={`${propName}.input`}
|
||||||
value={value}
|
value={value}
|
||||||
label={propName}
|
label={propName}
|
||||||
|
location={Screens.COMPONENT_LIBRARY}
|
||||||
/>
|
/>
|
||||||
), [propName, value]);
|
), [propName, value]);
|
||||||
const preparedProp = useMemo(() => ({[propName]: value}), [propName, value]);
|
const preparedProp = useMemo(() => ({[propName]: value}), [propName, value]);
|
||||||
|
|
@ -99,6 +102,7 @@ export const useDropdownProp = (
|
||||||
onSelected={onChange}
|
onSelected={onChange}
|
||||||
options={renderedOptions}
|
options={renderedOptions}
|
||||||
selected={value}
|
selected={value}
|
||||||
|
location={Screens.COMPONENT_LIBRARY}
|
||||||
/>
|
/>
|
||||||
), [onChange, propName, renderedOptions, value]);
|
), [onChange, propName, renderedOptions, value]);
|
||||||
const preparedProp = useMemo(() => (value === ALL_OPTION ? undefined : ({[propName]: value})), [propName, value]);
|
const preparedProp = useMemo(() => (value === ALL_OPTION ? undefined : ({[propName]: value})), [propName, value]);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import React, {useCallback, useMemo, useState} from 'react';
|
||||||
import {ScrollView, View, type StyleProp, type ViewStyle} from 'react-native';
|
import {ScrollView, View, type StyleProp, type ViewStyle} from 'react-native';
|
||||||
|
|
||||||
import AutocompleteSelector from '@components/autocomplete_selector';
|
import AutocompleteSelector from '@components/autocomplete_selector';
|
||||||
import {Preferences} from '@constants';
|
import {Preferences, Screens} from '@constants';
|
||||||
import {CustomThemeProvider} from '@context/theme';
|
import {CustomThemeProvider} from '@context/theme';
|
||||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||||
import SecurityManager from '@managers/security_manager';
|
import SecurityManager from '@managers/security_manager';
|
||||||
|
|
@ -122,6 +122,7 @@ const ComponentLibrary = ({componentId}: Props) => {
|
||||||
onSelected={onSelectComponent}
|
onSelected={onSelectComponent}
|
||||||
selected={selectedComponent}
|
selected={selectedComponent}
|
||||||
options={componentOptions}
|
options={componentOptions}
|
||||||
|
location={Screens.COMPONENT_LIBRARY}
|
||||||
/>
|
/>
|
||||||
<AutocompleteSelector
|
<AutocompleteSelector
|
||||||
testID='selectedTheme'
|
testID='selectedTheme'
|
||||||
|
|
@ -129,6 +130,7 @@ const ComponentLibrary = ({componentId}: Props) => {
|
||||||
onSelected={onSelectTheme}
|
onSelected={onSelectTheme}
|
||||||
selected={selectedTheme}
|
selected={selectedTheme}
|
||||||
options={themeOptions}
|
options={themeOptions}
|
||||||
|
location={Screens.COMPONENT_LIBRARY}
|
||||||
/>
|
/>
|
||||||
<AutocompleteSelector
|
<AutocompleteSelector
|
||||||
testID='selectedBackground'
|
testID='selectedBackground'
|
||||||
|
|
@ -136,6 +138,7 @@ const ComponentLibrary = ({componentId}: Props) => {
|
||||||
onSelected={onSelectBackground}
|
onSelected={onSelectBackground}
|
||||||
selected={selectedBackground}
|
selected={selectedBackground}
|
||||||
options={backgroundOptions}
|
options={backgroundOptions}
|
||||||
|
location={Screens.COMPONENT_LIBRARY}
|
||||||
/>
|
/>
|
||||||
<View style={backgroundStyle}>
|
<View style={backgroundStyle}>
|
||||||
<CustomThemeProvider theme={Preferences.THEMES[selectedTheme]}>
|
<CustomThemeProvider theme={Preferences.THEMES[selectedTheme]}>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import Loading from '@components/loading';
|
||||||
import Search from '@components/search';
|
import Search from '@components/search';
|
||||||
import SelectedUsers from '@components/selected_users';
|
import SelectedUsers from '@components/selected_users';
|
||||||
import ServerUserList from '@components/server_user_list';
|
import ServerUserList from '@components/server_user_list';
|
||||||
import {General} from '@constants';
|
import {General, Screens} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||||
|
|
@ -326,6 +326,7 @@ export default function CreateDirectMessage({
|
||||||
fetchFunction={userFetchFunction}
|
fetchFunction={userFetchFunction}
|
||||||
searchFunction={userSearchFunction}
|
searchFunction={userSearchFunction}
|
||||||
createFilter={createUserFilter}
|
createFilter={createUserFilter}
|
||||||
|
location={Screens.CREATE_DIRECT_MESSAGE}
|
||||||
/>
|
/>
|
||||||
<SelectedUsers
|
<SelectedUsers
|
||||||
keyboardOverlap={keyboardOverlap}
|
keyboardOverlap={keyboardOverlap}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {fireEvent, waitFor} from '@testing-library/react-native';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {DeviceEventEmitter} from 'react-native';
|
import {DeviceEventEmitter} from 'react-native';
|
||||||
|
|
||||||
import {Events} from '@constants';
|
import {Events, Screens} from '@constants';
|
||||||
import {renderWithIntl} from '@test/intl-test-helper';
|
import {renderWithIntl} from '@test/intl-test-helper';
|
||||||
import * as DraftUtils from '@utils/draft';
|
import * as DraftUtils from '@utils/draft';
|
||||||
import * as ScheduledPostUtils from '@utils/scheduled_post';
|
import * as ScheduledPostUtils from '@utils/scheduled_post';
|
||||||
|
|
@ -65,7 +65,7 @@ describe('DraftAndScheduledPostSwipeActions', () => {
|
||||||
<DraftAndScheduledPostSwipeActions
|
<DraftAndScheduledPostSwipeActions
|
||||||
draftType={DRAFT_TYPE_DRAFT}
|
draftType={DRAFT_TYPE_DRAFT}
|
||||||
item={mockDraft}
|
item={mockDraft}
|
||||||
location='global_drafts'
|
location={Screens.GLOBAL_DRAFTS}
|
||||||
layoutWidth={300}
|
layoutWidth={300}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
@ -79,7 +79,7 @@ describe('DraftAndScheduledPostSwipeActions', () => {
|
||||||
<DraftAndScheduledPostSwipeActions
|
<DraftAndScheduledPostSwipeActions
|
||||||
draftType={DRAFT_TYPE_SCHEDULED}
|
draftType={DRAFT_TYPE_SCHEDULED}
|
||||||
item={mockScheduledPost}
|
item={mockScheduledPost}
|
||||||
location='global_drafts'
|
location={Screens.GLOBAL_DRAFTS}
|
||||||
layoutWidth={300}
|
layoutWidth={300}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
@ -95,7 +95,7 @@ describe('DraftAndScheduledPostSwipeActions', () => {
|
||||||
<DraftAndScheduledPostSwipeActions
|
<DraftAndScheduledPostSwipeActions
|
||||||
draftType={DRAFT_TYPE_DRAFT}
|
draftType={DRAFT_TYPE_DRAFT}
|
||||||
item={mockDraft}
|
item={mockDraft}
|
||||||
location='global_drafts'
|
location={Screens.GLOBAL_DRAFTS}
|
||||||
layoutWidth={300}
|
layoutWidth={300}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
@ -110,7 +110,7 @@ describe('DraftAndScheduledPostSwipeActions', () => {
|
||||||
<DraftAndScheduledPostSwipeActions
|
<DraftAndScheduledPostSwipeActions
|
||||||
draftType={DRAFT_TYPE_DRAFT}
|
draftType={DRAFT_TYPE_DRAFT}
|
||||||
item={mockDraft}
|
item={mockDraft}
|
||||||
location='global_drafts'
|
location={Screens.GLOBAL_DRAFTS}
|
||||||
layoutWidth={300}
|
layoutWidth={300}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
@ -134,7 +134,7 @@ describe('DraftAndScheduledPostSwipeActions', () => {
|
||||||
<DraftAndScheduledPostSwipeActions
|
<DraftAndScheduledPostSwipeActions
|
||||||
draftType={DRAFT_TYPE_SCHEDULED}
|
draftType={DRAFT_TYPE_SCHEDULED}
|
||||||
item={mockScheduledPost}
|
item={mockScheduledPost}
|
||||||
location='global_drafts'
|
location={Screens.GLOBAL_DRAFTS}
|
||||||
layoutWidth={300}
|
layoutWidth={300}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,12 @@ import {typography} from '@utils/typography';
|
||||||
|
|
||||||
import type DraftModel from '@typings/database/models/servers/draft';
|
import type DraftModel from '@typings/database/models/servers/draft';
|
||||||
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
draftType: DraftType;
|
draftType: DraftType;
|
||||||
item: DraftModel | ScheduledPostModel;
|
item: DraftModel | ScheduledPostModel;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
layoutWidth: number;
|
layoutWidth: number;
|
||||||
firstItem?: boolean;
|
firstItem?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,11 @@ import DraftAndScheduledPostSwipeActions from '../draft_and_scheduled_post_swipe
|
||||||
import DraftEmptyComponent from '../draft_empty_component';
|
import DraftEmptyComponent from '../draft_empty_component';
|
||||||
|
|
||||||
import type DraftModel from '@typings/database/models/servers/draft';
|
import type DraftModel from '@typings/database/models/servers/draft';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
allDrafts: DraftModel[];
|
allDrafts: DraftModel[];
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
tutorialWatched: boolean;
|
tutorialWatched: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,11 @@ import DraftAndScheduledPostSwipeActions from '../draft_and_scheduled_post_swipe
|
||||||
import ScheduledPostEmptyComponent from '../scheduled_post_empty_component';
|
import ScheduledPostEmptyComponent from '../scheduled_post_empty_component';
|
||||||
|
|
||||||
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
import type ScheduledPostModel from '@typings/database/models/servers/scheduled_post';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
allScheduledPosts: ScheduledPostModel[];
|
allScheduledPosts: ScheduledPostModel[];
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
tutorialWatched: boolean;
|
tutorialWatched: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,12 @@ import type ChannelModel from '@typings/database/models/servers/channel';
|
||||||
import type PostModel from '@typings/database/models/servers/post';
|
import type PostModel from '@typings/database/models/servers/post';
|
||||||
import type ThreadModel from '@typings/database/models/servers/thread';
|
import type ThreadModel from '@typings/database/models/servers/thread';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
author?: UserModel;
|
author?: UserModel;
|
||||||
channel?: ChannelModel;
|
channel?: ChannelModel;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
post?: PostModel;
|
post?: PostModel;
|
||||||
teammateNameDisplay: string;
|
teammateNameDisplay: string;
|
||||||
testID: string;
|
testID: string;
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,12 @@ import {typography} from '@utils/typography';
|
||||||
|
|
||||||
import type ThreadModel from '@typings/database/models/servers/thread';
|
import type ThreadModel from '@typings/database/models/servers/thread';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
author?: UserModel;
|
author?: UserModel;
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
participants: UserModel[];
|
participants: UserModel[];
|
||||||
testID: string;
|
testID: string;
|
||||||
thread: ThreadModel;
|
thread: ThreadModel;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {fetchProfiles, searchProfiles} from '@actions/remote/user';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import SearchBar from '@components/search';
|
import SearchBar from '@components/search';
|
||||||
import ServerUserList from '@components/server_user_list';
|
import ServerUserList from '@components/server_user_list';
|
||||||
import {General, View as ViewConstants} from '@constants';
|
import {General, Screens, View as ViewConstants} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {debounce} from '@helpers/api/general';
|
import {debounce} from '@helpers/api/general';
|
||||||
|
|
@ -571,6 +571,7 @@ function IntegrationSelector(
|
||||||
searchFunction={userSearchFunction}
|
searchFunction={userSearchFunction}
|
||||||
createFilter={createUserFilter}
|
createFilter={createUserFilter}
|
||||||
testID={'integration_selector.user_list'}
|
testID={'integration_selector.user_list'}
|
||||||
|
location={Screens.INTEGRATION_SELECTOR}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import AutocompleteSelector from '@components/autocomplete_selector';
|
||||||
import BoolSetting from '@components/settings/bool_setting';
|
import BoolSetting from '@components/settings/bool_setting';
|
||||||
import RadioSetting from '@components/settings/radio_setting';
|
import RadioSetting from '@components/settings/radio_setting';
|
||||||
import TextSetting from '@components/settings/text_setting';
|
import TextSetting from '@components/settings/text_setting';
|
||||||
|
import {Screens} from '@constants';
|
||||||
import {selectKeyboardType as selectKB} from '@utils/integrations';
|
import {selectKeyboardType as selectKB} from '@utils/integrations';
|
||||||
import {filterOptions} from '@utils/message_attachment';
|
import {filterOptions} from '@utils/message_attachment';
|
||||||
|
|
||||||
|
|
@ -109,6 +110,7 @@ function DialogElement({
|
||||||
secureTextEntry={subtype === 'password'}
|
secureTextEntry={subtype === 'password'}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
|
location={Screens.INTERACTIVE_DIALOG}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'select':
|
case 'select':
|
||||||
|
|
@ -126,6 +128,7 @@ function DialogElement({
|
||||||
selected={getStringValue(value)}
|
selected={getStringValue(value)}
|
||||||
roundedBorders={false}
|
roundedBorders={false}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
|
location={Screens.INTERACTIVE_DIALOG}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'radio':
|
case 'radio':
|
||||||
|
|
@ -138,6 +141,7 @@ function DialogElement({
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
value={getStringValue(value)}
|
value={getStringValue(value)}
|
||||||
|
location={Screens.INTERACTIVE_DIALOG}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'bool':
|
case 'bool':
|
||||||
|
|
@ -151,6 +155,7 @@ function DialogElement({
|
||||||
optional={optional}
|
optional={optional}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
|
location={Screens.INTERACTIVE_DIALOG}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import React from 'react';
|
||||||
import {View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
|
|
||||||
import Markdown from '@components/markdown';
|
import Markdown from '@components/markdown';
|
||||||
|
import {Screens} from '@constants';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
||||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
|
|
@ -41,7 +42,7 @@ function DialogIntroductionText({value}: Props) {
|
||||||
disableHashtags={true}
|
disableHashtags={true}
|
||||||
disableAtMentions={true}
|
disableAtMentions={true}
|
||||||
disableChannelLink={true}
|
disableChannelLink={true}
|
||||||
location=''
|
location={Screens.INTERACTIVE_DIALOG}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,7 @@ export default function ManageChannelMembers({
|
||||||
tutorialWatched={tutorialWatched}
|
tutorialWatched={tutorialWatched}
|
||||||
includeUserMargin={true}
|
includeUserMargin={true}
|
||||||
fetchMore={handleReachedBottom}
|
fetchMore={handleReachedBottom}
|
||||||
|
location={Screens.MANAGE_CHANNEL_MEMBERS}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
107
app/screens/navigation.test.ts
Normal file
107
app/screens/navigation.test.ts
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
import {DeviceEventEmitter, Keyboard, type EmitterSubscription} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
||||||
|
import {Events, Preferences, Screens} from '@constants';
|
||||||
|
import NavigationStore from '@store/navigation_store';
|
||||||
|
|
||||||
|
import {openAsBottomSheet, openUserProfileModal} from './navigation';
|
||||||
|
|
||||||
|
import type {FirstArgument} from '@typings/utils/utils';
|
||||||
|
import type {IntlShape} from 'react-intl';
|
||||||
|
|
||||||
|
function expectShowModalCalledWith(screen: string, title: string, props?: Record<string, unknown>) {
|
||||||
|
expect(Navigation.showModal).toHaveBeenCalledWith({
|
||||||
|
stack: {
|
||||||
|
children: [{
|
||||||
|
component: {
|
||||||
|
id: screen,
|
||||||
|
name: screen,
|
||||||
|
passProps: {
|
||||||
|
...props,
|
||||||
|
isModal: true,
|
||||||
|
},
|
||||||
|
options: expect.any(Object),
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectShowModalOverCurrentContext(screen: string, props?: Record<string, unknown>) {
|
||||||
|
expectShowModalCalledWith(screen, '', props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectOpenAsBottomSheetCalledWith(props: FirstArgument<typeof openAsBottomSheet>, isTablet: boolean) {
|
||||||
|
if (isTablet) {
|
||||||
|
expectShowModalCalledWith(props.screen, props.title, {closeButtonId: props.closeButtonId, ...props.props});
|
||||||
|
} else {
|
||||||
|
expectShowModalOverCurrentContext(props.screen, props.props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectDismissBottomSheetCalledWith(screenToDismiss: string, listenerCallback: jest.Mock) {
|
||||||
|
expect(listenerCallback).toHaveBeenCalled();
|
||||||
|
expect(NavigationStore.waitUntilScreensIsRemoved).toHaveBeenCalledWith(screenToDismiss);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectNotDismissBottomSheetCalledWith(listenerCallback: jest.Mock) {
|
||||||
|
expect(listenerCallback).not.toHaveBeenCalled();
|
||||||
|
expect(NavigationStore.waitUntilScreensIsRemoved).not.toHaveBeenCalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('openUserProfileModal', () => {
|
||||||
|
const intl = {
|
||||||
|
formatMessage: jest.fn(({defaultMessage}) => defaultMessage),
|
||||||
|
} as unknown as IntlShape;
|
||||||
|
const theme = Preferences.THEMES.denim;
|
||||||
|
const props = {
|
||||||
|
userId: 'user123',
|
||||||
|
};
|
||||||
|
|
||||||
|
let eventSubscription: EmitterSubscription;
|
||||||
|
const listenerCallback = jest.fn();
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
eventSubscription = DeviceEventEmitter.addListener(Events.CLOSE_BOTTOM_SHEET, listenerCallback);
|
||||||
|
jest.spyOn(NavigationStore, 'waitUntilScreensIsRemoved').mockImplementation();
|
||||||
|
});
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
eventSubscription.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dismiss the keyboard', () => {
|
||||||
|
openUserProfileModal(intl, theme, props);
|
||||||
|
expect(Keyboard.dismiss).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dismiss the bottom sheet if screenToDismiss is provided', async () => {
|
||||||
|
const screenToDismiss = Screens.BOTTOM_SHEET;
|
||||||
|
await openUserProfileModal(intl, theme, props, screenToDismiss);
|
||||||
|
expectDismissBottomSheetCalledWith(screenToDismiss, listenerCallback);
|
||||||
|
expectOpenAsBottomSheetCalledWith({
|
||||||
|
screen: Screens.USER_PROFILE,
|
||||||
|
title: 'Profile',
|
||||||
|
closeButtonId: 'close-user-profile',
|
||||||
|
theme,
|
||||||
|
props,
|
||||||
|
}, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call dismiss if no screenToDismiss is provided', async () => {
|
||||||
|
await openUserProfileModal(intl, theme, props);
|
||||||
|
expectNotDismissBottomSheetCalledWith(listenerCallback);
|
||||||
|
expectOpenAsBottomSheetCalledWith({
|
||||||
|
screen: Screens.USER_PROFILE,
|
||||||
|
title: 'Profile',
|
||||||
|
closeButtonId: 'close-user-profile',
|
||||||
|
theme,
|
||||||
|
props,
|
||||||
|
}, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
/* eslint-disable max-lines */
|
/* eslint-disable max-lines */
|
||||||
|
|
||||||
import merge from 'deepmerge';
|
import merge from 'deepmerge';
|
||||||
import {Appearance, DeviceEventEmitter, StatusBar, Platform, Alert, type EmitterSubscription} from 'react-native';
|
import {Appearance, DeviceEventEmitter, StatusBar, Platform, Alert, type EmitterSubscription, Keyboard} from 'react-native';
|
||||||
import {type ComponentWillAppearEvent, type ImageResource, type LayoutOrientation, Navigation, type Options, OptionsModalPresentationStyle, type OptionsTopBarButton, type ScreenPoppedEvent, type EventSubscription} from 'react-native-navigation';
|
import {type ComponentWillAppearEvent, type ImageResource, type LayoutOrientation, Navigation, type Options, OptionsModalPresentationStyle, type OptionsTopBarButton, type ScreenPoppedEvent, type EventSubscription} from 'react-native-navigation';
|
||||||
import tinyColor from 'tinycolor2';
|
import tinyColor from 'tinycolor2';
|
||||||
|
|
||||||
|
|
@ -20,8 +20,11 @@ import {appearanceControlledScreens, mergeNavigationOptions} from '@utils/naviga
|
||||||
import {changeOpacity, setNavigatorStyles} from '@utils/theme';
|
import {changeOpacity, setNavigatorStyles} from '@utils/theme';
|
||||||
|
|
||||||
import type {BottomSheetFooterProps} from '@gorhom/bottom-sheet';
|
import type {BottomSheetFooterProps} from '@gorhom/bottom-sheet';
|
||||||
|
import type {default as UserProfileScreen} from '@screens/user_profile';
|
||||||
import type {LaunchProps} from '@typings/launch';
|
import type {LaunchProps} from '@typings/launch';
|
||||||
import type {AvailableScreens, NavButtons} from '@typings/screens/navigation';
|
import type {AvailableScreens, NavButtons} from '@typings/screens/navigation';
|
||||||
|
import type {ComponentProps} from 'react';
|
||||||
|
import type {IntlShape} from 'react-intl';
|
||||||
|
|
||||||
const alpha = {
|
const alpha = {
|
||||||
from: 0,
|
from: 0,
|
||||||
|
|
@ -889,3 +892,20 @@ export async function findChannels(title: string, theme: Theme) {
|
||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function openUserProfileModal(
|
||||||
|
intl: IntlShape,
|
||||||
|
theme: Theme,
|
||||||
|
props: Omit<ComponentProps<typeof UserProfileScreen>, 'closeButtonId'>,
|
||||||
|
screenToDismiss?: AvailableScreens,
|
||||||
|
) {
|
||||||
|
if (screenToDismiss) {
|
||||||
|
await dismissBottomSheet(screenToDismiss);
|
||||||
|
}
|
||||||
|
const screen = Screens.USER_PROFILE;
|
||||||
|
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
||||||
|
const closeButtonId = 'close-user-profile';
|
||||||
|
|
||||||
|
Keyboard.dismiss();
|
||||||
|
openAsBottomSheet({screen, title, theme, closeButtonId, props: {...props}});
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,11 @@ import EmojiBar from './emoji_bar';
|
||||||
import ReactorsList from './reactors_list';
|
import ReactorsList from './reactors_list';
|
||||||
|
|
||||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialEmoji: string;
|
initialEmoji: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
reactions?: ReactionModel[];
|
reactions?: ReactionModel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,10 @@ import {useBottomSheetListsFix} from '@hooks/bottom_sheet_lists_fix';
|
||||||
import Reactor from './reactor';
|
import Reactor from './reactor';
|
||||||
|
|
||||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
reactions: ReactionModel[];
|
reactions: ReactionModel[];
|
||||||
type?: BottomSheetList;
|
type?: BottomSheetList;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,21 @@
|
||||||
|
|
||||||
import React, {useEffect} from 'react';
|
import React, {useEffect} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Keyboard} from 'react-native';
|
|
||||||
|
|
||||||
import {fetchUsersByIds} from '@actions/remote/user';
|
import {fetchUsersByIds} from '@actions/remote/user';
|
||||||
import UserItem from '@components/user_item';
|
import UserItem from '@components/user_item';
|
||||||
import {Screens} from '@constants';
|
import {Screens} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useTheme} from '@context/theme';
|
import {useTheme} from '@context/theme';
|
||||||
import {dismissBottomSheet, openAsBottomSheet} from '@screens/navigation';
|
import {openUserProfileModal} from '@screens/navigation';
|
||||||
|
|
||||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||||
import type UserModel from '@typings/database/models/servers/user';
|
import type UserModel from '@typings/database/models/servers/user';
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
channelId: string;
|
channelId: string;
|
||||||
location: string;
|
location: AvailableScreens;
|
||||||
reaction: ReactionModel;
|
reaction: ReactionModel;
|
||||||
user?: UserModel;
|
user?: UserModel;
|
||||||
}
|
}
|
||||||
|
|
@ -28,14 +28,11 @@ const Reactor = ({channelId, location, reaction, user}: Props) => {
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
const openUserProfile = async () => {
|
const openUserProfile = async () => {
|
||||||
if (user) {
|
if (user) {
|
||||||
await dismissBottomSheet(Screens.REACTIONS);
|
openUserProfileModal(intl, theme, {
|
||||||
const screen = Screens.USER_PROFILE;
|
userId: user.id,
|
||||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
channelId,
|
||||||
const closeButtonId = 'close-user-profile';
|
location,
|
||||||
const props = {closeButtonId, location, userId: user.id, channelId};
|
}, Screens.REACTIONS);
|
||||||
|
|
||||||
Keyboard.dismiss();
|
|
||||||
openAsBottomSheet({screen, title, theme, closeButtonId, props});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {View} from 'react-native';
|
||||||
|
|
||||||
import {sendTestNotification} from '@actions/remote/notifications';
|
import {sendTestNotification} from '@actions/remote/notifications';
|
||||||
import SectionNotice from '@components/section_notice';
|
import SectionNotice from '@components/section_notice';
|
||||||
|
import {Screens} from '@constants';
|
||||||
import {useServerUrl} from '@context/server';
|
import {useServerUrl} from '@context/server';
|
||||||
import {useExternalLink} from '@hooks/use_external_link';
|
import {useExternalLink} from '@hooks/use_external_link';
|
||||||
import {isMinimumServerVersion} from '@utils/helpers';
|
import {isMinimumServerVersion} from '@utils/helpers';
|
||||||
|
|
@ -131,6 +132,7 @@ const SendTestNotificationNotice = ({
|
||||||
primaryButton={primaryButton}
|
primaryButton={primaryButton}
|
||||||
secondaryButton={secondaryButton}
|
secondaryButton={secondaryButton}
|
||||||
type='hint'
|
type='hint'
|
||||||
|
location={Screens.SETTINGS_NOTIFICATION_PUSH}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ jest.mock('react-native-navigation', () => ({
|
||||||
registerComponentDidDisappearListener: jest.fn(),
|
registerComponentDidDisappearListener: jest.fn(),
|
||||||
}),
|
}),
|
||||||
dismissOverlay: jest.fn(),
|
dismissOverlay: jest.fn(),
|
||||||
|
setDefaultOptions: jest.fn(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ const Thread = ({
|
||||||
testID='thread.post_draft'
|
testID='thread.post_draft'
|
||||||
containerHeight={containerHeight}
|
containerHeight={containerHeight}
|
||||||
isChannelScreen={false}
|
isChannelScreen={false}
|
||||||
|
location={Screens.THREAD}
|
||||||
/>
|
/>
|
||||||
</ExtraKeyboardProvider>
|
</ExtraKeyboardProvider>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,12 @@ import {useTheme} from '@context/theme';
|
||||||
import {dismissBottomSheet} from '@screens/navigation';
|
import {dismissBottomSheet} from '@screens/navigation';
|
||||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||||
|
|
||||||
|
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||||
|
|
||||||
export type OptionsType = 'all' | 'message';
|
export type OptionsType = 'all' | 'message';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
location: string;
|
location?: AvailableScreens;
|
||||||
type: OptionsType;
|
type: OptionsType;
|
||||||
userId: string;
|
userId: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ type Props = {
|
||||||
isSystemAdmin: boolean;
|
isSystemAdmin: boolean;
|
||||||
isTeamAdmin: boolean;
|
isTeamAdmin: boolean;
|
||||||
manageMode?: boolean;
|
manageMode?: boolean;
|
||||||
location: AvailableScreens;
|
location?: AvailableScreens;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
teammateDisplayName: string;
|
teammateDisplayName: string;
|
||||||
user: UserModel;
|
user: UserModel;
|
||||||
|
|
@ -91,7 +91,7 @@ const UserProfile = ({
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const {formatMessage, locale} = useIntl();
|
const {formatMessage, locale} = useIntl();
|
||||||
const serverUrl = useServerUrl();
|
const serverUrl = useServerUrl();
|
||||||
const channelContext = channelContextScreens.includes(location);
|
const channelContext = location ? channelContextScreens.includes(location) : false;
|
||||||
const showOptions: OptionsType = channelContext && !user.isBot ? 'all' : 'message';
|
const showOptions: OptionsType = channelContext && !user.isBot ? 'all' : 'message';
|
||||||
const override = Boolean(userIconOverride || usernameOverride);
|
const override = Boolean(userIconOverride || usernameOverride);
|
||||||
const {bottom} = useSafeAreaInsets();
|
const {bottom} = useSafeAreaInsets();
|
||||||
|
|
|
||||||
|
|
@ -21,35 +21,6 @@ import {
|
||||||
alertSlashCommandFailed,
|
alertSlashCommandFailed,
|
||||||
} from './';
|
} from './';
|
||||||
|
|
||||||
jest.mock('react-native', () => {
|
|
||||||
const RN = jest.requireActual('react-native');
|
|
||||||
return {
|
|
||||||
Platform: RN.Platform,
|
|
||||||
NativeModules: {
|
|
||||||
...RN.NativeModules,
|
|
||||||
RNUtils: {
|
|
||||||
getConstants: () => ({
|
|
||||||
appGroupIdentifier: 'group.mattermost.rnbeta',
|
|
||||||
appGroupSharedDirectory: {
|
|
||||||
sharedDirectory: '',
|
|
||||||
databasePath: '',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
addListener: jest.fn(),
|
|
||||||
removeListeners: jest.fn(),
|
|
||||||
isRunningInSplitView: jest.fn().mockReturnValue({isSplit: false, isTablet: false}),
|
|
||||||
getDeliveredNotifications: jest.fn().mockResolvedValue([]),
|
|
||||||
removeChannelNotifications: jest.fn().mockImplementation(),
|
|
||||||
removeThreadNotifications: jest.fn().mockImplementation(),
|
|
||||||
removeServerNotifications: jest.fn().mockImplementation(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Alert: {
|
|
||||||
alert: jest.fn(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
jest.mock('@i18n', () => ({
|
jest.mock('@i18n', () => ({
|
||||||
t: (id: string) => id,
|
t: (id: string) => id,
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ jest.doMock('react-native', () => {
|
||||||
InteractionManager: RNInteractionManager,
|
InteractionManager: RNInteractionManager,
|
||||||
NativeModules: RNNativeModules,
|
NativeModules: RNNativeModules,
|
||||||
Linking: RNLinking,
|
Linking: RNLinking,
|
||||||
|
Keyboard: RNKeyboard,
|
||||||
} = ReactNative;
|
} = ReactNative;
|
||||||
|
|
||||||
const Alert = {
|
const Alert = {
|
||||||
|
|
@ -250,6 +251,14 @@ jest.doMock('react-native', () => {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Keyboard = {
|
||||||
|
...RNKeyboard,
|
||||||
|
dismiss: jest.fn(),
|
||||||
|
addListener: jest.fn(() => ({
|
||||||
|
remove: jest.fn(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
return Object.setPrototypeOf({
|
return Object.setPrototypeOf({
|
||||||
Platform: {
|
Platform: {
|
||||||
...Platform,
|
...Platform,
|
||||||
|
|
@ -270,6 +279,7 @@ jest.doMock('react-native', () => {
|
||||||
InteractionManager,
|
InteractionManager,
|
||||||
NativeModules,
|
NativeModules,
|
||||||
Linking,
|
Linking,
|
||||||
|
Keyboard,
|
||||||
Animated: {
|
Animated: {
|
||||||
...ReactNative.Animated,
|
...ReactNative.Animated,
|
||||||
timing: jest.fn(() => ({
|
timing: jest.fn(() => ({
|
||||||
|
|
@ -393,6 +403,7 @@ jest.mock('react-native-share', () => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('@screens/navigation', () => ({
|
jest.mock('@screens/navigation', () => ({
|
||||||
|
...jest.requireActual('@screens/navigation'),
|
||||||
resetToChannel: jest.fn(),
|
resetToChannel: jest.fn(),
|
||||||
resetToSelectServer: jest.fn(),
|
resetToSelectServer: jest.fn(),
|
||||||
resetToTeams: jest.fn(),
|
resetToTeams: jest.fn(),
|
||||||
|
|
|
||||||
4
types/utils/utils.ts
Normal file
4
types/utils/utils.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
export type FirstArgument<T> = T extends (...args: infer P) => any ? P[0] : never;
|
||||||
Loading…
Reference in a new issue