Removed Recipe Template as it was not needed.
Moved host listeners to the component declaration. Form submit on Return fixed.
This commit is contained in:
+4
-4
@@ -7,7 +7,7 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto basis-30">
|
||||
<mat-label>Product Group</mat-label>
|
||||
<mat-select [formField]="form.productGroup" (selectionChange)="filterOn($event.value)">
|
||||
<mat-select [formField]="form.productGroup">
|
||||
<mat-option>-- All Products --</mat-option>
|
||||
@for (pg of productGroups(); track pg) {
|
||||
<mat-option [value]="pg.id">
|
||||
@@ -18,10 +18,10 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
@if (resource.isLoading()) {
|
||||
@if (listResource.isLoading()) {
|
||||
<app-skeleton-loader type="table" [count]="1" />
|
||||
} @else if (resource.error()) {
|
||||
<app-error-state [message]="'Failed to load data.'" (retryAction)="resource.reload()" />
|
||||
} @else if (listResource.error()) {
|
||||
<app-error-state [message]="'Failed to load data.'" (retryAction)="listResource.reload()" />
|
||||
} @else {
|
||||
<mat-table [dataSource]="dataSource()">
|
||||
<!-- Name Column -->
|
||||
|
||||
+65
-28
@@ -1,5 +1,5 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, inject, computed, linkedSignal } from '@angular/core';
|
||||
import { Component, inject, computed, linkedSignal, input, debounced, effect } from '@angular/core';
|
||||
import { FormField, FormRoot, form as createForm } from '@angular/forms/signals';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
@@ -7,12 +7,13 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
|
||||
import { Product, StockKeepingUnit } from '../../core/product';
|
||||
import { ProductGroupService } from '../../product-group/product-group.service';
|
||||
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
|
||||
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
||||
import { TemporalProduct } from '../temporal-product';
|
||||
import { TemporalProductService } from '../temporal-product.service';
|
||||
|
||||
export interface TemporalProductListFormData {
|
||||
@@ -42,48 +43,84 @@ export interface TemporalProductListFormData {
|
||||
],
|
||||
})
|
||||
export class TemporalProductListComponent {
|
||||
private router = inject(Router);
|
||||
private route = inject(ActivatedRoute);
|
||||
private ser = inject(TemporalProductService);
|
||||
private productGroupSer = inject(ProductGroupService);
|
||||
|
||||
q = input('', { transform: (v: string | null | undefined) => v ?? '' });
|
||||
g = input('', { transform: (v: string | null | undefined) => v ?? '' });
|
||||
productGroupsResource = this.productGroupSer.list();
|
||||
productGroups = computed(() => this.productGroupsResource.value() ?? []);
|
||||
|
||||
listResource = this.ser.list();
|
||||
list = computed(() => this.listResource.value() ?? []);
|
||||
|
||||
formModel = linkedSignal({
|
||||
source: () => null,
|
||||
computation: (): TemporalProductListFormData => ({
|
||||
filter: '',
|
||||
productGroup: '',
|
||||
source: () => ({ q: this.q(), g: this.g() }),
|
||||
computation: (v: { q: string; g: string }): TemporalProductListFormData => ({
|
||||
filter: v.q,
|
||||
productGroup: v.g,
|
||||
}),
|
||||
});
|
||||
|
||||
form = createForm(this.formModel);
|
||||
filterSignal = computed(() => this.formModel().filter);
|
||||
debouncedFilter = debounced(this.filterSignal, 150);
|
||||
filteredList = computed(() => {
|
||||
const data = this.list();
|
||||
const search = this.debouncedFilter.value() ?? '';
|
||||
const productGroup = this.formModel().productGroup;
|
||||
const groupId =
|
||||
typeof productGroup === 'string'
|
||||
? productGroup
|
||||
: productGroup && 'id' in productGroup
|
||||
? (productGroup.id ?? '')
|
||||
: '';
|
||||
|
||||
productGroupsResource = this.productGroupSer.list();
|
||||
productGroups = computed(() => this.productGroupsResource.value() ?? []);
|
||||
const tokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
||||
|
||||
resource = this.ser.list();
|
||||
return data.filter((tp: TemporalProduct) => {
|
||||
const products = tp.products ?? [];
|
||||
const skus = tp.skus ?? [];
|
||||
|
||||
dataSource = computed(() => {
|
||||
let data = this.resource.value() ?? [];
|
||||
const filterValue = (this.formModel().filter ?? '').trim().toLowerCase();
|
||||
const groupValue = this.formModel().productGroup;
|
||||
const matchesSearch =
|
||||
tokens.length === 0 ||
|
||||
tokens.every(
|
||||
(token) =>
|
||||
products.some((p) => {
|
||||
const hay = `${p.name ?? ''} ${p.fractionUnits ?? ''} ${p.productGroup?.name ?? ''}`.toLowerCase();
|
||||
return hay.includes(token);
|
||||
}) ||
|
||||
skus.some((k) => {
|
||||
const hay = `${k.units ?? ''}`.toLowerCase();
|
||||
return hay.includes(token);
|
||||
}),
|
||||
);
|
||||
|
||||
if (filterValue || groupValue) {
|
||||
data = data.filter((d) => {
|
||||
let match = true;
|
||||
if (filterValue) {
|
||||
match = match && d.products[0].name.toLowerCase().includes(filterValue);
|
||||
}
|
||||
if (groupValue) {
|
||||
match = match && d.products[0].productGroup?.id === groupValue;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
}
|
||||
return data;
|
||||
const matchesProductGroup = !groupId || products.some((k) => (k.productGroup?.id ?? '') === groupId);
|
||||
return matchesSearch && matchesProductGroup;
|
||||
});
|
||||
});
|
||||
|
||||
dataSource = computed(() => this.filteredList());
|
||||
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns: string[] = ['product', 'sku', 'info'];
|
||||
|
||||
filterOn(val: string) {
|
||||
this.formModel.update((m) => ({ ...m, productGroup: val }));
|
||||
constructor() {
|
||||
effect(() => {
|
||||
const q = this.debouncedFilter.value() ?? '';
|
||||
const g = this.formModel().productGroup;
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
queryParams: {
|
||||
q: q || null,
|
||||
g: g || null,
|
||||
},
|
||||
queryParamsHandling: 'merge',
|
||||
replaceUrl: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user