@if (getFlagUrl(row.iso2); as flagUrl) {
diff --git a/src/app/features/global-masters/countries/pages/country-list/country-list.ts b/src/app/features/global-masters/countries/pages/country-list/country-list.ts
index a13bbe6b..faf66fb9 100644
--- a/src/app/features/global-masters/countries/pages/country-list/country-list.ts
+++ b/src/app/features/global-masters/countries/pages/country-list/country-list.ts
@@ -1,11 +1,13 @@
import { Component, DestroyRef, OnInit, inject, signal, viewChild } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
-import { finalize } from 'rxjs/operators';
+import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
+import { finalize, map } from 'rxjs/operators';
import { NotificationService } from '../../../../../core/services/common/notification.service';
import { CountryDto, UpdateCountryRequest } from '../../models/country.model';
import { CountryService } from '../../data-access/country.service';
-import { DataTable } from '../../../../../shared/components/data-table/data-table';
+import { RegionLookupDto, RegionService } from '../../../regions/public-api';
+import { DataTable, DataTableToolbarDirective } from '../../../../../shared/components/data-table/data-table';
import { DataTableStore } from '../../../../../shared/components/data-table/data-table.store';
import {
DataTableAction,
@@ -14,7 +16,15 @@ import {
DataTableRecord
} from '../../../../../shared/components/data-table/data-table.types';
import { DataTableCellDirective } from '../../../../../shared/directives/data-table-cell.directive';
+import { Autocomplete } from '../../../../../shared/components/form/autocomplete/autocomplete';
+import {
+ AutocompleteDisplayFn,
+ AutocompleteResolveValueFn,
+ AutocompleteSearchFn,
+ AutocompleteValueFn
+} from '../../../../../shared/components/form/autocomplete/autocomplete.types';
import { ConfirmDialog } from '../../../../../shared/components/confirm-dialog/confirm-dialog';
+import { Button as AppButton } from '../../../../../shared/components/button/button';
import { CountryFormModalComponent } from '../../components/country-form-modal/country-form-modal';
interface CountryTableRow extends DataTableRecord {
@@ -24,6 +34,9 @@ interface CountryTableRow extends DataTableRecord {
name: string;
phoneCode: string | null;
defaultCurrencyId: string | null;
+ regionId: string | null;
+ regionCode?: string | null;
+ regionName?: string | null;
isActive: boolean;
serialNumber: number;
createdOn?: string;
@@ -33,7 +46,16 @@ interface CountryTableRow extends DataTableRecord {
@Component({
selector: 'country-list',
standalone: true,
- imports: [DataTable, DataTableCellDirective, ConfirmDialog, CountryFormModalComponent],
+ imports: [
+ DataTable,
+ DataTableToolbarDirective,
+ DataTableCellDirective,
+ ReactiveFormsModule,
+ Autocomplete,
+ ConfirmDialog,
+ AppButton,
+ CountryFormModalComponent
+ ],
providers: [DataTableStore],
templateUrl: './country-list.html',
styleUrl: './country-list.scss',
@@ -41,6 +63,8 @@ interface CountryTableRow extends DataTableRecord {
export class CountryList implements OnInit {
private readonly destroyRef = inject(DestroyRef);
private readonly countryApi = inject(CountryService);
+ private readonly regionApi = inject(RegionService);
+ private readonly formBuilder = inject(FormBuilder);
private readonly notification = inject(NotificationService);
readonly tableStore = inject(DataTableStore
);
@@ -49,6 +73,22 @@ export class CountryList implements OnInit {
readonly pendingDeleteCountry = signal(null);
readonly deleteConfirmDialog = viewChild(ConfirmDialog);
+ readonly showFilters = signal(false);
+ readonly selectedRegionLookup = signal(null);
+
+ readonly regionFilterForm = this.formBuilder.nonNullable.group({
+ regionId: ['']
+ });
+
+ readonly searchRegions: AutocompleteSearchFn = (term, limit) =>
+ this.regionApi.autocomplete(term, limit);
+ readonly displayRegion: AutocompleteDisplayFn = region => region.name;
+ readonly regionValue: AutocompleteValueFn = region => region.id;
+ readonly resolveRegion: AutocompleteResolveValueFn = value =>
+ this.regionApi.getRegionById(value).pipe(
+ map(region => ({ id: region.id, code: region.code, name: region.name }))
+ );
+
readonly columns = signal[]>([
{ key: 'serialNumber', label: 'Sr. No.', header: 'Sr.No.', sortable: false, width: '90px' },
{ key: 'name', label: 'Name', header: 'Name', sortable: true, headerAlign: 'center', align: 'left' },
@@ -59,7 +99,12 @@ export class CountryList implements OnInit {
badgeClass: value => value ? 'badge bg-primary/10 text-primary' : 'badge bg-secondary/10 text-secondary'
},
{
- key: 'phoneCode', label: 'Phone Code', header: 'Phone Code', sortable: true, headerAlign: 'center', align: 'center',
+ key: 'phoneCode', label: 'Phone Code', header: 'Phone Code', sortable: true, headerAlign: 'center', align: 'center', badge: true,
+ badgeClass: value => value ? 'badge bg-primary/10 text-primary' : '',
+ formatter: value => (typeof value === 'string' && value.trim().length > 0) ? value : '—'
+ },
+ {
+ key: 'regionName', label: 'Region', header: 'Region', sortable: false, headerAlign: 'center', align: 'center',
formatter: value => (typeof value === 'string' && value.trim().length > 0) ? value : '—'
},
{
@@ -87,10 +132,32 @@ export class CountryList implements OnInit {
ngOnInit(): void {
this.tableStore.initialize({
- fetcher: query => this.countryApi.getCountryDataTable(query)
+ fetcher: query => {
+ const regionId = this.regionFilterForm.controls.regionId.value || null;
+ return this.countryApi.getCountryDataTable(query, regionId);
+ }
});
}
+ onFilterRegionSelected(region: RegionLookupDto | null): void {
+ this.selectedRegionLookup.set(region);
+ this.regionFilterForm.controls.regionId.setValue(region ? region.id : '');
+ }
+
+ onApplyFilter(): void {
+ this.tableStore.refresh();
+ }
+
+ onResetFilter(): void {
+ this.regionFilterForm.reset({ regionId: '' });
+ this.selectedRegionLookup.set(null);
+ this.tableStore.reset();
+ }
+
+ onToggleFilters(): void {
+ this.showFilters.update(value => !value);
+ }
+
onAddCountry(): void {
this.tableStore.openCreateModal();
}
diff --git a/src/app/features/global-masters/exchange-rates/components/exchange-rate-form-modal/exchange-rate-form-modal.html b/src/app/features/global-masters/exchange-rates/components/exchange-rate-form-modal/exchange-rate-form-modal.html
index 43351583..04e7f064 100644
--- a/src/app/features/global-masters/exchange-rates/components/exchange-rate-form-modal/exchange-rate-form-modal.html
+++ b/src/app/features/global-masters/exchange-rates/components/exchange-rate-form-modal/exchange-rate-form-modal.html
@@ -1,7 +1,7 @@
import('./plans/pages/plan-list/plan-list').then((m) => m.PlanList),
data: { childTitle: 'Plan Management', parentTitle: 'Global Master', subParentTitle: 'Configuration' },
+ },
+ {
+ path: 'regions',
+ canActivate: [superAdminGuard],
+ loadComponent: () => import('./regions/pages/region-list/region-list').then((m) => m.RegionList),
+ data: { childTitle: 'Region Management', parentTitle: 'Global Master', subParentTitle: 'Configuration' },
}
];
diff --git a/src/app/features/global-masters/regions/components/region-form-modal/region-form-modal.html b/src/app/features/global-masters/regions/components/region-form-modal/region-form-modal.html
new file mode 100644
index 00000000..b64950fd
--- /dev/null
+++ b/src/app/features/global-masters/regions/components/region-form-modal/region-form-modal.html
@@ -0,0 +1,53 @@
+
+ @if (modalLoading()) {
+
+
+ Loading region...
+
+ } @else {
+
+ }
+
diff --git a/src/app/features/global-masters/regions/components/region-form-modal/region-form-modal.ts b/src/app/features/global-masters/regions/components/region-form-modal/region-form-modal.ts
new file mode 100644
index 00000000..3c9216de
--- /dev/null
+++ b/src/app/features/global-masters/regions/components/region-form-modal/region-form-modal.ts
@@ -0,0 +1,166 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ DestroyRef,
+ computed,
+ effect,
+ inject,
+ input,
+ output,
+ signal
+} from '@angular/core';
+import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { HttpErrorResponse } from '@angular/common/http';
+import { finalize } from 'rxjs/operators';
+import { NotificationService } from '../../../../../core/services/common/notification.service';
+
+import {
+ CreateRegionRequest,
+ RegionDto,
+ RegionModalMode,
+ UpdateRegionRequest
+} from '../../models/region.model';
+import { RegionService } from '../../data-access/region.service';
+import { FormInput } from '../../../../../shared/components/form/form-input/form-input';
+import { Modal } from '../../../../../shared/components/modal/modal';
+
+@Component({
+ selector: 'app-region-form-modal',
+ standalone: true,
+ imports: [Modal, ReactiveFormsModule, FormInput],
+ templateUrl: './region-form-modal.html',
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class RegionFormModalComponent {
+ private readonly destroyRef = inject(DestroyRef);
+ private readonly formBuilder = inject(FormBuilder);
+ private readonly regionApi = inject(RegionService);
+ private readonly notification = inject(NotificationService);
+
+ readonly open = input(false);
+ readonly mode = input('create');
+ readonly regionId = input(null);
+
+ readonly saved = output();
+ readonly closed = output();
+
+ readonly modalLoading = signal(false);
+ readonly saving = signal(false);
+ readonly regionSubmitAttempted = signal(false);
+ readonly selectedRegion = signal(null);
+
+ readonly regionForm = this.formBuilder.nonNullable.group({
+ name: ['', [Validators.required, Validators.maxLength(150)]],
+ code: ['', [Validators.required, Validators.maxLength(10)]]
+ });
+
+ readonly isViewMode = computed(() => this.mode() === 'view');
+ readonly modalTitle = computed(() => {
+ switch (this.mode()) {
+ case 'create': return 'Add Region';
+ case 'edit': return 'Edit Region';
+ case 'view': return 'View Region';
+ }
+ });
+
+ constructor() {
+ effect(() => {
+ if (this.open()) {
+ this.prepareModal(this.regionId());
+ }
+ });
+ }
+
+ prepareModal(id: string | null): void {
+ this.regionSubmitAttempted.set(false);
+ this.regionForm.reset({ name: '', code: '' });
+
+ if (!id || this.mode() === 'create') {
+ this.selectedRegion.set(null);
+ this.modalLoading.set(false);
+ return;
+ }
+
+ this.modalLoading.set(true);
+ this.regionApi.getRegionById(id).pipe(
+ finalize(() => this.modalLoading.set(false)),
+ takeUntilDestroyed(this.destroyRef)
+ ).subscribe({
+ next: region => {
+ this.selectedRegion.set(region);
+ this.regionForm.patchValue({
+ name: region.name,
+ code: region.code
+ });
+ },
+ error: () => {
+ this.notification.error('Unable to load region details.');
+ this.closeModal();
+ }
+ });
+ }
+
+ saveRegion(): void {
+ if (this.isViewMode()) {
+ this.closeModal();
+ return;
+ }
+
+ this.regionSubmitAttempted.set(true);
+ if (this.regionForm.invalid || this.saving()) return;
+
+ this.saving.set(true);
+ if (this.mode() === 'create') {
+ const request: CreateRegionRequest = {
+ name: this.regionForm.controls.name.value.trim(),
+ code: this.regionForm.controls.code.value.trim().toUpperCase()
+ };
+
+ this.regionApi.createRegion(request).pipe(
+ finalize(() => this.saving.set(false)),
+ takeUntilDestroyed(this.destroyRef)
+ ).subscribe({
+ next: () => {
+ this.notification.success('Region created successfully.');
+ this.saved.emit();
+ this.closed.emit();
+ },
+ error: err => this.handleSaveError(err, 'create')
+ });
+ } else {
+ const id = this.regionId();
+ if (!id) return;
+
+ const request: UpdateRegionRequest = {
+ name: this.regionForm.controls.name.value.trim(),
+ code: this.regionForm.controls.code.value.trim().toUpperCase()
+ };
+
+ this.regionApi.updateRegion(id, request).pipe(
+ finalize(() => this.saving.set(false)),
+ takeUntilDestroyed(this.destroyRef)
+ ).subscribe({
+ next: () => {
+ this.notification.success('Region updated successfully.');
+ this.saved.emit();
+ this.closed.emit();
+ },
+ error: err => this.handleSaveError(err, 'update')
+ });
+ }
+ }
+
+ closeModal(): void {
+ if (this.saving()) return;
+ this.closed.emit();
+ }
+
+ private handleSaveError(error: HttpErrorResponse, action: 'create' | 'update'): void {
+ if (error.status === 409) {
+ this.notification.error('A region with this code or name already exists.');
+ return;
+ }
+ this.notification.error(`Unable to ${action} region. Please try again.`);
+ }
+}
diff --git a/src/app/features/global-masters/regions/data-access/region.endpoints.ts b/src/app/features/global-masters/regions/data-access/region.endpoints.ts
new file mode 100644
index 00000000..6b0d5efb
--- /dev/null
+++ b/src/app/features/global-masters/regions/data-access/region.endpoints.ts
@@ -0,0 +1,21 @@
+import { buildApiUrl } from '../../../../core/config/api-url.util';
+
+export const REGION_ENDPOINTS = {
+ dataTable: buildApiUrl('masterAdmin', '/v1/regions/datatable'),
+
+ create: buildApiUrl('masterAdmin', '/v1/regions'),
+
+ getById: (id: string) =>
+ buildApiUrl('masterAdmin', `/v1/regions/${encodeURIComponent(id)}`),
+
+ autocomplete: buildApiUrl('masterAdmin', '/v1/regions/autocomplete'),
+
+ update: (id: string) =>
+ buildApiUrl('masterAdmin', `/v1/regions/${encodeURIComponent(id)}`),
+
+ delete: (id: string) =>
+ buildApiUrl('masterAdmin', `/v1/regions/${encodeURIComponent(id)}`),
+
+ changeStatus: (id: string) =>
+ buildApiUrl('masterAdmin', `/v1/regions/${encodeURIComponent(id)}/status`),
+} as const;
diff --git a/src/app/features/global-masters/regions/data-access/region.service.ts b/src/app/features/global-masters/regions/data-access/region.service.ts
new file mode 100644
index 00000000..17a64f73
--- /dev/null
+++ b/src/app/features/global-masters/regions/data-access/region.service.ts
@@ -0,0 +1,53 @@
+import { HttpClient, HttpParams } from '@angular/common/http';
+import { Injectable, inject } from '@angular/core';
+import { Observable } from 'rxjs';
+
+import {
+ DataTableQuery,
+ DataTableResult,
+} from '../../../../shared/components/data-table/data-table.types';
+import {
+ CreateRegionRequest,
+ RegionDto,
+ RegionLookupDto,
+ UpdateRegionRequest,
+ UpdateRegionStatusRequest,
+} from '../models/region.model';
+import { REGION_ENDPOINTS } from './region.endpoints';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class RegionService {
+ private readonly http = inject(HttpClient);
+
+ getRegionDataTable(query: DataTableQuery): Observable> {
+ return this.http.post>(REGION_ENDPOINTS.dataTable, query);
+ }
+
+ createRegion(request: CreateRegionRequest): Observable {
+ return this.http.post(REGION_ENDPOINTS.create, request);
+ }
+
+ updateRegion(id: string, request: UpdateRegionRequest): Observable {
+ return this.http.put(REGION_ENDPOINTS.update(id), request);
+ }
+
+ updateStatus(id: string, request: UpdateRegionStatusRequest): Observable {
+ return this.http.patch(REGION_ENDPOINTS.changeStatus(id), request);
+ }
+
+ delete(id: string): Observable {
+ return this.http.delete(REGION_ENDPOINTS.delete(id));
+ }
+
+ getRegionById(id: string): Observable {
+ return this.http.get(REGION_ENDPOINTS.getById(id));
+ }
+
+ autocomplete(term = '', limit = 50): Observable {
+ return this.http.get(REGION_ENDPOINTS.autocomplete, {
+ params: new HttpParams().set('term', term).set('limit', limit),
+ });
+ }
+}
diff --git a/src/app/features/global-masters/regions/models/region.model.ts b/src/app/features/global-masters/regions/models/region.model.ts
new file mode 100644
index 00000000..31f1d5cb
--- /dev/null
+++ b/src/app/features/global-masters/regions/models/region.model.ts
@@ -0,0 +1,28 @@
+export interface RegionDto {
+ id: string;
+ code: string;
+ name: string;
+ countryCount?: number;
+ isActive: boolean;
+ createdOn?: string;
+ modifiedOn?: string | null;
+}
+
+export interface RegionLookupDto {
+ id: string;
+ code: string;
+ name: string;
+}
+
+export interface CreateRegionRequest {
+ code: string;
+ name: string;
+}
+
+export type UpdateRegionRequest = CreateRegionRequest;
+
+export interface UpdateRegionStatusRequest {
+ isActive: boolean;
+}
+
+export type RegionModalMode = 'create' | 'edit' | 'view';
diff --git a/src/app/features/global-masters/regions/pages/region-list/region-list.html b/src/app/features/global-masters/regions/pages/region-list/region-list.html
new file mode 100644
index 00000000..18e43887
--- /dev/null
+++ b/src/app/features/global-masters/regions/pages/region-list/region-list.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
diff --git a/src/app/features/global-masters/regions/pages/region-list/region-list.scss b/src/app/features/global-masters/regions/pages/region-list/region-list.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/features/global-masters/regions/pages/region-list/region-list.ts b/src/app/features/global-masters/regions/pages/region-list/region-list.ts
new file mode 100644
index 00000000..e78af58a
--- /dev/null
+++ b/src/app/features/global-masters/regions/pages/region-list/region-list.ts
@@ -0,0 +1,154 @@
+import { Component, DestroyRef, OnInit, inject, signal, viewChild } from '@angular/core';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { finalize } from 'rxjs/operators';
+import { NotificationService } from '../../../../../core/services/common/notification.service';
+
+import { RegionDto } from '../../models/region.model';
+import { RegionService } from '../../data-access/region.service';
+import { DataTable } from '../../../../../shared/components/data-table/data-table';
+import { DataTableStore } from '../../../../../shared/components/data-table/data-table.store';
+import {
+ DataTableAction,
+ DataTableActionEvent,
+ DataTableColumn,
+ DataTableRecord
+} from '../../../../../shared/components/data-table/data-table.types';
+import { ConfirmDialog } from '../../../../../shared/components/confirm-dialog/confirm-dialog';
+import { RegionFormModalComponent } from '../../components/region-form-modal/region-form-modal';
+
+interface RegionTableRow extends DataTableRecord {
+ id: string;
+ code: string;
+ name: string;
+ countryCount?: number;
+ isActive: boolean;
+ serialNumber: number;
+ createdOn?: string;
+ modifiedOn?: string | null;
+}
+
+@Component({
+ selector: 'region-list',
+ standalone: true,
+ imports: [DataTable, ConfirmDialog, RegionFormModalComponent],
+ providers: [DataTableStore],
+ templateUrl: './region-list.html',
+ styleUrl: './region-list.scss',
+})
+export class RegionList implements OnInit {
+ private readonly destroyRef = inject(DestroyRef);
+ private readonly regionApi = inject(RegionService);
+ private readonly notification = inject(NotificationService);
+ readonly tableStore = inject(DataTableStore);
+
+ readonly statusChangingId = signal(null);
+ readonly deletingId = signal(null);
+ readonly pendingDeleteRegion = signal(null);
+ readonly deleteConfirmDialog = viewChild(ConfirmDialog);
+
+ readonly columns = signal[]>([
+ { key: 'serialNumber', label: 'Sr. No.', header: 'Sr.No.', sortable: false, width: '90px' },
+ { key: 'name', label: 'Name', header: 'Name', sortable: true, headerAlign: 'center', align: 'left' },
+ { key: 'code', label: 'Code', header: 'Code', sortable: true, headerAlign: 'center', align: 'center', width: '110px', badge: true,
+ badgeClass: value => value ? 'badge bg-primary/10 text-primary' : 'badge bg-secondary/10 text-secondary'
+ },
+ {
+ key: 'countryCount', label: 'Countries', header: 'Countries', sortable: false, headerAlign: 'center', align: 'center', width: '110px',
+ formatter: value => (typeof value === 'number' ? value : 0).toString()
+ },
+ {
+ key: 'isActive', label: 'Status', header: 'Status', sortable: true, badge: true,
+ badgeClass: value => value === true ? 'badge bg-success/10 text-success' : 'badge bg-danger/10 text-danger',
+ formatter: value => value ? 'Active' : 'Inactive'
+ }
+ ]);
+
+ readonly actions = signal[]>([
+ { type: 'edit', label: 'Edit', icon: 'ti ti-edit', className: 'text-primary' },
+ {
+ type: 'deactivate', label: 'Deactivate', icon: 'ti ti-toggle-right', className: 'text-warning',
+ visible: row => row.isActive, disabled: row => this.statusChangingId() === row.id || this.deletingId() === row.id
+ },
+ {
+ type: 'activate', label: 'Activate', icon: 'ti ti-toggle-left', className: 'text-success',
+ visible: row => !row.isActive, disabled: row => this.statusChangingId() === row.id || this.deletingId() === row.id
+ },
+ {
+ type: 'delete', label: 'Delete', icon: 'ti ti-trash', className: 'text-danger',
+ disabled: row => this.statusChangingId() === row.id || this.deletingId() === row.id
+ }
+ ]);
+
+ ngOnInit(): void {
+ this.tableStore.initialize({
+ fetcher: query => this.regionApi.getRegionDataTable(query)
+ });
+ }
+
+ onAddRegion(): void {
+ this.tableStore.openCreateModal();
+ }
+
+ onActionClick(event: DataTableActionEvent): void {
+ if (event.action.type === 'view') this.tableStore.openViewModal(event.row);
+ if (event.action.type === 'edit') this.tableStore.openEditModal(event.row);
+ if (event.action.type === 'delete') this.requestDeleteRegion(event.row);
+ if (event.action.type === 'activate') this.changeRegionStatus(event.row, true);
+ if (event.action.type === 'deactivate') this.changeRegionStatus(event.row, false);
+ }
+
+ onDeleteConfirmed(): void {
+ const region = this.pendingDeleteRegion();
+ if (!region) return;
+ this.pendingDeleteRegion.set(null);
+ this.deletingId.set(region.id);
+
+ this.regionApi.delete(region.id).pipe(
+ finalize(() => this.deletingId.set(null)),
+ takeUntilDestroyed(this.destroyRef)
+ ).subscribe({
+ next: () => {
+ this.notification.success('Region deleted successfully.');
+ this.tableStore.refresh();
+ },
+ error: (err) => {
+ let errorMsg = 'Unable to delete region.';
+ if (err?.status === 409) {
+ errorMsg = err?.error?.message || err?.error?.detail || 'Cannot delete region because countries are still assigned to it.';
+ } else if (err?.status === 404) {
+ errorMsg = err?.error?.message || 'Region not found or has already been deleted.';
+ } else if (err?.error?.message || err?.error?.title) {
+ errorMsg = err.error.message || err.error.title;
+ }
+ this.notification.error(errorMsg);
+ }
+ });
+ }
+
+ onDeleteCancelled(): void {
+ this.pendingDeleteRegion.set(null);
+ }
+
+ private requestDeleteRegion(region: RegionTableRow): void {
+ this.pendingDeleteRegion.set(region);
+ this.deleteConfirmDialog()?.open();
+ }
+
+ private changeRegionStatus(region: RegionTableRow, activate: boolean): void {
+ this.statusChangingId.set(region.id);
+
+ this.regionApi.updateStatus(region.id, { isActive: activate }).pipe(
+ finalize(() => this.statusChangingId.set(null)),
+ takeUntilDestroyed(this.destroyRef)
+ ).subscribe({
+ next: () => {
+ this.notification.success(`Region ${activate ? 'activated' : 'deactivated'} successfully.`);
+ this.tableStore.refresh();
+ },
+ error: (err) => {
+ const msg = err?.error?.message || err?.error?.title || `Unable to ${activate ? 'activate' : 'deactivate'} region.`;
+ this.notification.error(msg);
+ }
+ });
+ }
+}
diff --git a/src/app/features/global-masters/regions/public-api.ts b/src/app/features/global-masters/regions/public-api.ts
new file mode 100644
index 00000000..a670576d
--- /dev/null
+++ b/src/app/features/global-masters/regions/public-api.ts
@@ -0,0 +1,2 @@
+export { RegionService } from './data-access/region.service';
+export type { RegionLookupDto } from './models/region.model';