/** * Copyright since 2025 Mifos Initiative * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { Component, OnInit, inject } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { catchError, of } from 'rxjs'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { OrganizationService } from '../organization.service'; const BRANCH_TYPES = [ { value: 'HEAD_OFFICE', label: 'Head Office' }, { value: 'BRANCH', label: 'Branch' }, { value: 'REGIONAL_OFFICE', label: 'Regional Office' }, { value: 'ZONAL_OFFICE', label: 'Zonal Office' } ]; /** * The real-world operational fields behind a branch — code, address, contact, type and working * hours — kept as their own screen on top of the stock Manage Offices flow, since m_office (the * core Fineract entity) was deliberately left untouched. Pick an office, fill in what real-world * UCB branch setup expects, save. */ @Component({ selector: 'mifosx-branch-profile', templateUrl: './branch-profile.component.html', styleUrls: ['./branch-profile.component.scss'], imports: [...STANDALONE_SHARED_IMPORTS] }) export class BranchProfileComponent implements OnInit { private formBuilder = inject(UntypedFormBuilder); private organizationService = inject(OrganizationService); branchTypes = BRANCH_TYPES; offices: any[] = []; selectedOfficeId: number | null = null; form: UntypedFormGroup; loadingOffices = true; loadingProfile = false; saving = false; errorMsg = ''; successMsg = ''; lastUpdated: any = null; ngOnInit(): void { this.form = this.formBuilder.group({ branchCode: [''], branchType: [null], address: [''], pincode: [''], contactPhone: [''], contactEmail: [''], workingHoursStart: [''], workingHoursEnd: [''], workingDays: [''], ifscCode: [''], micrCode: [''], latitude: [null], longitude: [null] }); this.organizationService .getBranchProfiles() .pipe( catchError((err: any) => { this.errorMsg = err?.error?.errors?.[0]?.defaultUserMessage ?? 'Could not load branches.'; return of([]); }) ) .subscribe((res: any[]) => { this.loadingOffices = false; this.offices = res || []; if (this.offices.length === 1) { this.selectOffice(this.offices[0].officeId); } }); } selectOffice(officeId: number): void { this.selectedOfficeId = officeId; this.loadingProfile = true; this.errorMsg = ''; this.successMsg = ''; this.organizationService .getBranchProfile(officeId) .pipe( catchError((err: any) => { this.loadingProfile = false; this.errorMsg = err?.error?.errors?.[0]?.defaultUserMessage ?? 'Could not load this branch.'; return of(null); }) ) .subscribe((res: any) => { this.loadingProfile = false; if (!res) return; this.form.patchValue({ branchCode: res.branchCode ?? '', branchType: res.branchType ?? null, address: res.address ?? '', pincode: res.pincode ?? '', contactPhone: res.contactPhone ?? '', contactEmail: res.contactEmail ?? '', workingHoursStart: res.workingHoursStart ?? '', workingHoursEnd: res.workingHoursEnd ?? '', workingDays: res.workingDays ?? '', ifscCode: res.ifscCode ?? '', micrCode: res.micrCode ?? '', latitude: res.latitude ?? null, longitude: res.longitude ?? null }); this.lastUpdated = res.updatedByUsername ? { by: res.updatedByUsername, at: res.updatedAt } : null; this.form.markAsPristine(); // Reflect the just-loaded office in the list so the selector stays accurate without a reload. const idx = this.offices.findIndex((o) => o.officeId === officeId); if (idx >= 0) this.offices[idx] = res; }); } officeLabel(o: any): string { return o.branchCode ? `${o.officeName} (${o.branchCode})` : o.officeName; } submit(): void { if (this.saving || !this.selectedOfficeId) return; this.saving = true; this.errorMsg = ''; this.successMsg = ''; this.organizationService .updateBranchProfile(this.selectedOfficeId, this.form.value) .pipe( catchError((err: any) => { this.saving = false; this.errorMsg = err?.error?.errors?.[0]?.defaultUserMessage ?? 'Could not save this branch.'; return of(null); }) ) .subscribe((res: any) => { this.saving = false; if (!res) return; if (res.rollbackTransaction) { // Parked for checker approval - the branch profile has not actually changed yet. this.successMsg = 'Branch profile update has been submitted for approval.'; this.form.markAsPristine(); return; } this.successMsg = 'Branch profile saved.'; this.form.markAsPristine(); // The response is now a CommandProcessingResult, not the updated row (the write goes through // the command pipeline) - reload the saved row from the server instead of patching state from // this response. this.organizationService.getBranchProfile(this.selectedOfficeId!).subscribe((updated: any) => { if (!updated) return; this.lastUpdated = updated.updatedByUsername ? { by: updated.updatedByUsername, at: updated.updatedAt } : null; const idx = this.offices.findIndex((o) => o.officeId === this.selectedOfficeId); if (idx >= 0) this.offices[idx] = updated; }); }); } }