Skip to content

Commit 02ce7bb

Browse files
committed
[IMP] website_sale: design ecommerce dashboard
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
1 parent 91a027e commit 02ce7bb

File tree

7 files changed

+194
-119
lines changed

7 files changed

+194
-119
lines changed

addons/website_sale/__manifest__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@
161161
'website_sale/static/src/scss/kanban_record.scss',
162162
'website_sale/static/src/js/website_sale_dashboard/**/*',
163163
'website_sale/static/src/views/**/*',
164+
('remove', 'website_sale/static/src/js/website_sale_dashboard/**/*.dark.scss'),
165+
],
166+
"web.assets_web_dark": [
167+
'website_sale/static/src/js/website_sale_dashboard/**/*.dark.scss',
164168
],
165169
'website.website_builder_assets': [
166170
'website_sale/static/src/js/website_sale_form_editor.js',

addons/website_sale/static/src/js/website_sale_dashboard/date_filter_button/date_filter_button.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class DateFilterButton extends Component {
2626
static template = 'website_sale.DateFilterButton';
2727
static components = { Dropdown, DropdownItem };
2828
static props = {
29-
selectedFilter: {
29+
selectedDateFilter: {
3030
type: Object,
3131
optional: true,
3232
shape: {

addons/website_sale/static/src/js/website_sale_dashboard/date_filter_button/date_filter_button.xml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
<?xml version="1.0" encoding="UTF-8" ?>
22
<templates>
33
<t t-name="website_sale.DateFilterButton">
4-
<Dropdown navigationOptions="{ 'shouldFocusChildInput': false }">
5-
<button class="btn btn-secondary">
6-
<i class="fa fa-calendar me-2"/>
7-
<span t-esc="props.selectedFilter.label"/>
4+
<Dropdown navigationOptions="{ 'shouldFocusChildInput': false }" position="'bottom-end'">
5+
<button class="border-0 px-4 bg-transparent fw-normal">
6+
<i class="fa fa-calendar-o me-2"/>
7+
<span t-esc="props.selectedDateFilter.label"/>
8+
<i class="fa fa-caret-down ms-2"/>
89
</button>
910
<t t-set-slot="content">
1011
<t t-foreach="dateFilters" t-as="filter" t-key="filter.id">
1112
<DropdownItem
1213
tag="'div'"
13-
class="{ 'selected': props.selectedFilter.id === filter.id, 'd-flex justify-content-between': true }"
14+
class="{ 'selected': props.selectedDateFilter.id === filter.id, 'd-flex justify-content-between': true }"
1415
closingMode="'none'"
1516
onSelected="() => this.props.update(filter)"
1617
>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.o_dashboard_card {
2+
--DashboardCard__purple-bg-color: #{$purple-200};
3+
--DashboardCard__purple-bg-color--active: #{$purple-300};
4+
--DashboardCard__orange-bg-color: #{$orange-200};
5+
--DashboardCard__orange-bg-color--active: #{$orange-300};
6+
--DashboardCard__cyan-bg-color: #{$cyan-200};
7+
--DashboardCard__cyan-bg-color--active: #{$cyan-300};
8+
}

addons/website_sale/static/src/js/website_sale_dashboard/website_sale_dashboard.js

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useService } from '@web/core/utils/hooks';
1+
import { useService, useBus } from '@web/core/utils/hooks';
22
import { Component, onWillStart, onWillUpdateProps, useState } from '@odoo/owl';
33
import { DateFilterButton, DATE_OPTIONS } from './date_filter_button/date_filter_button';
44

@@ -10,10 +10,17 @@ export class WebsiteSaleDashboard extends Component {
1010
setup() {
1111
this.state = useState({
1212
eCommerceData: {},
13-
selectedFilter: DATE_OPTIONS[0],
13+
selectedDateFilter: DATE_OPTIONS[0],
14+
selectedFilter: [],
1415
});
1516
this.orm = useService('orm');
1617

18+
useBus(this.env.searchModel, 'update', () => {
19+
if(!this.isSameFilter(this.state.selectedFilter)) {
20+
this.state.selectedFilter = null;
21+
}
22+
});
23+
1724
onWillStart(async () => {
1825
await this.updateDashboardState();
1926
});
@@ -24,10 +31,10 @@ export class WebsiteSaleDashboard extends Component {
2431

2532
async updateDashboardState(filter = false) {
2633
if (filter) {
27-
this.state.selectedFilter = filter;
34+
this.state.selectedDateFilter = filter;
2835
}
2936
this.state.eCommerceData = await this.orm.call('sale.order', 'retrieve_dashboard', [
30-
this.state.selectedFilter.id,
37+
this.state.selectedDateFilter.id,
3138
]);
3239
}
3340

@@ -45,6 +52,15 @@ export class WebsiteSaleDashboard extends Component {
4552
for (const item of searchItems) {
4653
this.env.searchModel.toggleSearchItem(item.id);
4754
}
55+
this.state.selectedFilter = filters;
56+
}
57+
58+
isSameFilter(filters) {
59+
if (!filters) {
60+
return false;
61+
}
62+
const activeSearchFilterNames = this.env.searchModel.getSearchItems(el => el.isActive && el.type === 'filter')?.map(el => el.name).sort();
63+
return filters.length === activeSearchFilterNames?.length && filters.sort().every((val, i) => val === activeSearchFilterNames[i]);
4864
}
4965

5066
getPeriodCardClass(dataName) {
@@ -53,6 +69,26 @@ export class WebsiteSaleDashboard extends Component {
5369
} else if (this.state.eCommerceData['period_gain'][dataName] < 0) {
5470
return 'text-danger';
5571
}
56-
return 'text-muted';
72+
return '';
73+
}
74+
75+
getDashboardCardAdditionalClass(filterName) {
76+
const dashboardCardColor = {
77+
'to_fulfill': 'purple',
78+
'to_confirm': 'orange',
79+
'to_invoice': 'cyan',
80+
};
81+
let dashboardCardClasses = [];
82+
const noData = this.state.eCommerceData['overall'][filterName] == 0;
83+
if(noData) {
84+
dashboardCardClasses.push('bg-secondary text-secondary-emphasis disabled');
85+
} else {
86+
dashboardCardClasses.push('o_dashboard_card_' + dashboardCardColor[filterName]);
87+
}
88+
const filters = filterName == 'to_confirm' ? [filterName, 'from_website'] : [filterName, 'from_website','order_confirmed'];
89+
if(this.isSameFilter(filters)) {
90+
dashboardCardClasses.push('active');
91+
}
92+
return dashboardCardClasses.join(' ');
5793
}
5894
}
Lines changed: 52 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,65 @@
11
.o_dashboard_card {
2-
min-width: 120px;
3-
min-height: 90px;
4-
align-content: center;
5-
}
6-
7-
.o_purple_card {
8-
background-color: $purple-300;
9-
}
10-
11-
.o_orange_card {
12-
background-color: $orange-300;
13-
}
14-
15-
.o_blue_card {
16-
background-color: $blue-300;
17-
}
2+
$dashboard-colors: (
3+
purple: (
4+
bg: var(--DashboardCard__purple-bg-color, #{$purple-100}),
5+
bg-active: var(--DashboardCard__purple-bg-color--active, #{$purple-200}),
6+
color: var(--DashboardCard__purple-color, #{$purple-600}),
7+
color-active: var(--DashboardCard__purple-color--active, #{$purple-800}),
8+
),
9+
cyan: (
10+
bg: var(--DashboardCard__cyan-bg-color, #{$cyan-100}),
11+
bg-active: var(--DashboardCard__cyan-bg-color--active, #{$cyan-200}),
12+
color: var(--DashboardCard__cyan-color, #{$cyan-700}),
13+
color-active: var(--DashboardCard__cyan-color--active, #{$cyan-800}),
14+
),
15+
orange: (
16+
bg: var(--DashboardCard__orange-bg-color, #{$orange-100}),
17+
bg-active: var(--DashboardCard__orange-bg-color--active, #{$orange-200}),
18+
color: var(--DashboardCard__orange-color, #{$orange-700}),
19+
color-active: var(--DashboardCard__orange-color--active, #{$orange-800}),
20+
),
21+
);
1822

19-
@media (max-width: 768px) {
20-
.o_website_sale_dashboard {
21-
flex-direction: column !important;
22-
align-items: center !important;
23-
justify-content: center !important;
24-
gap: 1.5rem !important;
25-
}
23+
@each $name, $states in $dashboard-colors {
24+
&.o_dashboard_card_#{$name} {
25+
--btn-bg: #{map-get($states, bg)};
26+
--btn-hover-bg: #{map-get($states, bg-active)};
27+
--btn-active-bg: #{map-get($states, bg-active)};
28+
--btn-active-border-color: transparent;
2629

27-
/* Left Section: 3 cards in one row */
28-
.o_left_section {
29-
flex-direction: row !important;
30-
justify-content: center !important;
31-
flex-wrap: wrap !important;
32-
gap: 1rem !important;
33-
}
30+
.o_dashboard_card_data {
31+
color: #{map-get($states, color)};
32+
}
3433

35-
/* Right Section: DateFilterButton first, then metrics in one row */
36-
.o_right_section {
37-
flex-direction: column !important;
38-
align-items: center !important;
39-
justify-content: center !important;
40-
gap: 1rem !important;
41-
}
34+
&.active {
35+
outline: $border-width $border-style #{map-get($states, color-active)};
36+
outline-offset: $border-width;
4237

43-
.o_date_filter_wrapper {
44-
order: -1;
45-
justify-content: center !important;
46-
width: 100% !important;
47-
margin-bottom: 0.5rem !important;
38+
.o_dashboard_card_data {
39+
color: #{map-get($states, color-active)};
40+
}
41+
}
42+
}
4843
}
44+
}
4945

50-
.o_cards_container {
51-
flex-direction: row !important;
52-
justify-content: center !important;
53-
flex-wrap: wrap !important;
54-
gap: 0.8rem !important;
55-
}
46+
.o_website_sale_dashboard {
47+
background-color: $o-control-panel-background-color;
48+
}
5649

57-
/* Card Sizing */
58-
.o_dashboard_card {
59-
width: 90px !important;
60-
max-width: 130px !important;
61-
text-align: center !important;
50+
html .o_web_client > .o_action_manager > [class*="o_website_sale_dashboard"] {
51+
.o_content {
52+
height: calc(100% - 4rem);
6253
}
6354

64-
/* Font Adjustments */
65-
.o_dashboard_card_data {
66-
font-size: 1.1rem !important;
67-
}
55+
.o_renderer {
56+
@include media-breakpoint-up(lg) {
57+
height: calc(100% - 6.75rem);
58+
min-height: calc(100% - 6.75rem);
59+
}
6860

69-
.o_dashboard_card_text {
70-
margin-top: 4px;
71-
font-size: 0.7rem !important;
61+
height: calc(100% - 6rem);
62+
min-height: calc(100% - 6rem);
63+
overflow: auto;
7264
}
7365
}

0 commit comments

Comments
 (0)