npm package: @sapenlinea/shared-services
Description: Librería compartida con servicios comunes para proyectos Angular de Sconnect
Author: Sapenlinea Team
Latest version: 0.0.5

# 📚 Shared Services

Librería que centraliza los servicios y catálogos comunes entre los distintos microfrontends  
(**devices, administration, documents, etc.**) para evitar duplicación y mantener consistencia.

---

## 🚀 Funcionalidad

- Carga y cacheo de catálogos: **ciudades, países, departamentos, tipos de documento**.
- Exposición de datos en **arrays** y **mapas por id/nombre**.
- Generación de **opciones para selects** (`{ value, label }`).
- Observable `dataLoaded$` para reaccionar cuando la data esté disponible.
- Métodos de búsqueda por nombre (`getCityByName`, `getCountryByName`, etc.).

---

## 📖 Servicios incluidos

- `CityService` → Ciudades  
- `CountryService` → Países  
- `DepartamentService` → Departamentos  
- `DocumentsTypeService` → Tipos de documento  
- `SharedDataService` → Punto central para manejar todos los catálogos y exponer utilidades  

---

## 🛠️ Uso básico

### 1. Cargar datos compartidos

```ts
import { inject } from '@angular/core';
import { SharedDataService } from '@sconnectnpm/shared-services';

export class MiComponente {
  private sharedData = inject(SharedDataService);

  ngOnInit() {
    this.sharedData.loadSharedServicesData();

    this.sharedData.dataLoaded$.subscribe((loaded) => {
      if (loaded) {
        console.log(this.sharedData.getCitiesArray());
      }
    });
  }
}
```

### 2. Obtener opciones para selects

```ts
const cityOptions = this.sharedData.getOptions('city');
const deptOptions = this.sharedData.getOptions('department');
```

Resultado típico:

```ts
[
  { value: 1, label: 'Bogotá' },
  { value: 2, label: 'Medellín' }
]
```

### 3. Obtener opciones para varios campos a la vez

```ts
const fieldOptions = this.sharedData.getOptionsForFields({
  loc_city: 'city',
  infpl_department: 'department',
  own_doc_type: 'documentType',
  inf_license_country: 'country',
});
```

---

## 📋 Ejemplo en `formSectionsDevice`

Puedes definir tus `formSections` con `options` vacíos y luego llenarlos dinámicamente desde `SharedDataService`:

```ts
{
  key: 'department',
  label: 'Departamento',
  type: 'select',
  placeholder: 'Selecciona el departamento',
  required: false,
  col: 6,
  options: [] // se llenará con sharedData.getOptions('department')
},
{
  key: 'municipality',
  label: 'Municipio',
  type: 'select',
  placeholder: 'Selecciona el municipio',
  required: false,
  col: 6,
  options: [] // se llenará con sharedData.getOptions('city')
}
```

Y en tu componente:

```ts
this.sharedData.dataLoaded$.subscribe((loaded) => {
  if (loaded) {
    const fieldOptions = this.sharedData.getOptionsForFields({
      department: 'department',
      municipality: 'city'
    });

    this.updateFieldOptions('department', fieldOptions['department']);
    this.updateFieldOptions('municipality', fieldOptions['municipality']);
  }
});
```

---

## ✅ Beneficios

- **Centralización** → una sola fuente de verdad para catálogos.
- **Reutilización** → usado en todos los microfrontends sin duplicar código.
- **Flexibilidad** → obtener arrays, mapas o directamente opciones para formularios.
- **Sincronización** → eventos reactivos para actualizar la UI al cargar datos.

---

## 📚 API Completa

### Métodos principales

#### `loadSharedServicesData(): void`
Carga todos los catálogos compartidos (solo se ejecuta una vez).

#### `dataLoaded$: Observable<boolean>`
Observable que emite `true` cuando todos los datos están cargados.

#### `isDataLoaded(): boolean`
Retorna `true` si los datos ya fueron cargados.

### Obtener datos como arrays

```ts
getCitiesArray(): any[]
getCountriesArray(): any[]
getDepartmentsArray(): any[]
getDocumentTypesArray(): any[]
getAllAsArrays(): { countries, departments, cities, documentTypes }
```

### Búsqueda por nombre

```ts
getCityByName(name: string): any
getCountryByName(name: string): any
getDepartmentByName(name: string): any
getDocumentTypeByName(name: string): any
```

### Generación de opciones

```ts
getOptions(field: 'city' | 'country' | 'department' | 'documentType', placeholder?: string): Array<{value, label}>

getOptionsForFields(
  fieldMap: { [key: string]: 'city' | 'country' | 'department' | 'documentType' },
  placeholder?: string
): { [key: string]: any[] }
```

---

## 🎯 Casos de uso

### Cargar datos al iniciar la aplicación

```ts
// app.component.ts
export class AppComponent {
  private sharedData = inject(SharedDataService);

  ngOnInit() {
    this.sharedData.loadSharedServicesData();
  }
}
```

### Usar en formularios reactivos

```ts
export class FormComponent {
  private sharedData = inject(SharedDataService);
  cityOptions: any[] = [];
  countryOptions: any[] = [];

  ngOnInit() {
    this.sharedData.dataLoaded$
      .pipe(filter(loaded => loaded))
      .subscribe(() => {
        this.cityOptions = this.sharedData.getOptions('city');
        this.countryOptions = this.sharedData.getOptions('country');
      });
  }
}
```

### Buscar por nombre

```ts
const bogota = this.sharedData.getCityByName('Bogotá');
console.log(bogota); // { id: 1, name: 'Bogotá', ... }
```

---

## 🔧 Estructura interna

El servicio utiliza `Map` para almacenamiento eficiente:

```ts
private maps = {
  cities: new Map<number, any>(),           // búsqueda por ID
  citiesByName: new Map<string, any>(),     // búsqueda por nombre
  countries: new Map<number, any>(),
  countriesByName: new Map<string, any>(),
  departments: new Map<number, any>(),
  departmentsByName: new Map<string, any>(),
  documentTypes: new Map<number, any>(),
  documentTypesByName: new Map<string, any>(),
};
```

---

## 📝 Notas

- Los datos se cargan **una sola vez** por sesión.
- Si intentas cargar nuevamente con `loadSharedServicesData()`, se ignora la petición.
- Todos los servicios hijos (`CityService`, `CountryService`, etc.) deben implementar métodos `load()` y `getXxx()` que retornen observables.

---