controllers/dashboard/years_controller.js

import { Controller } from "@hotwired/stimulus"
import { subscription } from "~/javascripts/store/mixins/subscription"

/**
 * @class Dashboard.YearsController
 * @classdesc Stimulus controller that fetches the data to populate the years and months buttons.
 * @extends Controller
 **/
export default class extends Controller {
  static targets = [ "buttonGroup", "button" ]
  static values = {
    storeId: String,
    function: String,
    status: String
  }

  /** 
   * Subscribe to the store. Setup dataVizData and then fetch years and months data
   * 
   * @instance
   * @memberof Dashboard.YearsController
   **/
  connect() {
    subscription(this)
    this.subscribe()
    if (!this.store("dataVizData")) this.editStore("dataVizData", {})
    if (!this.store("yearsAndMonths")) this.yearsAndMonths()
    
    this.reconnect()
  }

  /** 
   * Handles a repeated Turbo visit to the dashboard page.
   * 
   * @instance
   * @memberof Dashboard.YearsController
   **/
  reconnect() {
    if (this.store("selectedDataVizData")) {
      this.storeUpdated("yearsAndMonths", this.storeIdValue)
    }
  }

  /** 
   * Triggered when the years and months data is loaded. Uses a document fragment to fully create the
   * years buttons before removing the load button and adding all the new years buttons. The last button
   * is set as selected
   * 
   * @instance
   * @memberof Dashboard.YearsController
   **/
  statusValueChanged() {
    if (this.statusValue === "loaded") {
      let fragment = document.createDocumentFragment()
      this.store("years").forEach(year => {
        const buttonClone = this.buttonTarget.cloneNode(false)
        const button = fragment.appendChild(buttonClone)
        button.innerHTML = year
      });
      this.buttonTarget.remove()
      this.buttonGroupTarget.appendChild(fragment)
      this.buttonTargets[this.buttonTargets.length - 1].classList.add("selected")
    }
  }

  /** 
   * Ignores year if already clicked. Set the months data for the selected year. Set the last month as
   * selected in the store and gives the class selected to the clicked year.
   * 
   * @instance
   * @memberof Dashboard.YearsController
   **/
  yearClicked(event) {
    if (this.store("yearSelected") === parseInt(event.target.innerHTML)) return
    
    this.editStore("yearSelected", parseInt(event.target.innerHTML))
    const yearAndMonths = this.store("yearsAndMonths").find(data => {
      return data.year === this.store("yearSelected")
    })
    this.editStore("months", yearAndMonths.month_numbers)
    this.editStore("monthSelected", this.store("months")[this.store("months").length - 1])

    this.buttonTargets.forEach(buttonTarget => buttonTarget.classList.remove("selected"))
    event.target.classList.add("selected")
  }

  /** 
   * Fetch the data for years and months.
   * 
   * @instance
   * @memberof Dashboard.YearsController
   **/
  yearsAndMonths() {
    fetch("/.netlify/functions/supabase-get-functions", { 
      headers: { "Function-Name": this.functionValue }
    })
      .then(responseCheck => {
        if (!responseCheck.ok) { throw Error(responseCheck.status); }
        return responseCheck;
      })
      .then(res => res.json())
      .then(yearsAndMonths => {
        this.editStore("yearsAndMonths", yearsAndMonths)
      })
      .catch(error => {
        console.warn(error)
        this.editStore("yearsAndMonths", undefined)
      });
  }

  /** 
   * Triggered by the store whenever any store data changes. Sets us the store when yearsAndMonths data
   * has been set following the fetch statement
   * 
   * @instance
   * @memberof Dashboard.YearsController
   **/
  storeUpdated(prop, storeId) {
    if (prop === "yearsAndMonths" && storeId === this.storeIdValue) {
      this.editStore("years", this.store("yearsAndMonths").map(data => data.year))
      this.editStore("yearSelected", this.store("years")[this.store("years").length - 1])
      this.editStore(
        "months", this.store("yearsAndMonths").slice(-1).map(data => data.month_numbers).flat()
      )
      this.editStore("monthSelected", this.store("months")[this.store("months").length - 1])

      this.statusValue = "loaded"
    }
  }

  /** 
   * Unsubscribe from the store
   * 
   * @instance
   * @memberof Dashboard.YearsController
   **/
  disconnect() {
    this.statusValue = "loading"
    this.unsubscribe()
  }
}