Skip to content

Commit 6b171d1

Browse files
authored
Merge pull request Expensify#94149 from callstack-internal/decompose/ral-10
Decompose ReportActionsList: 10
2 parents f981534 + 59e62db commit 6b171d1

21 files changed

Lines changed: 91 additions & 291 deletions

src/CONST/index.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5925,20 +5925,13 @@ const CONST = {
59255925
DOT_INDICATOR_TEST_ID: 'DotIndicator',
59265926
ANIMATED_COLLAPSIBLE_CONTENT_TEST_ID: 'animated-collapsible-content',
59275927

5928-
CHAT_HEADER_LOADER_HEIGHT: 36,
5929-
59305928
HORIZONTAL_SPACER: {
59315929
DEFAULT_BORDER_BOTTOM_WIDTH: 1,
59325930
DEFAULT_MARGIN_VERTICAL: 8,
59335931
HIDDEN_MARGIN_VERTICAL: 4,
59345932
HIDDEN_BORDER_BOTTOM_WIDTH: 0,
59355933
},
59365934

5937-
LIST_COMPONENTS: {
5938-
HEADER: 'header',
5939-
FOOTER: 'footer',
5940-
},
5941-
59425935
MISSING_TRANSLATION: 'MISSING TRANSLATION',
59435936

59445937
/**
@@ -7942,7 +7935,6 @@ const CONST = {
79427935
},
79437936
REPORT: {
79447937
FLOATING_MESSAGE_COUNTER: 'Report-FloatingMessageCounter',
7945-
LIST_BOUNDARY_LOADER_RETRY: 'Report-ListBoundaryLoaderRetry',
79467938
SEND_BUTTON: 'Report-SendButton',
79477939
ATTACHMENT_PICKER_CREATE_BUTTON: 'Report-AttachmentPickerCreateButton',
79487940
ATTACHMENT_PICKER_EXPAND_BUTTON: 'Report-AttachmentPickerExpandButton',

src/hooks/useMarkAsRead.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {useIsFocused, useRoute} from '@react-navigation/native';
2-
import {useEffect, useRef, useState} from 'react';
2+
import {useEffect, useEffectEvent, useRef, useState} from 'react';
33
import {DeviceEventEmitter} from 'react-native';
44
import type {OnyxEntry} from 'react-native-onyx';
55
import DateUtils from '@libs/DateUtils';
@@ -92,7 +92,7 @@ function useMarkAsRead({reportID, report, transactionThreadReport, sortedVisible
9292

9393
const didMarkOnReportChangeRef = useRef(false);
9494

95-
useEffect(() => {
95+
const handleReportChangeMarkAsRead = useEffectEvent(() => {
9696
didMarkOnReportChangeRef.current = false;
9797
if (reportID !== prevReportID) {
9898
return;
@@ -115,11 +115,14 @@ function useMarkAsRead({reportID, report, transactionThreadReport, sortedVisible
115115
}
116116

117117
readActionSkippedRef.current = true;
118-
// This effect should only run when the newest visible action changes, otherwise every action/report object update can prematurely consume unread state.
119-
// eslint-disable-next-line react-hooks/exhaustive-deps
120-
}, [report?.lastVisibleActionCreated, transactionThreadReport?.lastVisibleActionCreated, reportID, isVisible, isReportActionsLoaded]);
118+
});
121119

120+
// Only re-run when the newest visible action changes, otherwise every action/report object update can prematurely consume unread state.
122121
useEffect(() => {
122+
handleReportChangeMarkAsRead();
123+
}, [report?.lastVisibleActionCreated, transactionThreadReport?.lastVisibleActionCreated, reportID, isVisible, isReportActionsLoaded]);
124+
125+
const handleAppVisibilityMarkAsRead = useEffectEvent(() => {
123126
if (didMarkOnReportChangeRef.current) {
124127
didMarkOnReportChangeRef.current = false;
125128
return;
@@ -153,8 +156,11 @@ function useMarkAsRead({reportID, report, transactionThreadReport, sortedVisible
153156

154157
readNewestAction(reportID, true);
155158
userActiveSince.current = DateUtils.getDBTime();
156-
// This effect should only run when app visibility/focus changes; the helper reads the latest report/action values without making every action update mark the report as read.
157-
// eslint-disable-next-line react-hooks/exhaustive-deps
159+
});
160+
161+
// Only re-run when app visibility/focus changes, so action updates don't keep marking the report as read.
162+
useEffect(() => {
163+
handleAppVisibilityMarkAsRead();
158164
}, [isVisible, isFocused]);
159165

160166
const markNewestActionAsRead = () => {

src/hooks/useReportActionsScroll.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {useRoute} from '@react-navigation/native';
2-
import {useContext, useEffect, useState} from 'react';
2+
import {useContext, useEffect, useEffectEvent, useState} from 'react';
33
import type {NativeScrollEvent, NativeSyntheticEvent, ViewToken} from 'react-native';
44
import type {OnyxEntry} from 'react-native-onyx';
55
import {AUTOSCROLL_TO_TOP_THRESHOLD} from '@components/FlatList/hooks/useFlatListScrollKey';
@@ -228,12 +228,12 @@ function useReportActionsScroll({
228228
});
229229
}, [draftAutoScrollKey, hasNewestReportAction, previousDraftAutoScrollKey, reportScrollManager, scrollOffsetRef, setIsFloatingMessageCounterVisible]);
230230

231-
useEffect(() => {
231+
const scheduleInitialScrollToBottom = useEffectEvent(() => {
232232
if (initialScrollKey) {
233-
return;
233+
return undefined;
234234
}
235235

236-
const handle = TransitionTracker.runAfterTransitions({
236+
return TransitionTracker.runAfterTransitions({
237237
callback: () => {
238238
if (shouldFocusToTopOnMount) {
239239
return;
@@ -243,9 +243,12 @@ function useReportActionsScroll({
243243
},
244244
waitForUpcomingTransition: true,
245245
});
246-
return () => handle.cancel();
247-
// The initial scroll-to-bottom must be scheduled exactly once, on mount; re-running it as deps change would yank the user back down while they read history.
248-
// eslint-disable-next-line react-hooks/exhaustive-deps
246+
});
247+
248+
// The initial scroll-to-bottom must be scheduled exactly once, on mount; re-running it as deps change would yank the user back down while they read history.
249+
useEffect(() => {
250+
const handle = scheduleInitialScrollToBottom();
251+
return () => handle?.cancel();
249252
}, []);
250253

251254
// Fixes Safari-specific issue where the whisper option is not highlighted correctly on hover after adding new transaction.
@@ -281,18 +284,18 @@ function useReportActionsScroll({
281284
const lastIOUActionWithError = sortedVisibleReportActions.find((action) => action.errors);
282285
const prevLastIOUActionWithError = usePrevious(lastIOUActionWithError);
283286

284-
useEffect(() => {
285-
if (lastIOUActionWithError?.reportActionID === prevLastIOUActionWithError?.reportActionID) {
286-
return;
287+
// Scroll to the bottom when a new errored action appears, so the user sees the failed money request. Re-checked
288+
// only when a new action arrives (keyed on lastAction), so loading older history never yanks a user who has
289+
// scrolled up. The !lastIOUActionWithError guard keeps a cleared error (retry succeeded / dismissed) from scrolling.
290+
const scheduleScrollToNewError = useEffectEvent(() => {
291+
if (!lastIOUActionWithError || lastIOUActionWithError.reportActionID === prevLastIOUActionWithError?.reportActionID) {
292+
return undefined;
287293
}
288-
const handle = TransitionTracker.runAfterTransitions({
289-
callback: () => {
290-
reportScrollManager.scrollToBottom();
291-
},
292-
});
293-
return () => handle.cancel();
294-
// Intentionally keyed to lastAction (not the error object) so the scroll re-evaluates once per new action; the reportActionID comparison above guards actual re-runs.
295-
// eslint-disable-next-line react-hooks/exhaustive-deps
294+
return TransitionTracker.runAfterTransitions({callback: () => reportScrollManager.scrollToBottom()});
295+
});
296+
useEffect(() => {
297+
const handle = scheduleScrollToNewError();
298+
return () => handle?.cancel();
296299
}, [lastAction]);
297300

298301
const scrollToBottomAndMarkReportAsRead = () => {

src/languages/de.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9356,10 +9356,6 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
93569356
takeMeToExpensifyClassic: 'Bring mich zu Expensify Classic',
93579357
goBackJustOnce: 'Nur dieses Mal zurück',
93589358
},
9359-
listBoundary: {
9360-
errorMessage: 'Beim Laden weiterer Nachrichten ist ein Fehler aufgetreten',
9361-
tryAgain: 'Erneut versuchen',
9362-
},
93639359
systemMessage: {
93649360
mergedWithCashTransaction: 'hat eine Quittung mit dieser Transaktion abgeglichen',
93659361
},

src/languages/en.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9437,10 +9437,6 @@ const translations = {
94379437
takeMeToExpensifyClassic: 'Take me to Expensify Classic',
94389438
goBackJustOnce: 'Go back just once',
94399439
},
9440-
listBoundary: {
9441-
errorMessage: 'An error occurred while loading more messages',
9442-
tryAgain: 'Try again',
9443-
},
94449440
systemMessage: {
94459441
mergedWithCashTransaction: 'matched a receipt to this transaction',
94469442
},

src/languages/es.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9516,10 +9516,6 @@ ${amount} para ${merchant} - ${date}`,
95169516
takeMeToExpensifyClassic: 'Llévame a Expensify Classic',
95179517
goBackJustOnce: 'Volver solo esta vez',
95189518
},
9519-
listBoundary: {
9520-
errorMessage: 'Se ha producido un error al cargar más mensajes',
9521-
tryAgain: 'Inténtalo de nuevo',
9522-
},
95239519
systemMessage: {
95249520
mergedWithCashTransaction: 'encontró un recibo para esta transacción',
95259521
},

src/languages/fr.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9390,10 +9390,6 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
93909390
takeMeToExpensifyClassic: 'M’emmener vers Expensify Classic',
93919391
goBackJustOnce: 'Revenir une seule fois',
93929392
},
9393-
listBoundary: {
9394-
errorMessage: 'Une erreur est survenue lors du chargement de messages supplémentaires',
9395-
tryAgain: 'Réessayer',
9396-
},
93979393
systemMessage: {
93989394
mergedWithCashTransaction: 'a fait correspondre un reçu à cette transaction',
93999395
},

src/languages/it.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9346,10 +9346,6 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
93469346
takeMeToExpensifyClassic: 'Portami a Expensify Classic',
93479347
goBackJustOnce: 'Torna solo per questa volta',
93489348
},
9349-
listBoundary: {
9350-
errorMessage: 'Si è verificato un errore durante il caricamento di altri messaggi',
9351-
tryAgain: 'Riprova',
9352-
},
93539349
systemMessage: {
93549350
mergedWithCashTransaction: 'ha associato una ricevuta a questa transazione',
93559351
},

src/languages/ja.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9226,10 +9226,6 @@ ${reportName}`,
92269226
takeMeToExpensifyClassic: 'Expensify Classic に移動',
92279227
goBackJustOnce: '一度だけ戻る',
92289228
},
9229-
listBoundary: {
9230-
errorMessage: 'さらにメッセージを読み込む際にエラーが発生しました',
9231-
tryAgain: '再試行',
9232-
},
92339229
systemMessage: {
92349230
mergedWithCashTransaction: 'この取引にレシートを照合しました',
92359231
},

src/languages/nl.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9315,10 +9315,6 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
93159315
takeMeToExpensifyClassic: 'Breng me naar Expensify Classic',
93169316
goBackJustOnce: 'Eenmalig teruggaan',
93179317
},
9318-
listBoundary: {
9319-
errorMessage: 'Er is een fout opgetreden bij het laden van meer berichten',
9320-
tryAgain: 'Probeer het opnieuw',
9321-
},
93229318
systemMessage: {
93239319
mergedWithCashTransaction: 'heeft een bonnetje aan deze transactie gekoppeld',
93249320
},

0 commit comments

Comments
 (0)