Skip to content

Show an error when the default workspace does not have travel enabled - #98484

Open
blimpich wants to merge 13 commits into
mainfrom
blimpich-travelDefaultWorkspaceGuard
Open

Show an error when the default workspace does not have travel enabled#98484
blimpich wants to merge 13 commits into
mainfrom
blimpich-travelDefaultWorkspaceGuard

Conversation

@blimpich

@blimpich blimpich commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Explanation of Change

Today a member whose default workspace does not have travel enabled can still book travel from a different, travel-enabled workspace. A traveler is provisioned against their default workspace, so they land in Expensify Travel without a travel profile. They never appear in that company's traveler list and their booking does not behave as expected. This change stops the booking at the point of the click. It shows a modal that tells the member to either enable travel on their default workspace, or switch their default workspace to one that is travel-enabled. Setting up travel on a workspace is unaffected, because only the hand-off into Expensify Travel is blocked.

Fixed Issues

$ #92551
PROPOSAL: #92551 (comment)

Tests

  • Verify that no errors appear in the JS console

Offline tests

QA Steps

The modal is the same in every scenario below:

  • Title: Travel is not enabled
  • Message: To book, please enable travel on your default workspace or switch your default workspace to one that is travel-enabled.

Precondition

  1. Sign in to https://staging.new.expensify.com with an account whose primary contact method is a private-domain email.
  2. Verify that the account is an admin on two paid workspaces, Collect or Control.
  3. Name one workspace "Travel WS" and enable Expensify Travel on it.
  4. Name the other workspace "No Travel WS" and leave travel disabled on it.
  5. Navigate to Settings > Workspaces.
  6. Open the three-dot menu on "No Travel WS" and click "Set as default workspace".

Scenario 1: Travel quick action on Home

  1. Open the app in a wide browser window. The quick action row is hidden on narrow layouts.
  2. Navigate to Home.
  3. Click "Travel" in the quick action row above the widgets.
  4. Verify that the modal appears, and that Expensify Travel does not open.

Scenario 2: Manage travel on the workspace travel page

  1. Navigate to Settings > Workspaces > "Travel WS" > Travel.
  2. Click "Manage travel".
  3. Verify that the modal appears, and that Expensify Travel does not open.

Scenario 3: Book travel on the My trips page

  1. Open https://staging.new.expensify.com/travel?policyID=<policyID of Travel WS>.
  2. Click "Book travel".
  3. Verify that the modal appears, and that Expensify Travel does not open.

Scenario 4: The modal is gone once the default workspace is travel-enabled

  1. Navigate to Settings > Workspaces.
  2. Open the three-dot menu on "Travel WS" and click "Set as default workspace".
  3. Repeat scenarios 1, 2 and 3.
  4. Verify that Expensify Travel opens every time, and that the modal never appears.

Scenario 5: Enabling travel on a workspace is never blocked

  1. Set "No Travel WS" as the default workspace again.
  2. Open a third paid workspace that does not have travel enabled.
  3. Navigate to More features and toggle Travel on.
  4. Open the new Travel item in the left menu and click "Let's go".
  5. Verify that the travel setup flow opens as normal, and that the modal does not appear.

Scenario 6: Paths that always book with the default workspace are unaffected

  1. Set "No Travel WS" as the default workspace.
  2. Open the green "+" button in the bottom bar.
  3. Verify that "Book travel" is not listed, because the default workspace has no travel.
  4. Set "Travel WS" as the default workspace.
  5. Open the green "+" button and click "Book travel".
  6. Verify that Expensify Travel opens, and that the modal does not appear.
  7. Navigate to Reports and run a search with the type "Trip" that returns no results.
  8. Click "Book a trip" in the empty state.
  9. Verify that Expensify Travel opens, and that the modal does not appear.

Screenshots/Videos

Screenshot 2026-08-12 at 1 21 23 PM

@OSBotify

This comment has been minimized.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
src/components/BookTravelButton.tsx 83.54% <100.00%> (+1.96%) ⬆️
...nents/Navigation/QuickCreationActionsBar/index.tsx 92.04% <100.00%> (+5.99%) ⬆️
src/hooks/useDefaultWorkspaceTravelGuard.ts 100.00% <100.00%> (ø)
src/libs/PolicyUtils.ts 77.71% <100.00%> (+0.03%) ⬆️
...bar/FABPopoverContent/menuItems/TravelMenuItem.tsx 4.34% <ø> (+0.34%) ⬆️
...rc/pages/workspace/travel/BookOrManageYourTrip.tsx 0.00% <0.00%> (ø)
... and 9 files with indirect coverage changes

