diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 85744329d487..0d22d3714fe6 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -630,6 +630,8 @@ type OnyxValuesMapping = { [ONYXKEYS.BETAS]: OnyxTypes.Beta[]; [ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf; [ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE]: OnyxTypes.BlockedFromConcierge; + + // The value of this nvp is a string representation of the date when the block expires, or an empty string if the user is not blocked [ONYXKEYS.NVP_BLOCKED_FROM_CHAT]: string; [ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string; [ONYXKEYS.NVP_TRY_FOCUS_MODE]: boolean; diff --git a/src/pages/home/report/ReportFooter.tsx b/src/pages/home/report/ReportFooter.tsx index aa4139f8ee50..3bb6693934b4 100644 --- a/src/pages/home/report/ReportFooter.tsx +++ b/src/pages/home/report/ReportFooter.tsx @@ -1,7 +1,7 @@ import lodashIsEqual from 'lodash/isEqual'; import React, {memo, useCallback} from 'react'; import {Keyboard, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import AnonymousReportFooter from '@components/AnonymousReportFooter'; import ArchivedReportFooter from '@components/ArchivedReportFooter'; @@ -15,6 +15,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import Log from '@libs/Log'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as UserUtils from '@libs/UserUtils'; @@ -29,18 +30,7 @@ import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ReportActionCompose from './ReportActionCompose/ReportActionCompose'; import SystemChatReportFooterMessage from './SystemChatReportFooterMessage'; -type ReportFooterOnyxProps = { - /** Whether to show the compose input */ - shouldShowComposeInput: OnyxEntry; - - /** Session info for the currently logged in user. */ - session: OnyxEntry; - - /** Whether user is blocked from chat. */ - blockedFromChat: OnyxEntry; -}; - -type ReportFooterProps = ReportFooterOnyxProps & { +type ReportFooterProps = { /** Report object for the current report */ report?: OnyxTypes.Report; @@ -79,17 +69,14 @@ type ReportFooterProps = ReportFooterOnyxProps & { function ReportFooter({ lastReportAction, pendingAction, - session, report = {reportID: '0'}, reportMetadata, reportNameValuePairs, policy, - shouldShowComposeInput = false, isEmptyChat = true, isReportReadyForDisplay = true, listHeight = 0, isComposerFullSize = false, - blockedFromChat, onComposerBlur, onComposerFocus, }: ReportFooterProps) { @@ -97,15 +84,32 @@ function ReportFooter({ const {isOffline} = useNetwork(); const {translate} = useLocalize(); const {windowWidth, isSmallScreenWidth} = useWindowDimensions(); + + const [shouldShowComposeInput] = useOnyx(ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, {initialValue: false}); + const [isAnonymousUser] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.authTokenType === CONST.AUTH_TOKEN_TYPES.ANONYMOUS}); + const [isBlockedFromChat] = useOnyx(ONYXKEYS.NVP_BLOCKED_FROM_CHAT, { + selector: (dateString) => { + if (!dateString) { + return false; + } + try { + return new Date(dateString) >= new Date(); + } catch (error) { + // If the NVP is malformed, we'll assume the user is not blocked from chat. This is not expected, so if it happens we'll log an alert. + Log.alert(`[${CONST.ERROR.ENSURE_BUGBOT}] Found malformed ${ONYXKEYS.NVP_BLOCKED_FROM_CHAT} nvp`, dateString); + return false; + } + }, + }); + const chatFooterStyles = {...styles.chatFooter, minHeight: !isOffline ? CONST.CHAT_FOOTER_MIN_HEIGHT : 0}; const isArchivedRoom = ReportUtils.isArchivedRoom(report, reportNameValuePairs); - const isAnonymousUser = session?.authTokenType === CONST.AUTH_TOKEN_TYPES.ANONYMOUS; const isSmallSizeLayout = windowWidth - (isSmallScreenWidth ? 0 : variables.sideBarWidth) < variables.anonymousReportFooterBreakpoint; // If a user just signed in and is viewing a public report, optimistically show the composer while loading the report, since they will have write access when the response comes back. - const showComposerOptimistically = !isAnonymousUser && ReportUtils.isPublicRoom(report) && reportMetadata?.isLoadingInitialReportActions; - const hideComposer = (!ReportUtils.canUserPerformWriteAction(report, reportNameValuePairs) && !showComposerOptimistically) || blockedFromChat; + const shouldShowComposerOptimistically = !isAnonymousUser && ReportUtils.isPublicRoom(report) && !!reportMetadata?.isLoadingInitialReportActions; + const shouldHideComposer = (!ReportUtils.canUserPerformWriteAction(report, reportNameValuePairs) && !shouldShowComposerOptimistically) || isBlockedFromChat; const canWriteInReport = ReportUtils.canWriteInReport(report); const isSystemChat = ReportUtils.isSystemChat(report); const isAdminsOnlyPostingRoom = ReportUtils.isAdminsOnlyPostingRoom(report); @@ -166,7 +170,7 @@ function ReportFooter({ return ( <> - {hideComposer && ( + {shouldHideComposer && ( )} {isArchivedRoom && } - {!isArchivedRoom && blockedFromChat && } + {!isArchivedRoom && isBlockedFromChat && } {!isAnonymousUser && !canWriteInReport && isSystemChat && } - {isAdminsOnlyPostingRoom && !isUserPolicyAdmin && !isArchivedRoom && !isAnonymousUser && !blockedFromChat && ( + {isAdminsOnlyPostingRoom && !isUserPolicyAdmin && !isArchivedRoom && !isAnonymousUser && !isBlockedFromChat && ( )} - {!isSmallScreenWidth && {hideComposer && }} + {!isSmallScreenWidth && ( + {shouldHideComposer && } + )} )} - {!hideComposer && (!!shouldShowComposeInput || !isSmallScreenWidth) && ( + {!shouldHideComposer && (shouldShowComposeInput || !isSmallScreenWidth) && ( ({ - shouldShowComposeInput: { - key: ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, - initialValue: false, - }, - session: { - key: ONYXKEYS.SESSION, - }, - blockedFromChat: { - key: ONYXKEYS.NVP_BLOCKED_FROM_CHAT, - }, -})( - memo( - ReportFooter, - (prevProps, nextProps) => - lodashIsEqual(prevProps.report, nextProps.report) && - prevProps.pendingAction === nextProps.pendingAction && - prevProps.listHeight === nextProps.listHeight && - prevProps.isComposerFullSize === nextProps.isComposerFullSize && - prevProps.isEmptyChat === nextProps.isEmptyChat && - prevProps.lastReportAction === nextProps.lastReportAction && - prevProps.shouldShowComposeInput === nextProps.shouldShowComposeInput && - prevProps.isReportReadyForDisplay === nextProps.isReportReadyForDisplay && - lodashIsEqual(prevProps.session, nextProps.session) && - lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata), - ), +export default memo( + ReportFooter, + (prevProps, nextProps) => + lodashIsEqual(prevProps.report, nextProps.report) && + prevProps.pendingAction === nextProps.pendingAction && + prevProps.listHeight === nextProps.listHeight && + prevProps.isComposerFullSize === nextProps.isComposerFullSize && + prevProps.isEmptyChat === nextProps.isEmptyChat && + prevProps.lastReportAction === nextProps.lastReportAction && + prevProps.isReportReadyForDisplay === nextProps.isReportReadyForDisplay && + lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata), );