Skip to content

Conversation

@ldau-odoo
Copy link

This PR adapts the e-commerce dashboard design by:

  • emphasizing the cards when there is data to display.
  • making the card active on click.
  • hiding the "To confirm" card when there is no data to display because
    it's not a common case.

task-5177259

@robodoo
Copy link

robodoo commented Oct 28, 2025

This PR targets the un-managed branch odoo-dev/odoo:master-awesome-ecommerce-dashboard-nipl, it needs to be retargeted before it can be merged.

@ldau-odoo ldau-odoo force-pushed the master-awesome-ecommerce-dashboard-ldau branch 2 times, most recently from c14465f to fdeda0a Compare October 29, 2025 13:08
Copy link

@nipl-odoo nipl-odoo left a comment

Choose a reason for hiding this comment

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

Hello Laetitia 👋🏻, thanks for the new design iteration, the dashboard’s looking really nice!
I’ve left a few comments on the JS diff. Not sure if you or I should handle those, so let me know if it’s on my side.

Comment on lines 18 to 23
useBus(this.env.searchModel, 'update', () => {
if(!this.getIsActiveSearchEquivalentToFilterCard(this.state.selectedFilter)) {
this.state.selectedFilter = null;
}
});

Choose a reason for hiding this comment

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

Instead of this, why don't you maintain a variable like I did with selectedDateFilter?
Because with this diff, if I select a similar filter as a card from the search bar, the card will stay selected, but the state variable will not be the same, which kinda feels weird for a state variable.

I would suggest setting a variable with the active filter values in this searchModel update and in onwillstart, you just compare that state variable with the current search items by sorting the same way you did in getIsActiveSearchEquivalentToFilterCard.

this.state.selectedFilter = filters;
}

