Untitled

mail@pastecode.io avatar
unknown
javascript
5 months ago
7.0 kB
2
Indexable
document.addEventListener('alpine:init', () => {

  Alpine.data('transdevApp', () => ({

    scheduleTickNr: 0,
    adsTickNr: 0,
    lastSuccessfulAPIFetch: '',

    heapSize: '',
    loadsInProgress: 0,
    hasErrors: false,
    firstDataGet: false,
    adsLayerVisible: false,
    currentAd: -1,
    scheduleData: [] as ScheduleEntity[],

    appSettings: { ...appDefaults, ...window.appSettings },

    ads: window.initialAds,
    newAds: [] as Advertisement[] | false,

    get availableAds(): Advertisement[] {
      return this.ads.filter((ad) => this.isCurrentTimeBetween(ad.visible_time_from, ad.visible_time_to));
    },

    /**
     * Returns true if current time is between startTime and endTime
     * If startTime > endTime, it is assumed that the time range is over midnight
     * @param startTime 
     * @param endTime 
     */
    isCurrentTimeBetween: (startTime: string | null | undefined, endTime: string | null | undefined): boolean => {
      if (!startTime || !endTime || startTime === '' || endTime === '') return true;
      const currentTime = new Date();
      const currentMs = currentTime.getHours() * 60 * 60 * 1000 +
        currentTime.getMinutes() * 60 * 1000 +
        currentTime.getSeconds() * 1000 +
        currentTime.getMilliseconds();

      const [startHours, startMinutes] = startTime.split(':').map(Number);
      const [endHours, endMinutes] = endTime.split(':').map(Number);

      const startMs = startHours * 60 * 60 * 1000 + startMinutes * 60 * 1000;
      const endMs = endHours * 60 * 60 * 1000 + endMinutes * 60 * 1000;

      if (startMs < endMs) {
        return currentMs >= startMs && currentMs <= endMs;
      } else {
        return currentMs >= startMs || currentMs <= endMs;
      }
    },
    loadAdsList: ()=>{},

    init() {

      const hardcodedDepartures: Departure[] = [
        {
          id: 1,
          station_id: 1,
          type: 'platform',
          state: 'OK',
          platform: '1',
          transport_full_name: 'bus',
          transport_name: '707',
          transport_number: '1',
          transport_description: null,
          transport_class: null,
          transport_operator: null,
          origin_name: null,
          destination_name: 'Zuhause',
          hints: null,
          departure_planned: '2024-08-02T03:55:25.000000Z',
          departure_estimated: null,
          departure_delay: 5,
          created_at: '2024-08-02T03:55:25.000000Z',
          updated_at: '2024-08-02T03:55:25.000000Z'
        },
        // Add more hardcoded departure objects as needed
      ];

      const parseResponse = (response: Departure[]): ScheduleEntity[] => {
        return response.map((entity) => {
          const departureTime = new Date(entity.departure_planned);
          const estimatedTime = entity.departure_estimated === null ? new Date(0) : new Date(entity.departure_estimated);

          const connection: ScheduleEntity = {
            platform: entity.platform,

            departureTime,
            estimatedTime,
            departureString: getTimeGerman(departureTime),
            estimatedString: getTimeGerman(estimatedTime),

            destination: entity.destination_name,

            transportTitle: entity.transport_name
              ? `${entity.transport_name} ${entity.transport_number}`
              : (entity.transport_full_name || null),

            transportClass: entity.transport_class,
            transportIcon: getTranportIcon(entity.transport_class),

            hint: entity.hints || '',

            delay: (estimatedTime > departureTime) ? (estimatedTime.getTime() - departureTime.getTime()) / (60 * 1000) : 0

          };
          return connection;
        }).sort((a, b) => a.departureTime.getTime() - b.departureTime.getTime());
      };

      const getTranportIcon = (transportClass: TransportClass): string | null => {
        switch (transportClass) {

          case 'BUS':
          case 'CITY_BUS':
          case 'EXPRESS_BUS':
          case 'REGIONAL_BUS':
          case 'CALL_BUS':
          case 'CITIZEN_BUS':
            return 'busLogo.svg';

          case 'TRAM':
          case 'UNDERGROUND':
            return 'tramLogo.svg';

          case 'REGIONAL_TRAIN':
          case 'NATIONAL_TRAIN':
          case 'INTERNATIONAL_TRAIN':
            return 'trainLogo.svg';

          case 'SUBURBAN_TRAIN':
            return 'sLogo.svg';

          default:
            return null;
        }
      }

      const getTimeGerman = (date: Date) => {
        return date.toLocaleDateString('de-DE', { hour: 'numeric', minute: 'numeric' }).split(',')[1];
      };

      const doAppTick = async () => {
        this.scheduleTickNr++;
        const departuresData = hardcodedDepartures;

        if (departuresData !== null) {

          try {
            this.lastSuccessfulAPIFetch = (new Date()).toLocaleDateString('de-DE', { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });
            this.firstDataGet = true;
            this.scheduleData = parseResponse(departuresData);
          } catch (error) {
            this.hasErrors = true;
            throw new Error('Error in departures API response:' + error);
          }

          return;
        }
      };

      const findNextAdIndex = (ads: Partial<Advertisement>[]) => {
        const nextAd = ads.findIndex(ad => ad.id === this.currentAd);
        if (nextAd === -1) {
          return 0;
        }
        return nextAd === (ads.length - 1) ? 0 : nextAd + 1;
      }

      /**
       * Tick load ads, but they updates only if they are in not visible time range
       */
      const doAdsTick = () => {
        this.adsTickNr++;

        let defaultSpaceBetweenAds = this.appSettings.departuresInterval * 1000;
        // const availableAds = ads.filter((ad) => isCurrentTimeBetween(ad.visible_time_from, ad.visible_time_to));

        if (this.availableAds.length === 0) {
          // do nothing
          setTimeout(() => {
            checkNewAds();
            doAdsTick();
          }, defaultSpaceBetweenAds);
          return;
        }

        const nextAdIndex = findNextAdIndex(this.availableAds);
        const currentAdVisibilityTime = () => {
          return this.availableAds[nextAdIndex].ad_interval ? this.availableAds[nextAdIndex].ad_interval! * 1000 : this.appSettings.adInterval * 1000;
        }

        this.currentAd = this.availableAds[nextAdIndex].id!;
        this.adsLayerVisible = true;

        setTimeout(() => {
          this.adsLayerVisible = false;
          checkNewAds();
        }, currentAdVisibilityTime());

        setTimeout(() => {
          doAdsTick();
        }, currentAdVisibilityTime() + defaultSpaceBetweenAds);
      }

      const checkNewAds = () => {
        if (this.newAds !== false && this.newAds.length > 0) {
          this.ads = this.newAds;
          this.newAds = [];
        }
      }

      this.loadAdsList = async () => {
        const adsData = window.initialAds; // 
Leave a Comment