Documentation

TypeScript Integration

TypeScript Integration

UltraViolet Pro includes comprehensive TypeScript support with a well-structured admin.ts file that handles all core dashboard functionality.

Overview

The TypeScript integration provides:

  • Type Safety - Compile-time error checking and IntelliSense support
  • Modern JavaScript Features - ES6+ features with backward compatibility
  • Modular Architecture - Well-organized code with clear separation of concerns
  • Development Experience - Enhanced IDE support and debugging capabilities
  • Maintainability - Self-documenting code with interfaces and type definitions

Project Structure

TypeScript Configuration

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "outDir": "./public/build",
    "rootDir": "./resources/js"
  },
  "include": [
    "resources/js/**/*"
  ],
  "exclude": [
    "node_modules",
    "public/build"
  ]
}

File Organization

resources/js/
├── admin.ts                    # Main TypeScript file
├── admin-background-animations.js  # Background animation module
├── code-highlighting.js        # Code highlighting utilities
├── toast-helpers.js           # Toast notification helpers
└── types/                      # Type definitions
    ├── dashboard.ts           # Dashboard-specific types
    ├── charts.ts              # Chart-related types
    └── maps.ts                # Map-related types

Core Architecture

Main AdminDashboard Class

The admin.ts file is structured around a central AdminDashboard class that manages all dashboard functionality:

class AdminDashboard {
  private config: DashboardConfig
  private simpleBarInstances: SimpleBar[] = []
  public themeVerificationTimeout: NodeJS.Timeout | null = null
  public systemThemeListener: ((e: MediaQueryListEvent) => void) | null = null

  constructor(config: DashboardConfig) {
    this.config = config
    this.init()
  }
}

Key Features

1. Theme Management

interface DashboardConfig {
  defaultTheme: 'dark' | 'light'
  themeTransitionDuration: number
}

class AdminDashboard {
  private initTheme(): void {
    // Initialize theme with system preference detection
    const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
    const savedTheme = localStorage.getItem('theme') as 'dark' | 'light' | null
    const theme = savedTheme || (systemPrefersDark ? 'dark' : this.config.defaultTheme)

    this.applyTheme(theme)
  }

  private applyTheme(theme: 'dark' | 'light'): void {
    document.documentElement.setAttribute('data-bs-theme', theme)
    localStorage.setItem('theme', theme)
  }
}

2. RTL/LTR Support

interface DashboardConfig {
  defaultDirection: 'ltr' | 'rtl'
}

class AdminDashboard {
  private initDirection(): void {
    const savedDirection = localStorage.getItem('direction') as 'ltr' | 'rtl' | null
    const direction = savedDirection || this.config.defaultDirection

    document.documentElement.setAttribute('dir', direction)
    localStorage.setItem('direction', direction)
  }
}

3. Component Initialization

class AdminDashboard {
  private initComponents(): void {
    this.initScrollbars()
    this.initHeadroom()
    this.initBackgroundAnimations()
    this.initCharts()
    this.initMaps()
    this.initMasonry()
  }

  private initScrollbars(): void {
    const scrollbarElements = document.querySelectorAll('[data-simplebar]')
    scrollbarElements.forEach(element => {
      const simpleBar = new SimpleBar(element as HTMLElement)
      this.simpleBarInstances.push(simpleBar)
    })
  }
}

Type Definitions

Core Interfaces

interface DashboardConfig {
  apiBaseUrl: string
  defaultTheme: 'dark' | 'light'
  themeTransitionDuration: number
  defaultDirection: 'ltr' | 'rtl'
  defaultBackgroundAnimation: string
}

interface MapConfig {
  container: string
  style: string
  center: [number, number]
  zoom: number
}

interface ChartConfig {
  type: 'line' | 'bar' | 'pie' | 'area' | 'donut'
  data: any[]
  options: ApexCharts.ApexOptions
}

interface ThemeSettings {
  theme: 'dark' | 'light'
  direction: 'ltr' | 'rtl'
  backgroundAnimation: string
  sidebarCollapsed: boolean
}