@OSBotify

This comment has been minimized.

@blimpich
blimpich marked this pull request as ready for review August 12, 2026 20:25
@blimpich
blimpich requested review from a team as code owners August 12, 2026 20:25
@melvin-bot
melvin-bot Bot requested review from joekaufmanexpensify and situchan and removed request for a team August 12, 2026 20:25
@melvin-bot

melvin-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

@situchan Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@melvin-bot
melvin-bot Bot requested review from a team and truph01 August 12, 2026 20:25
@melvin-bot

melvin-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

@truph01 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@melvin-bot
melvin-bot Bot removed the request for review from a team August 12, 2026 20:25
@blimpich

Copy link
Copy Markdown
Contributor Author

Hmm not sure why two C+ got assigned to review. Going to unassign @truph01

@blimpich
blimpich removed the request for review from truph01 August 12, 2026 20:27
@situchan

situchan commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
Android: mWeb Chrome
iOS: HybridApp
ios.mov
iOS: mWeb Safari
MacOS: Chrome / Safari
case1.mov
case2.mov
case3.mov
case5.mov
case6.mov

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c931a41077

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/libs/PolicyUtils.ts
Comment thread src/components/Navigation/QuickCreationActionsBar/index.tsx

@joekaufmanexpensify joekaufmanexpensify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good for product

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2fb4dee678

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/components/BookTravelButton.tsx Outdated
@MelvinBot

Copy link
Copy Markdown
Contributor

🤖 Reviewed the change. The core logic is sound and nicely refactored — the previously duplicated hasAcceptedTerms ?? (accountTerms && provisioned) expression is now consolidated into one hasAcceptedTravelTerms() helper used by all three travel entry points, and the guard is well covered by the new unit/UI tests. One UX inconsistency worth confirming before merge, plus a minor naming nit.

One thing to confirm

The three entry points diverge when the default workspace lacks travel. The block is applied consistently, but the user-facing outcome is not:

  • BookTravelButton → shows an explanatory modal telling the user to enable travel on / switch their default workspace (BookTravelButton.tsx:165-177).
  • QuickCreationActionsBarisTravelReady becomes false, so handleBookTravel silently navigates to My Trips with no explanation (index.tsx:204-214).

Since shouldShowBookTravel only checks that some workspace has travel, a user whose default lacks travel still sees the Travel button in the quick-create bar — clicking it just drops them on My Trips with no hint as to why booking didn't open, whereas the same user gets a clear modal from BookTravelButton. If that's intentional, great; otherwise consider surfacing the same defaultWorkspaceTravelDisabled modal (or an equivalent) from the quick-create path so the guard reads the same everywhere.

Minor

  • Helper name vs. behavior. hasAcceptedTravelTerms(policy, accountTravelSettings) actually returns whether travel is usable on the workspace (policy terms or account-level terms + provisioned) — which is what its doc comment says, but the name only describes one branch. Something like isTravelEnabledOnWorkspace/canBookTravelWithWorkspace would read truer at every call site (e.g. if (activePolicy && !hasAcceptedTravelTerms(activePolicy, travelSettings))). Non-blocking.
Things that check out
  • The refactored helper is behavior-preserving vs. the old inline expressions (same ??/&& structure, only adds a !! coercion).
  • defaultPolicy/activePolicy are read from NVP_ACTIVE_POLICY_ID, so the guard correctly gates on the user's default workspace; when no default is set the guard is skipped and existing behavior is preserved.
  • The guard can't misfire when the booking workspace is the default (it necessarily has travel to reach that branch).
  • Removed isWorkspaceProvisionedForTravel imports are fully unused in QuickCreationActionsBar and TravelMenuItem; still imported where still needed in BookTravelButton.
  • useMemo deps updated correctly (activePolicy added, travelSettings object used).
  • Language files: apostrophe/quote typography is locale-correct (e.g. fr uses U+2019), delimiters untouched, all 12 locales covered.
  • Good test coverage — notably the case that an admin can still reach the enable-travel stepper while their default workspace has no travel.

