Skip to content

New mobile menu#328

Closed
NoeBerdoz wants to merge 5 commits into
14.0from
new-mobile-menu
Closed

New mobile menu#328
NoeBerdoz wants to merge 5 commits into
14.0from
new-mobile-menu

Conversation

@NoeBerdoz
Copy link
Copy Markdown
Contributor

image

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request implements a mobile-specific bottom navigation bar for the /my2/ portal, featuring new pictograms and an animated indicator. The review feedback points out that the navigation spacer and global body margin are currently applied to all pages, leading to layout issues on non-portal views. Other recommendations include correcting the icon for the mobile 'write' button, changing its positioning to fixed for better visibility, and replacing hardcoded tab widths with flexible layout properties to enhance maintainability.

Comment thread my_compassion/views/my2_bottom_nav.xml Outdated
<attribute name="t-attf-class" add="#{ 'd-none d-md-block' if request.session.uid and '/my2/' in request.httprequest.path else '' }" separator=" "/>
</xpath>
<xpath expr="//footer" position="after">
<div id="bottom_nav_spacer" class="d-block d-md-none w-100"></div>
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.

high

The #bottom_nav_spacer is currently added to every page on the website for mobile users because it is not wrapped in a conditional check. This will cause unwanted whitespace at the bottom of the entire site. It should be wrapped in the same t-if condition as the navigation bar.

            <t t-if="request.session.uid and '/my2/' in request.httprequest.path">
                <div id="bottom_nav_spacer" class="d-block d-md-none w-100"></div>
            </t>

Comment on lines +163 to +165
body {
margin-bottom: calc(5rem + env(safe-area-inset-bottom)) !important;
}
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.

high

This global margin-bottom on the body affects every page of the website on mobile devices. Combined with the #bottom_nav_spacer div, this creates significant redundant whitespace at the bottom of the entire site. This margin should be removed, as the spacer div in the template is sufficient to handle the layout offset for the fixed navigation bar.

Comment thread my_compassion/templates/pages/my2_child_letters.xml Outdated
Comment thread my_compassion/templates/pages/my2_child_letters.xml Outdated
Comment thread theme_compassion_2025/static/src/scss/layout/_header.scss Outdated
- Fix broken write button on letters page
- Implement conditional rendering of Sponsorships and Letters tabs
- Render cart badge only when cart is non-empty
- Refactor the blue color to use the new core one
- Fix pre-commit
@NoeBerdoz
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request implements a mobile-specific bottom navigation bar for the /my2/ portal, featuring animated tabs and a floating action button for writing letters. The changes include new SVG pictograms and corresponding SCSS styles. Review feedback identifies layout issues where navigation-related spacing (global body margin and a spacer div) is incorrectly applied to all mobile pages. It is recommended to restrict these styles and elements to the portal context to prevent unwanted whitespace across the rest of the website.

Comment thread theme_compassion_2025/static/src/scss/layout/_header.scss Outdated
Comment thread my_compassion/views/my2_bottom_nav.xml Outdated
Comment thread my_compassion/views/my2_bottom_nav.xml
@NoeBerdoz
Copy link
Copy Markdown
Contributor Author

@Danielgergely I added a few changes and fixes.

  • Fix broken write button on letters page
  • Implement conditional rendering of Sponsorships and Letters tabs
  • Render cart badge only when cart is non-empty
  • Refactor the blue color to use the new core one
  • Fix pre-commit

I could have implemented a regression regarding the mobile bottom margin, but the initial proposition added a bottom margin on every pages, even if the bottom bar wasn't shown, so I removed part of the concerned code.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 6, 2026

Confidence Score: 4/5

Safe to merge — all findings are P2 style/cosmetic issues with no runtime or data integrity impact.

Only P2 findings are present (missing i18n, indicator default position, SVG clip-path ID). No logic errors, security issues, or breaking changes were identified.

