[REF] pos*, web: use reactivity to react to changes in UI size

pos*: point_of_sale, pos_restaurant, pos_sale

Previously the pos would rerender the entire UI when the window was
resized. In practice, most components do not care about the size of the
UI for their rendering, and so we're doing a lot of needless work, and
also using an owl feature (deep renders) whose perennity is not certain
(we may want to remove the ability to do deep renders completely in the
future).

This commit changes the pos code to use the ui service `isSmall` field,
makes the ui service reactive so that components can subscribe to
changes inside of it with `useState`, and makes the ui service update
its internal state at most once per animation frame, instead of after
100ms without resizing, so that resizing the viewport results in a
smoother user experience.

closes odoo/odoo#121343

Signed-off-by: adgu-odoo <adgu@odoo.com>
This commit is contained in:
Samuel Degueldre
2023-05-15 13:59:22 +02:00
parent 26bb317708
commit ba29387924
38 changed files with 102 additions and 112 deletions
@@ -31,6 +31,7 @@ export class Navbar extends Component {
};
setup() {
this.pos = usePos();
this.ui = useState(useService("ui"));
this.debug = useService("debug");
this.popup = useService("popup");
this.notification = useService("pos_notification");
@@ -5,7 +5,7 @@
<div class="pos-topheader">
<div t-if="pos.tempScreen" class="block-top-header" />
<div class="pos-branding">
<img t-if="!env.isMobile" class="pos-logo" t-on-click="() => debug.toggleWidget()" src="/point_of_sale/static/src/img/logo.png" alt="Logo" />
<img t-if="!ui.isSmall" class="pos-logo" t-on-click="() => debug.toggleWidget()" src="/point_of_sale/static/src/img/logo.png" alt="Logo" />
</div>
<div class="pos-rightheader">
<div class="status-buttons">
+1 -25
View File
@@ -1,20 +1,12 @@
/** @odoo-module */
import { useService } from "@web/core/utils/hooks";
import { throttleForAnimation } from "@web/core/utils/timing";
import { Transition } from "@web/core/transition";
import { MainComponentsContainer } from "@web/core/main_components_container";
import { ErrorHandler } from "@web/core/utils/components";
import { Navbar } from "@point_of_sale/app/navbar/navbar";
import { usePos } from "@point_of_sale/app/pos_hook";
import {
useExternalListener,
useSubEnv,
reactive,
onWillUnmount,
Component,
onMounted,
} from "@odoo/owl";
import { reactive, Component, onMounted } from "@odoo/owl";
/**
* Chrome is the root component of the PoS App.
@@ -30,22 +22,6 @@ export class Chrome extends Component {
const reactivePos = reactive(this.pos.globalState);
// TODO: Should we continue on exposing posmodel as global variable?
window.posmodel = reactivePos;
// FIXME POSREF: remove
useSubEnv({
get isMobile() {
return window.innerWidth <= 768;
},
});
let currentIsMobile = this.env.isMobile;
const updateUI = throttleForAnimation(() => {
if (this.env.isMobile !== currentIsMobile) {
currentIsMobile = this.env.isMobile;
// FIXME POSREF use reactive mobile instead
this.render(true);
}
});
useExternalListener(window, "resize", updateUI);
onWillUnmount(updateUI.cancel);
// prevent backspace from performing a 'back' navigation
document.addEventListener("keydown", (ev) => {
@@ -1,7 +1,8 @@
/** @odoo-module */
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { usePos } from "@point_of_sale/app/pos_hook";
import { useService } from "@web/core/utils/hooks";
// Previously UsernameWidget
export class CashierName extends Component {
@@ -9,6 +10,7 @@ export class CashierName extends Component {
setup() {
this.pos = usePos();
this.ui = useState(useService("ui"));
}
get username() {
const { name } = this.pos.globalState.get_cashier();
@@ -12,6 +12,7 @@ export class ProxyStatus extends Component {
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
const hardwareProxy = useService("hardware_proxy");
this.connectionInfo = useState(hardwareProxy.connectionInfo);
}
@@ -1,7 +1,7 @@
/** @odoo-module */
import { Component, useExternalListener, useState } from "@odoo/owl";
import { useAutofocus } from "@web/core/utils/hooks";
import { useAutofocus, useService } from "@web/core/utils/hooks";
/**
* This is a simple configurable search bar component. It has search fields
@@ -29,7 +29,7 @@ export class SearchBar extends Component {
static template = "point_of_sale.SearchBar";
setup() {
super.setup();
this.ui = useState(useService("ui"));
useAutofocus();
useExternalListener(window, "click", this._hideOptions);
this.filterOptionsList = [...this.props.config.filter.options.keys()];
@@ -65,9 +65,7 @@ export class SearchBar extends Component {
if (["ArrowUp", "ArrowDown"].includes(event.key)) {
this.state.selectedSearchFieldId = this._fieldIdToSelect(event.key);
} else if (event.key === "Enter" || this.state.searchInput == "") {
this._onClickSearchField(
this.searchFieldsList[this.state.selectedSearchFieldId],
);
this._onClickSearchField(this.searchFieldsList[this.state.selectedSearchFieldId]);
} else {
if (this.state.selectedSearchFieldId === -1 && this.searchFieldsList.length) {
this.state.selectedSearchFieldId = 0;
@@ -1,5 +1,5 @@
/** @odoo-module */
import { reactive } from "@odoo/owl";
// Create global context objects
// e.g. component.env.device = new Context({ isMobile: false });
// FIXME POSREF singletons exported by modules are not testable, this should probably be a service
export const orderManagement = reactive({ searchString: "", selectedOrder: null });
@@ -32,6 +32,7 @@ export class PartnerListScreen extends Component {
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
this.orm = useService("orm");
this.notification = useService("pos_notification");
this.searchWordInputRef = useRef("search-word-input-partner");
@@ -15,7 +15,7 @@ import { PaymentScreenNumpad } from "./PaymentScreenNumpad";
import { PaymentScreenPaymentLines } from "./PaymentScreenPaymentLines";
import { PaymentScreenStatus } from "./PaymentScreenStatus";
import { usePos } from "@point_of_sale/app/pos_hook";
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { sprintf } from "@web/core/utils/strings";
export class PaymentScreen extends Component {
@@ -29,6 +29,7 @@ export class PaymentScreen extends Component {
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
this.orm = useService("orm");
this.popup = useService("popup");
this.report = useService("report");
@@ -1,7 +1,8 @@
/** @odoo-module */
import { usePos } from "@point_of_sale/app/pos_hook";
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
/**
* @props partner
@@ -14,6 +15,7 @@ export class ActionpadWidget extends Component {
setup() {
this.pos = usePos();
this.ui = useState(useService("ui"));
}
get isLongName() {
@@ -37,6 +37,7 @@ export class ProductScreen extends ControlButtonsMixin(Component) {
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
this.popup = useService("popup");
this.orm = useService("orm");
this.notification = useService("pos_notification");
@@ -15,6 +15,7 @@ export class ProductsWidgetControlPanel extends Component {
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
this.notification = useService("pos_notification");
this.orm = useService("orm");
this.updateSearch = debounce(this.updateSearch, 100);
@@ -29,7 +30,7 @@ export class ProductsWidgetControlPanel extends Component {
}
get displayCategImages() {
return (
!this.env.isMobile &&
!this.ui.isSmall &&
Object.values(this.pos.globalState.db.category_by_id).some((categ) => categ.has_image)
);
}
@@ -5,7 +5,7 @@ import { AbstractReceiptScreen } from "@point_of_sale/js/Misc/AbstractReceiptScr
import { OfflineErrorPopup } from "@point_of_sale/js/Popups/OfflineErrorPopup";
import { registry } from "@web/core/registry";
import { OrderReceipt } from "./OrderReceipt";
import { onMounted, useRef, status } from "@odoo/owl";
import { onMounted, useRef, status, useState } from "@odoo/owl";
import { usePos } from "@point_of_sale/app/pos_hook";
import { useService } from "@web/core/utils/hooks";
import { BasePrinter } from "@point_of_sale/app/printer/base_printer";
@@ -18,6 +18,7 @@ export class ReceiptScreen extends AbstractReceiptScreen {
super.setup();
this.pos = usePos();
useErrorHandlers();
this.ui = useState(useService("ui"));
this.orm = useService("orm");
this.orderReceipt = useRef("order-receipt");
this.buttonMailReceipt = useRef("order-mail-receipt-button");
@@ -48,6 +48,7 @@ export class TicketScreen extends IndependentToOrderScreen {
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
this.popup = useService("popup");
this.orm = useService("orm");
this.numberBuffer = useService("number_buffer");
@@ -56,7 +57,7 @@ export class TicketScreen extends IndependentToOrderScreen {
});
this._state = this.pos.globalState.TICKET_SCREEN_STATE;
this.state = useState({
showSearchBar: !this.env.isMobile,
showSearchBar: !this.ui.isSmall,
});
const defaultUIState = this.props.reuseSavedUIState
? this._state.ui
@@ -3,7 +3,7 @@
<t t-name="CashierName" owl="1">
<div t-att-class="cssClass">
<span class="cashier-name"><img t-att-src="avatar" t-att-alt="username" class="avatar"/> <span t-if="!env.isMobile" t-esc="username" class="username"/></span>
<span class="cashier-name"><img t-att-src="avatar" t-att-alt="username" class="avatar"/> <span t-if="!ui.isSmall" t-esc="username" class="username"/></span>
</div>
</t>
@@ -3,7 +3,7 @@
<t t-name="ProxyStatus" owl="1">
<div class="oe_status js_proxy" t-on-click="() => this.pos.connectToProxy()">
<span t-if="this.message and !env.isMobile" class="js_msg">
<span t-if="this.message and !ui.isSmall" class="js_msg">
<t t-esc="this.message" />
</span>
<span t-if="connectionInfo.status === 'connected' and !this.message" class="js_connected oe_green">
@@ -4,7 +4,7 @@
<t t-name="point_of_sale.SearchBar" owl="1">
<div class="pos-search-bar">
<div class="search">
<span class="search-icon" t-if="!env.isMobile"><i class="fa fa-search"></i></span>
<span class="search-icon" t-if="!ui.isSmall"><i class="fa fa-search"></i></span>
<input class="radius-left" t-ref="autofocus" t-att-class="{ 'radius-right': !props.config.filter.show }"
t-model="state.searchInput" t-on-keydown="onSearchInputKeydown" t-on-keyup="onSearchInputKeyup" type="text" t-att-placeholder="props.placeholder" />
<div t-if="state.showSearchFields and state.searchInput" class="fields">
@@ -6,20 +6,20 @@
<div class="screen-content">
<div class="top-content">
<div class="button highlight" t-if="state.detailIsShown" t-on-click="() => this.partnerEditor.save()">
<i t-if="env.isMobile" class="fa fa-floppy-o"/>
<t t-if="!env.isMobile">
<i t-if="ui.isSmall" class="fa fa-floppy-o"/>
<t t-else="">
<span> Save</span>
</t>
</div>
<div t-if="!state.detailIsShown" class="button new-customer highlight" role="img" aria-label="Add a customer"
t-on-click="createPartner"
title="Add a customer">
<i t-if="env.isMobile" class="fa fa-plus"/>
<t t-if="!env.isMobile"> Create</t>
<i t-if="ui.isSmall" class="fa fa-plus"/>
<t t-else=""> Create</t>
</div>
<div class="button back" t-on-click="back">
<i t-if="env.isMobile" class="fa fa-angle-double-left"/>
<t t-if="!env.isMobile"> Discard</t>
<i t-if="ui.isSmall" class="fa fa-angle-double-left"/>
<t t-else=""> Discard</t>
</div>
<div class="top-right-buttons">
<div t-if="state.detailIsShown &amp;&amp; state.editModeProps.partner.id" class="button more-info">
@@ -4,7 +4,7 @@
<t t-name="PaymentScreen" owl="1">
<div class="payment-screen screen" t-att-class="{ oe_hidden: !props.isShown }">
<div class="screen-content">
<t t-if="!env.isMobile">
<t t-if="!ui.isSmall">
<div class="top-content">
<div class="button back"
t-on-click="() => pos.showScreen('ProductScreen')">
@@ -16,7 +16,7 @@
</t>
<div class="main-content">
<div class="left-content">
<t t-if="env.isMobile">
<t t-if="ui.isSmall">
<section class="paymentlines-container">
<PaymentScreenStatus order="currentOrder" />
</section>
@@ -44,7 +44,7 @@
sendPaymentRequest.bind="sendPaymentRequest"
selectLine.bind="selectPaymentLine"/>
</div>
<div t-if="!env.isMobile" class="button next validation" t-att-class="{ highlight: currentOrder.is_paid() and currentOrder._isValidEmptyOrder() }"
<div t-if="!ui.isSmall" class="button next validation" t-att-class="{ highlight: currentOrder.is_paid() and currentOrder._isValidEmptyOrder() }"
t-on-click="() => this.validateOrder()">
<div class="pay-circle">
<i class="oi oi-chevron-right" role="img" aria-label="Pay" title="Pay" />
@@ -53,7 +53,7 @@
</div>
</div>
<div class="center-content">
<t t-if="!env.isMobile">
<t t-if="!ui.isSmall">
<section class="paymentlines-container">
<PaymentScreenStatus order="currentOrder" />
</section>
@@ -108,7 +108,7 @@
</div>
</div>
</div>
<t t-if="env.isMobile">
<t t-if="ui.isSmall">
<div class="switchpane">
<button class="btn-switchpane"
t-att-class="{ secondary: !(currentOrder.is_paid() and currentOrder._isValidEmptyOrder()) }"
@@ -5,7 +5,7 @@
<div class="actionpad">
<button class="button set-partner" t-att-class="{'decentered': isLongName}"
t-on-click="() => this.pos.selectPartner()">
<t t-if="!env.isMobile"><i class="fa fa-user" role="img" aria-label="Customer" title="Customer" /></t>
<t t-if="!ui.isSmall"><i class="fa fa-user" role="img" aria-label="Customer" title="Customer" /></t>
<t t-if="props.partner">
<t t-esc="props.partner.name" />
</t>
@@ -19,7 +19,7 @@
</div>
<t t-esc="props.actionName" />
</button>
<button t-if="env.isMobile" class="button back-button" t-on-click="props.onSwitchPane">
<button t-if="ui.isSmall" class="button back-button" t-on-click="props.onSwitchPane">
<i class="fa fa-angle-double-left"/>
Back
</button>
@@ -4,11 +4,11 @@
<t t-name="ProductScreen" owl="1">
<div class="product-screen screen" t-att-class="{ oe_hidden: !props.isShown }">
<div class="screen-full-width">
<div class="leftpane pane-border" t-if="!env.isMobile || state.mobile_pane === 'left'">
<div class="leftpane pane-border" t-if="!ui.isSmall || state.mobile_pane === 'left'">
<OrderWidget/>
<div class="pads">
<div class="control-buttons">
<t t-if="env.isMobile and controlButtons.length > 3">
<t t-if="ui.isSmall and controlButtons.length > 3">
<div class="control-button" t-on-click="_displayAllControlPopup">More...</div>
</t>
<t t-else="">
@@ -29,10 +29,10 @@
</div>
</div>
</div>
<div class="rightpane" t-if="!env.isMobile || state.mobile_pane === 'right'">
<div class="rightpane" t-if="!ui.isSmall || state.mobile_pane === 'right'">
<ProductsWidget />
<MobileOrderWidget
t-if="env.isMobile"
t-if="ui.isSmall"
pane="state.mobile_pane"
onSwitchPane.bind="switchPane"/>
</div>
@@ -5,10 +5,10 @@
<div class="products-widget-control">
<div class="rightpane-header">
<div class="search-bar-container sb-product">
<span t-if="env.isMobile" class="oe_status oe_icon icon" t-on-click="toggleMobileSearchBar">
<span t-if="ui.isSmall" class="oe_status oe_icon icon" t-on-click="toggleMobileSearchBar">
<i t-attf-class="fa oi {{state.mobileSearchBarIsShown ? 'oi-arrow-left' : 'fa-search'}}"/>
</span>
<t t-if="!env.isMobile || state.mobileSearchBarIsShown">
<t t-if="!ui.isSmall || state.mobileSearchBarIsShown">
<div class="pos-search-bar">
<i class="fa fa-search"/>
<input t-model="this.pos.globalState.searchProductWord" placeholder="Search Products..." type="text" autofocus="autofocus" t-on-keyup="updateSearch" />
@@ -4,7 +4,7 @@
<t t-name="ReceiptScreen" owl="1">
<div class="receipt-screen screen">
<div class="screen-content">
<div class="top-content" t-if="!env.isMobile">
<div class="top-content" t-if="!ui.isSmall">
<div class="top-content-center">
<h1>
<t t-esc="orderAmountPlusTip" />
@@ -6,20 +6,20 @@
<div class="screen-full-width">
<div class="rightpane pane-border">
<div class="controls">
<t t-if="!env.isMobile || !state.showSearchBar">
<t t-if="!ui.isSmall || !state.showSearchBar">
<div class="buttons">
<button class="discard" t-on-click="() => this.onCloseScreen()">
<span class="search-icon">
<i class="fa fa-angle-double-left"/>
</span>
<t t-if="!env.isMobile">
<t t-if="!ui.isSmall">
Back
</t>
</button>
<button t-if="allowNewOrders" class="highlight" t-on-click="() => this.onCreateNewOrder()">New Order</button>
</div>
</t>
<t t-if="env.isMobile">
<t t-if="ui.isSmall">
<t t-if="state.showSearchBar">
<button class="arrow-left" t-on-click="() => { state.showSearchBar = !state.showSearchBar }">
<span class="search-icon">
@@ -58,7 +58,7 @@
<div class="orders">
<t t-set="_filteredOrderList" t-value="getFilteredOrderList()" />
<t t-if="_filteredOrderList.length !== 0">
<div class="header-row" t-att-class="{ oe_hidden: env.isMobile }">
<div class="header-row" t-att-class="{ oe_hidden: ui.isSmall }">
<div class="col wide">Date</div>
<div class="col wide">Receipt Number</div>
<div class="col">Customer</div>
@@ -72,30 +72,30 @@
<div class="order-row" t-att-class="{ highlight: isHighlighted(order) }" t-on-click="() => this.onClickOrder(order)">
<div class="col wide">
<div><t t-esc="getDate(order)"></t></div>
<div t-if="env.isMobile"><t t-esc="getTotal(order)"></t></div>
<div t-if="ui.isSmall"><t t-esc="getTotal(order)"></t></div>
</div>
<div class="col wide">
<div><t t-esc="order.name"></t></div>
<div t-if="env.isMobile"><t t-esc="getStatus(order)"></t></div>
<div t-if="ui.isSmall"><t t-esc="getStatus(order)"></t></div>
</div>
<div class="col" t-if="!env.isMobile">
<div class="col" t-if="!ui.isSmall">
<div><t t-esc="getPartner(order)"></t></div>
</div>
<div t-if="showCardholderName() &amp;&amp; !env.isMobile" class="col">
<div t-if="showCardholderName() and !ui.isSmall" class="col">
<div><t t-esc="getCardholderName(order)"></t></div>
</div>
<div class="col">
<div t-if="env.isMobile"><t t-esc="getPartner(order)"></t></div>
<div t-att-class = "env.isMobile ? 'cashier':''"><t t-esc="getCashier(order)"></t></div>
<div t-if="ui.isSmall"><t t-esc="getPartner(order)"></t></div>
<div t-att-class = "ui.isSmall ? 'cashier':''"><t t-esc="getCashier(order)"></t></div>
</div>
<div class="col end" t-if="!env.isMobile">
<div class="col end" t-if="!ui.isSmall">
<div><t t-esc="getTotal(order)"></t></div>
</div>
<div class="col narrow" t-if="!env.isMobile">
<div class="col narrow" t-if="!ui.isSmall">
<div><t t-esc="getStatus(order)"></t></div>
</div>
<div t-if="!shouldHideDeleteButton(order)" class="col very-narrow delete-button" name="delete" t-on-click.stop="() => this.onDeleteOrder(order)">
<i class="fa fa-trash" aria-hidden="true"/><t t-if="env.isMobile"> Delete</t>
<i class="fa fa-trash" aria-hidden="true"/><t t-if="ui.isSmall"> Delete</t>
</div>
<div t-else="" class="col very-narrow"></div>
</div>
@@ -1,6 +1,7 @@
/** @odoo-module */
import { Component, useExternalListener } from "@odoo/owl";
import { Component, useExternalListener, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
export class EditBar extends Component {
static template = "pos_restaurant.EditBar";
@@ -24,6 +25,7 @@ export class EditBar extends Component {
setup() {
super.setup();
this.ui = useState(useService("ui"));
useExternalListener(window, "click", this.onOutsideClick);
}
@@ -34,12 +36,12 @@ export class EditBar extends Component {
}
getSelectedTablesShape() {
let shape = 'round';
let shape = "round";
this.props.selectedTables.forEach((table) => {
if (table.shape == 'square') {
shape = 'square';
if (table.shape == "square") {
shape = "square";
}
});
return shape;
return shape;
}
}
@@ -3,7 +3,7 @@
<t t-name="pos_restaurant.EditBar" owl="1">
<div class="edit-bar-top">
<span class="edit-button first-button" t-if="!env.isMobile"></span>
<span class="edit-button first-button" t-if="!ui.isSmall"></span>
<span class="edit-button" t-on-click.stop="props.createTable">
<i class="fa fa-plus icon-button" role="img" aria-label="Add" title="Add"></i>
<span class="text-button">ADD</span>
@@ -36,13 +36,8 @@ export class FloorScreen extends Component {
floorMapScrollTop: 0,
isColorPicker: false,
});
if (!this.pos.globalState.floorPlanStyle) {
if (this.env.isMobile) {
this.pos.globalState.floorPlanStyle = "kanban";
} else {
this.pos.globalState.floorPlanStyle = "default";
}
}
const ui = useState(useService("ui"));
this.pos.globalState.floorPlanStyle ||= ui.isSmall ? "kanban" : "default";
this.floorMapRef = useRef("floor-map-ref");
this.addFloorRef = useRef("add-floor-ref");
this.map = useRef("map");
@@ -1,14 +1,15 @@
/** @odoo-module */
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { usePos } from "@point_of_sale/app/pos_hook";
import { useService } from "@web/core/utils/hooks";
export class BackToFloorButton extends Component {
static template = "BackToFloorButton";
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
}
get table() {
return this.pos.globalState.table;
@@ -8,7 +8,7 @@
t-on-click="backToFloorScreen"
>
<i class="fa fa-angle-double-left" role="img" aria-label="Back to floor" title="Back to floor" />
<t t-if="env.isMobile">
<t t-if="ui.isSmall">
<span class="table-name" t-esc="table.name"/>
</t>
<t t-else="">
@@ -9,12 +9,12 @@
<xpath expr="//div[hasclass('order-row')]//div[@name='delete']" position="before">
<div t-if="pos.globalState.config.module_pos_restaurant" class="col" name="table">
<t t-if="order.tableId">
<div t-if="env.isMobile">Table</div>
<div t-if="ui.isSmall">Table</div>
<div><t t-esc="getTable(order)"></t></div>
</t>
</div>
<div t-if="_state.ui.filter == 'TIPPING'" class="col end narrow" name="tip">
<div t-if="env.isMobile">Tip</div>
<div t-if="ui.isSmall">Tip</div>
<div><TipCell order="order" /></div>
</div>
</xpath>
@@ -2,6 +2,7 @@
import { Component, useState } from "@odoo/owl";
import { SaleOrderRow } from "./SaleOrderRow";
import { useService } from "@web/core/utils/hooks";
/**
* @props {models.Order} [initHighlightedOrder] initially highligted order
@@ -12,7 +13,7 @@ export class SaleOrderList extends Component {
static template = "SaleOrderList";
setup() {
super.setup();
this.ui = useState(useService("ui"));
this.state = useState({ highlightedOrder: this.props.initHighlightedOrder || null });
}
get highlightedOrder() {
@@ -25,6 +25,7 @@ export class SaleOrderManagementControlPanel extends Component {
setup() {
this.pos = usePos();
this.ui = useState(useService("ui"));
this.saleOrderFetcher = useService("sale_order_fetcher");
this.orderManagementContext = useState(orderManagement);
useAutofocus();
@@ -1,5 +1,6 @@
/** @odoo-module */
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
/**
* @props {models.Order} order
@@ -9,6 +10,9 @@ import { Component } from "@odoo/owl";
export class SaleOrderRow extends Component {
static template = "SaleOrderRow";
setup() {
this.ui = useState(useService("ui"));
}
get order() {
return this.props.order;
}
@@ -2,7 +2,7 @@
import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductScreen";
import { usePos } from "@point_of_sale/app/pos_hook";
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
export class SetSaleOrderButton extends Component {
static template = "SetSaleOrderButton";
@@ -10,13 +10,14 @@ export class SetSaleOrderButton extends Component {
setup() {
super.setup();
this.pos = usePos();
this.ui = useState(useService("ui"));
this.orm = useService("orm");
}
async click() {
// FIXME POSREF why are we calling browse for a ping?
// Why don't we let the order management screen deal with the offline error?
await this.orm.call("sale.order", "browse", [[]]);
const screen = this.env.isMobile
const screen = this.ui.isSmall
? "MobileSaleOrderManagementScreen"
: "SaleOrderManagementScreen";
this.pos.showScreen(screen);
@@ -3,7 +3,7 @@
<t t-name="SaleOrderList" owl="1">
<div class="orders">
<div class="header-row" t-att-class="{ oe_hidden: env.isMobile }">
<div class="header-row" t-att-class="{ oe_hidden: ui.isSmall }">
<div class="col name">Order</div>
<div class="col date">Date</div>
<div class="col customer">Customer</div>
@@ -5,7 +5,7 @@
<div class="control-panel">
<div class="item button back" t-on-click="() => this.props.close()">
<i class="fa fa-angle-double-left"></i>
<span t-if="!env.isMobile"> Back</span>
<span t-if="!ui.isSmall"> Back</span>
</div>
<div class="item search-box">
<span class="icon">
@@ -6,23 +6,23 @@
t-att-class="{ highlight: highlighted }"
t-on-click="() => this.props.onClickSaleOrder(props.order)">
<div class="col name">
<div t-if="env.isMobile">Order</div>
<div t-if="ui.isSmall">Order</div>
<div><t t-esc="name"/></div>
</div>
<div class="col date">
<div t-if="env.isMobile">Date</div>
<div t-if="ui.isSmall">Date</div>
<div><t t-esc="date"/></div>
</div>
<div class="col partner">
<div t-if="env.isMobile">Customer</div>
<div t-if="ui.isSmall">Customer</div>
<div><t t-esc="partner"/></div>
</div>
<div class="col salesman">
<div t-if="env.isMobile">Salesman</div>
<div t-if="ui.isSmall">Salesman</div>
<div><t t-esc="salesman"/></div>
</div>
<div class="col end total">
<div t-if="env.isMobile">Total</div>
<div t-if="ui.isSmall">Total</div>
<div class="flex-container">
<div class="self-end">
<t t-esc="total"/>
@@ -33,7 +33,7 @@
</div>
</div>
<div class="col state">
<div t-if="env.isMobile">State</div>
<div t-if="ui.isSmall">State</div>
<div><t t-esc="state"/></div>
</div>
</div>
+7 -8
View File
@@ -2,13 +2,13 @@
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { debounce } from "@web/core/utils/timing";
import { throttleForAnimation } from "@web/core/utils/timing";
import { BlockUI } from "./block_ui";
import { browser } from "@web/core/browser/browser";
import { getTabableElements } from "@web/core/utils/ui";
import { getActiveHotkey } from "../hotkeys/hotkey_service";
import { EventBus, useEffect, useRef } from "@odoo/owl";
import { EventBus, reactive, useEffect, useRef } from "@odoo/owl";
export const SIZES = { XS: 0, VSM: 1, SM: 2, MD: 3, LG: 4, XL: 5, XXL: 6 };
@@ -173,7 +173,7 @@ export const uiService = {
}
}
const ui = {
const ui = reactive({
bus,
size: utils.getSize(),
get activeElement() {
@@ -182,25 +182,24 @@ export const uiService = {
get isBlocked() {
return blockCount > 0;
},
get isSmall() {
return utils.isSmall(ui);
},
isSmall: utils.isSmall(),
block,
unblock,
activateElement,
deactivateElement,
getActiveElementOf,
};
});
// listen to media query status changes
const updateSize = () => {
const prevSize = ui.size;
ui.size = utils.getSize();
if (ui.size !== prevSize) {
ui.isSmall = utils.isSmall(ui);
bus.trigger("resize");
}
};
browser.addEventListener("resize", debounce(updateSize, 100));
browser.addEventListener("resize", throttleForAnimation(updateSize));
Object.defineProperty(env, "isSmall", {
get() {