Chart Types

interface ChartData {
  labels: string[]
  datasets: {
    label: string
    data: number[]
    backgroundColor?: string | string[]
    borderColor?: string | string[]
    borderWidth?: number
  }[]
}

interface ChartOptions {
  responsive: boolean
  maintainAspectRatio: boolean
  plugins?: {
    legend?: {
      position: 'top' | 'bottom' | 'left' | 'right'
    }
    tooltip?: {
      enabled: boolean
    }
  }
  scales?: {
    x?: {
      display: boolean
      title?: {
        display: boolean
        text: string
      }
    }
    y?: {
      display: boolean
      title?: {
        display: boolean
        text: string
      }
    }
  }
}

Map Types

interface MapMarker {
  id: string
  position: [number, number]
  title: string
  description?: string
  icon?: string
  color?: string
}

interface MapLayer {
  id: string
  name: string
  type: 'fill' | 'line' | 'symbol' | 'circle'
  source: string
  paint: Record<string, any>
  layout?: Record<string, any>
}

interface MapSource {
  type: 'geojson' | 'vector' | 'raster'
  data: any
  cluster?: boolean
  clusterMaxZoom?: number
  clusterRadius?: number
}

Module System

Background Animations Module

// admin-background-animations.js
export default class AdminBackgroundAnimations {
  constructor() {
    this.init()
  }

  init() {
    this.detectSystemPreference()
    this.setupEventListeners()
  }

  detectSystemPreference() {
    const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
    if (prefersReducedMotion) {
      this.disableAnimations()
    }
  }

  setupEventListeners() {
    // Animation control event listeners
  }
}

Code Highlighting Module

// code-highlighting.js
export function initCodeHighlighting() {
  const codeBlocks = document.querySelectorAll('pre code')
  codeBlocks.forEach(block => {
    // Initialize Prism.js highlighting
    Prism.highlightElement(block)
  })
}

export function highlightCode(code: string, language: string): string {
  return Prism.highlight(code, Prism.languages[language], language)
}

Toast Helpers Module

// toast-helpers.js
export interface ToastOptions {
  title?: string
  message: string
  type?: 'success' | 'error' | 'warning' | 'info'
  duration?: number
  position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
}

export function showToast(options: ToastOptions): void {
  const toast = createToastElement(options)
  document.body.appendChild(toast)

  // Auto-remove after duration
  setTimeout(() => {
    toast.remove()
  }, options.duration || 5000)
}

function createToastElement(options: ToastOptions): HTMLElement {
  const toast = document.createElement('div')
  toast.className = `toast toast-${options.type || 'info'}`
  toast.innerHTML = `
    <div class="toast-header">
      <strong>${options.title || 'Notification'}</strong>
    </div>
    <div class="toast-body">
      ${options.message}
    </div>
  `
  return toast
}

Chart Integration

ApexCharts Integration

class AdminDashboard {
  private initCharts(): void {
    const chartElements = document.querySelectorAll('[data-chart]')
    chartElements.forEach(element => {
      const chartType = element.getAttribute('data-chart-type')
      const chartData = this.getChartData(element)

      if (chartType && chartData) {
        this.createChart(element as HTMLElement, chartType, chartData)
      }
    })
  }

  private createChart(element: HTMLElement, type: string, data: any): void {
    const options: ApexCharts.ApexOptions = {
      chart: {
        type: type as any,
        height: 350
      },
      series: data.series,
      xaxis: {
        categories: data.categories
      },
      theme: {
        mode: this.getCurrentTheme()
      }
    }

    const chart = new ApexCharts(element, options)
    chart.render()
  }

  private getCurrentTheme(): 'light' | 'dark' {
    return document.documentElement.getAttribute('data-bs-theme') as 'light' | 'dark'
  }
}

Chart Data Management

interface ChartDataManager {
  getChartData(element: HTMLElement): ChartData | null
  updateChart(chartId: string, newData: ChartData): void
  destroyChart(chartId: string): void
}