getIsActiveSearchEquivalentToFilterCard(filters) {

Choose a reason for hiding this comment

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

Maybe rename to compareFilter or isSameFilter if you want a shorter name. Up to you, though :p

Comment on lines 52 to 53
html .o_web_client > .o_action_manager > .o_website_sale_dashboard_kanban_view .o_content,
html .o_web_client > .o_action_manager > .o_website_sale_dashboard_list_view .o_content {

Choose a reason for hiding this comment

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

I am no CSS expert (correct me if I am wrong), but maybe

.o_website_sale_dashboard_kanban_view .o_content,
.o_website_sale_dashboard_list_view .o_content {}

this is enough, no? 🤔 Also move this to addons/website_sale/static/src/views/website_sale_kanban_view.scss and addons/website_sale/static/src/views/website_sale_list_view.scss it looks like their home.

<DateFilterButton update.bind="updateDashboardState" selectedFilter="state.selectedFilter"/>
<div class="d-none d-lg-flex border rounded-3 py-3">
<div class="o_date_filter_wrapper d-flex align-items-center">
<DateFilterButton update.bind="updateDashboardState" selectedFilter="state.selectedDateFilter"/>

Choose a reason for hiding this comment

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

Maybe also rename DateFilterButton's prop to selectedDateFilter, it's clearer, no?

@@ -10,10 +10,17 @@ export class WebsiteSaleDashboard extends Component {
setup() {
this.state = useState({
eCommerceData: {},
selectedFilter: DATE_OPTIONS[0],
selectedDateFilter: DATE_OPTIONS[0],
selectedFilter: null,

Choose a reason for hiding this comment

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

Suggested change
selectedFilter: null,
selectedFilter: [],

should be declared as an empty array since you will be maintaining an array with this variable

Comment on lines +59 to +63
if (!filters) {
return false;
}
const activeSearchFilterNames = this.env.searchModel.getSearchItems(el => el.isActive && el.type === 'filter')?.map(el => el.name).sort();
return filters.length === activeSearchFilterNames?.length && filters.sort().every((val, i) => val === activeSearchFilterNames[i]);

Choose a reason for hiding this comment

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

Instead of comparing with the searchModel's filters, maybe you can properly maintain the state variable and compare it.

So basically state variable will contain a subset of searchModel items (only with type filters), and you use that state variable to compare with the filters array in here.

@ldau-odoo ldau-odoo force-pushed the master-awesome-ecommerce-dashboard-ldau branch from fdeda0a to 190c448 Compare October 31, 2025 14:38
@ldau-odoo
Copy link
Author

Hey @nipl-odoo,
thanks for the feedback!
I've solved most of it, I'd rather leave the js to you, you'll be more efficient than me on this one :D
A member of my team will also do a quick check

Copy link

@Brieuc-brd Brieuc-brd left a comment

Choose a reason for hiding this comment

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

Good job @ldau-odoo, it looks nice 👍

I've made a first pass, see my comments below.

Thanks !

}
const filters = filterName == 'to_confirm' ? [filterName, 'from_website'] : [filterName, 'from_website','order_confirmed'];
if(this.isSameFilter(filters)) {
dashboardCardClasses.push('o_dashboard_card--active');

Choose a reason for hiding this comment

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

If you apply my suggestion you should change this class as well.

Suggested change
dashboardCardClasses.push('o_dashboard_card--active');
dashboardCardClasses.push('active');

<templates>
<t t-name="website_sale.WebsiteSaleDashboard">
<div class="o_website_sale_dashboard container-fluid d-flex flex-wrap justify-content-between align-items-start gap-3 p-3 border-bottom">
<div class="o_website_sale_dashboard container-fluid d-flex justify-content-between align-items-center gap-3 p-3 border-bottom">

Choose a reason for hiding this comment

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

To handle easily the size of dashboard cards (and avoid custom css like this : , I wonder if it wouldn't be easier to use grid 🤔 something like this :

<div class="o_website_sale_dashboard container-fluid grid gap-3 p-3 border-bottom">
     <!-- Left Section -->
     <div class="g-col-12 g-col-lg-5">
      ...
     </div>
     <!-- Right Section -->
     <div class="g-col-7 d-none d-lg-flex">
      ...
     </div>
</div>

You could easily manage the size depending on breakpoints 👍

Copy link
Author

Choose a reason for hiding this comment

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

I preferred to do it differently and fix the size, otherwise the right side wasn't great.

<h2 class="m-0 fw-bold o_dashboard_card_data" t-esc="state.eCommerceData['overall']['to_fulfill']"/>
<h4 class="fw-semibold text-muted o_dashboard_card_text">To Fulfill</h4>
</a>
<span class="o_dashboard_card_data fs-4 fw-bolder" t-esc="state.eCommerceData['overall']['to_fulfill']"/>

Choose a reason for hiding this comment

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

o_dashboard_card_data is no longer used if I'm not mistaken, you can remove it (same for the other iterations).

Copy link
Author

Choose a reason for hiding this comment

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

I kept it in order to use it to target the number and colour it (that way I can remove the famous text-body that was overwriting the colour I had defined).

</h3>
<div class="fw-semibold text-muted o_dashboard_card_text">Visitors</div>
</span>
<span class="o_dashboard_card_text fs-6 text-body fw-bold">Visitors</span>

Choose a reason for hiding this comment

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

Are you sure text-body is necessary here (same for the other iterations) ? 🤔

Copy link
Author

Choose a reason for hiding this comment

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

(see comment above)

@ldau-odoo ldau-odoo force-pushed the master-awesome-ecommerce-dashboard-ldau branch from 190c448 to fb510a9 Compare November 4, 2025 10:42
@ldau-odoo ldau-odoo requested a review from Brieuc-brd November 4, 2025 12:06
@nipl-odoo nipl-odoo force-pushed the master-awesome-ecommerce-dashboard-nipl branch from 30351d5 to 8a3d7df Compare November 4, 2025 13:27
@ldau-odoo ldau-odoo force-pushed the master-awesome-ecommerce-dashboard-ldau branch from fb510a9 to bb0079c Compare November 4, 2025 15:52
@nipl-odoo nipl-odoo force-pushed the master-awesome-ecommerce-dashboard-nipl branch 2 times, most recently from 4aa1139 to 91a027e Compare November 6, 2025 07:23
@ldau-odoo ldau-odoo force-pushed the master-awesome-ecommerce-dashboard-ldau branch from bb0079c to 02ce7bb Compare November 6, 2025 15:39
This commit adapts the ecommerce dashboard design by:
- emphasizing the cards when there is data to display.
- making the card active on click.
- hiding the "To confirm" card when there is no data to display because
it's not a common case.

task-5177259
@ldau-odoo ldau-odoo force-pushed the master-awesome-ecommerce-dashboard-ldau branch from 02ce7bb to b42e24c Compare November 12, 2025 14:40
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