digitalfabrik/integreat-app

View on GitHub
shared/api/models/PoiModel.ts

Summary

Maintainability
A
0 mins
Test Coverage
import distance from '@turf/distance'
import { DateTime, Interval } from 'luxon'

import { GeoJsonPoi, LocationType } from '../../constants/maps'
import ExtendedPageModel from './ExtendedPageModel'
import LocationModel from './LocationModel'
import OpeningHoursModel from './OpeningHoursModel'
import PageModel from './PageModel'
import PoiCategoryModel from './PoiCategoryModel'

class PoiModel extends ExtendedPageModel {
  _location: LocationModel<number>
  _excerpt: string
  _metaDescription: string | null
  _website: string | null
  _phoneNumber: string | null
  _email: string | null
  _openingHours: OpeningHoursModel[] | null
  _temporarilyClosed: boolean
  _category: PoiCategoryModel
  _appointmentUrl: string | null

  constructor(params: {
    path: string
    title: string
    content: string
    thumbnail: string | null
    availableLanguages: Record<string, string>
    metaDescription: string | null
    excerpt: string
    location: LocationModel<number>
    lastUpdate: DateTime
    email: string | null
    website: string | null
    phoneNumber: string | null
    temporarilyClosed: boolean
    openingHours: OpeningHoursModel[] | null
    category: PoiCategoryModel
    appointmentUrl: string | null
  }) {
    const {
      category,
      openingHours,
      temporarilyClosed,
      location,
      excerpt,
      metaDescription,
      website,
      phoneNumber,
      email,
      appointmentUrl,
      ...other
    } = params
    super(other)
    this._location = location
    this._excerpt = excerpt
    this._metaDescription = metaDescription
    this._website = website
    this._phoneNumber = phoneNumber
    this._email = email
    this._openingHours = openingHours
    this._temporarilyClosed = temporarilyClosed
    this._category = category
    this._appointmentUrl = appointmentUrl
  }

  get location(): LocationModel<number> {
    return this._location
  }

  get excerpt(): string {
    return this._excerpt
  }

  get metaDescription(): string | null {
    return this._metaDescription
  }

  get website(): string | null {
    return this._website
  }

  get phoneNumber(): string | null {
    return this._phoneNumber
  }

  get email(): string | null {
    return this._email
  }

  private getMarkerSymbol(): string {
    const { color, iconName } = this.category
    return `${iconName}_${color}`
  }

  getFeature(): GeoJsonPoi {
    return {
      id: this.location.id,
      title: this.title,
      symbol: this.getMarkerSymbol(),
      slug: this.slug,
    }
  }

  distance(location: LocationType): number {
    return distance(location, this.location.coordinates)
  }

  get openingHours(): OpeningHoursModel[] | null {
    return this._openingHours
  }

  get temporarilyClosed(): boolean {
    return this._temporarilyClosed
  }

  get appointmentUrl(): string | null {
    return this._appointmentUrl
  }

  get category(): PoiCategoryModel {
    return this._category
  }

  get isCurrentlyOpen(): boolean {
    if (!this.openingHours) {
      return false
    }
    // isoWeekday return 1-7 for the weekdays
    const currentWeekday = DateTime.now().weekday - 1
    const currentDay = this.openingHours[currentWeekday]

    if (currentDay) {
      if (currentDay.allDay) {
        return true
      }
      const dateFormat = 't'
      const currentTime = DateTime.now().toFormat(dateFormat, { locale: 'de' })
      return currentDay.timeSlots.some(timeslot =>
        Interval.fromDateTimes(
          DateTime.fromFormat(timeslot.start, dateFormat, { locale: 'de' }),
          DateTime.fromFormat(timeslot.end, dateFormat, { locale: 'de' }),
        ).contains(DateTime.fromFormat(currentTime, dateFormat, { locale: 'de' })),
      )
    }
    return false
  }

  isEqual(other: PageModel): boolean {
    return (
      other instanceof PoiModel &&
      super.isEqual(other) &&
      this.location.isEqual(other.location) &&
      this.excerpt === other.excerpt
    )
  }
}

export default PoiModel