class ChartDataManager implements ChartDataManager {
  private charts: Map<string, ApexCharts> = new Map()

  getChartData(element: HTMLElement): ChartData | null {
    const dataScript = element.querySelector('script[type="application/json"]')
    if (dataScript) {
      try {
        return JSON.parse(dataScript.textContent || '{}')
      } catch (error) {
        console.error('Error parsing chart data:', error)
        return null
      }
    }
    return null
  }

  updateChart(chartId: string, newData: ChartData): void {
    const chart = this.charts.get(chartId)
    if (chart) {
      chart.updateSeries(newData.series)
    }
  }

  destroyChart(chartId: string): void {
    const chart = this.charts.get(chartId)
    if (chart) {
      chart.destroy()
      this.charts.delete(chartId)
    }
  }
}

Map Integration

Livewire Integration

Livewire Event Handling

class AdminDashboard {
  private initLivewire(): void {
    // Listen for Livewire events
    document.addEventListener('livewire:load', () => {
      this.setupLivewireListeners()
    })

    // Handle Livewire updates
    document.addEventListener('livewire:update', () => {
      this.refreshComponents()
    })
  }

  private setupLivewireListeners(): void {
    // Chart updates
    Livewire.on('chart-updated', (data: any) => {
      this.updateChart(data.chartId, data.newData)
    })

    // Map updates
    Livewire.on('map-updated', (data: any) => {
      this.updateMap(data.mapId, data.newData)
    })

    // Theme changes
    Livewire.on('theme-changed', (theme: 'dark' | 'light') => {
      this.applyTheme(theme)
    })
  }

  private refreshComponents(): void {
    // Reinitialize components that might have changed
    this.initCharts()
    this.initMaps()
    this.initMasonry()
  }
}

Utility Functions

DOM Utilities

class DOMUtils {
  static querySelector<T extends HTMLElement>(selector: string): T | null {
    return document.querySelector<T>(selector)
  }

  static querySelectorAll<T extends HTMLElement>(selector: string): NodeListOf<T> {
    return document.querySelectorAll<T>(selector)
  }

  static addClass(element: HTMLElement, className: string): void {
    element.classList.add(className)
  }

  static removeClass(element: HTMLElement, className: string): void {
    element.classList.remove(className)
  }

  static toggleClass(element: HTMLElement, className: string): void {
    element.classList.toggle(className)
  }

  static hasClass(element: HTMLElement, className: string): boolean {
    return element.classList.contains(className)
  }
}

Event Utilities

class EventUtils {
  static on(element: HTMLElement, event: string, handler: EventListener): void {
    element.addEventListener(event, handler)
  }

  static off(element: HTMLElement, event: string, handler: EventListener): void {
    element.removeEventListener(event, handler)
  }

  static once(element: HTMLElement, event: string, handler: EventListener): void {
    element.addEventListener(event, handler, { once: true })
  }

  static emit(element: HTMLElement, event: string, detail?: any): void {
    const customEvent = new CustomEvent(event, { detail })
    element.dispatchEvent(customEvent)
  }
}

Storage Utilities

class StorageUtils {
  static setItem(key: string, value: any): void {
    try {
      localStorage.setItem(key, JSON.stringify(value))
    } catch (error) {
      console.error('Error saving to localStorage:', error)
    }
  }

  static getItem<T>(key: string, defaultValue?: T): T | null {
    try {
      const item = localStorage.getItem(key)
      return item ? JSON.parse(item) : defaultValue || null
    } catch (error) {
      console.error('Error reading from localStorage:', error)
      return defaultValue || null
    }
  }

  static removeItem(key: string): void {
    localStorage.removeItem(key)
  }

  static clear(): void {
    localStorage.clear()
  }
}

Development Workflow

Building TypeScript

# Install dependencies
npm install

# Build TypeScript
npm run build

# Watch for changes
npm run dev

# Type checking
npm run type-check

Package.json Scripts

{
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "type-check": "tsc --noEmit",
    "lint": "eslint resources/js/**/*.ts",
    "lint:fix": "eslint resources/js/**/*.ts --fix"
  }
}

