diff --git a/app/actions/remote/user.ts b/app/actions/remote/user.ts index 25fcbe7ec..ea6db0e7a 100644 --- a/app/actions/remote/user.ts +++ b/app/actions/remote/user.ts @@ -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 { + 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 { try { const client = NetworkManager.getClient(serverUrl); diff --git a/app/components/custom_status/custom_status_expiry.tsx b/app/components/custom_status/custom_status_expiry.tsx index 9e5b784da..3d2c1ed79 100644 --- a/app/components/custom_status/custom_status_expiry.tsx +++ b/app/components/custom_status/custom_status_expiry.tsx @@ -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; diff --git a/app/components/post_list/post/body/add_members/add_members.tsx b/app/components/post_list/post/body/add_members/add_members.tsx index 34e30e895..0217af3e8 100644 --- a/app/components/post_list/post/body/add_members/add_members.tsx +++ b/app/components/post_list/post/body/add_members/add_members.tsx @@ -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) => { diff --git a/app/components/post_list/post/body/message/message.tsx b/app/components/post_list/post/body/message/message.tsx index 0ac282ab6..cfb8df411 100644 --- a/app/components/post_list/post/body/message/message.tsx +++ b/app/components/post_list/post/body/message/message.tsx @@ -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), []); diff --git a/app/components/post_list/post/header/header.tsx b/app/components/post_list/post/header/header.tsx index 1e54536f5..44ec84ba7 100644 --- a/app/components/post_list/post/header/header.tsx +++ b/app/components/post_list/post/header/header.tsx @@ -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) => { {Boolean(rootAuthorDisplayName) && location === CHANNEL && diff --git a/app/components/post_list/post/index.ts b/app/components/post_list/post/index.ts index b009456cb..f827d0924 100644 --- a/app/components/post_list/post/index.ts +++ b/app/components/post_list/post/index.ts @@ -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); diff --git a/app/components/post_list/post/post.tsx b/app/components/post_list/post/post.tsx index 9d4708b9a..476e12b87 100644 --- a/app/components/post_list/post/post.tsx +++ b/app/components/post_list/post/post.tsx @@ -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; diff --git a/app/components/system_header/index.tsx b/app/components/system_header/index.tsx index 53f16110c..07e25ff51 100644 --- a/app/components/system_header/index.tsx +++ b/app/components/system_header/index.tsx @@ -25,7 +25,7 @@ type Props = { isMilitaryTime: boolean; isTimezoneEnabled: boolean; theme: Theme; - user: UserModel; + user?: UserModel; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { diff --git a/app/products/calls/components/calls_custom_message/calls_custom_message.tsx b/app/products/calls/components/calls_custom_message/calls_custom_message.tsx index d2d50ee7c..7ddde2133 100644 --- a/app/products/calls/components/calls_custom_message/calls_custom_message.tsx +++ b/app/products/calls/components/calls_custom_message/calls_custom_message.tsx @@ -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; diff --git a/app/queries/servers/system.ts b/app/queries/servers/system.ts index 06a2e04ff..7e7babc35 100644 --- a/app/queries/servers/system.ts +++ b/app/queries/servers/system.ts @@ -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}); diff --git a/app/screens/channel_info/index.ts b/app/screens/channel_info/index.ts index f81155610..f0456e686 100644 --- a/app/screens/channel_info/index.ts +++ b/app/screens/channel_info/index.ts @@ -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(), diff --git a/app/screens/custom_status/custom_status.tsx b/app/screens/custom_status/custom_status.tsx index 0ca8ba7b1..5422c315d 100644 --- a/app/screens/custom_status/custom_status.tsx +++ b/app/screens/custom_status/custom_status.tsx @@ -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 && diff --git a/app/screens/custom_status_clear_after/components/clear_after_menu_item.tsx b/app/screens/custom_status_clear_after/components/clear_after_menu_item.tsx index 92c3eb8ae..0acce66b7 100644 --- a/app/screens/custom_status_clear_after/components/clear_after_menu_item.tsx +++ b/app/screens/custom_status_clear_after/components/clear_after_menu_item.tsx @@ -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 )} diff --git a/app/screens/custom_status_clear_after/index.tsx b/app/screens/custom_status_clear_after/index.tsx index e7b1232dd..1964fcd1c 100644 --- a/app/screens/custom_status_clear_after/index.tsx +++ b/app/screens/custom_status_clear_after/index.tsx @@ -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; diff --git a/app/screens/edit_profile/edit_profile.tsx b/app/screens/edit_profile/edit_profile.tsx index 6b3c5662e..7925b1de5 100644 --- a/app/screens/edit_profile/edit_profile.tsx +++ b/app/screens/edit_profile/edit_profile.tsx @@ -53,12 +53,12 @@ const EditProfile = ({ const scrollViewRef = useRef(); const hasUpdateUserInfo = useRef(false); const [userInfo, setUserInfo] = useState({ - 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(); @@ -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 ? ( + + {updating && } + {Boolean(error) && } + + + + + + ) : null; + return ( <> {isTablet && @@ -203,41 +244,7 @@ const EditProfile = ({ style={styles.flex} testID='edit_profile.screen' > - - {updating && } - {Boolean(error) && } - - - - - + {content} ); diff --git a/app/screens/home/account/account.tsx b/app/screens/home/account/account.tsx index e1f072694..7a58a8f97 100644 --- a/app/screens/home/account/account.tsx +++ b/app/screens/home/account/account.tsx @@ -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 ? ( + + + + + ) : null; + return ( - - - - + {content} {isTablet && diff --git a/app/screens/home/channel_list/channel_list.tsx b/app/screens/home/channel_list/channel_list.tsx index 5ae8a3824..6a6248d4f 100644 --- a/app/screens/home/channel_list/channel_list.tsx +++ b/app/screens/home/channel_list/channel_list.tsx @@ -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) { diff --git a/app/screens/home/channel_list/index.ts b/app/screens/home/channel_list/index.ts index c1372a1bc..d8cfa54e3 100644 --- a/app/screens/home/channel_list/index.ts +++ b/app/screens/home/channel_list/index.ts @@ -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(), + ), }; }); diff --git a/app/screens/home/recent_mentions/index.ts b/app/screens/home/recent_mentions/index.ts index 9c152ad0e..b0e96c0b9 100644 --- a/app/screens/home/recent_mentions/index.ts +++ b/app/screens/home/recent_mentions/index.ts @@ -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))), diff --git a/app/screens/home/saved_messages/index.ts b/app/screens/home/saved_messages/index.ts index 31da6f722..c7f344369 100644 --- a/app/screens/home/saved_messages/index.ts +++ b/app/screens/home/saved_messages/index.ts @@ -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))), ), diff --git a/app/screens/home/tab_bar/account.tsx b/app/screens/home/tab_bar/account.tsx index b9bd4fb9c..ba4595297 100644 --- a/app/screens/home/tab_bar/account.tsx +++ b/app/screens/home/tab_bar/account.tsx @@ -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; } diff --git a/app/screens/settings/display/display.tsx b/app/screens/settings/display/display.tsx index 601ed48eb..7bb9e2246 100644 --- a/app/screens/settings/display/display.tsx +++ b/app/screens/settings/display/display.tsx @@ -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; diff --git a/app/screens/settings/display_timezone/display_timezone.tsx b/app/screens/settings/display_timezone/display_timezone.tsx index 40d0ef092..39edf2917 100644 --- a/app/screens/settings/display_timezone/display_timezone.tsx +++ b/app/screens/settings/display_timezone/display_timezone.tsx @@ -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); diff --git a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx index a5de314d1..eda42012b 100644 --- a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx +++ b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx @@ -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(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); diff --git a/app/screens/settings/notification_email/notification_email.tsx b/app/screens/settings/notification_email/notification_email.tsx index b60027138..cc15ad9d5 100644 --- a/app/screens/settings/notification_email/notification_email.tsx +++ b/app/screens/settings/notification_email/notification_email.tsx @@ -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); diff --git a/app/screens/settings/notification_mention/mention_settings.tsx b/app/screens/settings/notification_mention/mention_settings.tsx index 02b33b020..bd951c269 100644 --- a/app/screens/settings/notification_mention/mention_settings.tsx +++ b/app/screens/settings/notification_mention/mention_settings.tsx @@ -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 { diff --git a/app/screens/settings/notification_push/notification_push.tsx b/app/screens/settings/notification_push/notification_push.tsx index 8d4a240b7..beeae314d 100644 --- a/app/screens/settings/notification_push/notification_push.tsx +++ b/app/screens/settings/notification_push/notification_push.tsx @@ -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(notifyProps.push); const [pushStatus, setPushStatus] = useState(notifyProps.push_status); diff --git a/app/screens/settings/notifications/notifications.tsx b/app/screens/settings/notifications/notifications.tsx index 7ceaaabf8..85d1faadb 100644 --- a/app/screens/settings/notifications/notifications.tsx +++ b/app/screens/settings/notifications/notifications.tsx @@ -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 = ({ )} diff --git a/app/utils/user/index.ts b/app/utils/user/index.ts index 9cd8896fb..496bfa0e6 100644 --- a/app/utils/user/index.ts +++ b/app/utils/user/index.ts @@ -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) => { diff --git a/types/screens/edit_profile.ts b/types/screens/edit_profile.ts index 08c61f72a..502c20fa8 100644 --- a/types/screens/edit_profile.ts +++ b/types/screens/edit_profile.ts @@ -18,7 +18,7 @@ export interface UserInfo extends Record