npm package: @snovasys/smart-libraries
Description: Angular library for employee and team management with glassmorphism UI
Latest version: 1.0.1

# Smart Libraries - Angular Component Library

Angular library for employee and team management with glassmorphism dark theme UI.

## 📦 Installation

```bash
npm install @snovasys/smart-libraries@1.0.0
```

## 🚀 Quick Start

```typescript
import { OrganizationComponent } from '@snovasys/smart-libraries';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [OrganizationComponent],
  template: `
    <sl-organization
      [employees]="employees"
      [teams]="teams"
      [totalEmployees]="totalEmployees"
      [totalTeams]="totalTeams"
      [loading]="loading"
      [employeesForDropdown]="employeesForDropdown"
      [teamsForDropdown]="teamsForDropdown"
      [rolesForDropdown]="rolesForDropdown"
      [activeTab]="'employees'"
      [activeViewMode]="'table'"
      (tabChange)="onTabChange($event)"
      (viewModeChange)="onViewModeChange($event)"
      (employeeAction)="onEmployeeAction($event)"
      (teamAction)="onTeamAction($event)"
      (filterChange)="onFilterChange($event)">
    </sl-organization>
  `
})
export class AppComponent {
  employees: Employee[] = [];
  teams: Team[] = [];
  // ... component implementation
}
```

## 📚 Component Usage Options

### Option 1: OrganizationComponent (Recommended) ✅

Use `OrganizationComponent` when you need both Employees and Teams functionality with tab navigation.

**Benefits:**
- One component handles everything
- Built-in tab navigation
- Consistent UI/UX
- Less code in your app

**Example:**
```typescript
<sl-organization
  [employees]="employees"
  [teams]="teams"
  [totalEmployees]="totalEmployees"
  [totalTeams]="totalTeams"
  [loading]="loading"
  [employeesForDropdown]="employeesForDropdown"
  [teamsForDropdown]="teamsForDropdown"
  [rolesForDropdown]="rolesForDropdown"
  [activeTab]="activeTab"
  [activeViewMode]="activeViewMode"
  (tabChange)="onTabChange($event)"
  (viewModeChange)="onViewModeChange($event)"
  (dropdownSearchChange)="onDropdownSearchChange($event)"
  (employeeAction)="onEmployeeAction($event)"
  (teamAction)="onTeamAction($event)"
  (filterChange)="onFilterChange($event)">
</sl-organization>
```

### Option 2: Individual Components

Use individual components when you need only Employees or Teams functionality.

**Employees Only:**
```typescript
<sl-employees
  [employees]="employees"
  [totalEmployees]="totalEmployees"
  [loading]="loading"
  [employeesForDropdown]="employeesForDropdown"
  [teamsForDropdown]="teamsForDropdown"
  [rolesForDropdown]="rolesForDropdown"
  [activeViewMode]="activeViewMode"
  (employeeAction)="onEmployeeAction($event)"
  (filterChange)="onFilterChange($event)">
</sl-employees>
```

**Teams Only:**
```typescript
<sl-teams
  [teams]="teams"
  [totalTeams]="totalTeams"
  [loading]="loading"
  [employeesForDropdown]="employeesForDropdown"
  [teamsForDropdown]="teamsForDropdown"
  [rolesForDropdown]="rolesForDropdown"
  [activeViewMode]="activeViewMode"
  (dropdownSearchChange)="onDropdownSearchChange($event)"
  (teamAction)="onTeamAction($event)"
  (filterChange)="onFilterChange($event)">
</sl-teams>
```

## 🎯 Input/Output Pattern

The library components use the **Input/Output pattern** - they accept data through `@Input()` and emit events through `@Output()`. This makes them decoupled from specific service implementations.

**Pattern:**
- **Inputs**: Pass data to components (employees, teams, loading state, etc.)
- **Outputs**: Handle events from components (CRUD operations, filter changes, etc.)

You control all data fetching and business logic in your parent component.

## 📖 Components

### OrganizationComponent (`sl-organization`)
Combined view with tabs for employees and teams. Recommended for full-featured applications.

**Inputs:**
- `employees`, `teams`, `totalEmployees`, `totalTeams`, `loading`
- `employeesForDropdown`, `teamsForDropdown`, `rolesForDropdown`
- `activeTab`, `activeViewMode`

**Outputs:**
- `tabChange`, `viewModeChange`, `dropdownSearchChange`
- `employeeAction`, `teamAction`, `filterChange`

### EmployeesComponent (`sl-employees`)
Employee management with table and hierarchy views.

**Inputs:**
- `employees`, `totalEmployees`, `loading`
- `employeesForDropdown`, `teamsForDropdown`, `rolesForDropdown`
- `activeViewMode`

**Outputs:**
- `employeeAction`, `filterChange`, `dropdownSearchChange`

### TeamsComponent (`sl-teams`)
Team management with table and hierarchy views.

**Inputs:**
- `teams`, `totalTeams`, `loading`
- `employeesForDropdown`, `teamsForDropdown`, `rolesForDropdown`
- `activeViewMode`

