npm package: @flusys/ng-event-manager
Description: Event Manager and Calendar module for FLUSYS Angular applications
Latest version: 4.1.1

# @flusys/ng-event-manager

> Event and calendar management UI library for the FLUSYS Angular platform — month/week/day calendar views, event CRUD, recurrence patterns, and participant management.

[![npm version](https://img.shields.io/npm/v/@flusys/ng-event-manager.svg)](https://www.npmjs.com/package/@flusys/ng-event-manager)
[![Angular](https://img.shields.io/badge/Angular-21-red.svg)](https://angular.io)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

---

## Table of Contents

- [Overview](#overview)
- [Features](#features)
- [Compatibility](#compatibility)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Module Registration](#module-registration)
- [Calendar Views](#calendar-views)
- [Event Model](#event-model)
  - [ICalendarEvent](#icalendarevent)
  - [Recurrence Patterns](#recurrence-patterns)
  - [Participant Status](#participant-status)
- [Services](#services)
  - [CalendarStateService](#calendarstateservice)
  - [EventApiService](#eventapiservice)
  - [ParticipantApiService](#participantapiservice)
- [Components](#components)
  - [CalendarComponent](#calendarcomponent)
  - [EventFormComponent](#eventformcomponent)
  - [EventDetailComponent](#eventdetailcomponent)
- [Cross-Module Adapter](#cross-module-adapter)
- [API Endpoints](#api-endpoints)
- [Configuration Reference](#configuration-reference)
- [Troubleshooting](#troubleshooting)
- [License](#license)

---

## Overview

`@flusys/ng-event-manager` provides a fully-featured calendar and event management UI for FLUSYS applications. Users can create events with recurrence rules, invite participants, and track attendance — all from a familiar calendar interface with month, week, and day views.

The package uses the Provider Interface Pattern: it injects `USER_PROVIDER` and `COMPANY_PROVIDER` from `ng-shared` to get user context without depending on `ng-auth` directly.

---

## Features

- ✅ Three calendar views: month, week, day
- ✅ Event CRUD with drag-to-reschedule
- ✅ Recurrence engine: NONE, DAILY, WEEKLY, BIWEEKLY, MONTHLY
- ✅ Participant management with status tracking (PENDING, ACCEPTED, DECLINED, TENTATIVE)
- ✅ `provideEventManagerProviders()` — registers `EVENT_MANAGER_ADAPTER`
- ✅ `CalendarStateService` — signal-based calendar state
- ✅ Responsive design (mobile-friendly month view)
- ✅ Event color coding by category

---

## Compatibility

| Package | Version |
|---------|---------|
| Angular | 21+ |
| @flusys/ng-core | 4.x |
| @flusys/ng-shared | 4.x |

---

## Installation

```bash
npm install @flusys/ng-event-manager @flusys/ng-core @flusys/ng-shared
```

---

## Quick Start

### 1. Enable Event Manager in Config

```typescript
// environments/environment.ts
export const environment = {
  services: {
    eventManager: { enabled: true },
  },
};
```

### 2. Register Providers

```typescript
// app.config.ts
import { provideEventManagerProviders } from '@flusys/ng-event-manager';

export const appConfig: ApplicationConfig = {
  providers: [
    ...provideEventManagerProviders(),
  ],
};
```

### 3. Add Calendar Routes

```typescript
// app.routes.ts
import { EVENT_MANAGER_ROUTES } from '@flusys/ng-event-manager';

export const routes: Routes = [
  {
    path: 'calendar',
    loadChildren: () => EVENT_MANAGER_ROUTES,
  },
];
```

### 4. Embed Calendar Component

```typescript
import { CalendarComponent } from '@flusys/ng-event-manager';

@Component({
  imports: [CalendarComponent],
  template: `
    <flusys-calendar
      [view]="'month'"
      (eventClicked)="onEventClicked($event)"
      (dateClicked)="onDateClicked($event)"
    />
  `,
})
export class SchedulePageComponent {}
```

---

## Module Registration

### `provideEventManagerProviders()`

```typescript
import { provideEventManagerProviders } from '@flusys/ng-event-manager';

providers: [
  ...provideEventManagerProviders(),
]
```

Registers:
- `EVENT_MANAGER_ADAPTER` — implementation of `IEventManagerAdapter` (defined in `ng-shared`)

This token can be injected by other modules (e.g., `ng-notification`) to query upcoming events without importing `ng-event-manager` directly.

---

## Calendar Views

### Month View

Full calendar grid showing all days of the month. Events shown as colored chips per day.

```html
<flusys-calendar view="month" />
```

- Click a day to open day view or create an event
- Click an event chip to open event detail
- Navigate months with prev/next arrows

### Week View

7-column grid showing time slots (hourly) across one week.

```html
<flusys-calendar view="week" />
```

- Drag events to reschedule within the week
- Click empty slot to create event at that time
- Multi-day events span across columns

### Day View

Single-day timeline with hourly time slots.

```html
<flusys-calendar view="day" />
```

- Detailed time-slot grid
- Best for dense scheduling
- Drag events to reschedule within the day

---

## Event Model

### ICalendarEvent

```typescript
interface ICalendarEvent {
  id: string;
  title: string;
  description?: string;
  startDate: string;      // ISO 8601
  endDate: string;        // ISO 8601
  allDay: boolean;
  location?: string;
  color?: string;         // Hex color for calendar display
  recurrence: RecurrencePattern;
  recurrenceEndDate?: string;
  participants: IParticipant[];
  createdById: string;
  companyId?: string;
  createdAt: string;
  updatedAt: string;
}
```

### Recurrence Patterns

| Pattern | Value | Description |
|---------|-------|-------------|
| No recurrence | `NONE` | Single event |
| Daily | `DAILY` | Repeats every day |
| Weekly | `WEEKLY` | Repeats every week on same day |
| Bi-weekly | `BIWEEKLY` | Repeats every two weeks |
| Monthly | `MONTHLY` | Repeats on same day of month |

```typescript
import { RecurrencePattern } from '@flusys/ng-event-manager';

const weeklyMeeting: Partial<ICalendarEvent> = {
  title: 'Team Standup',
  recurrence: RecurrencePattern.WEEKLY,
  recurrenceEndDate: '2026-12-31',
};
```

### Participant Status

| Status | Value | Description |
|--------|-------|-------------|
| Pending | `PENDING` | Invitation sent, no response yet |
| Accepted | `ACCEPTED` | Participant confirmed attendance |
| Declined | `DECLINED` | Participant declined |
| Tentative | `TENTATIVE` | Participant is tentative |

```typescript
interface IParticipant {
  id: string;
  userId: string;
  userName: string;
  email: string;
  status: 'PENDING' | 'ACCEPTED' | 'DECLINED' | 'TENTATIVE';
  invitedAt: string;
  respondedAt?: string;
}
```

---

## Services

### CalendarStateService

Signal-based service managing the calendar's current view state:

```typescript
import { CalendarStateService } from '@flusys/ng-event-manager';

@Component({ ... })
export class CalendarPageComponent {
  private calState = inject(CalendarStateService);

  // Signals
  currentView = this.calState.view;              // Signal<'month' | 'week' | 'day'>
  currentDate = this.calState.currentDate;       // Signal<Date>
  events = this.calState.events;                 // Signal<ICalendarEvent[]>
  isLoading = this.calState.isLoading;           // Signal<boolean>
  selectedEvent = this.calState.selectedEvent;   // Signal<ICalendarEvent | null>

  // Actions
  navigatePrev(): void { this.calState.navigatePrev(); }
  navigateNext(): void { this.calState.navigateNext(); }
  navigateToday(): void { this.calState.navigateToday(); }
  setView(view: 'month' | 'week' | 'day'): void { this.calState.setView(view); }
  selectEvent(event: ICalendarEvent): void { this.calState.selectEvent(event); }
  refreshEvents(): void { this.calState.refresh(); }
}
```

### EventApiService

Typed API client for event CRUD:

```typescript
import { EventApiService } from '@flusys/ng-event-manager';

@Injectable({ ... })
export class MyService {
  private eventApi = inject(EventApiService);

  getEventsInRange(start: Date, end: Date): Observable<IListResponse<ICalendarEvent>> {
    return this.eventApi.getAll({
      filters: {
        startDate: start.toISOString(),
        endDate: end.toISOString(),
      },
    });
  }

  createEvent(event: CreateEventDto): Observable<ISingleResponse<ICalendarEvent>> {
    return this.eventApi.insert(event);
  }

  reschedule(id: string, startDate: string, endDate: string): Observable<ISingleResponse<ICalendarEvent>> {
    return this.eventApi.update({ id, startDate, endDate });
  }
}
```

### ParticipantApiService

Manages event participants:

```typescript
import { ParticipantApiService } from '@flusys/ng-event-manager';

@Injectable({ ... })
export class MyService {
  private participantApi = inject(ParticipantApiService);

  invite(eventId: string, userIds: string[]): Observable<IMessageResponse> {
    return this.participantApi.invite({ eventId, userIds });
  }

  respond(eventId: string, status: 'ACCEPTED' | 'DECLINED' | 'TENTATIVE'): Observable<IMessageResponse> {
    return this.participantApi.respond({ eventId, status });
  }
}
```

---

## Components

### CalendarComponent

Main calendar component with view switching:

```html
<flusys-calendar
  [view]="'month'"
  [initialDate]="today"
  [showViewSwitcher]="true"
  (eventClicked)="onEventClicked($event)"
  (dateClicked)="onDateClicked($event)"
  (eventDropped)="onEventRescheduled($event)"
/>
```

| Input | Type | Default | Description |
|-------|------|---------|-------------|
| `view` | `'month' \| 'week' \| 'day'` | `'month'` | Initial calendar view |
| `initialDate` | `Date` | today | Starting date |
| `showViewSwitcher` | `boolean` | `true` | Show view toggle buttons |

| Output | Type | Description |
|--------|------|-------------|
| `eventClicked` | `ICalendarEvent` | User clicked an event |
| `dateClicked` | `Date` | User clicked an empty date/slot |
| `eventDropped` | `{event, newStart, newEnd}` | Event drag-dropped to new time |

### EventFormComponent

Event creation/edit form (dialog or page):

```html
<flusys-event-form
  [eventId]="editEventId"
  [initialDate]="clickedDate"
  (saved)="onEventSaved($event)"
  (cancelled)="onFormCancelled()"
/>
```

### EventDetailComponent

Read-only event detail view with participant list and RSVP actions:

```html
<flusys-event-detail
  [eventId]="selectedEventId"
  (editRequested)="onEditRequested($event)"
  (deleteRequested)="onDeleteRequested($event)"
/>
```

---

## Cross-Module Adapter

`EVENT_MANAGER_ADAPTER` (defined in `ng-shared`) allows other packages to query event data without importing `ng-event-manager` directly.

```typescript
// In ng-notification — queries upcoming events without ng-event-manager dependency
import { EVENT_MANAGER_ADAPTER, IEventManagerAdapter } from '@flusys/ng-shared';

@Injectable({ providedIn: 'root' })
export class NotificationService {
  private eventAdapter = inject<IEventManagerAdapter>(EVENT_MANAGER_ADAPTER, { optional: true });

  getUpcomingEventCount(): number {
    return this.eventAdapter?.getUpcomingCount() ?? 0;
  }
}
```

```typescript
// IEventManagerAdapter interface (defined in ng-shared)
interface IEventManagerAdapter {
  getUpcomingEvents(limit?: number): Observable<ICalendarEvent[]>;
  getUpcomingCount(): number;
  getEventsForDate(date: Date): Observable<ICalendarEvent[]>;
}
```

---

## API Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/event/get-all` | List events (with date range filter) |
| POST | `/event/get/:id` | Get event by ID |
| POST | `/event/insert` | Create event |
| POST | `/event/update` | Update event |
| POST | `/event/delete` | Delete event |
| POST | `/event/delete-series` | Delete entire recurrence series |
| POST | `/event/participant/invite` | Invite participants |
| POST | `/event/participant/respond` | Accept/decline invitation |
| POST | `/event/participant/remove` | Remove participant |
| POST | `/event/my-events` | Get current user's events |

---

## Configuration Reference

| Config Key | Type | Default | Description |
|------------|------|---------|-------------|
| `services.eventManager.enabled` | `boolean` | `false` | Enable event manager module |

---

## Troubleshooting

**Calendar shows no events despite events existing**

`CalendarStateService` loads events for the visible date range. When navigating to a new month/week, it fetches that range. Check the date filter sent in `POST /event/get-all` via browser network tab.

**Drag-and-drop reschedule not working**

Drag-and-drop requires a pointer device. Touch devices may need CDK touch support. Check for `@angular/cdk` version compatibility with Angular 21.

**Recurring events showing too many instances**

The backend generates recurring instances. If instances appear infinitely, ensure `recurrenceEndDate` is set on the event when creating.

**Participant invitations not delivered**

Email delivery depends on `ng-email` being configured with a valid provider. Ensure `services.email.enabled: true` and at least one email provider is active on the server.

**`No provider for EVENT_MANAGER_ADAPTER`**

Register `provideEventManagerProviders()` in `app.config.ts`. If the event manager is optional in your app, inject with `{ optional: true }` in consuming services.

---

## License

MIT © FLUSYS