Skip to content

Commit

Permalink
Merge pull request #56452 from nkdengineer/fix/55990
Browse files Browse the repository at this point in the history
fix: New message marker is not displayed when the chat opened offline
  • Loading branch information
francoisl authored Feb 11, 2025
2 parents 63f03d2 + c265fed commit 70bd937
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 19 deletions.
6 changes: 3 additions & 3 deletions src/hooks/useNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ type UseNetworkProps = {
onReconnect?: () => void;
};

type UseNetwork = {isOffline: boolean};
type UseNetwork = {isOffline: boolean; lastOfflineAt?: Date};

export default function useNetwork({onReconnect = () => {}}: UseNetworkProps = {}): UseNetwork {
const callback = useRef(onReconnect);
// eslint-disable-next-line react-compiler/react-compiler
callback.current = onReconnect;

const {isOffline, networkStatus} = useContext(NetworkContext) ?? {...CONST.DEFAULT_NETWORK_DATA, networkStatus: CONST.NETWORK.NETWORK_STATUS.UNKNOWN};
const {isOffline, networkStatus, lastOfflineAt} = useContext(NetworkContext) ?? {...CONST.DEFAULT_NETWORK_DATA, networkStatus: CONST.NETWORK.NETWORK_STATUS.UNKNOWN};
const prevOfflineStatusRef = useRef(isOffline);
useEffect(() => {
// If we were offline before and now we are not offline then we just reconnected
Expand All @@ -31,5 +31,5 @@ export default function useNetwork({onReconnect = () => {}}: UseNetworkProps = {
}, [isOffline]);

// If the network status is undefined, we don't treat it as offline. Otherwise, we utilize the isOffline prop.
return {isOffline: networkStatus === CONST.NETWORK.NETWORK_STATUS.UNKNOWN ? false : isOffline};
return {isOffline: networkStatus === CONST.NETWORK.NETWORK_STATUS.UNKNOWN ? false : isOffline, lastOfflineAt};
}
15 changes: 10 additions & 5 deletions src/hooks/useNetworkWithOfflineStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,31 @@ import {useEffect, useRef} from 'react';
import DateUtils from '@libs/DateUtils';
import useLocalize from './useLocalize';
import useNetwork from './useNetwork';
import usePrevious from './usePrevious';

type UseNetworkWithOfflineStatus = {isOffline: boolean; lastOfflineAt: MutableRefObject<Date | undefined>; lastOnlineAt: MutableRefObject<Date | undefined>};

export default function useNetworkWithOfflineStatus(): UseNetworkWithOfflineStatus {
const {isOffline} = useNetwork();
const {isOffline, lastOfflineAt: lastOfflineAtFromOnyx} = useNetwork();
const prevIsOffline = usePrevious(isOffline);
const {preferredLocale} = useLocalize();

// The last time/date the user went/was offline. If the user was never offline, it is set to undefined.
const lastOfflineAt = useRef(isOffline ? DateUtils.getLocalDateFromDatetime(preferredLocale) : undefined);
const lastOfflineAt = useRef(isOffline ? lastOfflineAtFromOnyx : undefined);

// The last time/date the user went/was online. If the user was never online, it is set to undefined.
const lastOnlineAt = useRef(isOffline ? undefined : DateUtils.getLocalDateFromDatetime(preferredLocale));

useEffect(() => {
if (isOffline) {
// If the user has just gone offline (was online before but is now offline), update `lastOfflineAt` with the current local date/time.
if (isOffline && !prevIsOffline) {
lastOfflineAt.current = DateUtils.getLocalDateFromDatetime(preferredLocale);
} else {
}
// If the user has just come back online (was offline before but is now online), update `lastOnlineAt` with the current local date/time.
if (!isOffline && prevIsOffline) {
lastOnlineAt.current = DateUtils.getLocalDateFromDatetime(preferredLocale);
}
}, [isOffline, preferredLocale]);
}, [isOffline, preferredLocale, prevIsOffline]);

return {isOffline, lastOfflineAt, lastOnlineAt};
}
30 changes: 30 additions & 0 deletions src/libs/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import {timezoneBackwardMap} from '@src/TIMEZONES';
import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails';
import {setCurrentDate} from './actions/CurrentDate';
import {setNetworkLastOffline} from './actions/Network';
import {translate, translateLocal} from './Localize';
import Log from './Log';

Expand Down Expand Up @@ -88,6 +89,35 @@ Onyx.connect({
callback: (value) => (networkTimeSkew = value?.timeSkew ?? 0),
});

let isOffline: boolean | undefined;

let preferredLocaleFromOnyx: Locale;

Onyx.connect({
key: ONYXKEYS.NVP_PREFERRED_LOCALE,
callback: (value) => {
if (!value) {
return;
}
preferredLocaleFromOnyx = value;
},
});

Onyx.connect({
key: ONYXKEYS.NETWORK,
callback: (val) => {
if (!val?.lastOfflineAt) {
setNetworkLastOffline(getLocalDateFromDatetime(preferredLocaleFromOnyx));
}

const newIsOffline = val?.isOffline ?? val?.shouldForceOffline;
if (newIsOffline && isOffline === false) {
setNetworkLastOffline(getLocalDateFromDatetime(preferredLocaleFromOnyx));
}
isOffline = newIsOffline;
},
});

function isDate(arg: unknown): arg is Date {
return Object.prototype.toString.call(arg) === '[object Date]';
}
Expand Down
9 changes: 2 additions & 7 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1900,13 +1900,8 @@ function getReportActionsLength() {
}

function wasActionCreatedWhileOffline(action: ReportAction, isOffline: boolean, lastOfflineAt: Date | undefined, lastOnlineAt: Date | undefined, locale: Locale): boolean {
// The user was never online.
if (!lastOnlineAt) {
return true;
}

// The user never was never offline.
if (!lastOfflineAt) {
// The user has never gone offline or never come back online
if (!lastOfflineAt || !lastOnlineAt) {
return false;
}

Expand Down
22 changes: 18 additions & 4 deletions src/libs/actions/Network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import type {NetworkStatus} from '@libs/NetworkConnection';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ConnectionChanges} from '@src/types/onyx/Network';

function setIsOffline(isOffline: boolean, reason = '') {
function setNetworkLastOffline(lastOfflineAt: Date) {
Onyx.merge(ONYXKEYS.NETWORK, {lastOfflineAt});
}

function setIsOffline(isNetworkOffline: boolean, reason = '') {
if (reason) {
let textToLog = '[Network] Client is';
textToLog += isOffline ? ' entering offline mode' : ' back online';
textToLog += isNetworkOffline ? ' entering offline mode' : ' back online';
textToLog += ` because: ${reason}`;
Log.info(textToLog);
}
Onyx.merge(ONYXKEYS.NETWORK, {isOffline});
Onyx.merge(ONYXKEYS.NETWORK, {isOffline: isNetworkOffline});
}

function setNetWorkStatus(status: NetworkStatus) {
Expand Down Expand Up @@ -50,4 +54,14 @@ function setConnectionChanges(connectionChanges: ConnectionChanges) {
Onyx.merge(ONYXKEYS.NETWORK, {connectionChanges});
}

export {setIsOffline, setShouldForceOffline, setConnectionChanges, setShouldSimulatePoorConnection, setPoorConnectionTimeoutID, setShouldFailAllRequests, setTimeSkew, setNetWorkStatus};
export {
setIsOffline,
setShouldForceOffline,
setConnectionChanges,
setShouldSimulatePoorConnection,
setPoorConnectionTimeoutID,
setShouldFailAllRequests,
setTimeSkew,
setNetWorkStatus,
setNetworkLastOffline,
};
3 changes: 3 additions & 0 deletions src/types/onyx/Network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type Network = {

/** The network's status */
networkStatus?: NetworkStatus;

/** The time when network change from online to offline */
lastOfflineAt?: Date;
};

export default Network;
Expand Down

0 comments on commit 70bd937

Please sign in to comment.