**Outputs:**
- `teamAction`, `filterChange`, `dropdownSearchChange`

## 🔧 Setup: Create Your API Service

You'll need to create your own API service to fetch data. The library components don't depend on any specific service implementation.

### 1. Create Your API Service

**`src/app/services/my-api.service.ts`:**

```typescript
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { 
  Employee, 
  CreateEmployee, 
  Team, 
  CreateTeam,
  Role
} from '@snovasys/smart-libraries';

@Injectable({
  providedIn: 'root'
})
export class MyApiService {
  private apiUrl = 'https://your-api.com/api';

  constructor(private http: HttpClient) {}

  // Employee methods
  getEmployeesPaginated(
    searchText?: string,
    status?: string,
    page: number = 1,
    pageSize: number = 50
  ): Observable<{ employees: Employee[]; totalCount: number }> {
    let params = new HttpParams()
      .set('page', page.toString())
      .set('pageSize', pageSize.toString());

    if (searchText) params = params.set('searchText', searchText);
    if (status) params = params.set('status', status);

    return this.http.get<{ employees: Employee[]; totalCount: number }>(
      `${this.apiUrl}/employees`,
      { params }
    );
  }

  createEmployee(employee: CreateEmployee): Observable<Employee> {
    return this.http.post<Employee>(`${this.apiUrl}/employees`, employee);
  }

  updateEmployee(id: number, employee: Partial<CreateEmployee>): Observable<Employee> {
    return this.http.put<Employee>(`${this.apiUrl}/employees/${id}`, employee);
  }

  // Team methods
  getTeamsPaginated(
    searchText?: string,
    page: number = 1,
    pageSize: number = 100
  ): Observable<{ teams: Team[]; totalCount: number }> {
    let params = new HttpParams()
      .set('page', page.toString())
      .set('pageSize', pageSize.toString());

    if (searchText) params = params.set('searchText', searchText);

    return this.http.get<{ teams: Team[]; totalCount: number }>(
      `${this.apiUrl}/teams`,
      { params }
    );
  }

  createTeam(team: CreateTeam): Observable<Team> {
    return this.http.post<Team>(`${this.apiUrl}/teams`, team);
  }

  // Dropdown data methods
  getRoles(): Observable<Role[]> {
    return this.http.get<Role[]>(`${this.apiUrl}/roles`);
  }

  searchEmployees(searchText: string): Observable<Employee[]> {
    return this.http.get<Employee[]>(`${this.apiUrl}/employees/search`, {
      params: { searchText }
    });
  }

  searchTeams(searchText: string): Observable<Team[]> {
    return this.http.get<Team[]>(`${this.apiUrl}/teams/search`, {
      params: { searchText }
    });
  }
}
```

### 2. Provide HttpClient

**`src/app/app.config.ts` (Standalone):**

```typescript
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient()
  ]
};
```

## 💡 Complete Example

**`src/app/pages/organization-page.component.ts`:**

