Merged PR 1860: #5157 Return Input Ean Validation

- feat(oms-return-review): implement return review feature
- Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop
- Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop
- feat(oms-return-process, ui-input-controls): improve error feedback for EAN input and adjust text field container spacing

Refs: #5157
This commit is contained in:
Nino Righi
2025-06-13 13:55:32 +00:00
committed by Lorenz Hilpert
parent 0134f8dbf5
commit 6f80159281
3 changed files with 28 additions and 5 deletions

View File

@@ -8,12 +8,15 @@
<ui-text-field-container>
<ui-text-field size="small" class="min-w-[22.875rem]">
<input
#inputRef
uiInputControl
class="isa-text-body-2-bold placeholder:isa-text-body-2-bold"
placeholder="EAN eingeben / scannen"
type="text"
[formControl]="control"
(cleared)="resetProduct()"
(blur)="control.updateValueAndValidity()"
(keydown.enter)="check()"
/>
@if (!p) {
<button
@@ -32,17 +35,18 @@
</ui-text-field>
<ui-text-field-errors>
@if (!p && status().hasResult === false) {
@if (!p && status().hasResult === false && !control.invalid) {
<span>Kein Artikel gefunden</span>
}
@if (control.invalid && control.touched && !control.dirty) {
@if (control.invalid && control.touched) {
<span>Die eingegebene EAN ist ungültig</span>
}
</ui-text-field-errors>
</ui-text-field-container>
<shared-scanner-button
class="self-start"
[disabled]="!!control?.value"
(scan)="onScan($event)"
>

View File

@@ -2,9 +2,11 @@ import {
ChangeDetectionStrategy,
Component,
effect,
ElementRef,
inject,
input,
signal,
viewChild,
} from '@angular/core';
import {
AbstractControl,
@@ -19,7 +21,7 @@ import {
ReturnProcessProductQuestion,
ReturnProcessStore,
} from '@isa/oms/data-access';
import { IconButtonComponent, TextButtonComponent } from '@isa/ui/buttons';
import { TextButtonComponent } from '@isa/ui/buttons';
import {
InputControlDirective,
TextFieldClearComponent,
@@ -36,6 +38,7 @@ import { provideIcons } from '@ng-icons/core';
import { isaActionScanner } from '@isa/icons';
import { ScannerButtonComponent } from '@isa/shared/scanner';
import { ProductRouterLinkDirective } from '@isa/shared/product-router-link';
import { toSignal } from '@angular/core/rxjs-interop';
const eanValidator: ValidatorFn = (
control: AbstractControl,
@@ -61,7 +64,6 @@ const eanValidator: ValidatorFn = (
TextFieldComponent,
TextFieldClearComponent,
ProductImageDirective,
IconButtonComponent,
ScannerButtonComponent,
ProductRouterLinkDirective,
],
@@ -71,11 +73,14 @@ export class ReturnProcessProductQuestionComponent {
#returnProcessStore = inject(ReturnProcessStore);
#catalogueSearchService = inject(CatalougeSearchService);
inputElement = viewChild<ElementRef<HTMLInputElement>>('inputRef');
returnProcessId = input.required<number>();
question = input.required<ReturnProcessProductQuestion>();
control = new FormControl<string>('', [Validators.required, eanValidator]);
valueChanges = toSignal(this.control.valueChanges);
product = signal<Product | undefined>(undefined);
status = signal<{ fetching: boolean; hasResult?: boolean }>({
@@ -83,6 +88,14 @@ export class ReturnProcessProductQuestionComponent {
});
constructor() {
effect(() => {
const valueChanged = this.valueChanges();
if (valueChanged) {
this.control.setErrors(null);
this.status.set({ fetching: false, hasResult: undefined });
}
});
effect(() => {
const product = this.#returnProcessStore.entityMap()[
this.returnProcessId()
@@ -91,6 +104,8 @@ export class ReturnProcessProductQuestionComponent {
if (product) {
this.control.setValue(product.ean);
this.product.set(product);
} else {
this.inputElement()?.nativeElement?.focus();
}
});
}
@@ -101,6 +116,7 @@ export class ReturnProcessProductQuestionComponent {
this.returnProcessId(),
this.question().key,
);
this.inputElement()?.nativeElement?.focus();
}
onScan(value: string | null) {
@@ -114,6 +130,7 @@ export class ReturnProcessProductQuestionComponent {
pipe(
filter(() => this.control.valid),
tap(() => {
this.control.updateValueAndValidity();
this.status.set({ fetching: true, hasResult: undefined });
}),
switchMap(() =>

View File

@@ -1,7 +1,9 @@
.ui-text-field-container {
@apply flex flex-col gap-1 items-start justify-center;
@apply flex flex-col items-start justify-center;
&:has(.ui-text-field-errors > *) {
@apply gap-1;
.ui-text-field {
@apply border-isa-accent-red;
}