329 lines
12 KiB
TypeScript
329 lines
12 KiB
TypeScript
import { SearchDTO } from './../../../../models/masters/masters';
|
|
import { SubsidiaryDTO } from './../../../../models/account.model';
|
|
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
|
|
import { ConfirmationService, MessageService } from 'primeng/api';
|
|
import { TableModule } from 'primeng/table';
|
|
import { Dialog } from 'primeng/dialog';
|
|
import { Ripple } from 'primeng/ripple';
|
|
import { ButtonModule, Button } from 'primeng/button';
|
|
import { ToastModule } from 'primeng/toast';
|
|
import { ToolbarModule } from 'primeng/toolbar';
|
|
import { ConfirmDialog } from 'primeng/confirmdialog';
|
|
import { InputTextModule } from 'primeng/inputtext';
|
|
import { TextareaModule } from 'primeng/textarea';
|
|
import { CommonModule } from '@angular/common';
|
|
import { FileUpload } from 'primeng/fileupload';
|
|
import { SelectModule } from 'primeng/select';
|
|
import { Tag } from 'primeng/tag';
|
|
import { RadioButton } from 'primeng/radiobutton';
|
|
import { Rating } from 'primeng/rating';
|
|
import { Skeleton } from 'primeng/skeleton';
|
|
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
import { InputNumber } from 'primeng/inputnumber';
|
|
import { IconFieldModule } from 'primeng/iconfield';
|
|
import { InputIconModule } from 'primeng/inputicon';
|
|
import { Table } from 'primeng/table';
|
|
import { DropdownModule } from 'primeng/dropdown';
|
|
import { CompanyService } from '../../../../services/account/company/company.service';
|
|
import { FloatLabelModule } from "primeng/floatlabel";
|
|
import { ValidationService } from '../../../../services/utilities/validation.service';
|
|
import { TooltipModule } from 'primeng/tooltip';
|
|
import { AutoCompleteModule } from 'primeng/autocomplete';
|
|
import { MasterService } from '../../../../services/masters/master.service';
|
|
import { CityDTO } from '../../../../models/masters/masters';
|
|
import { debounceTime, Subject } from 'rxjs';
|
|
import { Request } from '../../../../models/request.model';
|
|
|
|
interface Column {
|
|
field: string;
|
|
header: string;
|
|
customExportHeader?: string;
|
|
}
|
|
|
|
interface ExportColumn {
|
|
title: string;
|
|
dataKey: string;
|
|
}
|
|
|
|
@Component({
|
|
selector: 'app-subsidiary',
|
|
templateUrl: './subsidiary.component.html',
|
|
standalone: true,
|
|
imports: [TableModule, Dialog, Ripple, SelectModule, ToastModule, ToolbarModule, ConfirmDialog, InputTextModule, TextareaModule, CommonModule, FileUpload, DropdownModule, Tag, RadioButton, Rating, InputTextModule, InputNumber, IconFieldModule, InputIconModule, Button, FloatLabelModule, FormsModule, ReactiveFormsModule, TooltipModule, Skeleton, AutoCompleteModule],
|
|
providers: [MessageService, ConfirmationService],
|
|
styleUrl: './subsidiary.component.css'
|
|
})
|
|
export class SubsidiaryComponent implements OnInit{
|
|
subsidiaryForm: FormGroup;
|
|
subsidiaryDialog: boolean = false;
|
|
subsidiaries!: SubsidiaryDTO[];
|
|
|
|
subsidiary!: SubsidiaryDTO;
|
|
|
|
selectedSubsidiaries!: SubsidiaryDTO[] | null;
|
|
|
|
submitted: boolean = false;
|
|
|
|
isLoading: boolean = true;
|
|
|
|
skeletonData: any[] = Array(10).fill({});
|
|
|
|
suggestions: CityDTO[] = [];
|
|
|
|
private searchSubject = new Subject<string>();
|
|
|
|
statuses!: any[];
|
|
|
|
@ViewChild('dt') dt!: Table;
|
|
|
|
cols!: Column[];
|
|
|
|
exportColumns!: ExportColumn[];
|
|
|
|
constructor(
|
|
private subsidiaryService: CompanyService,
|
|
private masterService: MasterService,
|
|
private messageService: MessageService,
|
|
private confirmationService: ConfirmationService,
|
|
private cd: ChangeDetectorRef,
|
|
private fb: FormBuilder,
|
|
) {
|
|
|
|
this.subsidiaryForm = this.fb.group({
|
|
id: [{ value: '', disabled: true }],
|
|
cityId: [{ value: null, disabled: true }],
|
|
code: [{ value: '', disabled: false }, [Validators.required, ValidationService.codeValidator()]],
|
|
name: [{ value: '', disabled: false }, [Validators.required, ValidationService.nameValidator()]],
|
|
officeNo: [{ value: '', disabled: false }],
|
|
street: [{ value: '', disabled: false }],
|
|
locality: [{ value: '', disabled: false }],
|
|
cityName: [{ value: '', disabled: false }],
|
|
stateName: [{ value: '', disabled: true }],
|
|
pinCode: [{ value: '', disabled: false }, [ValidationService.pincodeValidator()]],
|
|
emailId: [{ value: '', disabled: false }, [ValidationService.emailValidator()]],
|
|
contactNo: [{ value: '', disabled: false }, [ValidationService.mobileValidator()]],
|
|
contactPerson: [{ value: '', disabled: false }, [ValidationService.contactPersonValidator()]],
|
|
panNo: [{ value: '', disabled: false }, [ValidationService.panValidator()]],
|
|
cinNo: [{ value: '', disabled: false }, [ValidationService.cinValidator()]],
|
|
msmeNo: [{ value: '', disabled: false }, [ValidationService.msmeValidator()]],
|
|
stateId: [{ value: '', disabled: true }],
|
|
stateCode: [{ value: '', disabled: true }],
|
|
gstCode: [{ value: '', disabled: true }]
|
|
});
|
|
}
|
|
|
|
exportCSV() {
|
|
this.dt.exportCSV();
|
|
}
|
|
|
|
searchCities(event: any) {
|
|
const query = event.query;
|
|
this.searchSubject.next(query);
|
|
}
|
|
|
|
onSelectCity(event: any) {
|
|
const city = event.value as CityDTO;
|
|
this.subsidiaryForm.patchValue({
|
|
cityId: city.id,
|
|
stateId: city.stateId,
|
|
cityName: city.cityName,
|
|
stateName: city.stateName,
|
|
stateCode: city.stateCode,
|
|
gstCode: city.gstCode
|
|
});
|
|
}
|
|
|
|
ngOnInit() {
|
|
this.loadAllSubsidiaries();
|
|
}
|
|
|
|
loadAllSubsidiaries() {
|
|
this.isLoading = true;
|
|
this.subsidiaryService.getAllSubsidiaries().subscribe({
|
|
next: (data) => {
|
|
this.isLoading = false;
|
|
this.subsidiaries = data;
|
|
this.cd.markForCheck();
|
|
},
|
|
error: (err) => {
|
|
this.isLoading = false;
|
|
console.error(err);
|
|
}
|
|
});
|
|
|
|
this.statuses = [
|
|
{ label: 'Active', value: true },
|
|
{ label: 'Inactive', value: false }
|
|
];
|
|
|
|
this.cols = [
|
|
{ field: 'code', header: 'Code', customExportHeader: 'Code' },
|
|
{ field: 'name', header: 'Name' },
|
|
{ field: 'officeNo', header: 'Office No / Building / Floor' },
|
|
{ field: 'street', header: 'Street / Road' },
|
|
{ field: 'locality', header: 'Locality' },
|
|
{ field: 'cityName', header: 'City' },
|
|
{ field: 'emailId', header: 'Email' },
|
|
{ field: 'contactNo', header: 'Contact No' },
|
|
{ field: 'contactPerson', header: 'Contact Person' },
|
|
{ field: 'panNo', header: 'PAN No.' },
|
|
{ field: 'cinNo', header: 'CIN No.' },
|
|
{ field: 'msmeNo', header: 'MSME No.' },
|
|
{ field: 'updatedAt', header: 'Last Updated At' },
|
|
{ field: 'updatedUser', header: 'Last Updated By' }
|
|
];
|
|
|
|
this.exportColumns = this.cols.map((col) => ({ title: col.header, dataKey: col.field }));
|
|
|
|
this.searchSubject.pipe(debounceTime(300)).subscribe(query => {
|
|
if (query && query.length >= 2) {
|
|
const requestPayload: Request<SearchDTO> = {
|
|
data: {
|
|
searchBy: 'CITY',
|
|
searchValue: query
|
|
},
|
|
compressed: true,
|
|
target: 'models.commons.Search'
|
|
};
|
|
this.masterService.searchCityStates(requestPayload).subscribe({
|
|
next: (cities) => {
|
|
this.suggestions = cities.map(city => ({
|
|
...city,
|
|
display: `${city.cityName}, ${city.stateName}`
|
|
}));
|
|
this.cd.markForCheck();
|
|
},
|
|
error: (err) => {
|
|
console.error('Error searching cities', err);
|
|
this.suggestions = [];
|
|
}
|
|
});
|
|
} else {
|
|
this.suggestions = [];
|
|
}
|
|
});
|
|
}
|
|
|
|
openNew() {
|
|
this.subsidiary = {};
|
|
this.subsidiaryForm.reset();
|
|
this.submitted = false;
|
|
this.subsidiaryDialog = true;
|
|
}
|
|
|
|
editSubsidiary(subsidiary: SubsidiaryDTO) {
|
|
this.subsidiaryForm.reset();
|
|
this.subsidiary = { ...subsidiary };
|
|
this.subsidiaryForm.patchValue(subsidiary);
|
|
this.subsidiaryDialog = true;
|
|
console.log(this.subsidiaryForm.getRawValue());
|
|
}
|
|
|
|
|
|
hideDialog() {
|
|
this.subsidiaryDialog = false;
|
|
this.submitted = false;
|
|
}
|
|
|
|
toggleActive(subsidiary: SubsidiaryDTO) {
|
|
const isActivating = !subsidiary.active;
|
|
this.confirmationService.confirm({
|
|
message: `Are you sure you want to ${isActivating ? 'activate' : 'deactivate'} ` + subsidiary.name + '?',
|
|
header: 'Confirm',
|
|
icon: 'pi pi-exclamation-triangle',
|
|
rejectButtonProps: {
|
|
label: 'No',
|
|
severity: 'secondary',
|
|
variant: 'text'
|
|
},
|
|
acceptButtonProps: {
|
|
severity: isActivating ? 'success' : 'danger',
|
|
label: 'Yes'
|
|
},
|
|
accept: () => {
|
|
this.subsidiaryService.activateDeactivateSubsidiary(subsidiary.id?? '', isActivating).subscribe({
|
|
next: (updatedSubsidiary) => {
|
|
subsidiary.active = updatedSubsidiary.active;
|
|
this.subsidiaries = [...this.subsidiaries];
|
|
this.messageService.add({
|
|
severity: 'success',
|
|
summary: 'Successful',
|
|
detail: `Subsidiary ${isActivating ? 'Activated' : 'Deactivated'}`,
|
|
life: 3000
|
|
});
|
|
},
|
|
error: (err) => {
|
|
console.error('Error toggling subsidiary active status', err);
|
|
this.messageService.add({
|
|
severity: 'error',
|
|
summary: 'Error',
|
|
detail: 'Failed to update subsidiary status',
|
|
life: 3000
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
getSeverity(status: boolean) {
|
|
switch (status) {
|
|
case true:
|
|
return 'success';
|
|
case false:
|
|
return 'warn';
|
|
}
|
|
}
|
|
|
|
getErrorMessage(fieldName: string): string {
|
|
const control = this.subsidiaryForm.get(fieldName);
|
|
return control ? ValidationService.getErrorMessage(control, fieldName) : '';
|
|
}
|
|
|
|
isFieldInvalid(fieldName: string): boolean {
|
|
const control = this.subsidiaryForm.get(fieldName);
|
|
return !!(control && control.invalid && (control.dirty || control.touched || this.submitted));
|
|
}
|
|
|
|
saveSubsidiary() {
|
|
this.submitted = true;
|
|
|
|
if (this.subsidiaryForm.valid) {
|
|
const subsidiaryData = this.subsidiaryForm.getRawValue();
|
|
const existing = this.subsidiaries.find(sub => sub.id !== subsidiaryData.id && (sub.code === subsidiaryData.code || sub.name === subsidiaryData.name));
|
|
if (existing) {
|
|
this.messageService.add({
|
|
severity: 'error',
|
|
summary: 'Validation Error',
|
|
detail: 'Subsidiary code or name already exists',
|
|
life: 3000
|
|
});
|
|
return;
|
|
}
|
|
this.subsidiaryService.saveSubsidiary(subsidiaryData).subscribe({
|
|
next: (newSubsidiary) => {
|
|
this.subsidiaries.push(newSubsidiary);
|
|
this.subsidiaries = [...this.subsidiaries];
|
|
this.messageService.add({
|
|
severity: 'success',
|
|
summary: 'Successful',
|
|
detail: 'Subsidiary Created',
|
|
life: 3000
|
|
});
|
|
this.subsidiaryDialog = false;
|
|
this.subsidiary = {};
|
|
},
|
|
error: (err) => {
|
|
console.error('Error saving subsidiary', err);
|
|
this.messageService.add({
|
|
severity: 'error',
|
|
summary: 'Error',
|
|
detail: 'Failed to save subsidiary',
|
|
life: 3000
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|