```typescript
import { Component, OnInit } from '@angular/core';
import { 
  OrganizationComponent,
  Employee,
  Team,
  EmployeeActionEvent,
  TeamActionEvent,
  FilterChangeEvent
} from '@snovasys/smart-libraries';
import { MyApiService } from '../services/my-api.service';

@Component({
  selector: 'app-organization-page',
  standalone: true,
  imports: [OrganizationComponent],
  template: `
    <sl-organization
      [employees]="employees"
      [teams]="teams"
      [totalEmployees]="totalEmployees"
      [totalTeams]="totalTeams"
      [loading]="loading"
      [employeesForDropdown]="employeesForDropdown"
      [teamsForDropdown]="teamsForDropdown"
      [rolesForDropdown]="rolesForDropdown"
      [activeTab]="activeTab"
      [activeViewMode]="activeViewMode"
      (tabChange)="onTabChange($event)"
      (viewModeChange)="onViewModeChange($event)"
      (employeeAction)="onEmployeeAction($event)"
      (teamAction)="onTeamAction($event)"
      (filterChange)="onFilterChange($event)">
    </sl-organization>
  `
})
export class OrganizationPageComponent implements OnInit {
  employees: Employee[] = [];
  teams: Team[] = [];
  employeesForDropdown: Employee[] = [];
  teamsForDropdown: Team[] = [];
  rolesForDropdown: Role[] = [];
  totalEmployees = 0;
  totalTeams = 0;
  loading = false;
  activeTab: 'employees' | 'teams' = 'employees';
  activeViewMode: 'table' | 'hierarchy' = 'table';

  constructor(private apiService: MyApiService) {}

  ngOnInit() {
    this.loadData();
  }

  loadData() {
    this.loading = true;
    // Load initial data based on active tab
    if (this.activeTab === 'employees') {
      this.loadEmployees();
    } else {
      this.loadTeams();
    }
  }

  loadEmployees() {
    this.apiService.getEmployeesPaginated().subscribe({
      next: (response) => {
        this.employees = response.employees;
        this.totalEmployees = response.totalCount;
        this.loading = false;
      },
      error: (err) => {
        console.error('Error loading employees:', err);
        this.loading = false;
      }
    });
  }

  loadTeams() {
    this.apiService.getTeamsPaginated().subscribe({
      next: (response) => {
        this.teams = response.teams;
        this.totalTeams = response.totalCount;
        this.loading = false;
      },
      error: (err) => {
        console.error('Error loading teams:', err);
        this.loading = false;
      }
    });
  }

  onTabChange(event: { tab: 'employees' | 'teams' }) {
    this.activeTab = event.tab;
    this.loadData();
  }

  onViewModeChange(event: { mode: 'table' | 'hierarchy' }) {
    this.activeViewMode = event.mode;
  }

  onEmployeeAction(event: EmployeeActionEvent) {
    switch (event.action) {
      case 'create':
        this.apiService.createEmployee(event.data as CreateEmployee).subscribe({
          next: () => this.loadEmployees(),
          error: (err) => console.error('Error creating employee:', err)
        });
        break;
      case 'update':
        this.apiService.updateEmployee(event.data.id, event.data).subscribe({
          next: () => this.loadEmployees(),
          error: (err) => console.error('Error updating employee:', err)
        });
        break;
      // Handle other actions...
    }
  }

  onTeamAction(event: TeamActionEvent) {
    switch (event.action) {
      case 'create':
        this.apiService.createTeam(event.data as CreateTeam).subscribe({
          next: () => this.loadTeams(),
          error: (err) => console.error('Error creating team:', err)
        });
        break;
      // Handle other actions...
    }
  }

  onFilterChange(event: FilterChangeEvent) {
    // Reload data with new filters
    if (this.activeTab === 'employees') {
      this.apiService.getEmployeesPaginated(
        event.filters.searchText,
        event.filters.status,
        event.pagination.page,
        event.pagination.pageSize
      ).subscribe({
        next: (response) => {
          this.employees = response.employees;
          this.totalEmployees = response.totalCount;
        }
      });
    } else {
      this.apiService.getTeamsPaginated(
        event.filters.searchText,
        event.pagination.page,
        event.pagination.pageSize
      ).subscribe({
        next: (response) => {
          this.teams = response.teams;
          this.totalTeams = response.totalCount;
        }
      });
    }
  }
}
```

## 📋 Event Handling

### OrganizationComponent Events

- **`tabChange`** - When user switches between Employees/Teams tabs
- **`viewModeChange`** - When user toggles between Table/Hierarchy view
- **`dropdownSearchChange`** - When dropdown search text changes
- **`employeeAction`** - All employee-related CRUD operations (create, update, delete, toggleStatus, etc.)
- **`teamAction`** - All team-related CRUD operations (create, update, delete, addMember, etc.)
- **`filterChange`** - When filters or pagination change

### Event Payload Examples

**EmployeeActionEvent:**
```typescript
{
  action: 'create' | 'update' | 'delete' | 'toggleStatus' | 'toggleLogin',
  data: Employee | Partial<Employee>
}
```

**TeamActionEvent:**
```typescript
{
  action: 'create' | 'update' | 'delete' | 'addMember' | 'removeMember' | 'addAdmin',
  data: Team | Partial<Team> | any
}
```

**FilterChangeEvent:**
```typescript
{
  filters: {
    searchText?: string;
    status?: string;
    teamId?: number | null;
  };
  pagination: {
    page: number;
    pageSize: number;
    totalCount: number;
  };
}
```

## 🔍 Troubleshooting

### Components not rendering
- Check browser console for errors
- Verify all required inputs are provided
- Ensure HttpClient is provided (for API calls)

### Type errors
- Ensure all types/interfaces are imported from `@snovasys/smart-libraries`
- Check that event handlers match the expected event types

### Import errors
- Rebuild library: `ng build smart-libraries`
- Clear node_modules and reinstall: `rm -rf node_modules && npm install`

### Data not updating
- Ensure you're calling load methods after actions
- Check that event handlers are properly connected
- Verify API service methods are working correctly

## 📚 Additional Documentation

- **USAGE_GUIDE.md** - Complete detailed usage guide with more examples
- **DATA_FORMAT_REFERENCE.md** - Complete JSON format reference for all inputs and outputs

Access documentation:
- In `node_modules/@snovasys/smart-libraries/` after installation
- Or view on npm: `npm view @snovasys/smart-libraries`

## 🔧 Development

### Build Library

```bash
ng build smart-libraries
```

### Test Locally

```bash
# In library directory
cd dist/smart-libraries
npm link

# In consuming app
npm link @snovasys/smart-libraries
```

### Publishing

```bash
# Build the library
ng build smart-libraries

# Publish
cd dist/smart-libraries
npm publish --access public
```

## 📝 Peer Dependencies

- `@angular/common`: ^18.0.0
- `@angular/core`: ^18.0.0
- `@angular/forms`: ^18.0.0
- `@angular/router`: ^18.0.0
- `rxjs`: ^7.8.0 || ^8.0.0

## 📄 License

MIT

## 🔗 Further Help

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.