Vite Integration

// vite.config.js
import { defineConfig } from 'vite'
import { resolve } from 'path'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'resources/js/admin.ts'),
      name: 'AdminDashboard',
      fileName: 'admin'
    },
    rollupOptions: {
      external: ['bootstrap', 'simplebar', 'headroom.js'],
      output: {
        globals: {
          'bootstrap': 'Bootstrap',
          'simplebar': 'SimpleBar',
          'headroom.js': 'Headroom'
        }
      }
    }
  }
})

Best Practices

1. Type Safety

// Always define interfaces for data structures
interface User {
  id: number
  name: string
  email: string
  role: 'admin' | 'user' | 'moderator'
}

// Use type guards for runtime type checking
function isUser(obj: any): obj is User {
  return obj && typeof obj.id === 'number' && typeof obj.name === 'string'
}

2. Error Handling

class AdminDashboard {
  private handleError(error: Error, context: string): void {
    console.error(`Error in ${context}:`, error)

    // Show user-friendly error message
    this.showToast({
      type: 'error',
      title: 'Error',
      message: 'An unexpected error occurred. Please try again.'
    })
  }
}

3. Memory Management

class AdminDashboard {
  private cleanup(): void {
    // Clear timeouts
    if (this.themeVerificationTimeout) {
      clearTimeout(this.themeVerificationTimeout)
    }

    // Remove event listeners
    if (this.systemThemeListener) {
      window.matchMedia('(prefers-color-scheme: dark)')
        .removeEventListener('change', this.systemThemeListener)
    }

    // Destroy charts
    this.charts.forEach(chart => chart.destroy())

    // Destroy maps
    if (this.map) {
      this.map.remove()
    }
  }
}

4. Performance Optimization

class AdminDashboard {
  private debounce<T extends (...args: any[]) => any>(
    func: T,
    wait: number
  ): (...args: Parameters<T>) => void {
    let timeout: NodeJS.Timeout
    return (...args: Parameters<T>) => {
      clearTimeout(timeout)
      timeout = setTimeout(() => func.apply(this, args), wait)
    }
  }

  private debouncedResize = this.debounce(() => {
    this.handleResize()
  }, 250)
}

Troubleshooting

Common Issues

  1. Type Errors: Ensure all dependencies have type definitions
  2. Module Resolution: Check tsconfig.json moduleResolution setting
  3. Build Errors: Verify all imports are correct and files exist
  4. Runtime Errors: Use proper type guards and error handling

Debugging

// Enable debug mode
const DEBUG = process.env.NODE_ENV === 'development'

if (DEBUG) {
  console.log('AdminDashboard initialized with config:', this.config)
}

Production Deployment

Build Optimization

// Use conditional imports for better tree shaking
const loadMapbox = async () => {
  if (this.config.mapboxToken) {
    const { default: mapboxgl } = await import('mapbox-gl')
    return mapboxgl
  }
  return null
}

Environment Configuration

interface EnvironmentConfig {
  development: DashboardConfig
  production: DashboardConfig
  testing: DashboardConfig
}

const configs: EnvironmentConfig = {
  development: {
    apiBaseUrl: 'http://localhost:8000/api',
    defaultTheme: 'dark',
    themeTransitionDuration: 300,
    defaultDirection: 'ltr',
    defaultBackgroundAnimation: 'cosmic-wave'
  },
  production: {
    apiBaseUrl: '/api',
    defaultTheme: 'dark',
    themeTransitionDuration: 200,
    defaultDirection: 'ltr',
    defaultBackgroundAnimation: 'cosmic-wave'
  },
  testing: {
    apiBaseUrl: 'http://localhost:8000/api',
    defaultTheme: 'light',
    themeTransitionDuration: 0,
    defaultDirection: 'ltr',
    defaultBackgroundAnimation: 'none'
  }
}

The TypeScript integration in UltraViolet Pro provides a robust foundation for building maintainable, type-safe dashboard applications with excellent developer experience and production-ready code.