Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions addons/website_sale/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@
'website_sale/static/src/scss/kanban_record.scss',
'website_sale/static/src/js/website_sale_dashboard/**/*',
'website_sale/static/src/views/**/*',
('remove', 'website_sale/static/src/js/website_sale_dashboard/**/*.dark.scss'),
],
"web.assets_web_dark": [
'website_sale/static/src/js/website_sale_dashboard/**/*.dark.scss',
],
'website.website_builder_assets': [
'website_sale/static/src/js/website_sale_form_editor.js',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class DateFilterButton extends Component {
static template = 'website_sale.DateFilterButton';
static components = { Dropdown, DropdownItem };
static props = {
selectedFilter: {
selectedDateFilter: {
type: Object,
optional: true,
shape: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
<t t-name="website_sale.DateFilterButton">
<Dropdown navigationOptions="{ 'shouldFocusChildInput': false }">
<button class="btn btn-secondary">
<i class="fa fa-calendar me-2"/>
<span t-esc="props.selectedFilter.label"/>
<Dropdown navigationOptions="{ 'shouldFocusChildInput': false }" position="'bottom-end'">
<button class="border-0 bg-transparent fw-normal">
<i class="fa fa-calendar-o me-2"/>
<span t-esc="props.selectedDateFilter.label"/>
<i class="fa fa-caret-down ms-2"/>
</button>
<t t-set-slot="content">
<t t-foreach="dateFilters" t-as="filter" t-key="filter.id">
<DropdownItem
tag="'div'"
class="{ 'selected': props.selectedFilter.id === filter.id, 'd-flex justify-content-between': true }"
class="{ 'selected': props.selectedDateFilter.id === filter.id, 'd-flex justify-content-between': true }"
closingMode="'none'"
onSelected="() => this.props.update(filter)"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.o_dashboard_card {
--DashboardCard__purple-bg-color: #{$purple-200};
--DashboardCard__purple-bg-color--active: #{$purple-300};
--DashboardCard__orange-bg-color: #{$orange-200};
--DashboardCard__orange-bg-color--active: #{$orange-300};
--DashboardCard__cyan-bg-color: #{$cyan-200};
--DashboardCard__cyan-bg-color--active: #{$cyan-300};
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useService } from '@web/core/utils/hooks';
import { useService, useBus } from '@web/core/utils/hooks';
import { Component, onWillStart, onWillUpdateProps, useState } from '@odoo/owl';
import { DateFilterButton, DATE_OPTIONS } from './date_filter_button/date_filter_button';

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

useBus(this.env.searchModel, 'update', () => {
if(!this.isSameFilter(this.state.selectedFilter)) {
this.state.selectedFilter = null;
}
});

onWillStart(async () => {
await this.updateDashboardState();
});
Expand All @@ -24,10 +31,10 @@ export class WebsiteSaleDashboard extends Component {

async updateDashboardState(filter = false) {
if (filter) {
this.state.selectedFilter = filter;
this.state.selectedDateFilter = filter;
}
this.state.eCommerceData = await this.orm.call('sale.order', 'retrieve_dashboard', [
this.state.selectedFilter.id,
this.state.selectedDateFilter.id,
]);
}

Expand All @@ -45,6 +52,15 @@ export class WebsiteSaleDashboard extends Component {
for (const item of searchItems) {
this.env.searchModel.toggleSearchItem(item.id);
}
this.state.selectedFilter = filters;
}

isSameFilter(filters) {
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]);
Comment on lines +59 to +63

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.

}

getPeriodCardClass(dataName) {
Expand All @@ -53,6 +69,26 @@ export class WebsiteSaleDashboard extends Component {
} else if (this.state.eCommerceData['period_gain'][dataName] < 0) {
return 'text-danger';
}
return 'text-muted';
return '';
}

getDashboardCardAdditionalClass(filterName) {
const dashboardCardColor = {
'to_fulfill': 'purple',
'to_confirm': 'orange',
'to_invoice': 'cyan',
};
let dashboardCardClasses = [];
const noData = this.state.eCommerceData['overall'][filterName] == 0;
if(noData) {
dashboardCardClasses.push('bg-secondary text-secondary-emphasis disabled');
} else {
dashboardCardClasses.push('o_dashboard_card_' + dashboardCardColor[filterName]);
}
const filters = filterName == 'to_confirm' ? [filterName, 'from_website'] : [filterName, 'from_website','order_confirmed'];
if(this.isSameFilter(filters)) {
dashboardCardClasses.push('active');
}
return dashboardCardClasses.join(' ');
}
}
Original file line number Diff line number Diff line change
@@ -1,73 +1,92 @@
.o_dashboard_card {
min-width: 120px;
min-height: 90px;
align-content: center;
}
// flex-basis: 33%;

.o_purple_card {
background-color: $purple-300;
}
// @include media-breakpoint-up(md) {
// max-width: 8rem;
// }

.o_orange_card {
background-color: $orange-300;
}
$dashboard-colors: (
purple: (
bg: var(--DashboardCard__purple-bg-color, #{$purple-100}),
bg-active: var(--DashboardCard__purple-bg-color--active, #{$purple-200}),
color: var(--DashboardCard__purple-color, #{$purple-600}),
color-active: var(--DashboardCard__purple-color--active, #{$purple-800}),
),
cyan: (
bg: var(--DashboardCard__cyan-bg-color, #{$cyan-100}),
bg-active: var(--DashboardCard__cyan-bg-color--active, #{$cyan-200}),
color: var(--DashboardCard__cyan-color, #{$cyan-700}),
color-active: var(--DashboardCard__cyan-color--active, #{$cyan-800}),
),
orange: (
bg: var(--DashboardCard__orange-bg-color, #{$orange-100}),
bg-active: var(--DashboardCard__orange-bg-color--active, #{$orange-200}),
color: var(--DashboardCard__orange-color, #{$orange-700}),
color-active: var(--DashboardCard__orange-color--active, #{$orange-800}),
),
);

.o_blue_card {
background-color: $blue-300;
}
@each $name, $states in $dashboard-colors {
&.o_dashboard_card_#{$name} {
--btn-bg: #{map-get($states, bg)};
--btn-hover-bg: #{map-get($states, bg-active)};
--btn-active-bg: #{map-get($states, bg-active)};
--btn-active-border-color: transparent;

@media (max-width: 768px) {
.o_website_sale_dashboard {
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
gap: 1.5rem !important;
}
.o_dashboard_card_data {
color: #{map-get($states, color)};
}

/* Left Section: 3 cards in one row */
.o_left_section {
flex-direction: row !important;
justify-content: center !important;
flex-wrap: wrap !important;
gap: 1rem !important;
}
&.active {
outline: $border-width $border-style #{map-get($states, color-active)};
outline-offset: $border-width;

/* Right Section: DateFilterButton first, then metrics in one row */
.o_right_section {
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
gap: 1rem !important;
.o_dashboard_card_data {
color: #{map-get($states, color-active)};
}
}
}
}
}

.o_date_filter_wrapper {
order: -1;
justify-content: center !important;
width: 100% !important;
margin-bottom: 0.5rem !important;
}
.o_dashboard_card_evolution {
font-size: .75rem;
}

.o_cards_container {
flex-direction: row !important;
justify-content: center !important;
flex-wrap: wrap !important;
gap: 0.8rem !important;
.o_date_filter_wrapper {
@include media-breakpoint-up(md) {
border-right: $border-width $border-style $border-color;
background: transparent !important;
}
}

/* Card Sizing */
.o_dashboard_card {
width: 90px !important;
max-width: 130px !important;
text-align: center !important;
}
.o_website_sale_dashboard {
background-color: $o-control-panel-background-color;

/* Font Adjustments */
.o_dashboard_card_data {
font-size: 1.1rem !important;
@include media-breakpoint-up(md) {
border-bottom: $border-width $border-style $border-color;
}

.o_dashboard_card_text {
margin-top: 4px;
font-size: 0.7rem !important;
.o_kanban_renderer {
&.o_kanban_grouped, &.o_kanban_ungrouped {
min-height: auto; // override min-height: 100%
}
}
}

// html .o_web_client > .o_action_manager > [class*="o_website_sale_dashboard"] {
// .o_content {
// height: calc(100% - 4rem);
// }

// .o_renderer {
// @include media-breakpoint-up(lg) {
// height: calc(100% - 6.75rem);
// min-height: calc(100% - 6.75rem);
// }

// height: calc(100% - 6rem);
// min-height: calc(100% - 6rem);
// overflow: auto;
// }
// }
Loading