[Home Page] Upcoming travel section#82958
[Home Page] Upcoming travel section#82958adamgrzybowski wants to merge 11 commits intoExpensify:mainfrom
Conversation
Hotel reservations were incorrectly using chainName as cityName. Car reservations were missing the cityName field entirely.
…oper act() wrapping
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running: npx ts-node ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
|
@ZhenjaHorbach 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] |
src/pages/home/UpcomingTravelSection/useUpcomingTravelReservations.ts
Outdated
Show resolved
Hide resolved
|
This is looking so cool from the vids! |
1c53ece to
dc51b58
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c53ececf8
ℹ️ 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".
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
…tive date calculation
|
Lint issues |
|
@mountiny 🦜 🙏 🥺 |
|
I think we can ignore spellcheck for this one. It's about a string in tests. The string is the same as in already existing tests |
Maybe we can change the string ?😅 |
🦜 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 diffdiff --git a/src/languages/de.ts b/src/languages/de.ts
index b4f14030..3b454dff 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -983,6 +983,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: 'Anstehende To-dos werden hier angezeigt.',
},
},
+ upcomingTravel: 'Bevorstehende Reisen',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `Flug nach ${destination}`,
+ trainTo: ({destination}: {destination: string}) => `Zug nach ${destination}`,
+ hotelIn: ({destination}: {destination: string}) => `Hotel in ${destination}`,
+ carRentalIn: ({destination}: {destination: string}) => `Mietwagen in ${destination}`,
+ inOneWeek: 'In 1 Woche',
+ inDays: {one: 'In 1 Tag', other: (count: number) => `In ${count} Tagen`},
+ today: 'Heute',
+ },
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 809aa739..80cb549a 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -986,6 +986,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: 'Les tâches à venir apparaîtront ici.',
},
},
+ upcomingTravel: 'Voyages à venir',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `Vol vers ${destination}`,
+ trainTo: ({destination}: {destination: string}) => `Train pour ${destination}`,
+ hotelIn: ({destination}: {destination: string}) => `Hôtel à ${destination}`,
+ carRentalIn: ({destination}: {destination: string}) => `Location de voiture à ${destination}`,
+ inOneWeek: 'Dans 1 semaine',
+ inDays: {one: 'Dans 1 jour', other: (count: number) => `Dans ${count} jours`},
+ today: 'Aujourd’hui',
+ },
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index ebba8e0b..42644818 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -982,6 +982,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: 'Le prossime attività da fare verranno visualizzate qui.',
},
},
+ upcomingTravel: 'Prossimi viaggi',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `Volo per ${destination}`,
+ trainTo: ({destination}: {destination: string}) => `Treno per ${destination}`,
+ hotelIn: ({destination}: {destination: string}) => `Hotel a ${destination}`,
+ carRentalIn: ({destination}: {destination: string}) => `Noleggio auto a ${destination}`,
+ inOneWeek: 'Tra 1 settimana',
+ inDays: {one: 'Tra 1 giorno', other: (count: number) => `Tra ${count} giorni`},
+ today: 'Oggi',
+ },
},
allSettingsScreen: {
subscription: 'Abbonamento',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index f9942a74..a9dcb23e 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -977,6 +977,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: '今後のTo-doはここに表示されます。',
},
},
+ upcomingTravel: '今後の出張',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `${destination} 行きのフライト`,
+ trainTo: ({destination}: {destination: string}) => `${destination} 行きの電車`,
+ hotelIn: ({destination}: {destination: string}) => `${destination}のホテル`,
+ carRentalIn: ({destination}: {destination: string}) => `${destination}でのレンタカー`,
+ inOneWeek: '1週間後',
+ inDays: {one: '1日後', other: (count: number) => `${count}日後`},
+ today: '今日',
+ },
},
allSettingsScreen: {
subscription: 'サブスクリプション',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 95d7cd4f..5dcd7e82 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -981,6 +981,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: 'Aankomende taken verschijnen hier.',
},
},
+ upcomingTravel: 'Aankomende reizen',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `Vlucht naar ${destination}`,
+ trainTo: ({destination}: {destination: string}) => `Trein naar ${destination}`,
+ hotelIn: ({destination}: {destination: string}) => `Hotel in ${destination}`,
+ carRentalIn: ({destination}: {destination: string}) => `Autoverhuur in ${destination}`,
+ inOneWeek: 'Over 1 week',
+ inDays: {one: 'Over 1 dag', other: (count: number) => `Over ${count} dagen`},
+ today: 'Vandaag',
+ },
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 59a3b885..0fca0d12 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -982,6 +982,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: 'Nadchodzące zadania pojawią się tutaj.',
},
},
+ upcomingTravel: 'Nadchodząca podróż',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `Lot do ${destination}`,
+ trainTo: ({destination}: {destination: string}) => `Pociąg do ${destination}`,
+ hotelIn: ({destination}: {destination: string}) => `Hotel w ${destination}`,
+ carRentalIn: ({destination}: {destination: string}) => `Wynajem samochodu w ${destination}`,
+ inOneWeek: 'Za 1 tydzień',
+ inDays: {one: 'Za 1 dzień', other: (count: number) => `Za ${count} dni`},
+ today: 'Dzisiaj',
+ },
},
allSettingsScreen: {
subscription: 'Subskrypcja',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index cb056498..70b26ffc 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -980,6 +980,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: 'Os próximos afazeres aparecerão aqui.',
},
},
+ upcomingTravel: 'Próximas viagens',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `Voo para ${destination}`,
+ trainTo: ({destination}: {destination: string}) => `Trem para ${destination}`,
+ hotelIn: ({destination}: {destination: string}) => `Hotel em ${destination}`,
+ carRentalIn: ({destination}: {destination: string}) => `Aluguel de carro em ${destination}`,
+ inOneWeek: 'Em 1 semana',
+ inDays: {one: 'Em 1 dia', other: (count: number) => `Em ${count} dias`},
+ today: 'Hoje',
+ },
},
allSettingsScreen: {
subscription: 'Assinatura',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index de176b57..cd83a45b 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -964,6 +964,16 @@ const translations: TranslationDeepObject<typeof en> = {
upcomingTodos: '即将到来的待办事项会显示在这里。',
},
},
+ upcomingTravel: '即将出行',
+ upcomingTravelSection: {
+ flightTo: ({destination}: {destination: string}) => `飞往 ${destination} 的航班`,
+ trainTo: ({destination}: {destination: string}) => `前往 ${destination} 的火车`,
+ hotelIn: ({destination}: {destination: string}) => `${destination}的酒店`,
+ carRentalIn: ({destination}: {destination: string}) => `在 ${destination} 租车`,
+ inOneWeek: '1 周后',
+ inDays: {one: '1 天后', other: (count: number) => `在 ${count} 天后`},
+ today: '今天',
+ },
},
allSettingsScreen: {
subscription: '订阅',
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |

Explanation of Change
Add a new "Upcoming Travel" widget section to the HomePage that displays travel reservations scheduled within the next 7 days. The section shows flights, trains, hotels, and car rentals with contextual information (destination city, relative time, type identifier) and navigates to trip details on tap.
Key changes:
UpcomingTravelSection– new widget that fetches trip rooms from Onyx, extracts reservations starting within 7 days, and renders them sorted by start date.UpcomingTravelItem– renders each reservation with an icon, title (e.g. "Flight to Paris"), subtitle with relative time and identifier (e.g. "In 3 days · AA 1234"), and navigates to the trip detail route on press.useUpcomingTravelReservations– hook that filters all trip room reports for upcoming reservations within a 7-day window.TripReservationUtilsfix – hotel and car reservations now useaddress.localityforcityNameinstead ofchainName, so city names display correctly.homeWidgetIconContainerstyle and updatedhomePageRightColumnto include column gap.Fixed Issues
$ #81529
PROPOSAL:
Tests
Offline tests
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-02-19.at.17.01.13.mov