Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5924,20 +5924,13 @@ const CONST = {
DOT_INDICATOR_TEST_ID: 'DotIndicator',
ANIMATED_COLLAPSIBLE_CONTENT_TEST_ID: 'animated-collapsible-content',

CHAT_HEADER_LOADER_HEIGHT: 36,

HORIZONTAL_SPACER: {
DEFAULT_BORDER_BOTTOM_WIDTH: 1,
DEFAULT_MARGIN_VERTICAL: 8,
HIDDEN_MARGIN_VERTICAL: 4,
HIDDEN_BORDER_BOTTOM_WIDTH: 0,
},

LIST_COMPONENTS: {
HEADER: 'header',
FOOTER: 'footer',
},

MISSING_TRANSLATION: 'MISSING TRANSLATION',

/**
Expand Down Expand Up @@ -7941,7 +7934,6 @@ const CONST = {
},
REPORT: {
FLOATING_MESSAGE_COUNTER: 'Report-FloatingMessageCounter',
LIST_BOUNDARY_LOADER_RETRY: 'Report-ListBoundaryLoaderRetry',
SEND_BUTTON: 'Report-SendButton',
ATTACHMENT_PICKER_CREATE_BUTTON: 'Report-AttachmentPickerCreateButton',
ATTACHMENT_PICKER_EXPAND_BUTTON: 'Report-AttachmentPickerExpandButton',
Expand Down
20 changes: 13 additions & 7 deletions src/hooks/useMarkAsRead.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useIsFocused, useRoute} from '@react-navigation/native';
import {useEffect, useRef, useState} from 'react';
import {useEffect, useEffectEvent, useRef, useState} from 'react';
import {DeviceEventEmitter} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import DateUtils from '@libs/DateUtils';
Expand Down Expand Up @@ -92,7 +92,7 @@ function useMarkAsRead({reportID, report, transactionThreadReport, sortedVisible

const didMarkOnReportChangeRef = useRef(false);

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

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

// Only re-run when the newest visible action changes, otherwise every action/report object update can prematurely consume unread state.
useEffect(() => {
handleReportChangeMarkAsRead();
}, [report?.lastVisibleActionCreated, transactionThreadReport?.lastVisibleActionCreated, reportID, isVisible, isReportActionsLoaded]);

const handleAppVisibilityMarkAsRead = useEffectEvent(() => {
if (didMarkOnReportChangeRef.current) {
didMarkOnReportChangeRef.current = false;
return;
Expand Down Expand Up @@ -153,8 +156,11 @@ function useMarkAsRead({reportID, report, transactionThreadReport, sortedVisible

readNewestAction(reportID, true);
userActiveSince.current = DateUtils.getDBTime();
// 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.
// eslint-disable-next-line react-hooks/exhaustive-deps
});

// Only re-run when app visibility/focus changes, so action updates don't keep marking the report as read.
useEffect(() => {
handleAppVisibilityMarkAsRead();
}, [isVisible, isFocused]);

const markNewestActionAsRead = () => {
Expand Down
39 changes: 21 additions & 18 deletions src/hooks/useReportActionsScroll.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useRoute} from '@react-navigation/native';
import {useContext, useEffect, useState} from 'react';
import {useContext, useEffect, useEffectEvent, useState} from 'react';
import type {NativeScrollEvent, NativeSyntheticEvent, ViewToken} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {AUTOSCROLL_TO_TOP_THRESHOLD} from '@components/FlatList/hooks/useFlatListScrollKey';
Expand Down Expand Up @@ -228,12 +228,12 @@ function useReportActionsScroll({
});
}, [draftAutoScrollKey, hasNewestReportAction, previousDraftAutoScrollKey, reportScrollManager, scrollOffsetRef, setIsFloatingMessageCounterVisible]);

useEffect(() => {
const scheduleInitialScrollToBottom = useEffectEvent(() => {
if (initialScrollKey) {
return;
return undefined;
}

const handle = TransitionTracker.runAfterTransitions({
return TransitionTracker.runAfterTransitions({
callback: () => {
if (shouldFocusToTopOnMount) {
return;
Expand All @@ -243,9 +243,12 @@ function useReportActionsScroll({
},
waitForUpcomingTransition: true,
});
return () => handle.cancel();
// 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.
// eslint-disable-next-line react-hooks/exhaustive-deps
});

// 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.
useEffect(() => {
const handle = scheduleInitialScrollToBottom();
return () => handle?.cancel();
}, []);

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

useEffect(() => {
if (lastIOUActionWithError?.reportActionID === prevLastIOUActionWithError?.reportActionID) {
return;
// Scroll to the bottom when a new errored action appears, so the user sees the failed money request. Re-checked
// only when a new action arrives (keyed on lastAction), so loading older history never yanks a user who has
// scrolled up. The !lastIOUActionWithError guard keeps a cleared error (retry succeeded / dismissed) from scrolling.
const scheduleScrollToNewError = useEffectEvent(() => {
if (!lastIOUActionWithError || lastIOUActionWithError.reportActionID === prevLastIOUActionWithError?.reportActionID) {
return undefined;
}
const handle = TransitionTracker.runAfterTransitions({
callback: () => {
reportScrollManager.scrollToBottom();
},
});
return () => handle.cancel();
// 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.
// eslint-disable-next-line react-hooks/exhaustive-deps
return TransitionTracker.runAfterTransitions({callback: () => reportScrollManager.scrollToBottom()});
});
useEffect(() => {
const handle = scheduleScrollToNewError();
return () => handle?.cancel();
}, [lastAction]);

const scrollToBottomAndMarkReportAsRead = () => {
Expand Down
4 changes: 0 additions & 4 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9349,10 +9349,6 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
takeMeToExpensifyClassic: 'Bring mich zu Expensify Classic',
goBackJustOnce: 'Nur dieses Mal zurück',
},
listBoundary: {
errorMessage: 'Beim Laden weiterer Nachrichten ist ein Fehler aufgetreten',
tryAgain: 'Erneut versuchen',
},
systemMessage: {
mergedWithCashTransaction: 'hat eine Quittung mit dieser Transaktion abgeglichen',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9430,10 +9430,6 @@ const translations = {
takeMeToExpensifyClassic: 'Take me to Expensify Classic',
goBackJustOnce: 'Go back just once',
},
listBoundary: {
errorMessage: 'An error occurred while loading more messages',
tryAgain: 'Try again',
},
systemMessage: {
mergedWithCashTransaction: 'matched a receipt to this transaction',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9509,10 +9509,6 @@ ${amount} para ${merchant} - ${date}`,
takeMeToExpensifyClassic: 'Llévame a Expensify Classic',
goBackJustOnce: 'Volver solo esta vez',
},
listBoundary: {
errorMessage: 'Se ha producido un error al cargar más mensajes',
tryAgain: 'Inténtalo de nuevo',
},
systemMessage: {
mergedWithCashTransaction: 'encontró un recibo para esta transacción',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9383,10 +9383,6 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
takeMeToExpensifyClassic: 'M’emmener vers Expensify Classic',
goBackJustOnce: 'Revenir une seule fois',
},
listBoundary: {
errorMessage: 'Une erreur est survenue lors du chargement de messages supplémentaires',
tryAgain: 'Réessayer',
},
systemMessage: {
mergedWithCashTransaction: 'a fait correspondre un reçu à cette transaction',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9339,10 +9339,6 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
takeMeToExpensifyClassic: 'Portami a Expensify Classic',
goBackJustOnce: 'Torna solo per questa volta',
},
listBoundary: {
errorMessage: 'Si è verificato un errore durante il caricamento di altri messaggi',
tryAgain: 'Riprova',
},
systemMessage: {
mergedWithCashTransaction: 'ha associato una ricevuta a questa transazione',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9219,10 +9219,6 @@ ${reportName}`,
takeMeToExpensifyClassic: 'Expensify Classic に移動',
goBackJustOnce: '一度だけ戻る',
},
listBoundary: {
errorMessage: 'さらにメッセージを読み込む際にエラーが発生しました',
tryAgain: '再試行',
},
systemMessage: {
mergedWithCashTransaction: 'この取引にレシートを照合しました',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9308,10 +9308,6 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
takeMeToExpensifyClassic: 'Breng me naar Expensify Classic',
goBackJustOnce: 'Eenmalig teruggaan',
},
listBoundary: {
errorMessage: 'Er is een fout opgetreden bij het laden van meer berichten',
tryAgain: 'Probeer het opnieuw',
},
systemMessage: {
mergedWithCashTransaction: 'heeft een bonnetje aan deze transactie gekoppeld',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9292,10 +9292,6 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
takeMeToExpensifyClassic: 'Przejdź do Expensify Classic',
goBackJustOnce: 'Wróć tylko raz',
},
listBoundary: {
errorMessage: 'Wystąpił błąd podczas wczytywania kolejnych wiadomości',
tryAgain: 'Spróbuj ponownie',
},
systemMessage: {
mergedWithCashTransaction: 'dopasowano paragon do tej transakcji',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9295,10 +9295,6 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
takeMeToExpensifyClassic: 'Leve-me para o Expensify Classic',
goBackJustOnce: 'Voltar apenas desta vez',
},
listBoundary: {
errorMessage: 'Ocorreu um erro ao carregar mais mensagens',
tryAgain: 'Tentar novamente',
},
systemMessage: {
mergedWithCashTransaction: 'correspondeu um recibo a esta transação',
},
Expand Down
4 changes: 0 additions & 4 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9043,10 +9043,6 @@ ${reportName}`,
takeMeToExpensifyClassic: '带我前往 Expensify 经典版',
goBackJustOnce: '仅此一次返回',
},
listBoundary: {
errorMessage: '加载更多消息时出错',
tryAgain: '重试',
},
systemMessage: {
mergedWithCashTransaction: '已将一张收据匹配到此交易',
},
Expand Down
9 changes: 3 additions & 6 deletions src/pages/home/report/ConciergeThinkingMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, {useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import Animated, {Easing, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming} from 'react-native-reanimated';
import Icon from '@components/Icon';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
Expand All @@ -25,22 +24,20 @@ import ReportActionItemMessageHeaderSender from '@pages/inbox/report/ReportActio
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Report} from '@src/types/onyx';

type ConciergeThinkingMessageProps = {
/** The report for this thinking message */
report: OnyxEntry<Report>;
reportID: string;
Comment thread
LukasMod marked this conversation as resolved.
};

/**
* Renders one thinking bubble per agent the room is actively processing for (Concierge and/or
* custom agents). The candidate set comes from the per-agent processing-indicator NVP, so each
* bubble is attributed to the agent the server actually named — not a guessed persona.
*/
function ConciergeThinkingMessage({report}: ConciergeThinkingMessageProps) {
function ConciergeThinkingMessage({reportID}: ConciergeThinkingMessageProps) {
const {candidateAgentIDs} = useAgentZeroStatus();
const shouldSuppress = useShouldSuppressConciergeIndicators(report?.reportID);
const reportID = report?.reportID;
const shouldSuppress = useShouldSuppressConciergeIndicators(reportID);

if (shouldSuppress || !reportID || candidateAgentIDs.length === 0) {
return null;
Expand Down
Loading
Loading