Skip to content

Commit 8faabff

Browse files
authored
Merge pull request Expensify#68621 from DylanDylann/r-efactor-104
Remove Onyx.connect() for the key: ONYXKEYS.PERSONAL_DETAILS_LIST in src/libs/DateUtils.ts
2 parents 6a6685c + 791fe80 commit 8faabff

21 files changed

Lines changed: 154 additions & 156 deletions

src/components/LocaleContextProvider.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,20 @@ function LocaleContextProvider({children}: LocaleContextProviderProps) {
138138
const numberFormat = useMemo<LocaleContextProps['numberFormat']>(() => (number, options) => format(currentLocale, number, options), [currentLocale]);
139139

140140
const getLocalDateFromDatetime = useMemo<LocaleContextProps['getLocalDateFromDatetime']>(
141-
() => (datetime, currentSelectedTimezone) => DateUtils.getLocalDateFromDatetime(currentLocale, datetime, currentSelectedTimezone ?? selectedTimezone),
141+
() => (datetime, currentSelectedTimezone) =>
142+
DateUtils.getLocalDateFromDatetime(currentLocale, currentSelectedTimezone ?? selectedTimezone ?? CONST.DEFAULT_TIME_ZONE.selected, datetime),
142143
[currentLocale, selectedTimezone],
143144
);
144145

145-
const datetimeToRelative = useMemo<LocaleContextProps['datetimeToRelative']>(() => (datetime) => DateUtils.datetimeToRelative(currentLocale, datetime), [currentLocale]);
146+
const datetimeToRelative = useMemo<LocaleContextProps['datetimeToRelative']>(
147+
() => (datetime) => DateUtils.datetimeToRelative(currentLocale, datetime, selectedTimezone ?? CONST.DEFAULT_TIME_ZONE.selected),
148+
[currentLocale, selectedTimezone],
149+
);
146150

147151
const datetimeToCalendarTime = useMemo<LocaleContextProps['datetimeToCalendarTime']>(
148152
() =>
149153
(datetime, includeTimezone, isLowercase = false) =>
150-
DateUtils.datetimeToCalendarTime(currentLocale, datetime, includeTimezone, selectedTimezone, isLowercase),
154+
DateUtils.datetimeToCalendarTime(currentLocale, datetime, selectedTimezone ?? CONST.DEFAULT_TIME_ZONE.selected, includeTimezone, isLowercase),
151155
[currentLocale, selectedTimezone],
152156
);
153157

src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ function MoneyRequestReportActionsList({
123123
showReportActionsLoadingState,
124124
}: MoneyRequestReportListProps) {
125125
const styles = useThemeStyles();
126-
const {translate} = useLocalize();
127-
const {preferredLocale} = useLocalize();
126+
const {translate, getLocalDateFromDatetime} = useLocalize();
128127
const {isOffline, lastOfflineAt, lastOnlineAt} = useNetworkWithOfflineStatus();
129128
const reportScrollManager = useReportScrollManager();
130129
const lastMessageTime = useRef<string | null>(null);
@@ -358,12 +357,12 @@ function MoneyRequestReportActionsList({
358357
*/
359358
const earliestReceivedOfflineMessageIndex = useMemo(() => {
360359
const lastIndex = reportActions.findLastIndex((action) => {
361-
return wasMessageReceivedWhileOffline(action, isOffline, lastOfflineAt.current, lastOnlineAt.current, preferredLocale);
360+
return wasMessageReceivedWhileOffline(action, isOffline, lastOfflineAt.current, lastOnlineAt.current, getLocalDateFromDatetime);
362361
});
363362

364363
// The last index in the list is the earliest message that was received while offline
365364
return lastIndex > -1 ? lastIndex : undefined;
366-
}, [isOffline, lastOfflineAt, lastOnlineAt, preferredLocale, reportActions]);
365+
}, [getLocalDateFromDatetime, isOffline, lastOfflineAt, lastOnlineAt, reportActions]);
367366

368367
/**
369368
* The reportActionID the unread marker should display above

src/hooks/useNetwork.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ type UseNetworkProps = {
77
onReconnect?: () => void;
88
};
99

10-
type UseNetwork = {isOffline: boolean; lastOfflineAt?: Date};
10+
type UseNetwork = {isOffline: boolean; lastOfflineAt?: string};
1111

1212
export default function useNetwork({onReconnect = () => {}}: UseNetworkProps = {}): UseNetwork {
1313
const callback = useRef(onReconnect);

src/hooks/useNetworkWithOfflineStatus.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import type {MutableRefObject} from 'react';
1+
import type {RefObject} from 'react';
22
import {useEffect, useRef} from 'react';
33
import useLocalize from './useLocalize';
44
import useNetwork from './useNetwork';
55
import usePrevious from './usePrevious';
66

7-
type UseNetworkWithOfflineStatus = {isOffline: boolean; lastOfflineAt: MutableRefObject<Date | undefined>; lastOnlineAt: MutableRefObject<Date | undefined>};
7+
type UseNetworkWithOfflineStatus = {isOffline: boolean; lastOfflineAt: RefObject<Date | undefined>; lastOnlineAt: RefObject<Date | undefined>};
88

99
export default function useNetworkWithOfflineStatus(): UseNetworkWithOfflineStatus {
1010
const {isOffline, lastOfflineAt: lastOfflineAtFromOnyx} = useNetwork();
1111
const prevIsOffline = usePrevious(isOffline);
1212
const {getLocalDateFromDatetime} = useLocalize();
1313

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

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

src/libs/DateUtils.ts

Lines changed: 11 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import Onyx from 'react-native-onyx';
3636
import type {ValueOf} from 'type-fest';
3737
import type {LocaleContextProps} from '@components/LocaleContextProvider';
3838
import CONST from '@src/CONST';
39-
import IntlStore from '@src/languages/IntlStore';
4039
import ONYXKEYS from '@src/ONYXKEYS';
4140
import {timezoneBackwardToNewMap, timezoneNewToBackwardMap} from '@src/TIMEZONES';
4241
import type Locale from '@src/types/onyx/Locale';
@@ -51,37 +50,6 @@ type CustomStatusTypes = ValueOf<typeof CONST.CUSTOM_STATUS_TYPES>;
5150
type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6;
5251

5352
const TIMEZONE_UPDATE_THROTTLE_MINUTES = 5;
54-
55-
let currentUserAccountID: number | undefined;
56-
Onyx.connect({
57-
key: ONYXKEYS.SESSION,
58-
callback: (val) => {
59-
// When signed out, val is undefined
60-
if (!val) {
61-
return;
62-
}
63-
64-
currentUserAccountID = val.accountID;
65-
},
66-
});
67-
68-
let timezone: Required<Timezone> = CONST.DEFAULT_TIME_ZONE;
69-
Onyx.connect({
70-
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
71-
callback: (value) => {
72-
if (!currentUserAccountID) {
73-
return;
74-
}
75-
76-
const personalDetailsTimezone = value?.[currentUserAccountID]?.timezone;
77-
78-
timezone = {
79-
selected: personalDetailsTimezone?.selected ?? CONST.DEFAULT_TIME_ZONE.selected,
80-
automatic: personalDetailsTimezone?.automatic ?? CONST.DEFAULT_TIME_ZONE.automatic,
81-
};
82-
},
83-
});
84-
8553
let networkTimeSkew = 0;
8654
let isOffline: boolean | undefined;
8755

@@ -90,12 +58,12 @@ Onyx.connect({
9058
callback: (val) => {
9159
networkTimeSkew = val?.timeSkew ?? 0;
9260
if (!val?.lastOfflineAt) {
93-
setNetworkLastOffline(getLocalDateFromDatetime(IntlStore.getCurrentLocale()));
61+
setNetworkLastOffline(new Date().toISOString());
9462
}
9563

9664
const newIsOffline = val?.isOffline ?? val?.shouldForceOffline;
9765
if (newIsOffline && isOffline === false) {
98-
setNetworkLastOffline(getLocalDateFromDatetime(IntlStore.getCurrentLocale()));
66+
setNetworkLastOffline(new Date().toISOString());
9967
}
10068
isOffline = newIsOffline;
10169
},
@@ -126,7 +94,7 @@ function getWeekEndsOn(): WeekDay {
12694
* Date object for the given ISO-formatted datetime string
12795
*/
12896
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
129-
function getLocalDateFromDatetime(locale: Locale | undefined, datetime?: string, currentSelectedTimezone: string | SelectedTimezone = timezone.selected): Date {
97+
function getLocalDateFromDatetime(locale: Locale | undefined, currentSelectedTimezone: string | SelectedTimezone, datetime?: string): Date {
13098
if (!datetime) {
13199
const res = toZonedTime(new Date(), currentSelectedTimezone);
132100
if (Number.isNaN(res.getTime())) {
@@ -216,14 +184,8 @@ const fallbackToSupportedTimezone = memoize((timezoneInput: SelectedTimezone): S
216184
* Jan 20 at 5:30 PM within the past year
217185
* Jan 20, 2019 at 5:30 PM anything over 1 year ago
218186
*/
219-
function datetimeToCalendarTime(
220-
locale: Locale | undefined,
221-
datetime: string,
222-
includeTimeZone = false,
223-
currentSelectedTimezone: SelectedTimezone = timezone.selected,
224-
isLowercase = false,
225-
): string {
226-
const date = getLocalDateFromDatetime(locale, datetime, fallbackToSupportedTimezone(currentSelectedTimezone));
187+
function datetimeToCalendarTime(locale: Locale | undefined, datetime: string, currentSelectedTimezone: SelectedTimezone, includeTimeZone = false, isLowercase = false): string {
188+
const date = getLocalDateFromDatetime(locale, fallbackToSupportedTimezone(currentSelectedTimezone), datetime);
227189
const tz = includeTimeZone ? ' [UTC]Z' : '';
228190
let todayAt = translate(locale, 'common.todayAt');
229191
let tomorrowAt = translate(locale, 'common.tomorrowAt');
@@ -268,9 +230,9 @@ function datetimeToCalendarTime(
268230
* Jan 20 within the past year
269231
* Jan 20, 2019 anything over 1 year
270232
*/
271-
function datetimeToRelative(locale: Locale | undefined, datetime: string): string {
272-
const date = getLocalDateFromDatetime(locale, datetime);
273-
const now = getLocalDateFromDatetime(locale);
233+
function datetimeToRelative(locale: Locale | undefined, datetime: string, currentSelectedTimezone: SelectedTimezone): string {
234+
const date = getLocalDateFromDatetime(locale, currentSelectedTimezone, datetime);
235+
const now = getLocalDateFromDatetime(locale, currentSelectedTimezone);
274236
return formatDistance(date, now, {addSuffix: true});
275237
}
276238

@@ -338,12 +300,12 @@ function startCurrentDateUpdater() {
338300
});
339301
}
340302

341-
function getCurrentTimezone(): Required<Timezone> {
303+
function getCurrentTimezone(timezone: Timezone): Required<Timezone> {
342304
const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
343305
if (timezone.automatic && timezone.selected !== currentTimezone) {
344-
return {...timezone, selected: currentTimezone as SelectedTimezone};
306+
return {...timezone, selected: currentTimezone as SelectedTimezone, automatic: timezone.automatic ?? false};
345307
}
346-
return timezone;
308+
return {selected: timezone.selected ?? (CONST.DEFAULT_TIME_ZONE.selected as SelectedTimezone), automatic: timezone.automatic ?? false};
347309
}
348310

349311
/**

src/libs/ReportActionsUtils.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import isEmpty from 'lodash/isEmpty';
66
import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
77
import Onyx from 'react-native-onyx';
88
import type {ValueOf} from 'type-fest';
9+
import type {LocaleContextProps} from '@components/LocaleContextProvider';
910
import usePrevious from '@hooks/usePrevious';
1011
import CONST from '@src/CONST';
1112
import IntlStore from '@src/languages/IntlStore';
1213
import type {TranslationPaths} from '@src/languages/types';
1314
import ONYXKEYS from '@src/ONYXKEYS';
1415
import ROUTES from '@src/ROUTES';
15-
import type {Card, Locale, OnyxInputOrEntry, OriginalMessageIOU, Policy, PrivatePersonalDetails} from '@src/types/onyx';
16+
import type {Card, OnyxInputOrEntry, OriginalMessageIOU, Policy, PrivatePersonalDetails} from '@src/types/onyx';
1617
import type {JoinWorkspaceResolution, OriginalMessageChangeLog, OriginalMessageExportIntegration} from '@src/types/onyx/OriginalMessage';
1718
import type {PolicyReportFieldType} from '@src/types/onyx/Policy';
1819
import type Report from '@src/types/onyx/Report';
@@ -21,7 +22,6 @@ import type {Message, OldDotReportAction, OriginalMessage, ReportActions} from '
2122
import type ReportActionName from '@src/types/onyx/ReportActionName';
2223
import {isEmptyObject} from '@src/types/utils/EmptyObject';
2324
import {convertAmountToDisplayString, convertToDisplayString, convertToShortDisplayString} from './CurrencyUtils';
24-
import DateUtils from './DateUtils';
2525
import {getEnvironmentURL, getOldDotEnvironmentURL} from './Environment/Environment';
2626
import getBase62ReportID from './getBase62ReportID';
2727
import {isReportMessageAttachment} from './isReportMessageAttachment';
@@ -3003,13 +3003,19 @@ function getReportActions(report: Report) {
30033003
/**
30043004
* @private
30053005
*/
3006-
function wasActionCreatedWhileOffline(action: ReportAction, isOffline: boolean, lastOfflineAt: Date | undefined, lastOnlineAt: Date | undefined, locale: Locale): boolean {
3006+
function wasActionCreatedWhileOffline(
3007+
action: ReportAction,
3008+
isOffline: boolean,
3009+
lastOfflineAt: Date | undefined,
3010+
lastOnlineAt: Date | undefined,
3011+
getLocalDateFromDatetime: LocaleContextProps['getLocalDateFromDatetime'],
3012+
): boolean {
30073013
// The user has never gone offline or never come back online
30083014
if (!lastOfflineAt || !lastOnlineAt) {
30093015
return false;
30103016
}
30113017

3012-
const actionCreatedAt = DateUtils.getLocalDateFromDatetime(locale, action.created);
3018+
const actionCreatedAt = getLocalDateFromDatetime(action.created);
30133019

30143020
// The action was created before the user went offline.
30153021
if (actionCreatedAt <= lastOfflineAt) {
@@ -3028,9 +3034,15 @@ function wasActionCreatedWhileOffline(action: ReportAction, isOffline: boolean,
30283034
/**
30293035
* Whether a message is NOT from the active user, and it was received while the user was offline.
30303036
*/
3031-
function wasMessageReceivedWhileOffline(action: ReportAction, isOffline: boolean, lastOfflineAt: Date | undefined, lastOnlineAt: Date | undefined, locale: Locale = CONST.LOCALES.DEFAULT) {
3037+
function wasMessageReceivedWhileOffline(
3038+
action: ReportAction,
3039+
isOffline: boolean,
3040+
lastOfflineAt: Date | undefined,
3041+
lastOnlineAt: Date | undefined,
3042+
getLocalDateFromDatetime: LocaleContextProps['getLocalDateFromDatetime'],
3043+
) {
30323044
const wasByCurrentUser = wasActionTakenByCurrentUser(action);
3033-
const wasCreatedOffline = wasActionCreatedWhileOffline(action, isOffline, lastOfflineAt, lastOnlineAt, locale);
3045+
const wasCreatedOffline = wasActionCreatedWhileOffline(action, isOffline, lastOfflineAt, lastOnlineAt, getLocalDateFromDatetime);
30343046

30353047
return !wasByCurrentUser && wasCreatedOffline && !(action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD || action.isOptimisticAction);
30363048
}

src/libs/actions/Network.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type {NetworkStatus} from '@libs/NetworkConnection';
44
import ONYXKEYS from '@src/ONYXKEYS';
55
import type {ConnectionChanges} from '@src/types/onyx/Network';
66

7-
function setNetworkLastOffline(lastOfflineAt: Date) {
7+
function setNetworkLastOffline(lastOfflineAt: string) {
88
Onyx.merge(ONYXKEYS.NETWORK, {lastOfflineAt});
99
}
1010

src/libs/actions/Report.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ import type {
204204
TransactionViolations,
205205
} from '@src/types/onyx';
206206
import type {Decision} from '@src/types/onyx/OriginalMessage';
207+
import type {Timezone} from '@src/types/onyx/PersonalDetails';
207208
import type {ConnectionName} from '@src/types/onyx/Policy';
208209
import type {NotificationPreference, Participants, Participant as ReportParticipant, RoomVisibility, WriteCapability} from '@src/types/onyx/Report';
209210
import type {Message, ReportActions} from '@src/types/onyx/ReportAction';
@@ -667,7 +668,7 @@ function notifyNewAction(reportID: string | undefined, accountID: number | undef
667668
* - Adding one attachment
668669
* - Add both a comment and attachment simultaneously
669670
*/
670-
function addActions(reportID: string, text = '', file?: FileObject) {
671+
function addActions(reportID: string, timezoneParam: Timezone, text = '', file?: FileObject) {
671672
let reportCommentText = '';
672673
let reportCommentAction: OptimisticAddCommentReportAction | undefined;
673674
let attachmentAction: OptimisticAddCommentReportAction | undefined;
@@ -818,7 +819,7 @@ function addActions(reportID: string, text = '', file?: FileObject) {
818819

819820
// Update the timezone if it's been 5 minutes from the last time the user added a comment
820821
if (DateUtils.canUpdateTimezone() && currentUserAccountID) {
821-
const timezone = DateUtils.getCurrentTimezone();
822+
const timezone = DateUtils.getCurrentTimezone(timezoneParam);
822823
parameters.timezone = JSON.stringify(timezone);
823824
optimisticData.push({
824825
onyxMethod: Onyx.METHOD.MERGE,
@@ -837,19 +838,19 @@ function addActions(reportID: string, text = '', file?: FileObject) {
837838
}
838839

839840
/** Add an attachment and optional comment. */
840-
function addAttachment(reportID: string, file: FileObject, text = '', shouldPlaySound?: boolean) {
841+
function addAttachment(reportID: string, file: FileObject, timezoneParam: Timezone, text = '', shouldPlaySound?: boolean) {
841842
if (shouldPlaySound) {
842843
playSound(SOUNDS.DONE);
843844
}
844-
addActions(reportID, text, file);
845+
addActions(reportID, timezoneParam, text, file);
845846
}
846847

847848
/** Add a single comment to a report */
848-
function addComment(reportID: string, text: string, shouldPlaySound?: boolean) {
849+
function addComment(reportID: string, text: string, timezoneParam: Timezone, shouldPlaySound?: boolean) {
849850
if (shouldPlaySound) {
850851
playSound(SOUNDS.DONE);
851852
}
852-
addActions(reportID, text);
853+
addActions(reportID, timezoneParam, text);
853854
}
854855

855856
function reportActionsExist(reportID: string): boolean {
@@ -6035,12 +6036,18 @@ function changeReportPolicyAndInviteSubmitter(
60356036
* @param reportActionID - The specific report action ID to update
60366037
* @param selectedCategory - The category selected by the user
60376038
*/
6038-
function resolveConciergeCategoryOptions(reportID: string | undefined, actionReportID: string | undefined, reportActionID: string | undefined, selectedCategory: string) {
6039+
function resolveConciergeCategoryOptions(
6040+
reportID: string | undefined,
6041+
actionReportID: string | undefined,
6042+
reportActionID: string | undefined,
6043+
selectedCategory: string,
6044+
timezoneParam: Timezone,
6045+
) {
60396046
if (!reportID || !actionReportID || !reportActionID) {
60406047
return;
60416048
}
60426049

6043-
addComment(reportID, selectedCategory);
6050+
addComment(reportID, selectedCategory, timezoneParam);
60446051

60456052
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${actionReportID}`, {
60466053
[reportActionID]: {

src/pages/Share/ShareDetailsPage.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
1313
import ScrollView from '@components/ScrollView';
1414
import Text from '@components/Text';
1515
import TextInput from '@components/TextInput';
16+
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
1617
import useLocalize from '@hooks/useLocalize';
1718
import useOnyx from '@hooks/useOnyx';
1819
import useThemeStyles from '@hooks/useThemeStyles';
@@ -51,6 +52,7 @@ function ShareDetailsPage({
5152
const [validatedFile] = useOnyx(ONYXKEYS.VALIDATED_FILE_OBJECT, {canBeMissing: true});
5253

5354
const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: (val) => val?.reports});
55+
const personalDetail = useCurrentUserPersonalDetails();
5456
const isTextShared = currentAttachment?.mimeType === CONST.SHARE_FILE_MIMETYPE.TXT;
5557
const shouldUsePreValidatedFile = shouldValidateFile(currentAttachment);
5658
const [message, setMessage] = useState(isTextShared ? (currentAttachment?.content ?? '') : '');
@@ -103,7 +105,7 @@ function ShareDetailsPage({
103105
}
104106

105107
if (isTextShared) {
106-
addComment(report.reportID, message);
108+
addComment(report.reportID, message, personalDetail.timezone ?? CONST.DEFAULT_TIME_ZONE);
107109
const routeToNavigate = ROUTES.REPORT_WITH_ID.getRoute(reportOrAccountID);
108110
Navigation.navigate(routeToNavigate, {forceReplace: true});
109111
return;
@@ -125,7 +127,7 @@ function ShareDetailsPage({
125127
);
126128
}
127129
if (report.reportID) {
128-
addAttachment(report.reportID, file, message);
130+
addAttachment(report.reportID, file, personalDetail.timezone ?? CONST.DEFAULT_TIME_ZONE, message);
129131
}
130132

131133
const routeToNavigate = ROUTES.REPORT_WITH_ID.getRoute(reportOrAccountID);

0 commit comments

Comments
 (0)