forked from Ivasoft/mattermost-mobile
Handle currentUser not available throught the app and refetch it (#7333)
* Handle currentUser not available throught the app and refetch it * Address feedback
This commit is contained in:
committed by
GitHub
parent
3a416dc511
commit
162cdfb21d
@@ -14,7 +14,7 @@ import {debounce} from '@helpers/api/general';
|
||||
import NetworkManager from '@managers/network_manager';
|
||||
import {getMembersCountByChannelsId, queryChannelsByTypes} from '@queries/servers/channel';
|
||||
import {queryGroupsByNames} from '@queries/servers/group';
|
||||
import {getConfig, getCurrentUserId} from '@queries/servers/system';
|
||||
import {getConfig, getCurrentUserId, setCurrentUserId} from '@queries/servers/system';
|
||||
import {getCurrentUser, prepareUsers, queryAllUsers, queryUsersById, queryUsersByIdsOrUsernames, queryUsersByUsername} from '@queries/servers/user';
|
||||
import {getFullErrorMessage} from '@utils/errors';
|
||||
import {logDebug} from '@utils/log';
|
||||
@@ -67,6 +67,22 @@ export const fetchMe = async (serverUrl: string, fetchOnly = false): Promise<MyU
|
||||
}
|
||||
};
|
||||
|
||||
export const refetchCurrentUser = async (serverUrl: string, currentUserId: string | undefined) => {
|
||||
logDebug('re-fetching self');
|
||||
const {user} = await fetchMe(serverUrl);
|
||||
if (!user || currentUserId) {
|
||||
return;
|
||||
}
|
||||
|
||||
logDebug('missing currentUserId');
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
logDebug('missing operator');
|
||||
return;
|
||||
}
|
||||
setCurrentUserId(operator, user.id);
|
||||
};
|
||||
|
||||
export async function fetchProfilesInChannel(serverUrl: string, channelId: string, excludeUserId?: string, options?: GetUsersOptions, fetchOnly = false): Promise<ProfilesInChannelRequest> {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
|
||||
@@ -23,7 +23,7 @@ import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type Props = {
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
isMilitaryTime: boolean;
|
||||
showPrefix?: boolean;
|
||||
showTimeCompulsory?: boolean;
|
||||
|
||||
@@ -20,7 +20,7 @@ import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type AddMembersProps = {
|
||||
channelType: string | null;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
location: string;
|
||||
post: PostModel;
|
||||
theme: Theme;
|
||||
@@ -58,7 +58,7 @@ const AddMembers = ({channelType, currentUser, location, post, theme}: AddMember
|
||||
}
|
||||
|
||||
const handleAddChannelMember = () => {
|
||||
if (post && post.channelId) {
|
||||
if (post && post.channelId && currentUser) {
|
||||
addMembersToChannel(serverUrl, post.channelId, userIds, post.rootId, false);
|
||||
if (post.rootId) {
|
||||
const messages = usernames.map((addedUsername) => {
|
||||
|
||||
@@ -19,7 +19,7 @@ import type UserModel from '@typings/database/models/servers/user';
|
||||
import type {SearchPattern} from '@typings/global/markdown';
|
||||
|
||||
type MessageProps = {
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
highlight: boolean;
|
||||
isEdited: boolean;
|
||||
isPendingOrFailed: boolean;
|
||||
@@ -63,7 +63,7 @@ const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPo
|
||||
const textStyles = getMarkdownTextStyles(theme);
|
||||
|
||||
const mentionKeys = useMemo(() => {
|
||||
return currentUser.mentionKeys;
|
||||
return currentUser?.mentionKeys;
|
||||
}, [currentUser]);
|
||||
|
||||
const onLayout = useCallback((event: LayoutChangeEvent) => setHeight(event.nativeEvent.layout.height), []);
|
||||
|
||||
@@ -8,6 +8,7 @@ import FormattedTime from '@components/formatted_time';
|
||||
import PostPriorityLabel from '@components/post_priority/post_priority_label';
|
||||
import {CHANNEL, THREAD} from '@constants/screens';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {DEFAULT_LOCALE} from '@i18n';
|
||||
import {postUserDisplayName} from '@utils/post';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
@@ -24,7 +25,7 @@ import type UserModel from '@typings/database/models/servers/user';
|
||||
type HeaderProps = {
|
||||
author?: UserModel;
|
||||
commentCount: number;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
enablePostUsernameOverride: boolean;
|
||||
isAutoResponse: boolean;
|
||||
isCRTEnabled?: boolean;
|
||||
@@ -81,7 +82,7 @@ const Header = (props: HeaderProps) => {
|
||||
const isReplyPost = Boolean(post.rootId && !isEphemeral);
|
||||
const showReply = !isReplyPost && (location !== THREAD) && (shouldRenderReplyButton && (!rootPostAuthor && commentCount > 0));
|
||||
const displayName = postUserDisplayName(post, author, teammateNameDisplay, enablePostUsernameOverride);
|
||||
const rootAuthorDisplayName = rootPostAuthor ? displayUsername(rootPostAuthor, currentUser.locale, teammateNameDisplay, true) : undefined;
|
||||
const rootAuthorDisplayName = rootPostAuthor ? displayUsername(rootPostAuthor, currentUser?.locale, teammateNameDisplay, true) : undefined;
|
||||
const customStatus = getUserCustomStatus(author);
|
||||
const showCustomStatusEmoji = Boolean(
|
||||
isCustomStatusEnabled && displayName && customStatus &&
|
||||
@@ -139,7 +140,7 @@ const Header = (props: HeaderProps) => {
|
||||
</View>
|
||||
{Boolean(rootAuthorDisplayName) && location === CHANNEL &&
|
||||
<HeaderCommentedOn
|
||||
locale={currentUser.locale}
|
||||
locale={currentUser?.locale || DEFAULT_LOCALE}
|
||||
name={rootAuthorDisplayName!}
|
||||
theme={theme}
|
||||
/>
|
||||
|
||||
@@ -25,7 +25,7 @@ import type PostsInThreadModel from '@typings/database/models/servers/posts_in_t
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type PropsInput = WithDatabaseArgs & {
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
isCRTEnabled?: boolean;
|
||||
nextPost: PostModel | undefined;
|
||||
post: PostModel;
|
||||
@@ -95,12 +95,12 @@ const withPost = withObservables(
|
||||
({currentUser, database, isCRTEnabled, post, previousPost, nextPost, location}: PropsInput) => {
|
||||
let isLastReply = of$(true);
|
||||
let isPostAddChannelMember = of$(false);
|
||||
const isOwner = currentUser.id === post.userId;
|
||||
const isOwner = currentUser?.id === post.userId;
|
||||
const author = post.userId ? observePostAuthor(database, post) : of$(undefined);
|
||||
const canDelete = observePermissionForPost(database, post, currentUser, isOwner ? Permissions.DELETE_POST : Permissions.DELETE_OTHERS_POSTS, false);
|
||||
const isEphemeral = of$(isPostEphemeral(post));
|
||||
|
||||
if (post.props?.add_channel_member && isPostEphemeral(post)) {
|
||||
if (post.props?.add_channel_member && isPostEphemeral(post) && currentUser) {
|
||||
isPostAddChannelMember = observeCanManageChannelMembers(database, post.channelId, currentUser);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ const withPost = withObservables(
|
||||
if (!isCRTEnabled && location === Screens.CHANNEL) {
|
||||
highlightReplyBar = post.postsInThread.observe().pipe(
|
||||
switchMap((postsInThreads: PostsInThreadModel[]) => {
|
||||
if (postsInThreads.length) {
|
||||
if (postsInThreads.length && currentUser) {
|
||||
return observeShouldHighlightReplyBar(database, currentUser, post, postsInThreads[0]);
|
||||
}
|
||||
return of$(false);
|
||||
|
||||
@@ -39,7 +39,7 @@ import type {SearchPattern} from '@typings/global/markdown';
|
||||
type PostProps = {
|
||||
appsEnabled: boolean;
|
||||
canDelete: boolean;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
customEmojiNames: string[];
|
||||
differentThreadSequence: boolean;
|
||||
hasFiles: boolean;
|
||||
|
||||
@@ -25,7 +25,7 @@ type Props = {
|
||||
isMilitaryTime: boolean;
|
||||
isTimezoneEnabled: boolean;
|
||||
theme: Theme;
|
||||
user: UserModel;
|
||||
user?: UserModel;
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
|
||||
@@ -23,7 +23,7 @@ import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type Props = {
|
||||
post: PostModel;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
author?: UserModel;
|
||||
isMilitaryTime: boolean;
|
||||
teammateNameDisplay?: string;
|
||||
|
||||
@@ -408,6 +408,19 @@ export async function prepareCommonSystemValues(
|
||||
}
|
||||
}
|
||||
|
||||
export async function setCurrentUserId(operator: ServerDataOperator, userId: string) {
|
||||
try {
|
||||
const models = await prepareCommonSystemValues(operator, {currentUserId: userId});
|
||||
if (models) {
|
||||
await operator.batchRecords(models, 'setCurrentChannelId');
|
||||
}
|
||||
|
||||
return {currentUserId: userId};
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
}
|
||||
|
||||
export async function setCurrentChannelId(operator: ServerDataOperator, channelId: string) {
|
||||
try {
|
||||
const models = await prepareCommonSystemValues(operator, {currentChannelId: channelId});
|
||||
|
||||
@@ -36,6 +36,7 @@ const enhanced = withObservables([], ({serverUrl, database}: Props) => {
|
||||
const channelId = channel.pipe(switchMap((c) => of$(c?.id || '')));
|
||||
const teamId = channel.pipe(switchMap((c) => (c?.teamId ? of$(c.teamId) : observeCurrentTeamId(database))));
|
||||
const userId = observeCurrentUserId(database);
|
||||
const currentUser = observeCurrentUser(database);
|
||||
const isTeamAdmin = combineLatest([teamId, userId]).pipe(
|
||||
switchMap(([tId, uId]) => observeUserIsTeamAdmin(database, uId, tId)),
|
||||
);
|
||||
@@ -49,7 +50,7 @@ const enhanced = withObservables([], ({serverUrl, database}: Props) => {
|
||||
switchMap((config) => of$(config.AllowEnableCalls)),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
const systemAdmin = observeCurrentUser(database).pipe(
|
||||
const systemAdmin = currentUser.pipe(
|
||||
switchMap((u) => (u ? of$(u.roles) : of$(''))),
|
||||
switchMap((roles) => of$(isSystemAdmin(roles || ''))),
|
||||
distinctUntilChanged(),
|
||||
@@ -99,7 +100,7 @@ const enhanced = withObservables([], ({serverUrl, database}: Props) => {
|
||||
);
|
||||
const isCallsEnabledInChannel = observeIsCallsEnabledInChannel(database, serverUrl, observeCurrentChannelId(database));
|
||||
|
||||
const canManageMembers = observeCurrentUser(database).pipe(
|
||||
const canManageMembers = currentUser.pipe(
|
||||
combineLatestWith(channelId),
|
||||
switchMap(([u, cId]) => (u ? observeCanManageChannelMembers(database, cId, u) : of$(false))),
|
||||
distinctUntilChanged(),
|
||||
|
||||
@@ -46,7 +46,7 @@ type NewStatusType = {
|
||||
|
||||
type Props = {
|
||||
customStatusExpirySupported: boolean;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
recentCustomStatuses: UserCustomStatus[];
|
||||
componentId: AvailableScreens;
|
||||
}
|
||||
@@ -80,8 +80,8 @@ const DEFAULT_DURATION: CustomStatusDuration = 'today';
|
||||
const BTN_UPDATE_STATUS = 'update-custom-status';
|
||||
const edges: Edge[] = ['bottom', 'left', 'right'];
|
||||
|
||||
const calculateExpiryTime = (duration: CustomStatusDuration, currentUser: UserModel, expiresAt: moment.Moment): string => {
|
||||
const userTimezone = getTimezone(currentUser.timezone);
|
||||
const calculateExpiryTime = (duration: CustomStatusDuration, currentUser: UserModel | undefined, expiresAt: moment.Moment): string => {
|
||||
const userTimezone = getTimezone(currentUser?.timezone);
|
||||
const currentTime = getCurrentMomentForTimezone(userTimezone);
|
||||
|
||||
switch (duration) {
|
||||
@@ -162,7 +162,7 @@ const CustomStatus = ({
|
||||
}, [currentUser]);
|
||||
|
||||
const initialStatus = useMemo(() => {
|
||||
const userTimezone = getTimezone(currentUser.timezone);
|
||||
const userTimezone = getTimezone(currentUser?.timezone);
|
||||
|
||||
// May be a ref
|
||||
const isCustomStatusExpired = verifyExpiredStatus(currentUser);
|
||||
@@ -239,6 +239,10 @@ const CustomStatus = ({
|
||||
}, [openClearAfterModal]);
|
||||
|
||||
const handleSetStatus = useCallback(async () => {
|
||||
if (!currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isStatusSet) {
|
||||
let isStatusSame =
|
||||
storedStatus?.emoji === newStatus.emoji &&
|
||||
|
||||
@@ -20,7 +20,7 @@ import DateTimePicker from './date_time_selector';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type Props = {
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
duration: CustomStatusDuration;
|
||||
expiryTime?: string;
|
||||
handleItemClick: (duration: CustomStatusDuration, expiresAt: string) => void;
|
||||
@@ -136,7 +136,7 @@ const ClearAfterMenuItem = ({currentUser, duration, expiryTime = '', handleItemC
|
||||
<DateTimePicker
|
||||
handleChange={handleCustomExpiresAtChange}
|
||||
theme={theme}
|
||||
timezone={getTimezone(currentUser.timezone)}
|
||||
timezone={getTimezone(currentUser?.timezone)}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -29,7 +29,7 @@ import type {AvailableScreens} from '@typings/screens/navigation';
|
||||
|
||||
interface Props {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
handleClearAfterClick: (duration: CustomStatusDuration, expiresAt: string) => void;
|
||||
initialDuration: CustomStatusDuration;
|
||||
intl: IntlShape;
|
||||
|
||||
@@ -53,12 +53,12 @@ const EditProfile = ({
|
||||
const scrollViewRef = useRef<KeyboardAwareScrollView>();
|
||||
const hasUpdateUserInfo = useRef<boolean>(false);
|
||||
const [userInfo, setUserInfo] = useState<UserInfo>({
|
||||
email: currentUser.email,
|
||||
firstName: currentUser.firstName,
|
||||
lastName: currentUser.lastName,
|
||||
nickname: currentUser.nickname,
|
||||
position: currentUser.position,
|
||||
username: currentUser.username,
|
||||
email: currentUser?.email || '',
|
||||
firstName: currentUser?.firstName || '',
|
||||
lastName: currentUser?.lastName || '',
|
||||
nickname: currentUser?.nickname || '',
|
||||
position: currentUser?.position || '',
|
||||
username: currentUser?.username || '',
|
||||
});
|
||||
const [canSave, setCanSave] = useState(false);
|
||||
const [error, setError] = useState<unknown>();
|
||||
@@ -117,6 +117,9 @@ const EditProfile = ({
|
||||
}, [componentId, rightButton]);
|
||||
|
||||
const submitUser = useCallback(preventDoubleTap(async () => {
|
||||
if (!currentUser) {
|
||||
return;
|
||||
}
|
||||
enableSaveButton(false);
|
||||
setError(undefined);
|
||||
setUpdating(true);
|
||||
@@ -187,6 +190,44 @@ const EditProfile = ({
|
||||
scrollViewRef.current?.scrollToPosition(0, 0, true);
|
||||
}, [enableSaveButton]);
|
||||
|
||||
const content = currentUser ? (
|
||||
<KeyboardAwareScrollView
|
||||
bounces={false}
|
||||
enableAutomaticScroll={Platform.select({ios: true, default: false})}
|
||||
enableOnAndroid={true}
|
||||
enableResetScrollToCoords={true}
|
||||
extraScrollHeight={Platform.select({ios: 45})}
|
||||
keyboardOpeningTime={0}
|
||||
keyboardDismissMode='none'
|
||||
keyboardShouldPersistTaps='handled'
|
||||
scrollToOverflowEnabled={true}
|
||||
testID='edit_profile.scroll_view'
|
||||
style={styles.flex}
|
||||
>
|
||||
{updating && <Updating/>}
|
||||
{Boolean(error) && <ProfileError error={error}/>}
|
||||
<View style={styles.top}>
|
||||
<UserProfilePicture
|
||||
currentUser={currentUser}
|
||||
lockedPicture={lockedPicture}
|
||||
onUpdateProfilePicture={onUpdateProfilePicture}
|
||||
/>
|
||||
</View>
|
||||
<ProfileForm
|
||||
canSave={canSave}
|
||||
currentUser={currentUser}
|
||||
isTablet={isTablet}
|
||||
lockedFirstName={lockedFirstName}
|
||||
lockedLastName={lockedLastName}
|
||||
lockedNickname={lockedNickname}
|
||||
lockedPosition={lockedPosition}
|
||||
onUpdateField={onUpdateField}
|
||||
userInfo={userInfo}
|
||||
submitUser={submitUser}
|
||||
/>
|
||||
</KeyboardAwareScrollView>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{isTablet &&
|
||||
@@ -203,41 +244,7 @@ const EditProfile = ({
|
||||
style={styles.flex}
|
||||
testID='edit_profile.screen'
|
||||
>
|
||||
<KeyboardAwareScrollView
|
||||
bounces={false}
|
||||
enableAutomaticScroll={Platform.select({ios: true, default: false})}
|
||||
enableOnAndroid={true}
|
||||
enableResetScrollToCoords={true}
|
||||
extraScrollHeight={Platform.select({ios: 45})}
|
||||
keyboardOpeningTime={0}
|
||||
keyboardDismissMode='none'
|
||||
keyboardShouldPersistTaps='handled'
|
||||
scrollToOverflowEnabled={true}
|
||||
testID='edit_profile.scroll_view'
|
||||
style={styles.flex}
|
||||
>
|
||||
{updating && <Updating/>}
|
||||
{Boolean(error) && <ProfileError error={error}/>}
|
||||
<View style={styles.top}>
|
||||
<UserProfilePicture
|
||||
currentUser={currentUser}
|
||||
lockedPicture={lockedPicture}
|
||||
onUpdateProfilePicture={onUpdateProfilePicture}
|
||||
/>
|
||||
</View>
|
||||
<ProfileForm
|
||||
canSave={canSave}
|
||||
currentUser={currentUser}
|
||||
isTablet={isTablet}
|
||||
lockedFirstName={lockedFirstName}
|
||||
lockedLastName={lockedLastName}
|
||||
lockedNickname={lockedNickname}
|
||||
lockedPosition={lockedPosition}
|
||||
onUpdateField={onUpdateField}
|
||||
userInfo={userInfo}
|
||||
submitUser={submitUser}
|
||||
/>
|
||||
</KeyboardAwareScrollView>
|
||||
{content}
|
||||
</SafeAreaView>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -19,7 +19,7 @@ import AccountUserInfo from './components/user_info';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type AccountScreenProps = {
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
enableCustomUserStatuses: boolean;
|
||||
showFullName: boolean;
|
||||
};
|
||||
@@ -92,6 +92,26 @@ const AccountScreen = ({currentUser, enableCustomUserStatuses, showFullName}: Ac
|
||||
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
const content = currentUser ? (
|
||||
<ScrollView
|
||||
alwaysBounceVertical={false}
|
||||
style={tabletSidebarStyle}
|
||||
contentContainerStyle={styles.totalHeight}
|
||||
>
|
||||
<AccountUserInfo
|
||||
user={currentUser}
|
||||
showFullName={showFullName}
|
||||
theme={theme}
|
||||
/>
|
||||
<AccountOptions
|
||||
enableCustomUserStatuses={enableCustomUserStatuses}
|
||||
isTablet={isTablet}
|
||||
user={currentUser}
|
||||
theme={theme}
|
||||
/>
|
||||
</ScrollView>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
edges={edges}
|
||||
@@ -106,23 +126,7 @@ const AccountScreen = ({currentUser, enableCustomUserStatuses, showFullName}: Ac
|
||||
onLayout={onLayout}
|
||||
style={[styles.flexRow, animated]}
|
||||
>
|
||||
<ScrollView
|
||||
alwaysBounceVertical={false}
|
||||
style={tabletSidebarStyle}
|
||||
contentContainerStyle={styles.totalHeight}
|
||||
>
|
||||
<AccountUserInfo
|
||||
user={currentUser}
|
||||
showFullName={showFullName}
|
||||
theme={theme}
|
||||
/>
|
||||
<AccountOptions
|
||||
enableCustomUserStatuses={enableCustomUserStatuses}
|
||||
isTablet={isTablet}
|
||||
user={currentUser}
|
||||
theme={theme}
|
||||
/>
|
||||
</ScrollView>
|
||||
{content}
|
||||
{isTablet &&
|
||||
<View style={[styles.tabletContainer, styles.tabletDivider]}>
|
||||
<AccountTabletView/>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {BackHandler, DeviceEventEmitter, StyleSheet, ToastAndroid, View} from 'r
|
||||
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
|
||||
import {type Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||
|
||||
import {refetchCurrentUser} from '@actions/remote/user';
|
||||
import AnnouncementBanner from '@components/announcement_banner';
|
||||
import ConnectionBanner from '@components/connection_banner';
|
||||
import TeamSidebar from '@components/team_sidebar';
|
||||
@@ -37,6 +38,8 @@ type ChannelProps = {
|
||||
showToS: boolean;
|
||||
launchType: LaunchType;
|
||||
coldStart?: boolean;
|
||||
currentUserId?: string;
|
||||
hasCurrentUser: boolean;
|
||||
};
|
||||
|
||||
const edges: Edge[] = ['bottom', 'left', 'right'];
|
||||
@@ -147,6 +150,12 @@ const ChannelListScreen = (props: ChannelProps) => {
|
||||
}
|
||||
}, [props.showToS]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!props.hasCurrentUser || !props.currentUserId) {
|
||||
refetchCurrentUser(serverUrl, props.currentUserId);
|
||||
}
|
||||
}, [props.currentUserId, props.hasCurrentUser]);
|
||||
|
||||
// Init the rate app. Only run the effect on the first render if ToS is not open
|
||||
useEffect(() => {
|
||||
if (hasRendered) {
|
||||
|
||||
@@ -7,10 +7,11 @@ import {of as of$} from 'rxjs';
|
||||
import {distinctUntilChanged, switchMap} from 'rxjs/operators';
|
||||
|
||||
import {queryAllMyChannelsForTeam} from '@queries/servers/channel';
|
||||
import {observeCurrentTeamId, observeLicense} from '@queries/servers/system';
|
||||
import {observeCurrentTeamId, observeCurrentUserId, observeLicense} from '@queries/servers/system';
|
||||
import {queryMyTeams} from '@queries/servers/team';
|
||||
import {observeShowToS} from '@queries/servers/terms_of_service';
|
||||
import {observeIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
|
||||
import ChannelsList from './channel_list';
|
||||
|
||||
@@ -40,6 +41,11 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
),
|
||||
isLicensed,
|
||||
showToS: observeShowToS(database),
|
||||
currentUserId: observeCurrentUserId(database),
|
||||
hasCurrentUser: observeCurrentUser(database).pipe(
|
||||
switchMap((u) => of$(Boolean(u))),
|
||||
distinctUntilChanged(),
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ const enhance = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
return queryPostsById(database, recentMentions, Q.asc).observe();
|
||||
}),
|
||||
),
|
||||
currentUser,
|
||||
currentTimezone: currentUser.pipe((switchMap((user) => of$(getTimezone(user?.timezone || null))))),
|
||||
customEmojiNames: queryAllCustomEmojis(database).observe().pipe(
|
||||
switchMap((customEmojis) => of$(mapCustomEmojiNames(customEmojis))),
|
||||
|
||||
@@ -39,7 +39,7 @@ const enhance = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
return queryPostsById(database, ids, Q.asc).observe();
|
||||
}),
|
||||
),
|
||||
currentTimezone: currentUser.pipe((switchMap((user) => of$(getTimezone(user?.timezone || null))))),
|
||||
currentTimezone: currentUser.pipe((switchMap((user) => of$(getTimezone(user?.timezone))))),
|
||||
customEmojiNames: queryAllCustomEmojis(database).observe().pipe(
|
||||
switchMap((customEmojis) => of$(mapCustomEmojiNames(customEmojis))),
|
||||
),
|
||||
|
||||
@@ -14,7 +14,7 @@ import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type Props = {
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
isFocused: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ const TIMEZONE_FORMAT = [
|
||||
|
||||
type DisplayProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
hasMilitaryTimeFormat: boolean;
|
||||
isCRTEnabled: boolean;
|
||||
isCRTSwitchEnabled: boolean;
|
||||
@@ -64,7 +64,7 @@ type DisplayProps = {
|
||||
const Display = ({componentId, currentUser, hasMilitaryTimeFormat, isCRTEnabled, isCRTSwitchEnabled, isThemeSwitchingEnabled, isTimezoneEnabled}: DisplayProps) => {
|
||||
const intl = useIntl();
|
||||
const theme = useTheme();
|
||||
const timezone = useMemo(() => getUserTimezoneProps(currentUser), [currentUser.timezone]);
|
||||
const timezone = useMemo(() => getUserTimezoneProps(currentUser), [currentUser?.timezone]);
|
||||
|
||||
const goToThemeSettings = preventDoubleTap(() => {
|
||||
const screen = Screens.SETTINGS_DISPLAY_THEME;
|
||||
|
||||
@@ -21,7 +21,7 @@ import type UserModel from '@typings/database/models/servers/user';
|
||||
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||
|
||||
type DisplayTimezoneProps = {
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
componentId: AvailableScreens;
|
||||
}
|
||||
const DisplayTimezone = ({currentUser, componentId}: DisplayTimezoneProps) => {
|
||||
@@ -78,7 +78,7 @@ const DisplayTimezone = ({currentUser, componentId}: DisplayTimezoneProps) => {
|
||||
}
|
||||
|
||||
close();
|
||||
}, [userTimezone, currentUser.timezone, serverUrl]);
|
||||
}, [userTimezone, serverUrl]);
|
||||
|
||||
useBackNavigation(saveTimezone);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
|
||||
type NotificationAutoResponderProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
}
|
||||
const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoResponderProps) => {
|
||||
const theme = useTheme();
|
||||
@@ -66,7 +66,7 @@ const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoR
|
||||
const intl = useIntl();
|
||||
const notifyProps = useMemo(() => getNotificationProps(currentUser), [/* dependency array should remain empty */]);
|
||||
|
||||
const initialAutoResponderActive = useMemo(() => Boolean(currentUser.status === General.OUT_OF_OFFICE && notifyProps.auto_responder_active === 'true'), [/* dependency array should remain empty */]);
|
||||
const initialAutoResponderActive = useMemo(() => Boolean(currentUser?.status === General.OUT_OF_OFFICE && notifyProps.auto_responder_active === 'true'), [/* dependency array should remain empty */]);
|
||||
const [autoResponderActive, setAutoResponderActive] = useState<boolean>(initialAutoResponderActive);
|
||||
|
||||
const initialOOOMsg = useMemo(() => notifyProps.auto_responder_message || intl.formatMessage(OOO), [/* dependency array should remain empty */]);
|
||||
@@ -87,10 +87,12 @@ const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoR
|
||||
auto_responder_message: autoResponderMessage,
|
||||
},
|
||||
});
|
||||
fetchStatusInBatch(serverUrl, currentUser.id);
|
||||
if (currentUser) {
|
||||
fetchStatusInBatch(serverUrl, currentUser.id);
|
||||
}
|
||||
}
|
||||
close();
|
||||
}, [serverUrl, autoResponderActive, autoResponderMessage, notifyProps, currentUser.id]);
|
||||
}, [serverUrl, autoResponderActive, autoResponderMessage, notifyProps, currentUser?.id]);
|
||||
|
||||
useBackNavigation(saveAutoResponder);
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ const emailFooterCRTText = {
|
||||
|
||||
type NotificationEmailProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
emailInterval: string;
|
||||
enableEmailBatching: boolean;
|
||||
isCRTEnabled: boolean;
|
||||
@@ -63,7 +63,7 @@ type NotificationEmailProps = {
|
||||
}
|
||||
|
||||
const NotificationEmail = ({componentId, currentUser, emailInterval, enableEmailBatching, isCRTEnabled, sendEmailNotifications}: NotificationEmailProps) => {
|
||||
const notifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser.notifyProps]);
|
||||
const notifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser?.notifyProps]);
|
||||
const initialInterval = useMemo(
|
||||
() => getEmailInterval(sendEmailNotifications && notifyProps?.email === 'true', enableEmailBatching, parseInt(emailInterval, 10)).toString(),
|
||||
[/* dependency array should remain empty */],
|
||||
@@ -81,6 +81,10 @@ const NotificationEmail = ({componentId, currentUser, emailInterval, enableEmail
|
||||
const close = () => popTopScreen(componentId);
|
||||
|
||||
const saveEmail = useCallback(() => {
|
||||
if (!currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
const canSaveSetting = notifyInterval !== initialInterval || emailThreads !== initialEmailThreads;
|
||||
if (canSaveSetting) {
|
||||
const promises = [];
|
||||
@@ -106,7 +110,7 @@ const NotificationEmail = ({componentId, currentUser, emailInterval, enableEmail
|
||||
Promise.all(promises);
|
||||
}
|
||||
close();
|
||||
}, [notifyProps, notifyInterval, emailThreads, serverUrl, currentUser.id, sendEmailNotifications]);
|
||||
}, [notifyProps, notifyInterval, emailThreads, serverUrl, currentUser?.id, sendEmailNotifications]);
|
||||
|
||||
useAndroidHardwareBackHandler(componentId, saveEmail);
|
||||
|
||||
|
||||
@@ -52,11 +52,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
};
|
||||
});
|
||||
|
||||
const getMentionProps = (currentUser: UserModel) => {
|
||||
const getMentionProps = (currentUser?: UserModel) => {
|
||||
const notifyProps = getNotificationProps(currentUser);
|
||||
const mKeys = (notifyProps.mention_keys || '').split(',');
|
||||
|
||||
const usernameMentionIndex = mKeys.indexOf(currentUser.username);
|
||||
const usernameMentionIndex = currentUser ? mKeys.indexOf(currentUser.username) : -1;
|
||||
if (usernameMentionIndex > -1) {
|
||||
mKeys.splice(usernameMentionIndex, 1);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ const getMentionProps = (currentUser: UserModel) => {
|
||||
|
||||
type MentionSectionProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
isCRTEnabled: boolean;
|
||||
}
|
||||
const MentionSettings = ({componentId, currentUser, isCRTEnabled}: MentionSectionProps) => {
|
||||
@@ -104,6 +104,10 @@ const MentionSettings = ({componentId, currentUser, isCRTEnabled}: MentionSectio
|
||||
}, [firstNameMentionOn, channelMentionOn, usernameMentionOn, mentionKeywords, notifyProps, replyNotificationType]);
|
||||
|
||||
const saveMention = useCallback(() => {
|
||||
if (!currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
const canSave = canSaveSettings();
|
||||
|
||||
if (canSave) {
|
||||
@@ -166,7 +170,7 @@ const MentionSettings = ({componentId, currentUser, isCRTEnabled}: MentionSectio
|
||||
<SettingOption
|
||||
action={onToggleFirstName}
|
||||
description={intl.formatMessage({id: 'notification_settings.mentions.sensitiveName', defaultMessage: 'Your case sensitive first name'})}
|
||||
label={currentUser.firstName}
|
||||
label={currentUser!.firstName}
|
||||
selected={firstNameMentionOn}
|
||||
testID='mention_notification_settings.case_sensitive_first_name.option'
|
||||
type='toggle'
|
||||
@@ -179,7 +183,7 @@ const MentionSettings = ({componentId, currentUser, isCRTEnabled}: MentionSectio
|
||||
<SettingOption
|
||||
action={onToggleUserName}
|
||||
description={intl.formatMessage({id: 'notification_settings.mentions.sensitiveUsername', defaultMessage: 'Your non-case sensitive username'})}
|
||||
label={currentUser.username}
|
||||
label={currentUser!.username}
|
||||
selected={usernameMentionOn}
|
||||
testID='mention_notification_settings.non_case_sensitive_username.option'
|
||||
type='toggle'
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {AvailableScreens} from '@typings/screens/navigation';
|
||||
|
||||
type NotificationMentionProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
isCRTEnabled: boolean;
|
||||
}
|
||||
const NotificationMention = ({componentId, currentUser, isCRTEnabled}: NotificationMentionProps) => {
|
||||
|
||||
@@ -22,14 +22,14 @@ import type {AvailableScreens} from '@typings/screens/navigation';
|
||||
|
||||
type NotificationMobileProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
isCRTEnabled: boolean;
|
||||
sendPushNotifications: boolean;
|
||||
};
|
||||
const NotificationPush = ({componentId, currentUser, isCRTEnabled, sendPushNotifications}: NotificationMobileProps) => {
|
||||
const serverUrl = useServerUrl();
|
||||
|
||||
const notifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser.notifyProps]);
|
||||
const notifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser?.notifyProps]);
|
||||
|
||||
const [pushSend, setPushSend] = useState<UserNotifyPropsPush>(notifyProps.push);
|
||||
const [pushStatus, setPushStatus] = useState<UserNotifyPropsPushStatus>(notifyProps.push_status);
|
||||
|
||||
@@ -29,7 +29,7 @@ const mentionTexts = {
|
||||
|
||||
type NotificationsProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
emailInterval: string;
|
||||
enableAutoResponder: boolean;
|
||||
enableEmailBatching: boolean;
|
||||
@@ -46,7 +46,7 @@ const Notifications = ({
|
||||
sendEmailNotifications,
|
||||
}: NotificationsProps) => {
|
||||
const intl = useIntl();
|
||||
const notifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser.notifyProps]);
|
||||
const notifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser?.notifyProps]);
|
||||
|
||||
const emailIntervalPref = useMemo(() =>
|
||||
getEmailInterval(
|
||||
@@ -120,7 +120,7 @@ const Notifications = ({
|
||||
<SettingItem
|
||||
onPress={goToNotificationAutoResponder}
|
||||
optionName='automatic_dm_replies'
|
||||
info={currentUser.status === General.OUT_OF_OFFICE && notifyProps.auto_responder_active === 'true' ? 'On' : 'Off'}
|
||||
info={currentUser?.status === General.OUT_OF_OFFICE && notifyProps.auto_responder_active === 'true' ? 'On' : 'Off'}
|
||||
testID='notification_settings.automatic_replies.option'
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -105,7 +105,7 @@ export const getUsersByUsername = (users: UserModel[]) => {
|
||||
return usersByUsername;
|
||||
};
|
||||
|
||||
export const getUserTimezoneProps = (currentUser: UserModel) => {
|
||||
export const getUserTimezoneProps = (currentUser?: UserModel) => {
|
||||
if (currentUser?.timezone) {
|
||||
return {
|
||||
...currentUser?.timezone,
|
||||
@@ -120,8 +120,8 @@ export const getUserTimezoneProps = (currentUser: UserModel) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const getUserTimezone = (user: UserModel | UserProfile) => {
|
||||
return getTimezone(user.timezone);
|
||||
export const getUserTimezone = (user?: UserModel | UserProfile) => {
|
||||
return getTimezone(user?.timezone);
|
||||
};
|
||||
|
||||
export const getTimezone = (timezone?: UserTimezone | null) => {
|
||||
|
||||
@@ -18,7 +18,7 @@ export interface UserInfo extends Record<string, string | undefined | null| bool
|
||||
|
||||
export type EditProfileProps = {
|
||||
componentId: AvailableScreens;
|
||||
currentUser: UserModel;
|
||||
currentUser?: UserModel;
|
||||
isModal?: boolean;
|
||||
isTablet?: boolean;
|
||||
lockedFirstName: boolean;
|
||||
|
||||
Reference in New Issue
Block a user