my_compassion/views/my2_bottom_nav.xml (missing translations), theme_compassion_2025/static/src/scss/layout/_header.scss (indicator default state), theme_compassion_2025/static/src/img/pictograms/Profile.svg (clip-path ID)

Important Files Changed

Filename Overview
my_compassion/views/my2_bottom_nav.xml New template that adds a mobile-only bottom navigation bar for /my2/ portal pages, with sponsor-conditional tabs and CSS-driven active indicator; tab labels are hardcoded English without i18n markers.
theme_compassion_2025/static/src/scss/layout/_header.scss Adds mobile bottom-nav and floating write-button styles; CSS sibling-selector indicator logic is correct for active tabs but defaults to Home position when no tab matches a route.
my_compassion/templates/pages/my2_child_letters.xml Adds a floating FAB (#write_button) visible only on mobile, linking to the new-letter route with an optional child_id query param; straightforward and correct.
theme_compassion_2025/static/src/img/pictograms/Profile.svg New Profile pictogram SVG; uses a hardcoded clipPath ID (_clip1) that could conflict with other SVGs if they are ever rendered inline on the same page.
theme_compassion_2025/data/pictograms.xml Registers three new pictograms (GiftBasket, Profile, Writing) in the theme data; straightforward additions with correct base64 file references.
my_compassion/manifest.py Adds my2_bottom_nav.xml to the data list; correctly placed in the load order.
.gitignore Adds *.DS_Store glob to gitignore; clean housekeeping.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Page Request to /my2/*"] --> B{request.session.uid?}
    B -- No --> C[Normal website.layout\nheader + footer visible]
    B -- Yes --> D["Hide header & footer on mobile\n(d-none d-md-block)"]
    D --> E{partner.is_sponsor?}
    E -- Yes 6 tabs --> F["Home · My Sponsorships · Letters\nGive · Gift Basket · Profile"]
    E -- No 4 tabs --> G["Home · Give · Gift Basket · Profile"]
    F --> H["Render my2-bottom-nav\n(fixed-bottom, d-flex d-md-none)"]
    G --> H
    H --> I["Active tab class set\nvia request.httprequest.path check"]
    I --> J["CSS nth-child sibling selector\nmoves .indicator-wrapper\ntransform: translateX(N x 100%)"]
    K["Letters page /my2/children/letters"] --> L["FAB #write_button visible on mobile\n(d-flex d-md-none)"]
    L --> M["Links to /my2/children/letters/new\n+ optional ?child_id= param"]
Loading

Reviews (1): Last reviewed commit: "[T3166] FIX: force scope on bottom_nav_s..." | Re-trigger Greptile

Comment on lines +32 to +78
<span>Home</span>
</a>
<t t-if="partner.is_sponsor">
<a
href="/my2/children"
t-attf-class="nav-tab d-flex flex-column align-items-center text-decoration-none #{'active text-core-blue' if '/my2/children' in request.httprequest.path and 'letter' not in request.httprequest.path else 'text-muted'}"
>
<i t-attf-class="pictogram-child-sponsorship vignette-icon" />
<span>My Sponsorships</span>
</a>
<a
href="/my2/children/letters"
t-attf-class="nav-tab d-flex flex-column align-items-center text-decoration-none #{'active text-core-blue' if '/my2/children/letters' in request.httprequest.path else 'text-muted'}"
>
<i t-attf-class="pictogram-letter-writing vignette-icon" />
<span>Letters</span>
</a>
</t>
<a
href="/my2/gifts"
t-attf-class="nav-tab d-flex flex-column align-items-center text-decoration-none #{'active text-core-blue' if request.httprequest.path == '/my2/gifts' else 'text-muted'}"
>
<i t-attf-class="pictogram-gift-donation-general vignette-icon" />
<span>Give</span>
</a>
<a
href="/my2/gift-package"
t-attf-class="nav-tab o_wsale_my_cart d-flex flex-column align-items-center text-decoration-none #{'active text-core-blue' if '/my2/gift-package' in request.httprequest.path else 'text-muted'}"
>
<div class="position-relative">
<i t-attf-class="pictogram-gift-basket vignette-icon" />
<t t-set="website_sale_order" t-value="website.sale_get_order()" />
<sup
t-if="website_sale_order and website_sale_order.cart_quantity"
class="my_cart_quantity badge text-white"
t-esc="website_sale_order.cart_quantity"
/>
</div>
<span>Gift basket</span>
</a>
<a
href="/my2/user_settings"
t-attf-class="nav-tab d-flex flex-column align-items-center text-decoration-none #{'active text-core-blue' if '/my2/user_settings' in request.httprequest.path or '/my2/donations' in request.httprequest.path else 'text-muted'}"
>
<i t-attf-class="pictogram-profile vignette-icon" />
<span>Profile</span>
</a>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Hardcoded English strings — missing i18n

All nav-tab labels (Home, My Sponsorships, Letters, Give, Gift basket, Profile) are hardcoded English strings with no Odoo translation markup. For a multilingual Compassion website, these won't be translated. Odoo QWeb supports translation via the t-esc="_('...')" pattern or the t-translation attribute on plain text nodes.

Similarly for the other <span> labels in the nav and the aria-label="Write a letter" attribute on the #write_button in my2_child_letters.xml.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is very true @Danielgergely And even more, there is no way for the user to switch its language anymore on mobile ! A solution has to be considered for this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@greptileai Great point, you could even have said that actually, the proposition removes the possibility for a mobile user to switch language, as they can't see the top menu anymore where the language selector is, which is a regression that should have been flagged.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You're absolutely right, and that's a more critical regression than the i18n markup issue I flagged. The d-none d-md-block on the header (lines 6-9) doesn't just hide the nav — it removes the entire language selector for mobile users. That's a functional regression, not just a translation quality issue.

My original comment focused on the static string labels but should have explicitly called out that hiding the header breaks language switching for mobile users entirely. The two issues together mean mobile users are both stuck in whatever language they loaded the page in and have no way to change it.

A concrete fix worth flagging: the language switcher (and any other header-only controls) needs to either be surfaced in the bottom nav or in a dedicated mobile menu/settings area before the header can be safely hidden on small screens.

Tip: You can give me more context with .greptile/rules.md so I get this right next time.

Comment on lines +128 to +142
left: 50%;
transform: translateX(-50%);
background: var(--core-blue);
border-radius: 50%;
border: 6px solid var(--pure-white);
}
}

/* --- THE SHIFTING LOGIC --- */
/* Moves the indicator wrapper by 100% of its own width for each slot */
.nav-tab:nth-child(1).active ~ .indicator-wrapper {
transform: translateX(0);
}

.nav-tab:nth-child(2).active ~ .indicator-wrapper {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Indicator defaults to Home position when no tab is active

The .indicator-wrapper has no initial transform override, so it sits at translateX(0) (Home slot) by default. When a user navigates to a /my2/ route that doesn't match any tab's active condition (e.g. a deep settings sub-page), no nth-child rule fires, and the indicator bubble visually "sits on" the Home icon even though it isn't active — the Home icon won't have the lifted/white styling, making the indicator appear orphaned or pointing at the wrong tab.

Consider setting a default that hides the indicator (e.g. opacity: 0) and only showing it when an active class is matched, or ensure every reachable /my2/ path maps to a tab.

Comment on lines +6 to +10
<clipPath id="_clip1">
<rect x="168.694" y="233.179" width="382.613" height="116.1"/>
</clipPath>
<g clip-path="url(#_clip1)">
<path d="M461.379,399.437C461.725,463.446 457.806,534.689 453.892,598.506C452.08,616.607 451.811,635.639 442.827,651.95C434.727,667.317 421.288,673.187 404.606,668.933C388.694,664.875 376.965,656.037 374.46,638.688C372.02,621.795 371.016,603.323 371.068,586.282C371.168,553.202 367.6,483.331 365.381,457.193C365.216,455.244 362.358,455.262 362.219,457.213C360.476,481.676 357.822,546.225 358.218,570.495C356.512,594.863 359.658,620.394 352.897,644.021C340.136,682.373 279.487,672.464 278.626,633.077C274.659,603.478 274.033,573.825 276.443,543.986C279.551,495.356 280.085,447.82 278.173,398.945C258.054,423.447 247.91,451.399 223.946,472.29C207.97,488.872 170.327,484.296 168.929,457.911C167.812,443.104 170.768,428.914 175.704,415.08C186.334,385.289 196.737,355.41 207.902,325.819C222.117,289.002 238.104,244.151 283.473,239.675C319.255,234.639 355.103,230.794 391.327,234.931C431.854,236.234 470.631,233.005 493.546,273.654C518.421,312.239 526.622,358.32 541.249,401.265C545.447,415.822 549.271,430.651 550.97,445.735C553.522,470.817 541.53,482.607 516.541,480.451C506.671,479.6 499.619,474.524 495.215,466.523C489.136,455.479 484.113,443.836 478.949,432.311C475.674,425.002 468.73,409.95 461.379,399.437ZM298.183,491.908C296.693,538.197 289.66,583.198 295.038,629.32C296.17,641.569 303.59,647.323 315.256,647.476C343.098,649.057 337.697,613.383 338.927,594.604C337.35,550.255 340.497,505.978 342.204,461.746C344.164,449.009 347.505,430.248 364.133,431.402C375.359,431.575 380.473,443.059 382.265,452.701C392.495,499.392 390.126,547.179 391.043,594.631C391.372,606.632 392.822,618.618 394.155,630.568C394.858,641.821 403.382,651.297 415.091,650.421C428.776,649.333 431.131,628.7 432.411,617.878C436.5,567.391 440.092,515.621 441.027,463.969C441.665,428.728 441.309,397.866 447.321,364.226C448.763,358.136 456.546,355.91 460.986,360.243C469.005,367.68 472.979,377.908 476.99,387.842C485.912,407.418 494.72,427.049 503.995,446.457C506.401,451.492 509.789,456.361 513.753,460.263C520.151,466.859 534.736,461.543 531.712,451.411C522.573,404.391 503.206,359.586 489.335,313.725C485.916,303.624 480.86,293.88 475.29,284.745C464.839,267.606 449.405,257.274 429.181,254.862C382.096,250.018 334.069,247.081 287.205,255.117C255.349,259.52 239.167,286.095 229.975,314.439C214.948,361.195 192.748,406.666 187.952,455.956C187.841,461.853 191.311,465.271 197.164,465.767C218.061,466.059 232.269,442.051 242.342,426.411C256.129,402.956 269.881,379.397 284.013,356.18C287.248,352.053 295.039,353.168 296.43,358.175C297.59,362.352 298.098,366.835 298.111,371.185C298.233,411.721 298.183,452.256 298.183,491.908Z" style="fill-rule:nonzero;"/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Hardcoded clipPath ID may conflict when SVGs are inlined

Profile.svg defines <clipPath id="_clip1"> with a non-unique, hardcoded ID. If this SVG is ever embedded inline in the HTML (rather than referenced as a background-image/<img>), multiple instances on the same page — or another SVG file that also has _clip1 — will produce an ID collision, causing the clipping region to be mis-applied and the icon to render incorrectly. Consider using a namespaced or truly unique ID (e.g. profile-clip1).

@Danielgergely
Copy link
Copy Markdown
Member

Thank you for your observations and changes!
I merged this branch into https://github.com/CompassionCH/compassion-website/tree/T2524-native-ios-app branch

@Danielgergely Danielgergely deleted the new-mobile-menu branch May 11, 2026 05:12
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.

2 participants