# NestJS Dynamic Templates

A powerful NestJS module for dynamic template management with support for multiple template engines and languages.

## Features

- 🚀 Multiple template engines (Nunjucks, Handlebars, EJS, Pug)
- 🌐 Multiple language support (HTML, MJML, Markdown, Text)
- 💾 Database storage for templates and layouts
- 🔧 Configurable and extensible
- 🎯 TypeScript support
- 📦 Easy integration

## Installation

```bash
npm install @ackplus/nest-dynamic-templates
# or
yarn add @ackplus/nest-dynamic-templates
```

## Usage

### Option 1: Basic Usage (No Configuration Required)

```typescript
import { Module } from '@nestjs/common';
import { NestDynamicTemplatesModule } from '@ackplus/nest-dynamic-templates';

@Module({
  imports: [
    NestDynamicTemplatesModule, // Provides basic services with default configuration
  ],
})
export class AppModule {}
```

### Option 2: Using forFeature() (Explicit Basic Usage)

```typescript
import { Module } from '@nestjs/common';
import { NestDynamicTemplatesModule } from '@ackplus/nest-dynamic-templates';

@Module({
  imports: [
    NestDynamicTemplatesModule.forFeature(), // Explicitly import basic services
  ],
})
export class AppModule {}
```

### Option 3: Using forRoot() (With Configuration)

```typescript
import { Module } from '@nestjs/common';
import { NestDynamicTemplatesModule, TemplateEngineEnum, TemplateLanguageEnum } from '@ackplus/nest-dynamic-templates';

@Module({
  imports: [
    NestDynamicTemplatesModule.forRoot({
      isGlobal: true,
      engines: {
        template: [TemplateEngineEnum.NUNJUCKS, TemplateEngineEnum.HANDLEBARS],
        language: [TemplateLanguageEnum.HTML, TemplateLanguageEnum.MJML],
      },
      enginesOptions: {
        filters: {
          uppercase: (str) => str.toUpperCase(),
          reverse: (str) => str.split('').reverse().join(''),
        },
        template: {
          [TemplateEngineEnum.NUNJUCKS]: {
            autoescape: true,
          },
        },
      },
    }),
  ],
})
export class AppModule {}
```

### Option 4: Using forRootAsync() (Async Configuration)

#### With useFactory

```typescript
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { NestDynamicTemplatesModule } from '@ackplus/nest-dynamic-templates';

@Module({
  imports: [
    ConfigModule.forRoot(),
    NestDynamicTemplatesModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        isGlobal: true,
        engines: {
          template: configService.get('TEMPLATE_ENGINES')?.split(',') || ['nunjucks'],
          language: configService.get('LANGUAGE_ENGINES')?.split(',') || ['html'],
        },
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}
```

#### With useClass

```typescript
import { Injectable } from '@nestjs/common';
import {
  NestDynamicTemplatesModuleOptionsFactory,
  NestDynamicTemplatesModuleConfig,
  TemplateEngineEnum,
  TemplateLanguageEnum
} from '@ackplus/nest-dynamic-templates';

@Injectable()
export class TemplatesConfigService implements NestDynamicTemplatesModuleOptionsFactory {
  createNestDynamicTemplatesModuleOptions(): NestDynamicTemplatesModuleConfig {
    return {
      isGlobal: true,
      engines: {
        template: [TemplateEngineEnum.NUNJUCKS],
        language: [TemplateLanguageEnum.HTML, TemplateLanguageEnum.MJML],
      },
    };
  }
}

@Module({
  imports: [
    NestDynamicTemplatesModule.forRootAsync({
      useClass: TemplatesConfigService,
    }),
  ],
  providers: [TemplatesConfigService],
})
export class AppModule {}
```

## Using the Services

Once imported, you can inject and use the template services:

```typescript
import { Injectable } from '@nestjs/common';
import { TemplateService, TemplateLayoutService } from '@ackplus/nest-dynamic-templates';

@Injectable()
export class EmailService {
  constructor(
    private readonly templateService: TemplateService,
    private readonly templateLayoutService: TemplateLayoutService,
  ) {}

  async sendWelcomeEmail(user: any) {
    // Create a template
    const template = await this.templateService.createTemplate({
      name: 'welcome-email',
      displayName: 'Welcome Email',
      engine: 'nunjucks',
      language: 'html',
      subject: 'Welcome {{ user.name }}!',
      content: '<h1>Hello {{ user.name }}</h1><p>Welcome to our platform!</p>',
      scope: 'system',
      locale: 'en',
    });

    // Render the template
    const rendered = await this.templateService.renderTemplate('welcome-email', {
      user: { name: user.name },
    });

    console.log('Rendered email:', rendered);
    // Send email using your preferred email service
  }

  async createEmailLayout() {
    // Create a layout
    const layout = await this.templateLayoutService.createTemplateLayout({
      name: 'email-layout',
      displayName: 'Email Layout',
      engine: 'nunjucks',
      language: 'html',
      content: `
        <!DOCTYPE html>
        <html>
          <head><title>{{ subject }}</title></head>
          <body>
            <header>Our Company</header>
            <main>{{ content | safe }}</main>
            <footer>© 2024 Our Company</footer>
          </body>
        </html>
      `,
      scope: 'system',
      locale: 'en',
    });

    return layout;
  }
}
```

## Configuration Options

### NestDynamicTemplatesModuleConfig

```typescript
interface NestDynamicTemplatesModuleConfig {
  isGlobal?: boolean; // Make module global
  engines?: {
    template?: TemplateEngineEnum[]; // Enabled template engines
    language?: TemplateLanguageEnum[]; // Enabled language engines
  };
  enginesOptions?: {
    filters?: Record<string, Function>; // Custom filters
    template?: Partial<Record<TemplateEngineEnum, any>>; // Engine-specific options
    language?: Partial<Record<TemplateLanguageEnum, any>>; // Language-specific options
  };
}
```

### Supported Engines

#### Template Engines
- `nunjucks` - Nunjucks templating
- `handlebars` - Handlebars templating
- `ejs` - EJS templating
- `pug` - Pug templating

#### Language Engines
- `html` - HTML output
- `mjml` - MJML email templates
- `markdown` - Markdown output
- `text` - Plain text output

## Benefits of Each Approach

### Basic Usage (`NestDynamicTemplatesModule`)
- ✅ **Zero configuration** - Works out of the box
- ✅ **Quick setup** - Just import and use
- ✅ **Default engines** - Nunjucks + HTML/MJML/Text
- ❌ **Limited customization** - No custom filters or options

### forFeature()
- ✅ **Explicit** - Clear intent for basic usage
- ✅ **Same as basic** - All benefits of basic usage
- ✅ **Consistent API** - Matches other NestJS modules

### forRoot()
- ✅ **Full configuration** - Complete control over engines and options
- ✅ **Custom filters** - Add your own template filters
- ✅ **Engine options** - Configure individual engines
- ✅ **Global module** - Available throughout the app

### forRootAsync()
- ✅ **Dynamic configuration** - Load config from external sources
- ✅ **Dependency injection** - Use other services for configuration
- ✅ **Environment-based** - Different configs for different environments
- ✅ **Factory pattern** - Clean separation of configuration logic

## Migration Guide

If you're upgrading from a previous version:

### Before
```typescript
// Only forRoot was available
NestDynamicTemplatesModule.forRoot(config)
```

### After
```typescript
// Multiple options now available
NestDynamicTemplatesModule                    // Basic usage
NestDynamicTemplatesModule.forFeature()       // Explicit basic usage
NestDynamicTemplatesModule.forRoot(config)    // With configuration
NestDynamicTemplatesModule.forRootAsync(...)  // Async configuration
```

## License

MIT