This is an automated review — treat it as a second set of eyes, not a gate. Reply with @MelvinBot <feedback> to refine.

@MelvinBot

Copy link
Copy Markdown
Contributor

🤖 Regression scan — no unintended regression found in the happy path. The refactor is behavior-preserving and the new guard is provably scoped to the target scenario, but there are two behavior changes worth a conscious sign-off.

Why the happy path is safe

The new block in BookTravelButton.tsx:163-179 can only fire when the booking policy's id differs from the default (NVP_ACTIVE_POLICY_ID) and the default lacks travel. Proof: it runs inside the hasPolicyAcceptedTravelTerms branch (booking policy has travel), then checks hasAcceptedTravelTerms(defaultPolicy). In every call site where the booking policy is the default, that second check is byte-for-byte the branch condition already satisfied, so it always passes → no false block. Verified across all callers:

  • EmptySearchView passes activePolicy?.id (= NVP_ACTIVE_POLICY_ID) → booking policy is default → guard never fires. ✅
  • ManageTrips via the FAB TravelMenuItem navigates with activePolicy?.id → same. ✅
  • ManageTrips via QuickCreationActionsBar only lands there with a non-default travel workspace when the default lacks travel → guard fires by design. ✅
  • GetStartedTravel (workspace setup CTA) → workspace isn't terms-accepted yet, so it takes the enablement-stepper path before the guard. ✅

The hasAcceptedTravelTerms() helper is a faithful extraction of the old inline terms ?? (accountTerms && provisioned) expression (only adds a !! coercion, no behavioral effect), and all three travel-gating sites were migrated — grep shows no stray copy of the old pattern left behind.

Two intentional behavior changes to sign off on

  1. Quick-create bar now silently redirects instead of booking. A user whose default workspace lacks travel but who has a separate travel-enabled workspace could previously book straight from the FAB quick bar; now isTravelReady is false and they're routed to My Trips with no explanation (index.tsx:207-211) — whereas the same user gets the explanatory modal from BookTravelButton. Intended block, but the inconsistent/silent UX is the thing to confirm (same point I raised in the code review).

  2. Possible over-block if travel provisioning is domain-scoped, not default-workspace-scoped. The guard assumes the traveler profile lives on the default workspace. If Spotnana actually provisions per travel-domain (shared across sibling workspaces), a user with a valid profile could be blocked when booking from a non-default workspace whose default happens to lack travel. I can't confirm the provisioning model from the App code — worth a gut-check against how Spotnana entities map to workspaces before merge. Low confidence.

Things explicitly checked and clear
  • useMemo deps in QCAB are complete (activePolicy + full travelSettings added) — no stale-closure regression.
  • When defaultPolicy/activePolicy is undefined (no default set), both guards are skipped → falls back to prior behavior.
  • When two travel-enabled workspaces exist and the default has travel, QCAB still opens travelEnabledPolicy?.id exactly as before — the added guard passes and doesn't change the target.
  • !! coercion changes undefinedfalse only; every consumer uses the result in boolean context.
  • Removed isWorkspaceProvisionedForTravel imports are fully unused in the files they were removed from.
  • Not a regression, but a pre-existing gap this PR doesn't close: useGettingStartedItems/EnableTravelContent still key off isWorkspaceProvisionedForTravel and aren't gated on the default workspace — out of scope here.

Automated regression scan — a second set of eyes, not a gate. Reply with @MelvinBot <feedback> to dig into any of these.

@blimpich

Copy link
Copy Markdown
Contributor Author

@situchan any update here?

