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:
Daniel Espino García
2023-05-05 21:40:59 +02:00
committed by GitHub
parent 3a416dc511
commit 162cdfb21d
31 changed files with 184 additions and 114 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) => {

View File

@@ -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), []);

View File

@@ -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}
/>

View File

@@ -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);

View File

@@ -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;

View File

@@ -25,7 +25,7 @@ type Props = {
isMilitaryTime: boolean;
isTimezoneEnabled: boolean;
theme: Theme;
user: UserModel;
user?: UserModel;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {

View File

@@ -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;

View File

@@ -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});

View File

@@ -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(),

View File

@@ -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 &&

View File

@@ -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>

View File

@@ -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;

View File

@@ -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>
</>
);

View File

@@ -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/>

View File

@@ -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) {

View File

@@ -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(),
),
};
});

View File

@@ -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))),

View File

@@ -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))),
),

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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'

View File

@@ -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) => {

View File

@@ -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);

View File

@@ -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'
/>
)}

View File

@@ -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) => {

View File

@@ -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;