mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
feat(remission): enhance quantity input handling and error validation
Refactor quantity input to use a direct input field instead of a toggle button. Add validation to ensure quantity does not exceed 999 and display relevant error messages. Improve overall user experience in the remission process. Refs: #5253
This commit is contained in:
@@ -1,38 +1,35 @@
|
||||
<div class="grid grid-cols-[1fr,auto] items-center justify-between">
|
||||
<div
|
||||
class="grid grid-cols-[1fr,auto] items-center justify-between"
|
||||
[attr.data-position]="position()"
|
||||
>
|
||||
<div class="isa-text-body-1-bold">Menge {{ position() }}</div>
|
||||
<div class="-mr-4">
|
||||
<ui-button
|
||||
(click)="showNumberInput.set(!showNumberInput())"
|
||||
role="switch"
|
||||
color="secondary"
|
||||
class="border-none justify-between w-auto min-w-0 gap-4"
|
||||
data-what="button"
|
||||
data-which="toggle-quantity"
|
||||
[attr.data-position]="position()"
|
||||
>
|
||||
{{
|
||||
showNumberInput() ? 'Menge' : quantityAndReason().quantity || 'Menge'
|
||||
}}
|
||||
<ng-icon
|
||||
[name]="
|
||||
showNumberInput() ? 'isaActionChevronUp' : 'isaActionChevronDown'
|
||||
"
|
||||
size="1.25rem"
|
||||
></ng-icon>
|
||||
</ui-button>
|
||||
<input
|
||||
name="quantity"
|
||||
placeholder="Menge eingeben"
|
||||
type="number"
|
||||
[ngModel]="quantityAndReason().quantity"
|
||||
(ngModelChange)="setQuantity($event)"
|
||||
#model="ngModel"
|
||||
[min]="1"
|
||||
[max]="999"
|
||||
required
|
||||
data-what="input"
|
||||
data-which="quantity"
|
||||
class="isa-text-body-2-bold placeholder:isa-text-body-2-regular placeholder:text-isa-neutral-200 text-isa-neutral-900 focus:outline-none w-[9rem] px-4 text-right"
|
||||
/>
|
||||
<ui-dropdown
|
||||
[ngModel]="quantityAndReason().reason"
|
||||
(ngModelChange)="setReason($event)"
|
||||
class="border-none max-w-56 truncate"
|
||||
data-what="dropdown"
|
||||
data-which="reason"
|
||||
[attr.data-position]="position()"
|
||||
label="Rückgabegrund"
|
||||
>
|
||||
@if (reasonResource.value(); as reasons) {
|
||||
@for (reson of reasons; track reson.key) {
|
||||
<ui-dropdown-option
|
||||
[value]="reson.value"
|
||||
<ui-dropdown-option
|
||||
[value]="reson.value"
|
||||
data-what="dropdown-option"
|
||||
data-which="reason-option"
|
||||
[attr.data-reason-key]="reson.key"
|
||||
@@ -46,36 +43,3 @@
|
||||
</ui-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (showNumberInput(); as showInput) {
|
||||
<form (ngSubmit)="setQuantity(model.value); showNumberInput.set(false)">
|
||||
<ui-text-field class="w-full">
|
||||
<input
|
||||
name="quantity"
|
||||
uiInputControl
|
||||
placeholder="Menge"
|
||||
type="number"
|
||||
[ngModel]="quantityAndReason().quantity"
|
||||
#model="ngModel"
|
||||
[min]="1"
|
||||
[max]="999"
|
||||
required
|
||||
data-what="input"
|
||||
data-which="quantity"
|
||||
[attr.data-position]="position()"
|
||||
/>
|
||||
<button
|
||||
uiTextButton
|
||||
type="submit"
|
||||
class="-mr-4 bg-transparent"
|
||||
color="strong"
|
||||
[disabled]="!model.valid"
|
||||
data-what="button"
|
||||
data-which="save-quantity"
|
||||
[attr.data-position]="position()"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</ui-text-field>
|
||||
</form>
|
||||
}
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
:host {
|
||||
@apply grid grid-flow-row gap-[0.62rem] px-4 py-[.44rem] border border-isa-neutral-400 rounded-lg;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
&::-webkit-inner-spin-button,
|
||||
&::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ import {
|
||||
model,
|
||||
resource,
|
||||
signal,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { FormsModule, NgModel } from '@angular/forms';
|
||||
import { RemissionReasonService, ReturnItem } from '@isa/remission/data-access';
|
||||
import {
|
||||
DropdownButtonComponent,
|
||||
@@ -15,12 +16,7 @@ import {
|
||||
} from '@isa/ui/input-controls';
|
||||
import { QuantityAndReason } from './select-remi-quantity-and-reason.component';
|
||||
import { ReturnValue } from '@isa/common/data-access';
|
||||
import {
|
||||
TextFieldComponent,
|
||||
InputControlDirective,
|
||||
} from '@isa/ui/input-controls';
|
||||
import { ButtonComponent, TextButtonComponent } from '@isa/ui/buttons';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
import { provideIcons } from '@ng-icons/core';
|
||||
import { isaActionChevronDown, isaActionChevronUp } from '@isa/icons';
|
||||
|
||||
@Component({
|
||||
@@ -29,21 +25,14 @@ import { isaActionChevronDown, isaActionChevronUp } from '@isa/icons';
|
||||
styleUrls: ['./quantity-and-reason-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [
|
||||
DropdownButtonComponent,
|
||||
DropdownOptionComponent,
|
||||
FormsModule,
|
||||
TextFieldComponent,
|
||||
InputControlDirective,
|
||||
ButtonComponent,
|
||||
TextButtonComponent,
|
||||
NgIcon,
|
||||
],
|
||||
imports: [DropdownButtonComponent, DropdownOptionComponent, FormsModule],
|
||||
providers: [provideIcons({ isaActionChevronDown, isaActionChevronUp })],
|
||||
})
|
||||
export class QuantityAndReasonItemComponent {
|
||||
#reasonService = inject(RemissionReasonService);
|
||||
|
||||
readonly control = viewChild.required<NgModel>('#model');
|
||||
|
||||
showNumberInput = signal(false);
|
||||
|
||||
position = input.required<number>();
|
||||
|
||||
@@ -47,12 +47,14 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-isa-accent-red isa-text-body-1-regular text-left">
|
||||
@if (canReturnErrors(); as errors) {
|
||||
@for (error of errors; track $index) {
|
||||
{{ error }}
|
||||
<div class="text-isa-accent-red isa-text-body-1-regular">
|
||||
<span>
|
||||
@if (canReturnErrors(); as errors) {
|
||||
@for (error of errors; track $index) {
|
||||
{{ error }}
|
||||
}
|
||||
}
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center gap-2">
|
||||
<button
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
ReturnSuggestion,
|
||||
} from '@isa/remission/data-access';
|
||||
import { injectFeedbackDialog } from '@isa/ui/dialog';
|
||||
import { BatchResponseArgs } from '@isa/common/data-access';
|
||||
|
||||
export interface QuantityAndReason {
|
||||
quantity: number;
|
||||
@@ -93,10 +94,27 @@ export class SelectRemiQuantityAndReasonComponent {
|
||||
canAddToRemiListResource = resource({
|
||||
params: this.params,
|
||||
loader: async ({ params, abortSignal }) => {
|
||||
if (!this.host.item() || params.some((p) => !p.reason)) {
|
||||
if (
|
||||
!this.host.item() ||
|
||||
params.some((p) => !p.reason) ||
|
||||
params.some((p) => !p.quantity)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const maxQuantityErrors = params.filter((p) => !(p.quantity <= 999));
|
||||
if (maxQuantityErrors.length > 0) {
|
||||
const errRes: BatchResponseArgs<ReturnItem> = {
|
||||
completed: false,
|
||||
error: true,
|
||||
total: maxQuantityErrors.length,
|
||||
invalidProperties: {
|
||||
quantity: 'Die Menge darf maximal 999 sein.',
|
||||
},
|
||||
};
|
||||
return errRes;
|
||||
}
|
||||
|
||||
return this.#remiService.canAddItemToRemiList(params, abortSignal);
|
||||
},
|
||||
});
|
||||
@@ -124,6 +142,10 @@ export class SelectRemiQuantityAndReasonComponent {
|
||||
|
||||
canReturnErrors = computed(() => {
|
||||
const results = this.canAddToRemiListResource.value();
|
||||
if (results?.invalidProperties) {
|
||||
return Object.values(results.invalidProperties);
|
||||
}
|
||||
|
||||
if (!results?.failed) {
|
||||
return [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user