Skip to content

Commit 50f9aeb

Browse files
committed
Add DSelectOption & status options support
Introduce a shared DSelectOption model and StatusOption/StatusOptionsResponse models. Add StatusService.getOptions to fetch status options from the API and map responses into DSelectOption shape. Refactor select and autocomplete components to use DSelectOption. Update product form to use signal-based statusOptions, call onStatusSearch during init, replace static status list, and adjust template binding ([options] uses statusOptions()). Also remove an informational panel in the product form template. Small import and signal reorganizations to support these changes.
1 parent de50d75 commit 50f9aeb

7 files changed

Lines changed: 62 additions & 91 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export interface DSelectOption {
2+
label: string;
3+
value: string | number;
4+
disabled?: boolean;
5+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export interface StatusOptionsResponse {
2+
success: boolean;
3+
message: string;
4+
data: StatusOption[];
5+
}
6+
7+
export interface StatusOption {
8+
id: string;
9+
label: string;
10+
description: string;
11+
icon: string;
12+
}

src/app/core/services/status-service.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { inject, Injectable } from '@angular/core';
33
import { PaginatedResponse } from '../models/pagination/pagination.model';
44
import { ProductResponse } from '../models/products/product-response.model';
55
import { environment } from '../../../environments/environment';
6+
import { buildHttpParams } from './build-http-params';
7+
import { GeneralOptionQuery } from '../models/generals/general-option-query.model';
8+
import { StatusOptionsResponse } from '../models/status/status-options.model';
69

710
@Injectable({
811
providedIn: 'root',
@@ -15,4 +18,12 @@ export class StatusService {
1518
getAll() {
1619
return this.http.get<PaginatedResponse<ProductResponse>>(`${this.api}/${this.flag}`);
1720
}
21+
22+
getOptions(module: string, limit: string | null = null) {
23+
const params = buildHttpParams({
24+
module: module,
25+
limit: limit,
26+
});
27+
return this.http.get<StatusOptionsResponse>(`${this.api}/${this.flag}/options`, { params });
28+
}
1829
}

src/app/design-system/autocomplete-select/autocomplete-select.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import {
1111
OnDestroy,
1212
} from '@angular/core';
1313
import { AppIconComponent } from '../icon/app-icon';
14-
import { SelectOption } from '../select/select';
1514
import { GeneralOptionQuery } from '../../core/models/generals/general-option-query.model';
15+
import { DSelectOption } from '../../core/models/design-system/select-option.model';
1616

17-
export interface AutocompleteOption extends SelectOption {
17+
export interface AutocompleteOption extends DSelectOption {
1818
sublabel?: string;
1919
category?: string;
2020
icon?: string;

src/app/design-system/select/select.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import { Component, ChangeDetectionStrategy, input, output } from '@angular/core';
22
import { AppIconComponent } from '../icon/app-icon';
3-
4-
export interface SelectOption {
5-
label: string;
6-
value: string | number;
7-
disabled?: boolean;
8-
}
3+
import { DSelectOption } from '../../core/models/design-system/select-option.model';
94

105
@Component({
116
selector: 'app-select',
@@ -19,7 +14,7 @@ export class SelectComponent {
1914
readonly label = input<string | undefined>(undefined);
2015
readonly value = input<string | number>('');
2116
readonly placeholder = input<string>('Selecione uma opção');
22-
readonly options = input.required<SelectOption[]>();
17+
readonly options = input.required<DSelectOption[]>();
2318
readonly disabled = input<boolean>(false);
2419
readonly required = input<boolean>(false);
2520
readonly error = input<string | undefined>(undefined);

src/app/features/catalog/product-form/product-form.html

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
[required]="true"
168168
placeholder="Selecione o status"
169169
[value]="formStatusId()"
170-
[options]="statusOptions"
170+
[options]="statusOptions()"
171171
[disabled]="isReadOnly()"
172172
[error]="errors()['status_id']"
173173
(valueChange)="updateField('status_id', $event)"
@@ -419,64 +419,6 @@ <h3 class="text-sm font-bold text-gray-900 dark:text-slate-100 flex items-center
419419
></span>
420420
</button>
421421
</div>
422-
423-
<!-- Painel Informativo: Campos Gerenciados Automaticamente pelo Sistema -->
424-
<div
425-
class="p-4 bg-gray-50/90 dark:bg-slate-900/50 rounded-xl border border-gray-200/70 dark:border-slate-700/70 space-y-3"
426-
>
427-
<div
428-
class="flex items-center gap-2 text-xs font-bold text-gray-700 dark:text-slate-300 uppercase tracking-wider"
429-
>
430-
<app-icon name="check-circle" size="w-4 h-4" class="text-[#4F8A6B]" />
431-
<span>Campos Gerenciados Automaticamente pelo Sistema</span>
432-
</div>
433-
434-
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-3 text-xs">
435-
<div
436-
class="p-3 rounded-lg bg-white dark:bg-slate-800 border border-gray-200/60 dark:border-slate-700/60 shadow-2xs"
437-
>
438-
<span class="block text-[11px] font-medium text-gray-400 dark:text-slate-400 mb-1">
439-
ID (id)
440-
</span>
441-
<span
442-
class="font-mono text-gray-800 dark:text-slate-200 text-[11px] bg-gray-100 dark:bg-slate-700/60 px-1.5 py-0.5 rounded"
443-
>
444-
Gerado Auto (UUID)
445-
</span>
446-
</div>
447-
448-
<div
449-
class="p-3 rounded-lg bg-white dark:bg-slate-800 border border-gray-200/60 dark:border-slate-700/60 shadow-2xs"
450-
>
451-
<span class="block text-[11px] font-medium text-gray-400 dark:text-slate-400 mb-1">
452-
Produto (product_id)
453-
</span>
454-
<span class="font-medium text-gray-800 dark:text-slate-200">Vínculo Automático</span>
455-
</div>
456-
457-
<div
458-
class="p-3 rounded-lg bg-white dark:bg-slate-800 border border-gray-200/60 dark:border-slate-700/60 shadow-2xs"
459-
>
460-
<span class="block text-[11px] font-medium text-gray-400 dark:text-slate-400 mb-1">
461-
Qtd. Reservada (reserved)
462-
</span>
463-
<span class="font-medium text-emerald-600 dark:text-emerald-400">0 (Inicial)</span>
464-
</div>
465-
466-
<div
467-
class="p-3 rounded-lg bg-white dark:bg-slate-800 border border-gray-200/60 dark:border-slate-700/60 shadow-2xs"
468-
>
469-
<span class="block text-[11px] font-medium text-gray-400 dark:text-slate-400 mb-1">
470-
Status (active)
471-
</span>
472-
<span
473-
class="inline-flex items-center px-2 py-0.5 rounded-md text-[10px] font-bold bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-300 border border-emerald-300/50"
474-
>
475-
Ativo (true)
476-
</span>
477-
</div>
478-
</div>
479-
</div>
480422
</div>
481423
}
482424

src/app/features/catalog/product-form/product-form.ts

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
import { ActivatedRoute, Router } from '@angular/router';
1010
import { PageHeaderComponent } from '../../../design-system/page-header/page-header';
1111
import { InputComponent } from '../../../design-system/input/input';
12-
import { SelectComponent, SelectOption } from '../../../design-system/select/select';
12+
import { SelectComponent } from '../../../design-system/select/select';
1313
import { ButtonComponent } from '../../../design-system/button/button';
1414
import { ConfirmDialogComponent } from '../../../design-system/dialog/confirm-dialog';
1515
import { AppIconComponent } from '../../../design-system/icon/app-icon';
@@ -29,6 +29,11 @@ import { debounceTime, distinctUntilChanged, Subject, switchMap } from 'rxjs';
2929
import { GeneralOptionQuery } from '../../../core/models/generals/general-option-query.model';
3030
import { ManufacturerOption } from '../../../core/models/manufactureres/manufaturer-options.model';
3131
import { StatusService } from '../../../core/services/status-service';
32+
import {
33+
StatusOption,
34+
StatusOptionsResponse,
35+
} from '../../../core/models/status/status-options.model';
36+
import { DSelectOption } from '../../../core/models/design-system/select-option.model';
3237

3338
export type ProductFormMode = 'create' | 'edit' | 'view' | 'duplicate';
3439
export type FormTab =
@@ -176,21 +181,21 @@ export class ProductFormComponent implements OnInit {
176181
readonly productNotes = signal<ProductNoteItem[]>([]);
177182

178183
readonly categoryLoading = signal(false);
179-
readonly categoryQuery = signal('');
184+
readonly manufacturerLoading = signal(false);
185+
186+
readonly fetchedStatuses = signal<StatusOption[]>([]);
180187
readonly fetchedCategories = signal<CategoryOption[]>([]);
181188
readonly fetchedManufacturers = signal<ManufacturerOption[]>([]);
182189

183-
readonly manufacturerLoading = signal(false);
190+
readonly statusQuery = signal('');
191+
readonly categoryQuery = signal('');
184192
readonly manufacturerQuery = signal('');
185-
// readonly manufacturerQuery = signal<GeneralOptionQuery>({
186-
// active: null,
187-
// search: '',
188-
// limit: 10,
189-
// });
190193

191194
private readonly categorySearch$ = new Subject<GeneralOptionQuery>();
192195
private readonly manufacturerSearch$ = new Subject<GeneralOptionQuery>();
193196

197+
private currentModule = signal<string>('PRODUCT');
198+
194199
readonly product = signal<ProductResponse>({
195200
id: 'p0000000-0002-0000-0000-000000000002',
196201
status: {
@@ -266,10 +271,10 @@ export class ProductFormComponent implements OnInit {
266271
});
267272

268273
readonly manufacturerOptions = computed<AutocompleteOption[]>(() => {
269-
const manufacturers = this.fetchedManufacturers();
274+
const status = this.fetchedStatuses();
270275
const query = this.manufacturerQuery().trim().toLowerCase() || '';
271276

272-
return manufacturers
277+
return status
273278
.filter((m) => !query || m.label.toLowerCase().includes(query))
274279
.map((m) => ({
275280
label: m.label,
@@ -278,14 +283,16 @@ export class ProductFormComponent implements OnInit {
278283
}));
279284
});
280285

281-
readonly partOriginOptions: SelectOption[] = [
286+
readonly statusOptions = signal<DSelectOption[]>([]);
287+
288+
readonly partOriginOptions: DSelectOption[] = [
282289
{ label: 'Nacional', value: 'po-01' },
283290
{ label: 'Importado Direto', value: 'po-02' },
284291
{ label: 'Original OEM', value: 'po-03' },
285292
{ label: 'Aftermarket Premium', value: 'po-04' },
286293
];
287294

288-
readonly unitOptions: SelectOption[] = [
295+
readonly unitOptions: DSelectOption[] = [
289296
{ label: 'Jogo', value: 'jogo' },
290297
{ label: 'Peça', value: 'peça' },
291298
{ label: 'Par', value: 'par' },
@@ -297,13 +304,7 @@ export class ProductFormComponent implements OnInit {
297304
{ label: 'Conjunto', value: 'conjunto' },
298305
];
299306

300-
readonly statusOptions: SelectOption[] = [
301-
{ label: 'Ativo', value: 'st-01' },
302-
{ label: 'Inativo', value: 'st-02' },
303-
{ label: 'Em Homologação', value: 'st-03' },
304-
];
305-
306-
readonly warehouseOptions: SelectOption[] = [
307+
readonly warehouseOptions: DSelectOption[] = [
307308
{ label: 'Depósito Central SP', value: 'wh-01' },
308309
{ label: 'Depósito Filial PR', value: 'wh-02' },
309310
{ label: 'Depósito Distribuição RJ', value: 'wh-03' },
@@ -384,9 +385,9 @@ export class ProductFormComponent implements OnInit {
384385
},
385386
});
386387

388+
this.onStatusSearch();
387389
this.onCategorySearch(this.queries());
388390
this.onManufacturerSearch(this.queries());
389-
this.getStatus();
390391

391392
if (id) {
392393
this.productById(id);
@@ -1068,10 +1069,15 @@ export class ProductFormComponent implements OnInit {
10681069
this.manufacturerSearch$.next(query);
10691070
}
10701071

1071-
getStatus() {
1072-
this.statusService.getAll().subscribe({
1072+
onStatusSearch(limit = null) {
1073+
this.statusService.getOptions(this.currentModule(), limit).subscribe({
10731074
next: (response) => {
1074-
console.log('Fetched Product Status Options:', response.data);
1075+
const result = response.data.map((status) => ({
1076+
label: status.label,
1077+
value: status.id,
1078+
description: status.description,
1079+
}));
1080+
this.statusOptions.set(result);
10751081
},
10761082
error: (error) => {
10771083
console.error('Error fetching product status options:', error);

0 commit comments

Comments
 (0)