Comment thread src/hooks/useDefaultWorkspaceTravelGuard.ts
if (blockIfDefaultWorkspaceLacksTravel()) {
return;
}
openTravelDotLink(travelEnabledPolicy?.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guard asserts the default workspace has travel, but the ID handed to openTravelDotLink is travelEnabledPolicy?.id, computed as line 82 as Object.values(allPolicies).find(p => p.isTravelEnabled) (insertion order, not the default).
So, with two travel-enabled workspaces, the guard passes and the user is still handed off to a non-default workspace.
This is not something introduced by this PR so out of scope.

@situchan situchan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please pull main and check #98484 (comment).
Otherwise looks good.

@melvin-bot
melvin-bot Bot requested a review from stitesExpensify August 19, 2026 09:58
@melvin-bot

melvin-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

@stitesExpensify Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@OSBotify

Copy link
Copy Markdown
Contributor

🦜 Polyglot Parrot! 🦜

Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues:

View the translation diff
diff --git a/src/languages/el.ts b/src/languages/el.ts
index 8e696d76..df1d29b6 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -4585,9 +4585,9 @@ ${amount} για ${merchant} - ${date}`,
                 'Γνωρίζατε ότι μπορείτε να κλείνετε και να διαχειρίζεστε ταξίδια με τρένο απευθείας στο Expensify; Και ότι ανεβάζει αυτόματα τις αποδείξεις για εσάς; Την επόμενη φορά απλώς κάντε κράτηση μέσω του <a href="https://travel.expensify.com">Expensify Travel</a> 🚂',
         },
         defaultWorkspaceTravelDisabled: {
-            title: 'Η ταξιδιωτική λειτουργία δεν είναι ενεργοποιημένη',
+            title: 'Τα ταξίδια δεν είναι ενεργοποιημένα',
             message:
-                'Για να κάνετε κράτηση, ενεργοποιήστε τα ταξίδια στον προεπιλεγμένο χώρο εργασίας σας ή αλλάξτε τον προεπιλεγμένο χώρο εργασίας σε κάποιον όπου τα ταξίδια είναι ενεργοποιημένα.',
+                'Για να κάνετε κράτηση, ενεργοποιήστε τα ταξίδια στον προεπιλεγμένο χώρο εργασίας σας ή αλλάξτε τον προεπιλεγμένο χώρο εργασίας σας σε κάποιον όπου τα ταξίδια είναι ενεργοποιημένα.',
         },
     },
     proactiveAppReview: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index c43ed39c..6d94f4fc 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -4418,7 +4418,7 @@ ${amount} para ${merchant} - ${date}`,
                 '¿Sabías que puedes reservar y gestionar viajes en tren directamente en Expensify? ¿Y que además sube los recibos automáticamente por ti? La próxima vez, simplemente reserva a través de <a href="https://travel.expensify.com">Expensify Travel</a> 🚂',
         },
         defaultWorkspaceTravelDisabled: {
-            title: 'Los viajes no están habilitados',
+            title: 'Viajes no está habilitado',
             message: 'Para reservar, habilita los viajes en tu espacio de trabajo predeterminado o cambia tu espacio de trabajo predeterminado a uno que tenga los viajes habilitados.',
         },
     },
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index c3d29736..51ffe107 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -4524,7 +4524,8 @@ ${amount} pour ${merchant} - ${date}`,
         },
         defaultWorkspaceTravelDisabled: {
             title: 'Voyage n’est pas activé',
-            message: 'Pour réserver, veuillez activer les voyages sur votre espace de travail par défaut ou définir par défaut un espace de travail sur lequel les voyages sont activés.',
+            message:
+                'Pour réserver, activez les voyages sur votre espace de travail par défaut ou remplacez votre espace de travail par défaut par un espace de travail avec voyages activés.',
         },
     },
     workspace: {
diff --git a/src/languages/it.ts b/src/languages/it.ts
index f2b601dd..1d0eaf59 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -4490,8 +4490,8 @@ ${amount} per ${merchant} - ${date}`,
                 'Sapevi che puoi prenotare e gestire i viaggi in treno direttamente in Expensify? E che le ricevute vengono caricate automaticamente per te? La prossima volta prenota semplicemente tramite <a href="https://travel.expensify.com">Expensify Travel</a> 🚂',
         },
         defaultWorkspaceTravelDisabled: {
-            title: 'Viaggi non abilitato',
-            message: 'Per prenotare, abilita i viaggi sul tuo spazio di lavoro predefinito oppure imposta come predefinito uno spazio di lavoro con viaggi abilitati.',
+            title: 'Viaggi non è abilitato',
+            message: 'Per prenotare, attiva i viaggi nel tuo spazio di lavoro predefinito oppure imposta come predefinito uno spazio di lavoro con viaggi abilitati.',
         },
     },
     workspace: {
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 86e76991..8f4a2268 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -4454,8 +4454,8 @@ ${integrationName === CONST.ONBOARDING_ACCOUNTING_MAPPING.other ? 'あなたの'
                 'Expensify で電車の予約や管理ができることをご存じでしたか?しかも領収書も自動でアップロードされます。次回からは、ぜひ <a href="https://travel.expensify.com">Expensify Travel</a> から予約してください 🚂',
         },
         defaultWorkspaceTravelDisabled: {
-            title: '出張機能は有効になっていません',
-            message: '予約するには、デフォルトのワークスペースで出張機能を有効にするか、出張機能が有効になっているワークスペースをデフォルトとして設定してください。',
+            title: '出張は有効になっていません',
+            message: '予約するには、デフォルトのワークスペースで出張機能を有効にするか、出張機能が有効になっているワークスペースをデフォルトに設定してください。',
         },
     },
     workspace: {
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index dac1eb2a..fe051e73 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -4489,7 +4489,7 @@ ${amount} voor ${merchant} - ${date}`,
         },
         defaultWorkspaceTravelDisabled: {
             title: 'Reizen is niet ingeschakeld',
-            message: 'Om te boeken, schakel reizen in op je standaardwerkruimte of stel een standaardwerkruimte in die reizen ondersteunt.',
+            message: 'Om te boeken, schakel reizen in op je standaardwerkruimte of wijzig je standaardwerkruimte naar een werkruimte waarop reizen is ingeschakeld.',
         },
     },
     workspace: {
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 896b7f4e..ad9c65d7 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -4473,8 +4473,8 @@ ${amount} dla ${merchant} - ${date}`,
                 'Wiesz, że możesz rezerwować i zarządzać przejazdami pociągiem bezpośrednio w Expensify? I że paragony są automatycznie przesyłane za Ciebie? Następnym razem po prostu zarezerwuj przez <a href="https://travel.expensify.com">Expensify Travel</a>',
         },
         defaultWorkspaceTravelDisabled: {
-            title: 'Podróże są wyłączone',
-            message: 'Aby dokonać rezerwacji, włącz podróże w swojej domyślnej przestrzeni roboczej lub ustaw jako domyślną inną przestrzeń roboczą, w której podróże są włączone.',
+            title: 'Podróże nie są włączone',
+            message: 'Aby zarezerwować, włącz podróże w swojej domyślnej przestrzeni roboczej albo ustaw jako domyślną inną przestrzeń roboczą, w której podróże są włączone.',
         },
     },
     workspace: {
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 9b186542..3a8601b0 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -4482,8 +4482,8 @@ ${amount} para ${merchant} - ${date}`,
                 'Você sabia que dá para reservar e gerenciar viagens de trem direto no Expensify? E que os recibos são enviados automaticamente para você? Da próxima vez, é só reservar pelo <a href="https://travel.expensify.com">Expensify Travel</a> 🚂',
         },
         defaultWorkspaceTravelDisabled: {
-            title: 'Viagem não está ativada',
-            message: 'Para fazer uma reserva, ative viagens no seu espaço de trabalho padrão ou altere seu espaço de trabalho padrão para um que tenha viagens ativadas.',
+            title: 'Viagens não estão ativadas',
+            message: 'Para reservar, ative viagens no seu workspace padrão ou altere seu workspace padrão para um que tenha viagens ativadas.',
         },
     },
     workspace: {
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index eda5d2d7..9e9c0133 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -4348,7 +4348,7 @@ ${amount},商户:${merchant} - 日期:${date}`,
             railManual: '你知道吗?你可以直接在 Expensify 中预订和管理火车行程!下次无需再手动创建报销,只需通过 <a href="https://travel.expensify.com">Expensify Travel</a> 预订即可 🚂',
             railCard: '你知道吗?你可以直接在 Expensify 中预订和管理火车行程,而且还会自动为你上传收据。下次只需通过 <a href="https://travel.expensify.com">Expensify Travel</a> 预订即可 🚂',
         },
-        defaultWorkspaceTravelDisabled: {title: '差旅功能未启用', message: '如需预订,请在您的默认工作区中启用差旅功能,或将默认工作区切换为已启用差旅功能的工作区。'},
+        defaultWorkspaceTravelDisabled: {title: '差旅功能未启用', message: '要预订,请在你的默认工作区启用差旅,或将默认工作区切换为已启用差旅的工作区。'},
     },
     workspace: {
         common: {

Note

You can apply these changes to your branch by copying the patch to your clipboard, then running pbpaste | git apply 😉

View workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants