Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 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
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
2 changes: 1 addition & 1 deletion src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,6 @@ const CONST = {
WISE_REIMBURSEMENTS: 'wiseReimbursements',
DEFAULT_LETTER_AVATARS: 'defaultLetterAvatars',
TRAVEL_CODING_SYNC: 'travelCodingSync',
CONCIERGE_RESPOND_IN_THREAD: 'conciergeRespondInThread',
ARCHIVE_POLICIES: 'archivePolicies',
MERGE_ATS: 'mergeATSConnections',
REPORT_MERGE: 'reportMerge',
Expand Down Expand Up @@ -3066,6 +3065,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
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ function AnchorRenderer({tnode, style, key}: AnchorRendererProps) {
if (isAttachment && !isVideo) {
return (
<AnchorForAttachmentsOnly
style={styles.mv1}
source={tryResolveUrlFromApiRoot(attrHref)}
displayName={displayName}
isDeleted={isDeleted}
Expand Down
13 changes: 7 additions & 6 deletions src/components/Search/SearchRouter/useAskConcierge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ 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';
Expand All @@ -27,16 +26,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)}`);

// Each new question gets its own Concierge thread, so a side panel showing an earlier thread still targets Concierge.
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 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 Down Expand Up @@ -73,8 +75,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
104 changes: 104 additions & 0 deletions src/hooks/useConciergeAskState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types';
import {isCreatedAction, isCurrentUserPendingAddAction} from '@libs/ReportActionsUtils';

import {useConciergeSessionState} from '@pages/inbox/ConciergeSessionContext';

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

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

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

import {isOpenChildTaskAction} from './useConciergeSidePanelReportActions';
import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
import useIsInSidePanel from './useIsInSidePanel';
import useOnyx from './useOnyx';
import useResponsiveLayout from './useResponsiveLayout';

type ConciergeAskState = {
/** Whether this is the Concierge chat in the Inbox */
isAskConciergeChat: boolean;

/** Whether the messages from before this session are 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 to show `Ask a new question` above the composer */
shouldLabelComposerAsNewQuestion: boolean;
};

function useConciergeAskState(reportID: string | undefined): ConciergeAskState {
const isInSidePanel = useIsInSidePanel();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const route = useRoute<PlatformStackRouteProp<ReportsSplitNavigatorParamList, typeof SCREENS.REPORT>>();
const {sessionStartTime, showFullHistory} = useConciergeSessionState();
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);

const hasSessionActivitySelector = (actions: OnyxEntry<ReportActions>) => {
if (!actions || !sessionStartTime) {
return false;
}
return Object.values(actions).some((action) => {
// The list pins a still-open task, so it stays on screen in every session.
if (isOpenChildTaskAction(action, currentUserAccountID)) {
return true;
}

// An action that opens its own report, like a question's thread or a task, keeps the welcome both while sending and once sent.
// Otherwise reconnecting would switch this chat to a partial view that `Hide chat history` can't return to.
if (action.actorAccountID === currentUserAccountID && !!action.childReportID) {
return false;
}
return isCurrentUserPendingAddAction(action, currentUserAccountID) || (!isCreatedAction(action) && action.created >= sessionStartTime);
});
};
const [hasSessionActivity] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {
selector: hasSessionActivitySelector,
});

// `View chat history` only appears once the user has messaged Concierge, so earlier messages without one stay on screen.
const hasHistoryWithoutUserMessageSelector = (actions: OnyxEntry<ReportActions>) => {
if (!actions || !sessionStartTime) {
return false;
}
const allActions = Object.values(actions);

// Until the chat's first action is loaded, the user's earlier messages may be on an older page.
if (!allActions.some((action) => isCreatedAction(action))) {
return false;
}
const previousActions = allActions.filter((action) => !isCreatedAction(action) && action.created < sessionStartTime);
return previousActions.length > 0 && !previousActions.some((action) => action.actorAccountID === currentUserAccountID);
Comment thread
rushatgabhane marked this conversation as resolved.
};
const [hasHistoryWithoutUserMessage] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {
selector: hasHistoryWithoutUserMessageSelector,
});

const isAskConciergeChat = !!reportID && reportID === conciergeReportID && !isInSidePanel;

const hasSessionBoundary = isAskConciergeChat && !!sessionStartTime;

// A linked action opens the report at that message, so the earlier conversation is on screen either way.
const isHistoryExpanded = showFullHistory || !!route.params?.reportActionID;

const shouldShowWelcome = hasSessionBoundary && !isHistoryExpanded && !hasSessionActivity && !hasHistoryWithoutUserMessage;
Comment thread
rushatgabhane marked this conversation as resolved.

return {
isAskConciergeChat,
isHistoryExpanded,
shouldShowWelcome,
shouldCenterWelcomeWithComposer: shouldShowWelcome && !shouldUseNarrowLayout,
shouldLabelComposerAsNewQuestion: hasSessionBoundary && showFullHistory && !hasSessionActivity,
};
}

export default useConciergeAskState;
20 changes: 10 additions & 10 deletions src/hooks/useConciergeSidePanelReportActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,6 @@ function useConciergeSidePanelReportActions({
return hasUserMessageInLoadedSet || hasOlderActions;
}, [isConciergeHiddenHistory, visibleReportActions, currentUserAccountID, sessionStartTime, hasOlderActions]);

const hasPreviousMessages = useMemo(() => {
if (!isConciergeHiddenHistory || !hadUserMessageAtSessionStart || !sessionStartTime) {
return false;
}
const hasPreSessionActionInLoadedSet = visibleReportActions.some((action) => !isCreatedAction(action) && action.created < sessionStartTime);
return hasPreSessionActionInLoadedSet || hasOlderActions;
}, [isConciergeHiddenHistory, visibleReportActions, sessionStartTime, hadUserMessageAtSessionStart, 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 = useMemo(() => {
Expand Down Expand Up @@ -224,10 +216,10 @@ function useConciergeSidePanelReportActions({
return actions;
}
const filtered = actions.filter(isCurrentSessionAction);
if (filtered.length === 0) {
if (filtered.length === 0 && !isConciergeMainDM) {
// 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 All @@ -254,6 +246,13 @@ function useConciergeSidePanelReportActions({
const filteredVisibleActions = useMemo(() => filterActions(visibleReportActions), [filterActions, visibleReportActions]);
const filteredReportActions = useMemo(() => filterActions(reportActions), [filterActions, reportActions]);

const hasPreviousMessages = useMemo(() => {
if (!isConciergeHiddenHistory || !hadUserMessageAtSessionStart || !sessionStartTime) {
return false;
}
return visibleReportActions.some((action) => !isCurrentSessionAction(action)) || hasOlderActions;
}, [isConciergeHiddenHistory, hadUserMessageAtSessionStart, sessionStartTime, visibleReportActions, isCurrentSessionAction, hasOlderActions]);

const handleShowPreviousMessages = useCallback(() => {
setShowFullHistory(true);
loadOlderChats(true);
Expand All @@ -270,3 +269,4 @@ function useConciergeSidePanelReportActions({
}

export default useConciergeSidePanelReportActions;
export {isOpenChildTaskAction};
27 changes: 26 additions & 1 deletion src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,32 @@ const translations: TranslationDeepObject<typeof en> = {
quarter: 'Quartal',
vacationDelegate: 'Urlaubsvertretung',
expensifyLogo: 'Expensify-Logo',
concierge: {greeting: 'Hallo, wie kann ich helfen?', showHistory: 'Verlauf anzeigen'},
concierge: {
greeting: 'Hallo, wie kann ich helfen?',
showHistory: 'Verlauf anzeigen',
subtitle: 'Dein persönlicher KI-Assistent',
welcomeDescription: 'Concierge kann Fragen beantworten, Ausgaben aktualisieren und mehr.',
viewChatHistory: 'Chatverlauf anzeigen',
hideChatHistory: 'Chatverlauf ausblenden',
askNewQuestion: 'Neue Frage stellen',
newChat: 'Neuer Chat',
composerPlaceholders: {
spendLastMonth: 'Wie viel habe ich letzten Monat ausgegeben?',
topExpenses: 'Zeig mir meine größten Ausgaben in diesem Monat',
spendDrivers: 'Was hat meine Ausgaben im letzten Quartal getrieben?',
travelSpendChange: 'Wie haben sich meine Reisekosten seit letztem Monat verändert?',
topSpender: 'Wer hat diesen Monat am meisten ausgegeben?',
missingCategory: 'Welche Ausgaben haben keine Kategorie?',
awaitingApproval: 'Welche Berichte warten auf meine Genehmigung?',
notReimbursed: 'Was wurde mir noch nicht erstattet?',
unsubmitted: 'Welche meiner Ausgaben sind noch nicht eingereicht?',
leftToPay: 'Was ist diesen Monat noch zu zahlen?',
createExpense: 'Erstelle eine Ausgabe über 30 $ für ein Mittagessen',
combineExpenses: 'Fasse alle meine offenen Ausgaben in einem Bericht zusammen',
exportPdf: 'Exportiere meinen letzten Bericht als PDF',
exportCsv: 'Gib mir eine CSV meiner Ausgaben über 50 $',
},
},
duplicateReport: 'Duplizierten Bericht',
approver: 'Genehmiger',
goToConcierge: 'Zu Concierge',
Expand Down
22 changes: 22 additions & 0 deletions src/languages/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,28 @@ const translations: TranslationDeepObject<typeof en> = {
concierge: {
greeting: 'Γεια σας, πώς μπορώ να σας βοηθήσω;',
showHistory: 'Εμφάνιση ιστορικού',
subtitle: 'Ο προσωπικός σας βοηθός AI',
welcomeDescription: 'Ο Concierge μπορεί να απαντήσει σε ερωτήσεις, να ενημερώσει δαπάνες και άλλα.',
viewChatHistory: 'Προβολή ιστορικού συνομιλιών',
hideChatHistory: 'Απόκρυψη ιστορικού συνομιλιών',
askNewQuestion: 'Κάντε μια νέα ερώτηση',
newChat: 'Νέα συνομιλία',
composerPlaceholders: {
spendLastMonth: 'Πόσα ξόδεψα τον προηγούμενο μήνα;',
topExpenses: 'Δείξε μου τις μεγαλύτερες δαπάνες μου αυτόν τον μήνα',
spendDrivers: 'Τι οδήγησε τις δαπάνες μου το προηγούμενο τρίμηνο;',
travelSpendChange: 'Πώς άλλαξαν οι δαπάνες ταξιδιού μου από τον προηγούμενο μήνα;',
topSpender: 'Ποιος ξόδεψε τα περισσότερα αυτόν τον μήνα;',
missingCategory: 'Ποιες δαπάνες δεν έχουν κατηγορία;',
awaitingApproval: 'Ποιες αναφορές περιμένουν την έγκρισή μου;',
notReimbursed: 'Τι δεν μου έχει αποζημιωθεί ακόμη;',
unsubmitted: 'Ποιες από τις δαπάνες μου δεν έχουν υποβληθεί ακόμη;',
leftToPay: 'Τι μένει να πληρωθεί αυτόν τον μήνα;',
createExpense: 'Δημιούργησε μια δαπάνη 30 $ για ένα γεύμα',
combineExpenses: 'Συνδύασε όλες τις ανοιχτές δαπάνες μου σε μία αναφορά',
exportPdf: 'Εξήγαγε την τελευταία μου αναφορά σε PDF',
exportCsv: 'Δώσε μου ένα CSV με τις δαπάνες μου άνω των 50 $',
},
},
vacationDelegate: 'Εκπρόσωπος διακοπών',
expensifyLogo: 'Λογότυπο Expensify',
Expand Down
22 changes: 22 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,28 @@ const translations = {
concierge: {
greeting: 'Hi there, how can I help?',
showHistory: 'Show history',
subtitle: 'Your personal AI assistant',
welcomeDescription: 'Concierge can answer questions, update expenses, and more.',
viewChatHistory: 'View chat history',
hideChatHistory: 'Hide chat history',
askNewQuestion: 'Ask a new question',
newChat: 'New chat',
composerPlaceholders: {
spendLastMonth: 'How much did I spend last month?',
topExpenses: 'Show me my top expenses this month',
spendDrivers: 'What drove my spend last quarter?',
travelSpendChange: 'How did my travel spend change from last month?',
topSpender: 'Who spent the most this month?',
missingCategory: 'Which expenses are missing a category?',
awaitingApproval: 'Which reports are waiting on my approval?',
notReimbursed: "What haven't I been reimbursed for yet?",
unsubmitted: 'Which of my expenses are still unsubmitted?',
leftToPay: "What's left to pay this month?",
createExpense: 'Create an expense for a $30 lunch',
combineExpenses: 'Combine all my open expenses into one report',
exportPdf: 'Export my last report to PDF',
exportCsv: 'Give me a CSV of my expenses over $50',
},
},
vacationDelegate: 'Vacation delegate',
expensifyLogo: 'Expensify logo',
Expand Down
22 changes: 22 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,28 @@ const translations: TranslationDeepObject<typeof en> = {
concierge: {
greeting: 'Hola, ¿en qué puedo ayudarte?',
showHistory: 'Mostrar historial',
subtitle: 'Tu asistente de IA personal',
welcomeDescription: 'Concierge puede responder preguntas, actualizar gastos y mucho más.',
viewChatHistory: 'Ver historial del chat',
hideChatHistory: 'Ocultar historial del chat',
askNewQuestion: 'Haz una nueva pregunta',
newChat: 'Nuevo chat',
composerPlaceholders: {
spendLastMonth: '¿Cuánto gasté el mes pasado?',
topExpenses: 'Muéstrame mis mayores gastos de este mes',
spendDrivers: '¿Qué impulsó mi gasto el trimestre pasado?',
travelSpendChange: '¿Cómo cambió mi gasto en viajes desde el mes pasado?',
topSpender: '¿Quién gastó más este mes?',
missingCategory: '¿Qué gastos no tienen categoría?',
awaitingApproval: '¿Qué informes están esperando mi aprobación?',
notReimbursed: '¿Qué no se me ha reembolsado todavía?',
unsubmitted: '¿Cuáles de mis gastos siguen sin enviarse?',
leftToPay: '¿Qué queda por pagar este mes?',
createExpense: 'Crea un gasto de $30 por un almuerzo',
combineExpenses: 'Combina todos mis gastos abiertos en un informe',
exportPdf: 'Exporta mi último informe a PDF',
exportCsv: 'Dame un CSV de mis gastos de más de $50',
},
},
vacationDelegate: 'Delegado de vacaciones',
expensifyLogo: 'Logo de Expensify',
Expand Down
Loading
Loading