[Behind Time Tracking Beta] Allow editing hour count and rate in time expense confirmation page#79214
Conversation
|
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 |
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
|
🚧 @grgia has triggered a test Expensify/App build. You can view the workflow run here. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…irmation-hours-rate-edit
…irmation-hours-rate-edit
|
@DylanDylann 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] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7bedff7025
ℹ️ 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".
|
yes, in this case the amount is invalid cause it is too high and it's definitely an edge case since the limit is very high. |
|
btw, this feature will be under beta for now and there will be more PRs coming soon, so we could change the error messages in one of them to not block this one, if we need more time to finalize the copy |
|
@dubielzyk-expensify @dannymcclain let's choose an error message for now while it's on our mind. Maybe we should only error on the confirmation page:
|
|
I like your suggestion @grgia 👍 |
grgia
left a comment
There was a problem hiding this comment.
Cool! @mhawryluk would you update this PR with the above error message and let me know when you're ready for a final build 🙇
sure, on it! |
🦜 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 4713b7d9..c340e4ed 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1507,6 +1507,7 @@ const translations: TranslationDeepObject<typeof en> = {
hrs: 'Std.',
hours: 'Stunden',
ratePreview: (rate: string) => `${rate} / Stunde`,
+ amountTooLargeError: 'Der Gesamtbetrag ist zu hoch. Verringere die Stunden oder reduziere den Satz.',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>Erklären</strong></a> ✨',
},
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index e922d9d8..b8b738f9 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1508,6 +1508,7 @@ const translations: TranslationDeepObject<typeof en> = {
hrs: 'h',
hours: 'Heures',
ratePreview: (rate: string) => `${rate} / heure`,
+ amountTooLargeError: 'Le montant total est trop élevé. Réduisez le nombre d’heures ou diminuez le tarif.',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>Expliquer</strong></a> ✨',
},
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 34977f37..ad6054e6 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1502,6 +1502,7 @@ const translations: TranslationDeepObject<typeof en> = {
hrs: 'ore',
hours: 'Ore',
ratePreview: (rate: string) => `${rate} / ora`,
+ amountTooLargeError: 'L’importo totale è troppo elevato. Riduci le ore o diminuisci la tariffa.',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>Spiegare</strong></a> ✨',
},
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 8d12346d..8420fc47 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -1501,6 +1501,7 @@ const translations: TranslationDeepObject<typeof en> = {
hrs: '時間',
hours: '時間',
ratePreview: (rate: string) => `${rate} / 時間`,
+ amountTooLargeError: '合計金額が大きすぎます。時間を減らすか、レートを下げてください。',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>説明する</strong></a> ✨',
},
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 622d0123..ad6eeaa3 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1501,6 +1501,7 @@ const translations: TranslationDeepObject<typeof en> = {
hrs: 'uur',
hours: 'Uren',
ratePreview: (rate: string) => `${rate} / uur`,
+ amountTooLargeError: 'Het totale bedrag is te hoog. Verlaag het aantal uren of verlaag het tarief.',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>Uitleggen</strong></a> ✨',
},
@@ -8008,7 +8009,6 @@ Hier is een *testbon* om je te laten zien hoe het werkt:`,
confirm: 'Afstandstracking negeren',
},
zeroDistanceTripModal: {title: 'Kan geen uitgave aanmaken', prompt: 'Je kunt geen uitgave aanmaken met dezelfde begin- en eindlocatie.'},
-
locationRequiredModal: {
title: 'Locatietoegang vereist',
prompt: 'Sta locatietoegang toe in de instellingen van je apparaat om GPS-afstandsregistratie te starten.',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 0507d2c3..0d2af082 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1498,7 +1498,8 @@ const translations: TranslationDeepObject<typeof en> = {
hoursAt: (hours: number, rate: string) => `${hours} ${hours === 1 ? 'godzina' : 'godziny'} @ ${rate} / godzinę`,
hrs: 'godz.',
hours: 'Godziny',
- ratePreview: (rate: string) => `${rate} / godzinę`,
+ ratePreview: (rate: string) => `${rate} / godzina`,
+ amountTooLargeError: 'Całkowita kwota jest zbyt wysoka. Zmniejsz liczbę godzin lub obniż stawkę.',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>Wyjaśnij</strong></a> ✨',
},
@@ -7983,7 +7984,6 @@ Oto *paragon testowy*, który pokazuje, jak to działa:`,
confirm: 'Odrzuć śledzenie dystansu',
},
zeroDistanceTripModal: {title: 'Nie można utworzyć wydatku', prompt: 'Nie możesz utworzyć wydatku z tym samym miejscem początkowym i końcowym.'},
-
locationRequiredModal: {
title: 'Wymagany dostęp do lokalizacji',
prompt: 'Aby rozpocząć śledzenie dystansu GPS, zezwól na dostęp do lokalizacji w ustawieniach swojego urządzenia.',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index beae2769..690925a3 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1498,6 +1498,7 @@ const translations: TranslationDeepObject<typeof en> = {
hrs: 'h',
hours: 'Horas',
ratePreview: (rate: string) => `${rate} / hora`,
+ amountTooLargeError: 'O valor total é muito alto. Reduza as horas ou diminua a tarifa.',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>Explicar</strong></a> ✨',
},
@@ -7993,7 +7994,6 @@ Aqui está um *recibo de teste* para mostrar como funciona:`,
confirm: 'Descartar rastreamento de distância',
},
zeroDistanceTripModal: {title: 'Não é possível criar a despesa', prompt: 'Você não pode criar uma despesa com o mesmo local de partida e de chegada.'},
-
locationRequiredModal: {
title: 'Acesso à localização necessário',
prompt: 'Permita o acesso à localização nas configurações do seu dispositivo para iniciar o rastreamento de distância por GPS.',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index a7fff3e7..ecd0749e 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1476,6 +1476,7 @@ const translations: TranslationDeepObject<typeof en> = {
hrs: '小时',
hours: '小时',
ratePreview: (rate: string) => `${rate} / 小时`,
+ amountTooLargeError: '总金额过大。请减少工时或降低费率。',
},
AskToExplain: '. <a href="new-expensify://concierge/explain"><strong>解释</strong></a> ✨',
},
@@ -7799,7 +7800,6 @@ ${reportName}
stopGpsTrackingModal: {title: '停止 GPS 追踪', prompt: '你确定吗?这将结束你当前的旅程。', cancel: '恢复追踪', confirm: '停止 GPS 追踪'},
discardDistanceTrackingModal: {title: '丢弃距离跟踪', prompt: '您确定吗?这将放弃您当前的流程,且无法撤销。', confirm: '丢弃距离跟踪'},
zeroDistanceTripModal: {title: '无法创建报销', prompt: '你不能创建起点和终点相同的报销。'},
-
locationRequiredModal: {title: '需要访问位置信息', prompt: '请在设备设置中允许位置访问以开始 GPS 距离跟踪。', allow: '允许'},
androidBackgroundLocationRequiredModal: {title: '需要后台位置访问权限', prompt: '请在设备设置中允许应用使用“始终允许”位置访问权限,以开始 GPS 距离跟踪。'},
preciseLocationRequiredModal: {title: '需要精确位置', prompt: '请在设备设置中启用“精确位置”以开始 GPS 距离跟踪。'},
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
|
@grgia the PR is ready! |
|
🚧 @grgia has triggered a test Expensify/App build. You can view the workflow run here. |
grgia
left a comment
There was a problem hiding this comment.
Code LGTM, going to test manually before merge.
cc @DylanDylann for final review as well 🎉
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by https://github.com/grgia in version: 9.3.5-0 🚀
|
|
🚀 Deployed to production by https://github.com/Beamanator in version: 9.3.5-7 🚀
|
Explanation of Change
Hides the merchant row and adds 2 new ones (hours and rate) in the money request confirmation page, when creating a time request.
Fixed Issues
$ #77683
PROPOSAL: N/A
Tests
1, Log in to an account with timeTracking beta enabled.
2. Create a Workspace.
3. Enable Time Tracking feature for the workspace in Expensify Classic and set some default time tracking rate value there. (Settings > Workspaces > select the workspace > Time).
4. Go to the Workspace's chat/report in new dot.
5. Click the + button > Create expense.
6. Select the "Time" tab.
7. Enter a valid value for the input and click next, there should be a confirmation page
9. There should be no merchant row.
10. The amount row should not be clickable.
11. There should be a new "Hours" row, click on it.
12. Change the value, check if only correct values are accepted, click save.
13. The amount should be updated correctly (round(hours * rate)).
14. There should be a new "Rate" row, it should display the rate correctly formatted, click on it.
15. Change the hourly rate value and click save.
16. The amount should be updated correctly (round(hours * rate)).
17. Create the expense.
18. Check if the created expense has a correct merchant value (reflecting the modified count and rate).
19. Start creating a time expense again, set the hours and rate to very big numbers, try to create the expense, an error should be shown and creation shouldn't be allowed.
Offline tests
N/A
QA Steps
Same as tests.
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
Nagranie.z.ekranu.2026-01-12.o.14.21.43.mov
Android: mWeb Chrome
Nagranie.z.ekranu.2026-01-12.o.14.23.35.mov
iOS: Native
Simulator.Screen.Recording.-.iPhone.16.Pro.Max.-.2026-01-12.at.13.58.04.mp4
iOS: mWeb Safari
Simulator.Screen.Recording.-.iPhone.16.Pro.Max.-.2026-01-12.at.14.11.44.mp4
MacOS: Chrome / Safari
Nagranie.z.ekranu.2026-01-9.o.17.48.28.mov