Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
180 commits
Select commit Hold shift + click to select a range
cdea881
Ask Concierge design
rushatgabhane Sep 7, 2026
f6bb415
Fix CI failures
rushatgabhane Sep 7, 2026
40ce940
Merge main
rushatgabhane Sep 13, 2026
60fe442
Fix Button import
rushatgabhane Sep 13, 2026
95be964
Remove quick actions
rushatgabhane Sep 13, 2026
a666030
Center welcome layout
rushatgabhane Sep 13, 2026
7329000
Responsive column width
rushatgabhane Sep 13, 2026
8260e1f
Remove top margin
rushatgabhane Sep 13, 2026
dbbb733
Rotate placeholder
rushatgabhane Sep 13, 2026
82a7efd
Reuse existing placeholders
rushatgabhane Sep 13, 2026
47eb7f4
Remove list padding
rushatgabhane Sep 13, 2026
43392ff
Fix history toggle
rushatgabhane Sep 13, 2026
05f6511
Fix title line height
rushatgabhane Sep 13, 2026
b44fa4c
Own welcome typography
rushatgabhane Sep 13, 2026
25df82d
Always show toggle
rushatgabhane Sep 13, 2026
405db86
Space welcome divider
rushatgabhane Sep 13, 2026
6a5df9b
Fix session race
rushatgabhane Sep 13, 2026
ea11c45
Add placeholder rotation
rushatgabhane Sep 14, 2026
eca32a2
Revert "Fix session race"
rushatgabhane Sep 14, 2026
f68bab5
Reapply "Fix session race"
rushatgabhane Sep 14, 2026
c5c9975
Fix CI checks
rushatgabhane Sep 14, 2026
c278aec
Drop CSV placeholder
rushatgabhane Sep 14, 2026
134ddab
Revert "Drop CSV placeholder"
rushatgabhane Sep 14, 2026
0f7309a
Fix history toggle
rushatgabhane Sep 14, 2026
75caf8d
Drop comment
rushatgabhane Sep 14, 2026
3e8dfe7
Welcome instead of skeleton
rushatgabhane Sep 14, 2026
dbb3eee
Keep onboarding passthrough
rushatgabhane Sep 14, 2026
7c9c6bd
Remove unused asset
rushatgabhane Sep 14, 2026
df8069e
Rename welcome component
rushatgabhane Sep 14, 2026
9e7242b
Add regression test
rushatgabhane Sep 14, 2026
7b057b0
Drop comments
rushatgabhane Sep 14, 2026
16d4486
Drop comment
rushatgabhane Sep 14, 2026
5faf565
Fix review findings
rushatgabhane Sep 14, 2026
c6aeb51
Test side panel button
rushatgabhane Sep 14, 2026
bc17861
Test toggle and empty state
rushatgabhane Sep 14, 2026
fa10412
Fix mock scope
rushatgabhane Sep 14, 2026
f693e6d
Fix toggle label source
rushatgabhane Sep 14, 2026
b84021c
Hide locked toggle
rushatgabhane Sep 14, 2026
56522fb
Unlock history toggle
rushatgabhane Sep 14, 2026
5bf9f36
Hide returns to empty state
rushatgabhane Sep 14, 2026
4c25305
Restore welcome toggle
rushatgabhane Sep 14, 2026
a384472
Load locale in tests
rushatgabhane Sep 14, 2026
ca23148
Single history source
rushatgabhane Sep 14, 2026
ce51952
Test ask state hook
rushatgabhane Sep 14, 2026
841e68a
Keep hide working
rushatgabhane Sep 14, 2026
298843a
Fix CI failures
rushatgabhane Sep 14, 2026
b0ccfb3
Fix landscape layout
rushatgabhane Sep 14, 2026
c39ff93
Fix CI failures
rushatgabhane Sep 14, 2026
c472804
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Sep 14, 2026
e88ee96
Address review feedback
rushatgabhane Sep 14, 2026
a0a44ba
Improve comments
rushatgabhane Sep 14, 2026
fd9b205
Fix welcome layout
rushatgabhane Sep 14, 2026
b35ad4c
Add concierge welcome tests
rushatgabhane Sep 14, 2026
ac2a83c
Fix lint errors
rushatgabhane Sep 15, 2026
1ef742b
Dock composer bottom
rushatgabhane Sep 15, 2026
afa8d95
Merge remote-tracking branch 'upstream/main' into concierge-ask-design
rushatgabhane Oct 2, 2026
066d51b
Mock useConciergeAskState in ReportActionsListPaddingView test
rushatgabhane Oct 2, 2026
e4b314e
Center welcome only on wide layout
rushatgabhane Oct 2, 2026
6b32d8e
Keep welcome while question opens its thread
rushatgabhane Oct 2, 2026
1ee6a03
Pad welcome description
rushatgabhane Oct 2, 2026
81a90ff
Keep Concierge welcome consistent and pad welcome description
MelvinBot Oct 8, 2026
6b155cc
Merge remote-tracking branch 'origin/main' into concierge-ask-design
MelvinBot Oct 9, 2026
1a099e8
Address review comments on the Ask Concierge screen
rushatgabhane Oct 12, 2026
0bfc66a
Merge remote-tracking branch 'upstream/main' into concierge-ask-design
rushatgabhane Oct 12, 2026
fcc7c62
Rename the history check to fix spellcheck
rushatgabhane Oct 12, 2026
360eee2
Return a route from the useRoute mock in ReportActionsListTest
rushatgabhane Oct 12, 2026
f68ae5e
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Oct 13, 2026
d50e8b8
Remove the conciergeRespondInThread beta
rushatgabhane Oct 13, 2026
3233984
Drop the conciergeRespondInThread beta checks from the Ask Concierge …
rushatgabhane Oct 13, 2026
f2e0cca
Update Ask Concierge tests for the removed beta
rushatgabhane Oct 13, 2026
e434431
Hide the Concierge greeting in the main Concierge chat
rushatgabhane Oct 13, 2026
840e6e0
Drop the beta from the Ask Concierge state doc comment
rushatgabhane Oct 13, 2026
ec355e8
Revert "Hide the Concierge greeting in the main Concierge chat"
rushatgabhane Oct 13, 2026
616c0a6
Merge remote-tracking branch 'origin/main' into concierge-ask-design
MelvinBot Oct 13, 2026
5039f13
Merge remote-tracking branch 'origin/main' into concierge-ask-design
MelvinBot Oct 14, 2026
6d108a8
Update useAskConcierge tests for removed Concierge thread beta
MelvinBot Oct 14, 2026
78f08c1
Show the New chat button only on Concierge chat threads
rushatgabhane Oct 14, 2026
9c9df70
Keep the Concierge welcome after creating a task in the chat
rushatgabhane Oct 14, 2026
8a96c8d
Revert "Show the New chat button only on Concierge chat threads"
rushatgabhane Oct 14, 2026
38515ce
Merge remote-tracking branch 'origin/concierge-ask-design' into conci…
rushatgabhane Oct 14, 2026
78c1e5d
Document the Concierge tests with Given, When and Then
rushatgabhane Oct 14, 2026
ef562c5
Keep the Concierge welcome while older messages are still unloaded
rushatgabhane Oct 14, 2026
f3acff1
Drop manual memoization from resetSession
rushatgabhane Oct 14, 2026
a71596c
Fix the grammar of the reimbursement prompt
rushatgabhane Oct 14, 2026
6914c25
Show the chat history after creating a task in Concierge
rushatgabhane Oct 14, 2026
a1b5ff3
Merge remote-tracking branch 'origin/main' into concierge-ask-design
MelvinBot Oct 14, 2026
7b28190
Show the chat history after sending several attachments to Concierge
rushatgabhane Oct 16, 2026
4735764
Keep an open Concierge task on screen instead of the welcome
rushatgabhane Oct 16, 2026
675535b
Hide the Ask a new question label while the composer is full size
rushatgabhane Oct 16, 2026
e24e81c
Start a new Concierge thread from Search while the side panel shows a…
rushatgabhane Oct 16, 2026
48e768b
Merge remote-tracking branch 'upstream/main' into concierge-ask-design
rushatgabhane Oct 16, 2026
20ab913
Return to the Concierge welcome when hiding history after sending sev…
rushatgabhane Oct 16, 2026
9a8cf01
Use a camelCase error key in the Concierge ask state test
rushatgabhane Oct 16, 2026
427f1aa
Build optimistic comments with several attachments
rushatgabhane Oct 16, 2026
1c872d5
Send extra attachments in the same AddAttachment request
rushatgabhane Oct 16, 2026
9c3556f
Open a Concierge thread for messages with several attachments
rushatgabhane Oct 16, 2026
70bc106
Re-read every attachment file for requests queued offline
rushatgabhane Oct 16, 2026
623ee00
Test that several attachments open one Concierge thread
rushatgabhane Oct 16, 2026
a84b7bc
Reconcile every queued attachment when editing a message
rushatgabhane Oct 16, 2026
ca486db
Space out file attachments in a message
rushatgabhane Oct 16, 2026
e87d4d0
Drop the chat history toggle for attachments that stay in the Concier…
rushatgabhane Oct 16, 2026
bcd753a
Revert "Use a camelCase error key in the Concierge ask state test"
rushatgabhane Oct 16, 2026
1053614
Revert "Return to the Concierge welcome when hiding history after sen…
rushatgabhane Oct 16, 2026
727b7bc
Read the Concierge history flag straight from the session in the list…
rushatgabhane Oct 16, 2026
4f220af
Fold the side panel check into the Concierge check
rushatgabhane Oct 16, 2026
de7c33d
Drop the isAskConciergeEnabled alias in the header
rushatgabhane Oct 16, 2026
1538cae
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Oct 16, 2026
64f75c7
Match extra attachment file keys with one shared regex
rushatgabhane Oct 16, 2026
529469c
Simplify rewriting a queued request's attachments after an edit
rushatgabhane Oct 16, 2026
804aff5
Fix ESLint errors in queued attachment edit handling
MelvinBot Oct 16, 2026
aa9baee
Merge remote-tracking branch 'upstream/main' into concierge-ask-design
rushatgabhane Oct 20, 2026
7be9669
Replace the Concierge session context with a chat history context
rushatgabhane Oct 20, 2026
f525f7b
Stop starting and resetting a Concierge session in the main chat
rushatgabhane Oct 20, 2026
a1b73de
Show the main Concierge chat unfiltered once its history is expanded
rushatgabhane Oct 20, 2026
c4d1ff7
Decide the Concierge welcome screen without a session timestamp
rushatgabhane Oct 20, 2026
5021743
Scan Concierge actions once, and only in the main Concierge chat
rushatgabhane Oct 20, 2026
cfa81b4
Update Concierge tests for the removed session
rushatgabhane Oct 20, 2026
ec221b3
Drop main Concierge chat cases from side panel and skeleton tests
rushatgabhane Oct 20, 2026
a7ea87c
Update the list UI test for the main Concierge chat without a session
rushatgabhane Oct 20, 2026
559af84
Show the Concierge welcome even with an open task or a linked message
rushatgabhane Oct 20, 2026
151db49
Close the open-report and send-message spans from the Concierge welcome
rushatgabhane Oct 20, 2026
c74cdf7
Keep every synced attachment when saving an edit made mid-upload
rushatgabhane Oct 20, 2026
5e04cc8
Drop the unused main chat flag and old session wording
rushatgabhane Oct 20, 2026
6682743
Remove unnecessary comments
rushatgabhane Oct 20, 2026
98716c6
Add tests for the Concierge welcome, New chat button, and new questio…
rushatgabhane Oct 20, 2026
937aafc
Match edited attachments by attachment ID
rushatgabhane Oct 20, 2026
a84ed29
Keep measuring sends from the Concierge welcome screen
rushatgabhane Oct 20, 2026
8ab8477
Remove Concierge ask state tests that cannot fail
rushatgabhane Oct 20, 2026
5862a8f
Drop a stale Concierge test and always restore the navigate spy
rushatgabhane Oct 20, 2026
45dbfa0
Drop an unused test helper parameter
rushatgabhane Oct 20, 2026
ab2a969
Reuse the shared session account ID selector
rushatgabhane Oct 20, 2026
c0175cc
Restore the side panel's earlier-messages check
rushatgabhane Oct 20, 2026
fb0a4c4
Only scan Concierge messages where the welcome screen is decided
rushatgabhane Oct 20, 2026
0cf0d7d
Fall back to matching edited attachments by position
rushatgabhane Oct 20, 2026
b5551af
Decide the Concierge welcome screen once in the list model
rushatgabhane Oct 20, 2026
6fe2b32
Drive the Concierge welcome list test from report actions
rushatgabhane Oct 20, 2026
6882047
Revert unrelated button and attachment spacing changes, drop the stat…
rushatgabhane Oct 20, 2026
a84b9e1
Test each Concierge welcome state on its own
rushatgabhane Oct 20, 2026
13c0c1f
Type the Concierge test report actions without casts
rushatgabhane Oct 20, 2026
096bbff
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Oct 20, 2026
7119b2b
Use replaceAll for local attachment references
rushatgabhane Oct 20, 2026
4960ab5
Fix lint and type errors in Concierge tests
rushatgabhane Oct 20, 2026
0ce7202
Render the Concierge thread header with a real parent question
rushatgabhane Oct 20, 2026
b11501f
Mock focus state in the ReportFooter test
rushatgabhane Oct 20, 2026
97e5317
Merge remote-tracking branch 'origin/concierge-ask-design' into conci…
rushatgabhane Oct 20, 2026
4ade97f
Merge remote-tracking branch 'upstream/main' into HEAD
rushatgabhane Oct 20, 2026
af9e242
Fix ESLint errors in Concierge tests
rushatgabhane Oct 20, 2026
e3f0371
Fix ESLint restricted Animated import in useShouldSuppressConciergeIn…
MelvinBot Oct 21, 2026
5fa9601
Keep unread and failed Concierge messages on screen instead of the we…
rushatgabhane Oct 21, 2026
c3c08be
Show a task sent from Search in the expanded Concierge chat history
rushatgabhane Oct 21, 2026
b227fc1
Use typographic apostrophes in the French Concierge placeholders
rushatgabhane Oct 21, 2026
b1df0ab
Add Given/When/Then comments to the several-attachment edit tests
rushatgabhane Oct 21, 2026
41971d5
Test that every attachment of an offline message is read on native
rushatgabhane Oct 21, 2026
c1886ca
Show the Concierge chat when opened from a link to a message
rushatgabhane Oct 21, 2026
54b9bfc
Fix typecheck and ESLint errors in Concierge and prepareRequestPayloa…
MelvinBot Oct 21, 2026
7d9d7b3
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Oct 21, 2026
f4a7288
Hide New chat on tasks under the Concierge chat
rushatgabhane Oct 21, 2026
1259a98
Revert "Hide New chat on tasks under the Concierge chat"
rushatgabhane Oct 21, 2026
1eaf378
Base the Concierge unread check on the report and mark it read on Hid…
rushatgabhane Oct 21, 2026
c5a928f
Match kept attachments by file name when editing after a restart
rushatgabhane Oct 21, 2026
aae443e
Apply the selector to the Concierge report in the ReportActionsList t…
rushatgabhane Oct 21, 2026
ad56bb3
Type the Concierge report selector in the ReportActionsList test mock
rushatgabhane Oct 21, 2026
4d2fba0
Always show the Concierge chat history toggle
rushatgabhane Oct 21, 2026
2a50da7
Show the Concierge welcome after the user hides chat history
rushatgabhane Oct 21, 2026
2bb6c1e
Fix types after the chat history toggle changes
rushatgabhane Oct 21, 2026
61da0f8
Match same-named attachments to different synced attachments
rushatgabhane Oct 21, 2026
88c74a8
Simplify same-name attachment matching
rushatgabhane Oct 21, 2026
068fe8d
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Oct 22, 2026
9213648
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Oct 23, 2026
9e3c4f0
Merge remote-tracking branch 'upstream/main' into concierge-ask-design
rushatgabhane Oct 23, 2026
01977a5
Merge remote-tracking branch 'origin/concierge-ask-design' into conci…
rushatgabhane Oct 23, 2026
937131d
Stop exporting getUploadingAttachmentSource
rushatgabhane Oct 23, 2026
d268b20
Use the shared readFileAsync mock in the multi-attachment payload test
rushatgabhane Oct 23, 2026
6951094
Key renamed attachment labels by a named attachment ID in tests
rushatgabhane Oct 23, 2026
80afd0a
Show the Concierge welcome to users who never messaged Concierge
rushatgabhane Oct 25, 2026
ff1edce
Fold the Concierge welcome tests into one case
rushatgabhane Oct 25, 2026
529ef45
Merge remote-tracking branch 'upstream/main' into concierge-ask-design
rushatgabhane Oct 25, 2026
779dd28
Address Ask Concierge review comments
rushatgabhane Oct 25, 2026
4af61f1
Merge remote-tracking branch 'upstream/main' into concierge-ask-design
rushatgabhane Oct 27, 2026
904fc5c
Merge branch 'Expensify:main' into concierge-ask-design
rushatgabhane Oct 27, 2026
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
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop';
import HybridAppHandler from './HybridAppHandler';
import OnyxUpdateManager from './libs/actions/OnyxUpdateManager';
import './libs/HybridApp';
import {ConciergeSessionProvider} from './pages/inbox/ConciergeSessionContext';
import {ConciergeChatHistoryProvider} from './pages/inbox/ConciergeChatHistoryContext';
import './setup/backgroundLocationTrackingTask';
import './setup/backgroundTask';
import './setup/fraudProtection';
Expand Down Expand Up @@ -115,7 +115,7 @@ function App() {
SafeArea,
PopoverContextProvider,
CurrentReportIDContextProvider,
ConciergeSessionProvider,
ConciergeChatHistoryProvider,
ScrollOffsetContextProvider,
PickerStateProvider,
EnvironmentProvider,
Expand Down
3 changes: 1 addition & 2 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,6 @@ const CONST = {
WISE_REIMBURSEMENTS: 'wiseReimbursements',
DEFAULT_LETTER_AVATARS: 'defaultLetterAvatars',
TRAVEL_CODING_SYNC: 'travelCodingSync',
CONCIERGE_RESPOND_IN_THREAD: 'conciergeRespondInThread',
Comment thread
rushatgabhane marked this conversation as resolved.
ARCHIVE_POLICIES: 'archivePolicies',
MERGE_ATS: 'mergeATSConnections',
REPORT_MERGE: 'reportMerge',
Expand Down Expand Up @@ -1745,7 +1744,6 @@ const CONST = {
EXAMPLE_PHONE_NUMBER: '+15005550006',
FORMATTED_EXAMPLE_PHONE_NUMBER: '+1-(201)-867-5309',
CONCIERGE_CHAT_NAME: 'Concierge',
CONCIERGE_SESSION_EXPIRATION_MS: 2 * 3600 * 1000, // 2 hours
CLOUDFRONT_URL,
EMPTY_ARRAY,
EMPTY_OBJECT,
Expand Down Expand Up @@ -3366,6 +3364,7 @@ const CONST = {
ATTACHMENT_SOURCE_ATTRIBUTE: 'data-expensify-source',
ATTACHMENT_ID_ATTRIBUTE: 'data-attachment-id',
ATTACHMENT_OPTIMISTIC_SOURCE_ATTRIBUTE: 'data-optimistic-src',
ADDITIONAL_ATTACHMENT_FILE_KEY_REGEX: /^file_\d+$/,
ATTACHMENT_PREVIEW_ATTRIBUTE: 'src',
ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE: 'data-name',
ATTACHMENT_LOCAL_URL_PREFIX: ['blob:', 'file:'],
Expand Down
18 changes: 12 additions & 6 deletions src/components/Search/SearchRouter/useAskConcierge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import useDelegateAccountID from '@hooks/useDelegateAccountID';
import useOnyx from '@hooks/useOnyx';
import useOpenConciergeAnywhere from '@hooks/useOpenConciergeAnywhere';
import usePermissions from '@hooks/usePermissions';
import useSidePanelReportID from '@hooks/useSidePanelReportID';

import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
import {generateReportID} from '@libs/ReportUtils';

import {useConciergeChatHistoryActions} from '@pages/inbox/ConciergeChatHistoryContext';

import {addAttachmentWithComment, addComment} from '@userActions/Report';
import {createTaskFromMarkdown} from '@userActions/Task';

Expand All @@ -27,16 +28,19 @@ function useAskConcierge({forceConcierge = false}: {forceConcierge?: boolean} =
const sidePanelReportID = useSidePanelReportID();
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
const {openConciergeAnywhere, isInSidePanel} = useOpenConciergeAnywhere();
const targetReportID = !forceConcierge && isInSidePanel && sidePanelReportID ? sidePanelReportID : conciergeReportID;
const [sidePanelReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(sidePanelReportID)}`);

const isSidePanelOnConciergeThread = !!conciergeReportID && sidePanelReport?.parentReportID === conciergeReportID;
const targetReportID = !forceConcierge && isInSidePanel && sidePanelReportID && !isSidePanelOnConciergeThread ? sidePanelReportID : conciergeReportID;
const [targetReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(targetReportID)}`);
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const {timezone, accountID: currentUserAccountID} = currentUserPersonalDetails;
const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE);
const delegateAccountID = useDelegateAccountID();
const {isBetaEnabled} = usePermissions();
const {setShowFullHistory} = useConciergeChatHistoryActions();
const shouldShowAskConcierge = !!targetReportID && !!targetReport;

const shouldRespondInThread = targetReportID === conciergeReportID && isBetaEnabled(CONST.BETAS.CONCIERGE_RESPOND_IN_THREAD);
const shouldRespondInThread = targetReportID === conciergeReportID;

const askConcierge = (searchQuery: string) => {
const trimmedQuery = searchQuery.trim();
Expand All @@ -45,6 +49,9 @@ function useAskConcierge({forceConcierge = false}: {forceConcierge?: boolean} =
}
const isTask = createTaskFromMarkdown({text: trimmedQuery, parentReport: targetReport, currentUserPersonalDetails, quickAction, delegateAccountID});
if (isTask) {
if (shouldRespondInThread && !isInSidePanel) {
setShowFullHistory(true);
}
openConciergeAnywhere({forceConcierge});
return;
}
Expand Down Expand Up @@ -73,8 +80,7 @@ function useAskConcierge({forceConcierge = false}: {forceConcierge?: boolean} =
return;
}

const willOpenThread = shouldRespondInThread && (!Array.isArray(attachments) || attachments.length === 1);
const conciergeThreadReportID = willOpenThread ? generateReportID() : undefined;
const conciergeThreadReportID = shouldRespondInThread ? generateReportID() : undefined;
addAttachmentWithComment({
report: targetReport,
notifyReportID: targetReportID,
Expand Down
71 changes: 71 additions & 0 deletions src/hooks/useConciergeAskState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types';

import {useConciergeChatHistoryState} from '@pages/inbox/ConciergeChatHistoryContext';

import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
import type {Report} from '@src/types/onyx';
import type {ReportActions} from '@src/types/onyx/ReportAction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

import type {OnyxEntry} from 'react-native-onyx';

import {useRoute} from '@react-navigation/native';

import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
import useIsAskConciergeChat from './useIsAskConciergeChat';
import useOnyx from './useOnyx';
import useResponsiveLayout from './useResponsiveLayout';

type ConciergeAskState = {
/** Whether the earlier conversation of the Concierge chat in the Inbox is shown */
isHistoryExpanded: boolean;

/** Whether to show the `Ask me anything!` welcome screen in place of the messages */
shouldShowWelcome: boolean;

/** Whether the welcome screen and the composer are centered together on the screen */
shouldCenterWelcomeWithComposer: boolean;

/** Whether the Concierge chat has a message from someone else that the user hasn't read */
hasUnreadMessageFromOthers: boolean;
};

function useConciergeAskState(reportID: string | undefined): ConciergeAskState {
const isAskConciergeChat = useIsAskConciergeChat(reportID);
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {showFullHistory, isHistoryCollapsedByUser} = useConciergeChatHistoryState();
const route = useRoute<PlatformStackRouteProp<ReportsSplitNavigatorParamList, typeof SCREENS.REPORT>>();
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();

const hasFailedSendSelector = (actions: OnyxEntry<ReportActions>) => {
if (!isAskConciergeChat || !actions) {
return false;
}

// A failed send stays on screen so the user can retry or dismiss it.
return Object.values(actions).some((action) => !isEmptyObject(action.errors));
};
const [hasFailedSend] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {
selector: hasFailedSendSelector,
});

const hasUnreadMessageFromOthersSelector = (report: OnyxEntry<Report>) =>
isAskConciergeChat && !!report?.lastReadTime && (report.lastVisibleActionCreated ?? '') > report.lastReadTime && report.lastActorAccountID !== currentUserAccountID;
const [hasUnreadMessageFromOthers = false] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {
selector: hasUnreadMessageFromOthersSelector,
});

const isHistoryExpanded = isAskConciergeChat && (showFullHistory || !!route.params?.reportActionID);
const shouldShowWelcome = isAskConciergeChat && !isHistoryExpanded && (isHistoryCollapsedByUser || !hasFailedSend) && !hasUnreadMessageFromOthers;

return {
isHistoryExpanded,
shouldShowWelcome,
shouldCenterWelcomeWithComposer: shouldShowWelcome && !shouldUseNarrowLayout,
hasUnreadMessageFromOthers,
};
}

export default useConciergeAskState;
18 changes: 0 additions & 18 deletions src/hooks/useConciergeSessionStartTime.ts

This file was deleted.

73 changes: 9 additions & 64 deletions src/hooks/useConciergeSidePanelReportActions.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
import DateUtils from '@libs/DateUtils';
import {isCreatedAction, isCurrentUserPendingAddAction, isDeletedParentAction} from '@libs/ReportActionsUtils';
import {isCreatedAction, isCurrentUserPendingAddAction} from '@libs/ReportActionsUtils';
import {buildConciergeGreetingReportAction} from '@libs/ReportUtils';

import CONST from '@src/CONST';
import type * as OnyxTypes from '@src/types/onyx';

import type {OnyxEntry} from 'react-native-onyx';

import {useLayoutEffect, useState} from 'react';

/** An OPEN task assigned to the current user. Canceled tasks stay OPEN optimistically, so deleted parents are excluded. */

function isOpenChildTaskAction(action: OnyxTypes.ReportAction, currentUserAccountID: number): boolean {
return (
action.childType === CONST.REPORT.TYPE.TASK &&
action.childManagerAccountID === currentUserAccountID &&
action.childStateNum === CONST.REPORT.STATE_NUM.OPEN &&
action.childStatusNum === CONST.REPORT.STATUS_NUM.OPEN &&
!isDeletedParentAction(action)
);
}
import {useState} from 'react';

type UseConciergeSidePanelReportActionsParams = {
report: OnyxEntry<OnyxTypes.Report>;
Expand All @@ -32,11 +19,6 @@ type UseConciergeSidePanelReportActionsParams = {
currentUserAccountID: number;
greetingText: string;
loadOlderChats: (force?: boolean) => void;
isConciergeMainDM?: boolean;
showFullHistory?: boolean;
onSetShowFullHistory?: (show: boolean) => void;
hadMessagesAtSessionStart?: boolean;
onSetHadMessagesAtSessionStart?: (value: boolean) => void;
};

function useConciergeSidePanelReportActions({
Expand All @@ -50,38 +32,22 @@ function useConciergeSidePanelReportActions({
currentUserAccountID,
greetingText,
loadOlderChats,
isConciergeMainDM,
showFullHistory: externalShowFullHistory,
onSetShowFullHistory,
hadMessagesAtSessionStart: externalHadMessagesAtSessionStart,
onSetHadMessagesAtSessionStart,
}: UseConciergeSidePanelReportActionsParams) {
const [localShowFullHistory, setLocalShowFullHistory] = useState(false);
const [localHadMessagesAtSessionStart, setLocalHadMessagesAtSessionStart] = useState(
() =>
externalHadMessagesAtSessionStart ??
(!!isConciergeMainDM && !!sessionStartTime && visibleReportActions.some((action) => !isCreatedAction(action) && action.created >= sessionStartTime)),
);
const [showFullHistory, setShowFullHistory] = useState(false);
const [prevSessionStartTime, setPrevSessionStartTime] = useState(sessionStartTime);
const [prevHasUserSentMessage, setPrevHasUserSentMessage] = useState(hasUserSentMessage);

// Actions sent this session, captured while pending. The server can re-stamp `created` below the boundary, so keep
// them sticky rather than re-deriving visibility from the timestamp.
const [sessionSentActionIDs, setSessionSentActionIDs] = useState<ReadonlySet<string>>(() => new Set());

const hadMessagesAtSessionStart = localHadMessagesAtSessionStart;
const showFullHistory = externalShowFullHistory ?? localShowFullHistory;
const setShowFullHistory = onSetShowFullHistory ?? setLocalShowFullHistory;

if (prevSessionStartTime !== sessionStartTime) {
setPrevSessionStartTime(sessionStartTime);
setLocalShowFullHistory(false);
const messagesExistAtStart = !!isConciergeMainDM && !!sessionStartTime && visibleReportActions.some((action) => !isCreatedAction(action) && action.created >= sessionStartTime);
setLocalHadMessagesAtSessionStart(messagesExistAtStart);
setShowFullHistory(false);
setSessionSentActionIDs(new Set());
} else if (prevHasUserSentMessage && !hasUserSentMessage) {
setPrevHasUserSentMessage(hasUserSentMessage);
setLocalShowFullHistory(false);
setShowFullHistory(false);
} else if (prevHasUserSentMessage !== hasUserSentMessage) {
setPrevHasUserSentMessage(hasUserSentMessage);
}
Expand All @@ -94,10 +60,6 @@ function useConciergeSidePanelReportActions({
setSessionSentActionIDs((prev) => new Set([...prev, ...pendingSentActionIDs]));
}

useLayoutEffect(() => {
onSetHadMessagesAtSessionStart?.(localHadMessagesAtSessionStart);
}, [localHadMessagesAtSessionStart, onSetHadMessagesAtSessionStart]);

// Check if the user had sent any message BEFORE this session started.
// Uses sessionStartTime as the boundary — any user message created before the
// panel opened is a pre-session message, regardless of when it was loaded.
Expand Down Expand Up @@ -125,18 +87,10 @@ function useConciergeSidePanelReportActions({
hasPreviousMessages = hasPreSessionActionInLoadedSet || hasOlderActions;
}

// Main DM only: check if there are any messages (from any actor) after sessionStartTime.
// When true, we have unread content to display and should not enter welcome mode.
const hasMessagesInSession =
!(!isConciergeMainDM || !isConciergeHiddenHistory || !sessionStartTime) && visibleReportActions.some((action) => !isCreatedAction(action) && action.created >= sessionStartTime);

// Main DM only: the welcome state must stand down for a pinned task, or `filterActions` returns before it renders.
const hasOpenChildTask = !(!isConciergeMainDM || !isConciergeHiddenHistory) && visibleReportActions.some((action) => isOpenChildTaskAction(action, currentUserAccountID));

// A re-stamp flips `hasUserSentMessage` too, so the sticky set is what keeps the welcome state from coming back.
const hasSentInSession = hasUserSentMessage || sessionSentActionIDs.size > 0;
const showConciergeSidePanelWelcome = isConciergeHiddenHistory && hadUserMessageAtSessionStart && !hasSentInSession && !showFullHistory && !hasMessagesInSession && !hasOpenChildTask;
const showConciergeGreeting = isConciergeHiddenHistory && hadUserMessageAtSessionStart && !showFullHistory && (!isConciergeMainDM || !hadMessagesAtSessionStart);
const showConciergeSidePanelWelcome = isConciergeHiddenHistory && hadUserMessageAtSessionStart && !hasSentInSession && !showFullHistory;
const showConciergeGreeting = isConciergeHiddenHistory && hadUserMessageAtSessionStart && !showFullHistory;

let conciergeGreetingAction;
if (!showConciergeGreeting) {
Expand All @@ -154,7 +108,7 @@ function useConciergeSidePanelReportActions({
// Used to filter actions so that only messages from the first user message
// onwards are shown (upstream side panel behavior).
const firstUserMessageCreated =
isConciergeMainDM || showConciergeSidePanelWelcome || !isConciergeHiddenHistory || !hasUserSentMessage || !sessionStartTime
showConciergeSidePanelWelcome || !isConciergeHiddenHistory || !hasUserSentMessage || !sessionStartTime
? undefined
: reportActions.reduce<string | undefined>((earliest, action) => {
const isCurrentSessionUserMessage =
Expand All @@ -175,15 +129,6 @@ function useConciergeSidePanelReportActions({
if (sessionSentActionIDs.has(action.reportActionID)) {
return true;
}
if (isConciergeMainDM) {
// Pin a still-open task so collapsing read history never buries something the user has to act on.
return (
isCreatedAction(action) ||
isCurrentUserPendingAddAction(action, currentUserAccountID) ||
isOpenChildTaskAction(action, currentUserAccountID) ||
action.created >= sessionStartTime
);
}
if (!firstUserMessageCreated) {
return false;
}
Expand Down Expand Up @@ -217,7 +162,7 @@ function useConciergeSidePanelReportActions({
if (filtered.length === 0) {
// Side panel: nothing matched the current session yet (e.g. just after reopen, before the new
// message propagates). Show the greeting instead of `actions` to avoid flashing stale history.
if (!isConciergeMainDM && conciergeGreetingAction) {
if (conciergeGreetingAction) {
const createdAction = actions.find(isCreatedAction);
return createdAction ? [conciergeGreetingAction, createdAction] : [conciergeGreetingAction];
}
Expand Down
13 changes: 13 additions & 0 deletions src/hooks/useIsAskConciergeChat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ONYXKEYS from '@src/ONYXKEYS';

import useIsInSidePanel from './useIsInSidePanel';
import useOnyx from './useOnyx';

/** Whether the report is the Concierge chat in the Inbox */
function useIsAskConciergeChat(reportID: string | undefined): boolean {
const isInSidePanel = useIsInSidePanel();
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
return !!reportID && reportID === conciergeReportID && !isInSidePanel;
}

export default useIsAskConciergeChat;
Loading
Loading