update superAdmin users business
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
const baseUrl = '/api/v1/catalog';
|
||||
|
||||
export const CATALOG_API_ROUTES = {
|
||||
guilds: () => `${baseUrl}/guilds`,
|
||||
providers: () => `${baseUrl}/providers`,
|
||||
devices: () => `${baseUrl}/devices`,
|
||||
deviceBrands: () => `${baseUrl}/device_brands`,
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { IListingResponse } from '@/core/models/service.model';
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { AbstractSelectComponent } from '@/shared/abstractClasses';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { CatalogsService } from '../../service';
|
||||
|
||||
@Component({
|
||||
selector: 'catalog-deviceBrand-select',
|
||||
templateUrl: '../../template.html',
|
||||
imports: [UikitFieldComponent, Select, ReactiveFormsModule],
|
||||
})
|
||||
export class CatalogDeviceBrandSelectComponent extends AbstractSelectComponent<
|
||||
ISummary,
|
||||
IListingResponse<ISummary>
|
||||
> {
|
||||
@Input() override showClear: boolean = false;
|
||||
@Input() label: string = '';
|
||||
private readonly service = inject(CatalogsService);
|
||||
|
||||
get preparedLabel() {
|
||||
return this.label || 'انتخاب برند دستگاه';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
getDataService() {
|
||||
return this.service.getDeviceBrands();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './components/select.component';
|
||||
@@ -0,0 +1,34 @@
|
||||
import { IListingResponse } from '@/core/models/service.model';
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { AbstractSelectComponent } from '@/shared/abstractClasses';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { CatalogsService } from '../../service';
|
||||
|
||||
@Component({
|
||||
selector: 'catalog-device-select',
|
||||
templateUrl: '../../template.html',
|
||||
imports: [UikitFieldComponent, Select, ReactiveFormsModule],
|
||||
})
|
||||
export class CatalogDeviceSelectComponent extends AbstractSelectComponent<
|
||||
ISummary,
|
||||
IListingResponse<ISummary>
|
||||
> {
|
||||
@Input() override showClear: boolean = false;
|
||||
@Input() label: string = '';
|
||||
private readonly service = inject(CatalogsService);
|
||||
|
||||
get preparedLabel() {
|
||||
return this.label || 'انتخاب دستگاه';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
getDataService() {
|
||||
return this.service.getDevices();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './components/select.component';
|
||||
@@ -0,0 +1,13 @@
|
||||
<uikit-field [label]="label" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[loading]="loading()"
|
||||
[options]="items()"
|
||||
optionLabel="name"
|
||||
[optionValue]="selectOptionValue"
|
||||
placeholder="انتخاب صنف"
|
||||
[formControl]="control"
|
||||
[showClear]="showClear"
|
||||
[filter]="true"
|
||||
appendTo="body"
|
||||
/>
|
||||
</uikit-field>
|
||||
@@ -0,0 +1,30 @@
|
||||
import { IListingResponse } from '@/core/models/service.model';
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { AbstractSelectComponent } from '@/shared/abstractClasses';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { CatalogsService } from '../../service';
|
||||
|
||||
@Component({
|
||||
selector: 'catalog-guild-select',
|
||||
templateUrl: './select.component.html',
|
||||
imports: [UikitFieldComponent, Select, ReactiveFormsModule],
|
||||
})
|
||||
export class CatalogGuildSelectComponent extends AbstractSelectComponent<
|
||||
ISummary,
|
||||
IListingResponse<ISummary>
|
||||
> {
|
||||
@Input() override showClear: boolean = false;
|
||||
@Input() label: string = '';
|
||||
private readonly service = inject(CatalogsService);
|
||||
|
||||
ngOnInit() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
getDataService() {
|
||||
return this.service.getGuilds();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './components/select.component';
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './devices';
|
||||
export * from './guild';
|
||||
export * from './providers';
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { IListingResponse } from '@/core/models/service.model';
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { AbstractSelectComponent } from '@/shared/abstractClasses';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { CatalogsService } from '../../service';
|
||||
|
||||
@Component({
|
||||
selector: 'catalog-provider-select',
|
||||
templateUrl: '../../template.html',
|
||||
imports: [UikitFieldComponent, Select, ReactiveFormsModule],
|
||||
})
|
||||
export class CatalogProviderSelectComponent extends AbstractSelectComponent<
|
||||
ISummary,
|
||||
IListingResponse<ISummary>
|
||||
> {
|
||||
@Input() override showClear: boolean = false;
|
||||
@Input() label: string = '';
|
||||
private readonly service = inject(CatalogsService);
|
||||
|
||||
get preparedLabel() {
|
||||
return this.label || 'انتخاب ارایهدهنده';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
getDataService() {
|
||||
return this.service.getProviders();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './components/select.component';
|
||||
@@ -0,0 +1,29 @@
|
||||
import { IListingResponse } from '@/core/models/service.model';
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { CATALOG_API_ROUTES } from './apiRoutes';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CatalogsService {
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
private apiRoutes = CATALOG_API_ROUTES;
|
||||
|
||||
getGuilds(): Observable<IListingResponse<ISummary>> {
|
||||
return this.http.get<IListingResponse<ISummary>>(this.apiRoutes.guilds());
|
||||
}
|
||||
|
||||
getProviders(): Observable<IListingResponse<ISummary>> {
|
||||
return this.http.get<IListingResponse<ISummary>>(this.apiRoutes.providers());
|
||||
}
|
||||
|
||||
getDevices(): Observable<IListingResponse<ISummary>> {
|
||||
return this.http.get<IListingResponse<ISummary>>(this.apiRoutes.devices());
|
||||
}
|
||||
|
||||
getDeviceBrands(): Observable<IListingResponse<ISummary>> {
|
||||
return this.http.get<IListingResponse<ISummary>>(this.apiRoutes.deviceBrands());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<uikit-field [label]="preparedLabel" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
|
||||
<p-select
|
||||
[loading]="loading()"
|
||||
[options]="items()"
|
||||
optionLabel="name"
|
||||
[optionValue]="selectOptionValue"
|
||||
[placeholder]="preparedLabel"
|
||||
[formControl]="control"
|
||||
[showClear]="showClear"
|
||||
[filter]="true"
|
||||
appendTo="body"
|
||||
/>
|
||||
</uikit-field>
|
||||
@@ -1,42 +1,48 @@
|
||||
<uikit-field [label]="label" [name]="name" [control]="control" [showLabel]="!!label" [showErrors]="showErrors">
|
||||
@if (type === "switch") {
|
||||
<p-toggleSwitch [formControl]="control" />
|
||||
} @else if (type === "price") {
|
||||
<p-inputgroup>
|
||||
<p-inputnumber
|
||||
[attr.id]="name"
|
||||
[formControl]="control"
|
||||
[attr.name]="name"
|
||||
[attr.placeholder]="placeholder"
|
||||
[attr.inputmode]="inputMode"
|
||||
[attr.maxlength]="maxLength || null"
|
||||
[attr.type]="htmlType"
|
||||
[attr.autocomplete]="autocomplete"
|
||||
[class]="` w-full ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
|
||||
[required]="isRequired"
|
||||
[invalid]="control.invalid && (control.touched || control.dirty)"
|
||||
(input)="onInput($event)"
|
||||
(onBlur)="blur.emit()"
|
||||
/>
|
||||
<p-inputgroup-addon>ریال</p-inputgroup-addon>
|
||||
</p-inputgroup>
|
||||
} @else {
|
||||
<input
|
||||
pInputText
|
||||
[attr.id]="name"
|
||||
[formControl]="control"
|
||||
[attr.name]="name"
|
||||
[attr.placeholder]="placeholder"
|
||||
[attr.inputmode]="inputMode"
|
||||
[attr.maxlength]="maxLength || null"
|
||||
[attr.type]="htmlType"
|
||||
[attr.autocomplete]="autocomplete"
|
||||
[class]="`${inputClass} w-full ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
|
||||
[required]="isRequired"
|
||||
[invalid]="control.invalid && (control.touched || control.dirty)"
|
||||
(input)="onInput($event)"
|
||||
(onBlur)="blur.emit()"
|
||||
/>
|
||||
<p-inputgroup>
|
||||
<!-- [minlength]="minlength || null" -->
|
||||
@if (type === "price") {
|
||||
<p-inputnumber
|
||||
[attr.id]="name"
|
||||
[formControl]="control"
|
||||
[maxlength]="preparedMaxLength || null"
|
||||
[attr.name]="name"
|
||||
[attr.placeholder]="preparedPlaceholder"
|
||||
[attr.type]="htmlType"
|
||||
[attr.autocomplete]="autocomplete"
|
||||
[class]="` w-full ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
|
||||
[required]="isRequired"
|
||||
[invalid]="control.invalid && (control.touched || control.dirty)"
|
||||
(onBlur)="blur.emit()"
|
||||
/>
|
||||
<!-- (input)="onInput($event)" -->
|
||||
} @else {
|
||||
<input
|
||||
pInputText
|
||||
[attr.id]="name"
|
||||
[formControl]="control"
|
||||
[attr.name]="name"
|
||||
[attr.placeholder]="preparedPlaceholder"
|
||||
[attr.inputmode]="inputMode"
|
||||
[attr.maxlength]="preparedMaxLength || null"
|
||||
[attr.type]="htmlType"
|
||||
[attr.autocomplete]="autocomplete"
|
||||
[class]="
|
||||
`${inputClass} w-full ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`
|
||||
"
|
||||
[required]="isRequired"
|
||||
[invalid]="control.invalid && (control.touched || control.dirty)"
|
||||
(onBlur)="blur.emit()"
|
||||
(input)="onInput($event)"
|
||||
/>
|
||||
}
|
||||
@if (preparedSuffix()) {
|
||||
<p-inputgroup-addon>{{ preparedSuffix() }}</p-inputgroup-addon>
|
||||
}
|
||||
</p-inputgroup>
|
||||
}
|
||||
@if (hint) {
|
||||
<small [attr.id]="name + '-help'">{{ hint }}</small>
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { UikitFieldComponent } from '@/uikit/uikit-field.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Component, computed, EventEmitter, inject, Input, Output } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { InputGroupModule } from 'primeng/inputgroup';
|
||||
import { InputGroupAddon } from 'primeng/inputgroupaddon';
|
||||
import { InputMaskModule } from 'primeng/inputmask';
|
||||
import { InputNumberModule } from 'primeng/inputnumber';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { KeyFilterModule } from 'primeng/keyfilter';
|
||||
import { ToggleSwitch } from 'primeng/toggleswitch';
|
||||
|
||||
@Component({
|
||||
@@ -21,6 +24,8 @@ import { ToggleSwitch } from 'primeng/toggleswitch';
|
||||
ToggleSwitch,
|
||||
InputGroupAddon,
|
||||
InputNumberModule,
|
||||
KeyFilterModule,
|
||||
InputMaskModule,
|
||||
],
|
||||
templateUrl: './input.component.html',
|
||||
})
|
||||
@@ -33,27 +38,43 @@ export class InputComponent {
|
||||
| 'email'
|
||||
| 'checkbox'
|
||||
| 'switch'
|
||||
| 'number'
|
||||
| 'price' = 'simple';
|
||||
@Input() control!: FormControl<Maybe<any>>;
|
||||
@Input() name!: string;
|
||||
@Input() label: string = '';
|
||||
@Input() customPlaceholder?: string;
|
||||
@Input() placeholder?: string;
|
||||
@Input() required = false;
|
||||
@Input() disabled = false;
|
||||
@Input() size?: 'small' | 'large';
|
||||
@Input() autocomplete?: string = 'off';
|
||||
@Input() showErrors = false;
|
||||
@Input() showErrors = true;
|
||||
@Input() hint?: string;
|
||||
@Input() isLtrInput = false;
|
||||
@Input() suffix: string = '';
|
||||
@Input() maxLength?: number;
|
||||
@Input() min?: number;
|
||||
@Input() max?: number;
|
||||
@Output() valueChange = new EventEmitter<string | number>();
|
||||
@Output() blur = new EventEmitter<void>();
|
||||
|
||||
onInput(ev: Event) {
|
||||
const v = (ev.target as HTMLInputElement).value;
|
||||
this.valueChange.emit(this.type === 'price' ? parseFloat(v) : v);
|
||||
}
|
||||
private readonly toastService = inject(ToastService);
|
||||
|
||||
get placeholder(): string | null {
|
||||
if (this.customPlaceholder) return this.customPlaceholder;
|
||||
// onInput(ev: Event) {
|
||||
// const v = (ev.target as HTMLInputElement).value;
|
||||
|
||||
// const newLocal = v || v == '0';
|
||||
// // this.valueChange.emit(this.type === 'price' && newLocal ? parseFloat(v) : v);
|
||||
// }
|
||||
|
||||
preparedSuffix = computed(() => {
|
||||
if (this.type === 'price') {
|
||||
return 'ریال';
|
||||
} else return this.suffix;
|
||||
});
|
||||
|
||||
get preparedPlaceholder(): string | null {
|
||||
if (this.placeholder) return this.placeholder;
|
||||
switch (this.type) {
|
||||
case 'mobile':
|
||||
return '09xxxxxxxx';
|
||||
@@ -76,13 +97,18 @@ export class InputComponent {
|
||||
case 'phone':
|
||||
case 'postalCode':
|
||||
case 'price':
|
||||
case 'number':
|
||||
return 'numeric';
|
||||
default:
|
||||
return 'text';
|
||||
}
|
||||
}
|
||||
|
||||
get maxLength(): number | null {
|
||||
get isNumeric(): boolean {
|
||||
return this.inputMode === 'numeric';
|
||||
}
|
||||
|
||||
get preparedMaxLength(): number | null {
|
||||
switch (this.type) {
|
||||
case 'mobile':
|
||||
return 11;
|
||||
@@ -91,28 +117,45 @@ export class InputComponent {
|
||||
case 'phone':
|
||||
return 11;
|
||||
default:
|
||||
return null;
|
||||
return this.maxLength || null;
|
||||
}
|
||||
}
|
||||
|
||||
get inputClass(): string {
|
||||
let inputClass = [];
|
||||
switch (this.type) {
|
||||
case 'mobile':
|
||||
case 'phone':
|
||||
case 'price':
|
||||
return 'ltrInput';
|
||||
case 'number':
|
||||
inputClass.push('ltrInput');
|
||||
break;
|
||||
case 'email':
|
||||
case 'postalCode':
|
||||
return 'ltrInput rtlPlaceholder';
|
||||
default:
|
||||
return '';
|
||||
inputClass.push('ltrInput', 'rtlPlaceholder');
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.isLtrInput) {
|
||||
inputClass.push('ltrInput', 'rtlPlaceholder');
|
||||
}
|
||||
return inputClass.join(' ');
|
||||
}
|
||||
|
||||
get htmlType(): string {
|
||||
switch (this.type) {
|
||||
case 'email':
|
||||
return 'email';
|
||||
case 'mobile':
|
||||
case 'phone':
|
||||
case 'price':
|
||||
case 'postalCode':
|
||||
case 'number':
|
||||
return 'number';
|
||||
case 'checkbox':
|
||||
return 'checkbox';
|
||||
case 'switch':
|
||||
return 'radio';
|
||||
default:
|
||||
return 'text';
|
||||
}
|
||||
@@ -121,4 +164,40 @@ export class InputComponent {
|
||||
get isRequired(): boolean {
|
||||
return this.required || this.control.hasValidator(Validators.required);
|
||||
}
|
||||
|
||||
onInput($event: Event) {
|
||||
// @ts-ignore
|
||||
const value = $event.target.value as string;
|
||||
if (this.type === 'number') {
|
||||
let newValue = parseFloat(value);
|
||||
|
||||
const minValidator = (this.min || this.min === 0) && parseFloat(value) < this.min!;
|
||||
const maxValidator = (this.max || this.max === 0) && parseFloat(value) > this.max;
|
||||
|
||||
if (minValidator || maxValidator) {
|
||||
if (minValidator) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار فیلد باید بیشتر از ${this.min} باشد.`,
|
||||
});
|
||||
}
|
||||
if (maxValidator) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار فیلد باید کمتر از ${this.max} باشد.`,
|
||||
});
|
||||
}
|
||||
|
||||
newValue = parseFloat(value.slice(0, value.length - 1));
|
||||
// @ts-ignore
|
||||
$event.target.value = newValue;
|
||||
}
|
||||
this.control.setValue(newValue);
|
||||
}
|
||||
|
||||
if (this.preparedMaxLength && this.preparedMaxLength < value.length) {
|
||||
let newValue = value.slice(0, value.length - 1);
|
||||
// @ts-ignore
|
||||
$event.target.value = newValue;
|
||||
this.control.setValue(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
|
||||
<ng-template #emptymessage>
|
||||
<tr class="">
|
||||
<td [colSpan]="columns.length.toString()" class="w-full">
|
||||
<td [colSpan]="(columns.length + 1).toString()" class="w-full">
|
||||
<uikit-empty-state
|
||||
[title]="emptyPlaceholderTitle"
|
||||
[description]="emptyPlaceholderDescription"
|
||||
@@ -105,11 +105,6 @@
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
<!-- <ng-template #emptymessage>
|
||||
<tr>
|
||||
<td colspan="6">There are no order for this product yet.</td>
|
||||
</tr>
|
||||
</ng-template> -->
|
||||
|
||||
<ng-template #loadingbody let-columns>
|
||||
@for (i of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; track i) {
|
||||
|
||||
@@ -150,10 +150,7 @@ export class PageDataListComponent<I> {
|
||||
if (!path) return '-';
|
||||
const nestedData = path
|
||||
.split('.')
|
||||
.reduce(
|
||||
(obj, key) => (obj && obj[key] !== undefined ? obj[key] : null),
|
||||
item[String(field)],
|
||||
);
|
||||
.reduce((obj, key) => (obj && obj[key] !== undefined ? obj[key] : null), item);
|
||||
|
||||
return nestedData || '-';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user