You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Please re-state the problem that we are trying to solve in this issue.
Add the persistent bottom-right product marketing window for the October 2026 Product Update ("Mileage on cruise control" / "Mileage handled automatically"), supporting two audience variants:
Subtext: Jump straight to your frequent trips and fix a trip’s stop location without starting over.
Admin Window Variant (Admins):
Title: Mileage handled automatically
Subtext: Mileage rates that keep themselves current, plus total control over how trips get logged.
Buttons & Link (Both variants):[Dismiss] and [Learn more] linking to https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses.
Visual Asset: Marketing promo image provided in the issue description.
What is the root cause of that problem?
This is a feature addition on the persistent product marketing window infrastructure (issue #95791 / PR #96141). Currently, ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENT in src/libs/ProductMarketingWindowUtils.ts statically serves the September 2026 announcement (PRODUCT_UPDATE_SEPTEMBER_2026) and does not dynamically distinguish between Admin and Non-Admin (Member) audiences.
What changes do you think we should make in order to solve the problem?
Add Constant and Asset:
In src/CONST/index.ts:
Add PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026' to CONST.MARKETING_WINDOW_UPDATE_KEYS.
Add october2026-promo.png (using the provided visual asset).
Add Localization Keys:
In src/languages/en.ts (and mirror across other language files):
productMarketingWindow: {october2026: {member: {heading: 'Mileage on cruise control',body: 'Jump straight to your frequent trips and fix a trip’s stop location without starting over.',},admin: {heading: 'Mileage handled automatically',body: 'Mileage rates that keep themselves current, plus total control over how trips get logged.',},},},
Update Announcement Logic with Role-Based Resolution in ProductMarketingWindowUtils.ts:
Define both variant announcements sharing updateKey: CONST.MARKETING_WINDOW_UPDATE_KEYS.PRODUCT_UPDATE_OCTOBER_2026, ctaUrl: CONST.DISTANCE_EXPENSES_HELP_URL, and image October2026PromoImage.
Export a helper function getActiveProductMarketingAnnouncement(isAdmin: boolean): ProductMarketingAnnouncement:
Why useHasActiveAdminPolicies() over useIsPaidPolicyAdmin()?
The audience specification requires that anyone who is an admin on at least one workspace receives the admin variant (and member variant only if not an admin on any workspace). useHasActiveAdminPolicies() evaluates active workspaces across both free and paid policies, perfectly matching the design doctrine.
Keep the dismissal key logic (lastDismissedMarketingWindow === updateKey) consistent so dismissing either variant persists under productUpdateOctober2026 across subsequent role changes.
Update Unit Tests:
In tests/unit/ProductMarketingWindowUtilsTest.ts: Update UNKNOWN_UPDATE_KEY from 'productUpdateOctober2026' to 'productUpdateNovember2026' so the stale/future client detection test continues to test an unregistered future key.
In tests/unit/ProductMarketingWindowTest.tsx: Add test asserting admin copy when hasActiveAdminPolicies is true, and member copy when false.
What alternative solutions did you explore? (Optional)
Using useIsPaidPolicyAdmin(): Excludes admins of free workspaces who should also receive the Admin variant.
Separate updateKeys for admin and member: Rejected because dismissing the October update should dismiss the monthly product update for the user permanently, preventing repeated popups if their workspace role changes.
Please re-state the problem that we are trying to solve in this issue.
Add the persistent bottom-right product marketing window for the October 2026 Product Update ("Mileage on cruise control" / "Mileage handled automatically") supporting audience-targeted variants:
Marketing visual image provided in the issue description.
What is the root cause of that problem?
Currently, ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENT in src/libs/ProductMarketingWindowUtils.ts statically serves the September 2026 announcement (PRODUCT_UPDATE_SEPTEMBER_2026) and only supports a single static heading/body without audience-role differentiation. Furthermore:
The October 2026 update key and help article URL are not yet defined in src/CONST/index.ts.
The new promotional image asset (october2026-promo.png) and translation strings need to be integrated.
Audience targeting (Admins vs Non-Admin Members where admin role prevails) needs to be resolved dynamically via policy state.
What changes do you think we should make in order to solve the problem?
1. Constants & Asset Integration
Asset: Save the provided promotional graphic to assets/images/october2026-promo.png.
src/CONST/index.ts:
Add PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026' to CONST.MARKETING_WINDOW_UPDATE_KEYS.
2. Localized Strings (src/languages/en.ts and other language files)
In src/languages/en.ts (and corresponding fallback entries in other locale files):
productMarketingWindow: {october2026: {member: {heading: 'Mileage on cruise control',body: 'Jump straight to your frequent trips and fix a trip’s stop location without starting over.',},admin: {heading: 'Mileage handled automatically',body: 'Mileage rates that keep themselves current, plus total control over how trips get logged.',},},},
3. Update Announcement Configuration in src/libs/ProductMarketingWindowUtils.ts
Define the October 2026 announcement with audience-targeted content while maintaining a single unified updateKey: CONST.MARKETING_WINDOW_UPDATE_KEYS.PRODUCT_UPDATE_OCTOBER_2026:
Non-Admin Member (not an admin on any workspace) -> Member variant.
Admin (admin on at least one workspace) -> Admin variant.
Both (member on some workspaces, admin on others) -> Admin prevails. useHasActiveAdminPolicies() uses hasActiveAdminPoliciesSelector(policies, login) which cleanly evaluates active workspaces where the user has an admin role across both free and paid policies (unlike useIsPaidPolicyAdmin() which excludes free workspace admins).
Dismissal logic (dismissMarketingWindow(announcement.updateKey)) remains unchanged and persists productUpdateOctober2026. This ensures that if an employee's role changes (e.g. member promoted to admin), a dismissed October announcement remains dismissed.
5. Unit & UI Test Updates
tests/unit/ProductMarketingWindowUtilsTest.ts:
Update UNKNOWN_UPDATE_KEY: In this file, UNKNOWN_UPDATE_KEY was hardcoded as 'productUpdateOctober2026'. Since productUpdateOctober2026 is now an active recognized key in CONST.MARKETING_WINDOW_UPDATE_KEYS, update UNKNOWN_UPDATE_KEY to 'productUpdateNovember2026' so the test asserting stale/unknown client detection continues to test an unregistered future key.
tests/unit/ProductMarketingWindowTest.tsx:
Update baseline announcement assertions to verify October 2026 promo image and translation keys.
Add a test verifying that when hasActiveAdminPolicies is true, the admin heading/body is rendered, and when false, the member heading/body is rendered.
Verify that dismissing or clicking the CTA persists productUpdateOctober2026 and opens CONST.DISTANCE_EXPENSES_HELP_URL.
Update the test translation lookup windowHeading to match the active announcement translation path.
What alternative solutions did you explore? (Optional)
Using useIsPaidPolicyAdmin(): Rejected because the audience criteria is simply "admin of at least one workspace", not restricted to paid policy types. Free policies with admin roles must also receive the admin variant.
Using separate update keys for Admin vs Member (e.g., productUpdateOctober2026Admin and productUpdateOctober2026Member): Rejected because dismissing the October update should dismiss the monthly product update for the user account permanently, preventing duplicate popups if their workspace permissions fluctuate.
Promotional graphics asset provided in the issue description (assets/images/october2026-promo.png).
What is the root cause of that problem?
This is a feature addition on the persistent product marketing window framework introduced in issue #95791 / PR #96141. Currently:
src/libs/ProductMarketingWindowUtils.ts statically exports ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENT for the September 2026 release (PRODUCT_UPDATE_SEPTEMBER_2026) and only supports a single static heading/body without audience-role differentiation.
The October 2026 update key (PRODUCT_UPDATE_OCTOBER_2026) and distance expenses help URL (DISTANCE_EXPENSES_HELP_URL) are not yet defined in src/CONST/index.ts.
Marketing image asset (october2026-promo.png) and localized copy are not yet added.
Audience targeting (Admin vs Non-Admin Member, where admin role takes precedence if a user has both) needs to be resolved dynamically via policy state.
What changes do you think we should make in order to solve the problem?
1. Constants & Visual Asset
In src/CONST/index.ts:
Add PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026' to CONST.MARKETING_WINDOW_UPDATE_KEYS.
Add the marketing illustration as october2026-promo.png.
2. Localization Strings
In src/languages/en.ts (and mirror in other locale files):
productMarketingWindow: {october2026: {member: {heading: 'Mileage on cruise control',body: 'Jump straight to your frequent trips and fix a trip’s stop location without starting over.',},admin: {heading: 'Mileage handled automatically',body: 'Mileage rates that keep themselves current, plus total control over how trips get logged.',},},},
3. Update Announcement Configuration in src/libs/ProductMarketingWindowUtils.ts
Export a helper function getActiveProductMarketingAnnouncement(isAdmin?: boolean) that returns the appropriate announcement while preserving ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENT for backwards compatibility:
Why useHasActiveAdminPolicies()?
Per issue requirements, anyone who is an admin of at least one workspace receives the Admin variant, and only users with no admin roles across all active workspaces receive the Member variant. useHasActiveAdminPolicies() directly uses hasActiveAdminPoliciesSelector which accounts for active workspaces across both free and paid policies (unlike useIsPaidPolicyAdmin which excludes free policy admins).
Dismissal persistence via dismissMarketingWindow(announcement.updateKey) continues to write productUpdateOctober2026, guaranteeing that dismissing either variant persists account-wide even if the user's role subsequently changes.
5. Unit & Navigation Test Suite Updates
tests/unit/ProductMarketingWindowUtilsTest.ts:
Update UNKNOWN_UPDATE_KEY from 'productUpdateOctober2026' to 'productUpdateNovember2026'. Because productUpdateOctober2026 is now a recognized key in CONST.MARKETING_WINDOW_UPDATE_KEYS, updating this ensures the test asserting unrecognized future keys continues to verify stale-client behavior.
tests/unit/ProductMarketingWindowTest.tsx:
Update announcement assertions for October 2026 assets and copy.
Add test asserting that when hasActiveAdminPolicies is true, the admin heading/body is rendered, and when false, the member heading/body is rendered.
Update windowHeading translation reference to match the active announcement heading.
What alternative solutions did you explore? (Optional)
Using useIsPaidPolicyAdmin(): Discarded because it excludes admins of free workspaces who must also receive the Admin variant.
Separate update keys per variant (e.g. productUpdateOctober2026Admin): Discarded because dismissing the monthly update should be persistent for the user regardless of future role changes.
Please re-state the problem that we are trying to solve in this issue.
Add the persistent bottom-right product marketing window for the October 2026 Product Update ("Mileage on cruise control" / "Mileage handled automatically"), supporting two audience variants:
Subtext: Jump straight to your frequent trips and fix a trip’s stop location without starting over.
Admin Window Variant (Admins):
Title: Mileage handled automatically
Subtext: Mileage rates that keep themselves current, plus total control over how trips get logged.
Buttons & Link (Both variants):[Dismiss] and [Learn more] linking to https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses.
This is a feature addition on the persistent product marketing window infrastructure (introduced in #95791). Currently, ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENT in src/libs/ProductMarketingWindowUtils.ts statically serves the September 2026 announcement (PRODUCT_UPDATE_SEPTEMBER_2026) and does not dynamically distinguish between Admin and Member audiences based on the user's active workspace permissions.
What changes do you think we should make in order to solve the problem?
1. Add Constants & Help URL
In src/CONST/index.ts:
Add PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026' to CONST.MARKETING_WINDOW_UPDATE_KEYS.
In src/languages/en.ts (and corresponding locale files):
productMarketingWindow: {october2026: {member: {heading: 'Mileage on cruise control',body: 'Jump straight to your frequent trips and fix a trip’s stop location without starting over.',},admin: {heading: 'Mileage handled automatically',body: 'Mileage rates that keep themselves current, plus total control over how trips get logged.',},},},
3. Update Announcement Configuration in src/libs/ProductMarketingWindowUtils.ts
Export a function getActiveProductMarketingAnnouncement(isAdmin?: boolean) that returns the appropriate announcement while maintaining ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENT for backwards compatibility:
4. Connect Audience Resolution in ProductMarketingWindowManager.tsx
Subscribe to ONYXKEYS.COLLECTION.POLICY and resolve whether the current user has any active admin workspaces using hasActiveAdminPoliciesSelector (from src/selectors/Policy.ts) and current user email from ONYXKEYS.SESSION:
Why hasActiveAdminPoliciesSelector?
Per the issue requirements, any user who is an admin on at least one active workspace (Collect, Control, or Free) should see the Admin variant; members with zero admin workspaces see the Member variant. hasActiveAdminPoliciesSelector precisely utilizes getActiveAdminWorkspaces, which accounts for both paid and free policies.
Dismissing the window calls dismissMarketingWindow(announcement.updateKey), persisting productUpdateOctober2026. This guarantees that dismissing either variant persists across the account even if their workspace role changes later.
5. Tests
tests/unit/ProductMarketingWindowUtilsTest.ts: Update UNKNOWN_UPDATE_KEY to 'productUpdateNovember2026' (since 'productUpdateOctober2026' is now registered in CONST.MARKETING_WINDOW_UPDATE_KEYS), ensuring the stale-client test continues to pass as expected.
tests/unit/ProductMarketingWindowTest.tsx: Add test coverage verifying that when hasActiveAdminPolicies is true, the admin variant heading/body is rendered, and when false, the member variant is rendered.
What alternative solutions did you explore? (Optional)
Separate keys per role (e.g. productUpdateOctober2026Admin): Discarded because dismissing the monthly update should apply account-wide regardless of role changes.
@catdevore We’re updating the help docs in #104781 to align with Neil’s comment before shipping this. Once the docs are updated, we’ll merge the App PR.
@catdevore can you chime in? It sounds like we need an additional image for the October product image? @ahmedGaber93 what exactly do you need from design?
Activity
melvin-bot commentedon Oct 19, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @ahmedGaber93 (
External)[-]October 2026 product update - Add persistent bottom-right product marketing window[/-][+][$175] October 2026 product update - Add persistent bottom-right product marketing window[/+]melvin-bot commentedon Oct 19, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022112330648272329318
camesenin commentedon Oct 19, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
Add the persistent bottom-right product marketing window for the October 2026 Product Update ("Mileage on cruise control" / "Mileage handled automatically"), supporting two audience variants:
[Dismiss]and[Learn more]linking tohttps://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses.What is the root cause of that problem?
This is a feature addition on the persistent product marketing window infrastructure (issue #95791 / PR #96141). Currently,
ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENTinsrc/libs/ProductMarketingWindowUtils.tsstatically serves the September 2026 announcement (PRODUCT_UPDATE_SEPTEMBER_2026) and does not dynamically distinguish between Admin and Non-Admin (Member) audiences.What changes do you think we should make in order to solve the problem?
Add Constant and Asset:
src/CONST/index.ts:PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026'toCONST.MARKETING_WINDOW_UPDATE_KEYS.DISTANCE_EXPENSES_HELP_URL: 'https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses'.assets/images/:october2026-promo.png(using the provided visual asset).Add Localization Keys:
src/languages/en.ts(and mirror across other language files):Update Announcement Logic with Role-Based Resolution in
ProductMarketingWindowUtils.ts:updateKey: CONST.MARKETING_WINDOW_UPDATE_KEYS.PRODUCT_UPDATE_OCTOBER_2026,ctaUrl: CONST.DISTANCE_EXPENSES_HELP_URL, and imageOctober2026PromoImage.getActiveProductMarketingAnnouncement(isAdmin: boolean): ProductMarketingAnnouncement:Integrate Role Check in
ProductMarketingWindowManager.tsx:useHasActiveAdminPolicies():useHasActiveAdminPolicies()overuseIsPaidPolicyAdmin()?The audience specification requires that anyone who is an admin on at least one workspace receives the admin variant (and member variant only if not an admin on any workspace).
useHasActiveAdminPolicies()evaluates active workspaces across both free and paid policies, perfectly matching the design doctrine.lastDismissedMarketingWindow === updateKey) consistent so dismissing either variant persists underproductUpdateOctober2026across subsequent role changes.Update Unit Tests:
tests/unit/ProductMarketingWindowUtilsTest.ts: UpdateUNKNOWN_UPDATE_KEYfrom'productUpdateOctober2026'to'productUpdateNovember2026'so the stale/future client detection test continues to test an unregistered future key.tests/unit/ProductMarketingWindowTest.tsx: Add test asserting admin copy whenhasActiveAdminPoliciesis true, and member copy when false.What alternative solutions did you explore? (Optional)
useIsPaidPolicyAdmin(): Excludes admins of free workspaces who should also receive the Admin variant.Contributor details
Your Expensify account email: camesenin@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~0170d6b02e9440e604
melvin-bot commentedon Oct 19, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
janiya2 commentedon Oct 20, 2026
Contributor details
Your Expensify account email: janithad2@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/janithad
Proposal
Please re-state the problem that we are trying to solve in this issue.
Add the persistent bottom-right product marketing window for the October 2026 Product Update ("Mileage on cruise control" / "Mileage handled automatically") supporting audience-targeted variants:
Mileage on cruise controlJump straight to your frequent trips and fix a trip’s stop location without starting over.Mileage handled automaticallyMileage rates that keep themselves current, plus total control over how trips get logged.[Dismiss]and[Learn more]https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-ExpensesWhat is the root cause of that problem?
Currently,
ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENTinsrc/libs/ProductMarketingWindowUtils.tsstatically serves the September 2026 announcement (PRODUCT_UPDATE_SEPTEMBER_2026) and only supports a single static heading/body without audience-role differentiation. Furthermore:src/CONST/index.ts.october2026-promo.png) and translation strings need to be integrated.What changes do you think we should make in order to solve the problem?
1. Constants & Asset Integration
assets/images/october2026-promo.png.src/CONST/index.ts:PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026'toCONST.MARKETING_WINDOW_UPDATE_KEYS.DISTANCE_EXPENSES_HELP_URL: 'https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses'.2. Localized Strings (
src/languages/en.tsand other language files)In
src/languages/en.ts(and corresponding fallback entries in other locale files):3. Update Announcement Configuration in
src/libs/ProductMarketingWindowUtils.tsupdateKey: CONST.MARKETING_WINDOW_UPDATE_KEYS.PRODUCT_UPDATE_OCTOBER_2026:4. Connect Audience Resolution in
ProductMarketingWindowManager.tsxsrc/components/ProductMarketingWindow/ProductMarketingWindowManager.tsx, consumeuseHasActiveAdminPolicies():ProductMarketingWindowManager:Why
useHasActiveAdminPolicies()?The audience specification in [Due for payment 2026-08-29] [$250] Add persistent bottom-right product marketing window #95791 dictates:
useHasActiveAdminPolicies()useshasActiveAdminPoliciesSelector(policies, login)which cleanly evaluates active workspaces where the user has an admin role across both free and paid policies (unlikeuseIsPaidPolicyAdmin()which excludes free workspace admins).Dismissal logic (
dismissMarketingWindow(announcement.updateKey)) remains unchanged and persistsproductUpdateOctober2026. This ensures that if an employee's role changes (e.g. member promoted to admin), a dismissed October announcement remains dismissed.5. Unit & UI Test Updates
tests/unit/ProductMarketingWindowUtilsTest.ts:UNKNOWN_UPDATE_KEY: In this file,UNKNOWN_UPDATE_KEYwas hardcoded as'productUpdateOctober2026'. SinceproductUpdateOctober2026is now an active recognized key inCONST.MARKETING_WINDOW_UPDATE_KEYS, updateUNKNOWN_UPDATE_KEYto'productUpdateNovember2026'so the test asserting stale/unknown client detection continues to test an unregistered future key.tests/unit/ProductMarketingWindowTest.tsx:hasActiveAdminPoliciesistrue, the admin heading/body is rendered, and whenfalse, the member heading/body is rendered.productUpdateOctober2026and opensCONST.DISTANCE_EXPENSES_HELP_URL.tests/ui/ProductMarketingWindowNavigationTest.tsx:windowHeadingto match the active announcement translation path.What alternative solutions did you explore? (Optional)
useIsPaidPolicyAdmin(): Rejected because the audience criteria is simply "admin of at least one workspace", not restricted to paid policy types. Free policies with admin roles must also receive the admin variant.productUpdateOctober2026AdminandproductUpdateOctober2026Member): Rejected because dismissing the October update should dismiss the monthly product update for the user account permanently, preventing duplicate popups if their workspace permissions fluctuate.melvin-bot commentedon Oct 20, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
sijo0218 commentedon Oct 20, 2026
Contributor details
Your Expensify account email: sijo0218@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~011091133bbb09cd1c
Proposal
Please re-state the problem that we are trying to solve in this issue.
Add the persistent bottom-right product marketing window for the October 2026 Product Update feature, supporting two audience-targeted variants:
Mileage on cruise controlJump straight to your frequent trips and fix a trip’s stop location without starting over.Mileage handled automaticallyMileage rates that keep themselves current, plus total control over how trips get logged.[Dismiss]and[Learn more]https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expensesassets/images/october2026-promo.png).What is the root cause of that problem?
This is a feature addition on the persistent product marketing window framework introduced in issue #95791 / PR #96141. Currently:
src/libs/ProductMarketingWindowUtils.tsstatically exportsACTIVE_PRODUCT_MARKETING_ANNOUNCEMENTfor the September 2026 release (PRODUCT_UPDATE_SEPTEMBER_2026) and only supports a single static heading/body without audience-role differentiation.PRODUCT_UPDATE_OCTOBER_2026) and distance expenses help URL (DISTANCE_EXPENSES_HELP_URL) are not yet defined insrc/CONST/index.ts.october2026-promo.png) and localized copy are not yet added.What changes do you think we should make in order to solve the problem?
1. Constants & Visual Asset
src/CONST/index.ts:PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026'toCONST.MARKETING_WINDOW_UPDATE_KEYS.DISTANCE_EXPENSES_HELP_URL: 'https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses'.assets/images/:october2026-promo.png.2. Localization Strings
src/languages/en.ts(and mirror in other locale files):3. Update Announcement Configuration in
src/libs/ProductMarketingWindowUtils.tsExport a helper function
getActiveProductMarketingAnnouncement(isAdmin?: boolean)that returns the appropriate announcement while preservingACTIVE_PRODUCT_MARKETING_ANNOUNCEMENTfor backwards compatibility:4. Connect Audience Resolution in
src/components/ProductMarketingWindow/ProductMarketingWindowManager.tsxuseHasActiveAdminPoliciesandgetActiveProductMarketingAnnouncement:ProductMarketingWindowManager:useHasActiveAdminPolicies()?Per issue requirements, anyone who is an admin of at least one workspace receives the Admin variant, and only users with no admin roles across all active workspaces receive the Member variant.
useHasActiveAdminPolicies()directly useshasActiveAdminPoliciesSelectorwhich accounts for active workspaces across both free and paid policies (unlikeuseIsPaidPolicyAdminwhich excludes free policy admins).dismissMarketingWindow(announcement.updateKey)continues to writeproductUpdateOctober2026, guaranteeing that dismissing either variant persists account-wide even if the user's role subsequently changes.5. Unit & Navigation Test Suite Updates
tests/unit/ProductMarketingWindowUtilsTest.ts:UNKNOWN_UPDATE_KEYfrom'productUpdateOctober2026'to'productUpdateNovember2026'. BecauseproductUpdateOctober2026is now a recognized key inCONST.MARKETING_WINDOW_UPDATE_KEYS, updating this ensures the test asserting unrecognized future keys continues to verify stale-client behavior.tests/unit/ProductMarketingWindowTest.tsx:hasActiveAdminPoliciesis true, the admin heading/body is rendered, and when false, the member heading/body is rendered.tests/ui/ProductMarketingWindowNavigationTest.tsx:windowHeadingtranslation reference to match the active announcement heading.What alternative solutions did you explore? (Optional)
useIsPaidPolicyAdmin(): Discarded because it excludes admins of free workspaces who must also receive the Admin variant.productUpdateOctober2026Admin): Discarded because dismissing the monthly update should be persistent for the user regardless of future role changes.melvin-bot commentedon Oct 20, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
RajGahoi commentedon Oct 20, 2026
Contributor details
Your Expensify account email: gahoiraj01@gmail.com
Upwork Profile Link: https://www.upwork.com/freelancers/~014898525b9c53fc32
Proposal
Please re-state the problem that we are trying to solve in this issue.
Add the persistent bottom-right product marketing window for the October 2026 Product Update ("Mileage on cruise control" / "Mileage handled automatically"), supporting two audience variants:
[Dismiss]and[Learn more]linking tohttps://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses.october2026-promo.png).What is the root cause of that problem?
This is a feature addition on the persistent product marketing window infrastructure (introduced in #95791). Currently,
ACTIVE_PRODUCT_MARKETING_ANNOUNCEMENTinsrc/libs/ProductMarketingWindowUtils.tsstatically serves the September 2026 announcement (PRODUCT_UPDATE_SEPTEMBER_2026) and does not dynamically distinguish between Admin and Member audiences based on the user's active workspace permissions.What changes do you think we should make in order to solve the problem?
1. Add Constants & Help URL
src/CONST/index.ts:PRODUCT_UPDATE_OCTOBER_2026: 'productUpdateOctober2026'toCONST.MARKETING_WINDOW_UPDATE_KEYS.DISTANCE_EXPENSES_HELP_URL: 'https://help.expensify.com/articles/new-expensify/reports-and-expenses/Distance-Expenses'.2. Add Localization Strings
src/languages/en.ts(and corresponding locale files):3. Update Announcement Configuration in
src/libs/ProductMarketingWindowUtils.tsExport a function
getActiveProductMarketingAnnouncement(isAdmin?: boolean)that returns the appropriate announcement while maintainingACTIVE_PRODUCT_MARKETING_ANNOUNCEMENTfor backwards compatibility:4. Connect Audience Resolution in
ProductMarketingWindowManager.tsxONYXKEYS.COLLECTION.POLICYand resolve whether the current user has any active admin workspaces usinghasActiveAdminPoliciesSelector(fromsrc/selectors/Policy.ts) and current user email fromONYXKEYS.SESSION:hasActiveAdminPoliciesSelector?Per the issue requirements, any user who is an admin on at least one active workspace (Collect, Control, or Free) should see the Admin variant; members with zero admin workspaces see the Member variant.
hasActiveAdminPoliciesSelectorprecisely utilizesgetActiveAdminWorkspaces, which accounts for both paid and free policies.dismissMarketingWindow(announcement.updateKey), persistingproductUpdateOctober2026. This guarantees that dismissing either variant persists across the account even if their workspace role changes later.5. Tests
tests/unit/ProductMarketingWindowUtilsTest.ts: UpdateUNKNOWN_UPDATE_KEYto'productUpdateNovember2026'(since'productUpdateOctober2026'is now registered inCONST.MARKETING_WINDOW_UPDATE_KEYS), ensuring the stale-client test continues to pass as expected.tests/unit/ProductMarketingWindowTest.tsx: Add test coverage verifying that whenhasActiveAdminPoliciesis true, the admin variant heading/body is rendered, and when false, the member variant is rendered.tests/ui/ProductMarketingWindowNavigationTest.tsx: Update expected heading translation keys.What alternative solutions did you explore? (Optional)
productUpdateOctober2026Admin): Discarded because dismissing the monthly update should apply account-wide regardless of role changes.melvin-bot commentedon Oct 20, 2026
✅ Contributor details stored successfully. Thank you for contributing to Expensify!
7 remaining items
shawnborton commentedon Oct 22, 2026
Here ya go: product-feature-gps.png.zip
ahmedGaber93 commentedon Oct 22, 2026
Thanks, I have asked melvin to use it #104699 (comment).
catdevore commentedon Oct 26, 2026
@ahmedGaber93 just checking on the status of this one so I can add it to my weekly update, thanks!
ahmedGaber93 commentedon Oct 26, 2026
@catdevore We’re updating the help docs in #104781 to align with Neil’s comment before shipping this. Once the docs are updated, we’ll merge the App PR.
melvin-bot commentedon Oct 28, 2026
Triggered auto assignment to @mjasikowski, see https://stackoverflow.com/c/expensify/questions/7972 for more details.
ahmedGaber93 commentedon Oct 29, 2026
Current statue: Waiting for design team input here #104699 (comment)
shawnborton commentedon Oct 29, 2026
@catdevore can you chime in? It sounds like we need an additional image for the October product image? @ahmedGaber93 what exactly do you need from design?
shawnborton commentedon Oct 29, 2026
Actually it looks like we want the same image for both, per the OP:
ahmedGaber93 commentedon Oct 29, 2026
@shawnborton @catdevore we do a few changes on the PR, feel free tow build adhoc and reviewing them.
We now use two different links, Neil add a fair comment here: #104699 (comment) to use links that directly access the topics.
Another fair comment here: #104699 (comment) about using different images, I think we need an image that clearly describes this feature.
Please let us know if we’ve misunderstood the product’s intent.
Screen.Recording.2026-10-29.at.11.00.35.PM.mov
shawnborton commentedon Oct 29, 2026
Okay I see what you are saying. We could do something like this? cc @Expensify/design
dannymcclain commentedon Oct 29, 2026
Looks good to me!
ahmedGaber93 commentedon Oct 29, 2026
This looks good to me also. I think this is what we are looking for.
shawnborton commentedon Oct 29, 2026
Let's see what @catdevore and @dubielzyk-expensify think.
dubielzyk-expensify commentedon Oct 30, 2026
LGTM! 👍