[IMP] pos_self_order: add search bar

After the merge of kiosk and mobile self, the search bar had not been
reimplemented.

In this commit, we add it.

closes odoo/odoo#137063

Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
David Monnom (moda)
2023-09-29 16:08:47 +00:00
parent ed47260648
commit cfe0a6f463
3 changed files with 90 additions and 35 deletions
@@ -1,12 +1,13 @@
/** @odoo-module */
import { Component, useEffect, useRef } from "@odoo/owl";
import { Component, useEffect, useRef, useState } from "@odoo/owl";
import { useSelfOrder } from "@pos_self_order/app/self_order_service";
import { ProductCard } from "@pos_self_order/app/components/product_card/product_card";
import { CancelPopup } from "@pos_self_order/app/components/cancel_popup/cancel_popup";
import { useService, useChildRef } from "@web/core/utils/hooks";
import { OrderWidget } from "@pos_self_order/app/components/order_widget/order_widget";
import { _t } from "@web/core/l10n/translation";
import { fuzzyLookup } from "@web/core/utils/search";
export class ProductListPage extends Component {
static template = "pos_self_order.ProductListPage";
@@ -19,7 +20,10 @@ export class ProductListPage extends Component {
this.productsList = useRef("productsList");
this.categoryList = useRef("categoryList");
this.currentProductCard = useChildRef();
this.state = useState({
search: false,
searchInput: "",
});
this.categoryButton = Object.fromEntries(
Array.from(this.selfOrder.categoryList).map((category) => {
return [category.name, useRef(`category_${category.name}`)];
@@ -73,12 +77,32 @@ export class ProductListPage extends Component {
);
}
get width() {
return window.innerWidth;
}
get productCategory() {
const productByCat = this.selfOrder.productsGroupedByCategory;
const currentCategory = this.selfOrder.currentCategory;
return productByCat[currentCategory] ? productByCat[currentCategory] : [];
}
focusSearch() {
this.state.search = !this.state.search;
if (!this.state.search) {
this.state.searchInput = "";
}
}
getFilteredProducts(products) {
return fuzzyLookup(
this.state.searchInput,
products,
(product) => product.name + product.description_sale
);
}
scrollTo(ref = null, { behavior = "smooth" } = {}) {
this.productsList.el.scroll({
top: ref?.el ? ref.el.offsetTop - this.productsList.el.offsetTop : 0,
@@ -1,18 +1,28 @@
.category-list {
.navbar-container {
height: 225px;
overflow-y: hidden;
.category-item {
width: 150px;
height: 150px;
padding: 0px !important;
.category-list {
width: calc(100% - 50px);
overflow-y: hidden;
.category-item {
width: 150px;
height: 150px;
padding: 0px !important;
}
img {
object-fit: cover;
}
}
img {
object-fit: cover;
.search-button {
width: 50px;
}
}
.product-list {
overflow-y: scroll;
margin-top: 225px;
@@ -34,16 +44,18 @@
height: calc(100% - 60px);
}
.category-list {
.navbar-container {
height: 60px;
overflow-y: hidden;
.category-item {
height: 40px;
}
.category-list {
.category-item {
height: 40px;
}
img {
display: none;
img {
display: none;
}
}
}
}
}
@@ -3,23 +3,39 @@
<t t-name="pos_self_order.ProductListPage">
<div class="vh-100 overflow-hidden">
<!-- Categories selector -->
<nav id="listgroup-categories" class="navbar category-list fixed-top d-flex flex-column flex-wrap gap-3 align-content-start py-2 px-3 shadow-sm bg-view" t-ref="categoryList">
<a
t-foreach="Array.from(selfOrder.categoryList)"
t-as="category"
t-key="category.id"
t-ref="category_{{category.name}}"
t-attf-class="nav-link btn btn-light d-flex flex-column align-items-center justify-content-center category-item h-100 border px-1 overflow-hidden"
t-attf-href="#scrollspy_{{category.id}}">
<img t-if="category.has_image"
class="rounded w-100 h-75 ratio ratio-1x1"
t-attf-src="/pos-self/get-category-image/{{ category.id }}"
alt="Product image"
loading="lazy"
onerror="this.remove()" />
<span class="w-100 fs-5 text-truncate" t-esc="category.name" />
</a>
</nav>
<div class="navbar-container w-100 fixed-top bg-view shadow-sm">
<div t-attf-class="{{ this.state.search and width > 576 ? 'h-75' : 'h-100' }} {{ !this.state.search || width > 576 ? '' : 'd-none' }} d-flex w-100">
<nav id="listgroup-categories" class="navbar category-list d-flex flex-column flex-wrap gap-3 align-content-start py-2 px-3 h-100" t-ref="categoryList">
<a
t-foreach="Array.from(selfOrder.categoryList)"
t-as="category"
t-key="category.id"
t-ref="category_{{category.name}}"
t-attf-class="nav-link btn btn-light d-flex flex-column align-items-center justify-content-center category-item h-100 border px-1 overflow-hidden"
t-attf-href="#scrollspy_{{category.id}}">
<img t-if="category.has_image"
class="rounded w-100 h-75 ratio ratio-1x1"
t-attf-src="/pos-self/get-category-image/{{ category.id }}"
alt="Product image"
loading="lazy"
onerror="this.remove()" />
<span class="w-100 fs-5 text-truncate" t-esc="category.name" />
</a>
</nav>
<button t-if="!this.state.search" class="btn btn-link text-dark px-3 search-button" t-on-click="focusSearch">
<i class="oi oi-search px-1"/>
</button>
</div>
<div t-if="this.state.search" t-attf-class="{{ this.state.search and width > 576 ? 'h-25' : 'h-100' }} d-flex align-items-center w-100">
<input type="text"
class="form-control p-3 border-0 shadow-none"
placeholder="Search product"
t-model="state.searchInput"/>
<button class="btn bg-200 rounded" t-on-click="focusSearch">
<i class="fa fa-times"/>
</button>
</div>
</div>
<!-- Products list -->
<div
@@ -38,11 +54,14 @@
t-attf-categId="{{category.id}}"
t-ref="productsWithCategory_{{category.name}}"
class="product-list-category row p-3">
<h2 class="pt-3 pb-1 px-4 m-0 fs-3" t-esc="category.name" />
<t t-foreach="selfOrder.productsGroupedByCategory[category.name]" t-as="product" t-key="product.id">
<t t-set="products" t-value="selfOrder.productsGroupedByCategory[category.name]" />
<t t-set="availableProducts" t-value="!state.searchInput ? products : getFilteredProducts(products)" />
<h2 t-if="availableProducts.length > 0" class="pt-3 pb-1 px-4 m-0 fs-3" t-esc="category.name" />
<t t-foreach="availableProducts" t-as="product" t-key="product.id">
<ProductCard product="product" currentProductCard="product.id === selfOrder.lastEditedProductId and currentProductCard" />
</t>
</section>
<p t-if="getFilteredProducts(selfOrder.products).length === 0" class="mx-auto mt-3 text-center">No products found</p>
</div>
<!-- Page buttons -->