import { Controller } from "@hotwired/stimulus"
import { subscription } from "~/javascripts/store/mixins/subscription"
const monthMapper = {
1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "May", 6: "Jun", 7: "Jul", 8: "Aug", 9: "Sep", 10: "Oct",
11: "Nov", 12: "Dec"
}
/**
* @class Dashboard.MonthsController
* @classdesc Stimulus controller that handles the months buttons data and interaction.
* @extends Controller
**/
export default class extends Controller {
static targets = [ "buttonGroup", "button" ]
static values = {
function: String,
storeId: String,
yearSelected: Number
}
/**
* Subscribe to the store.
*
* @instance
* @memberof Dashboard.MonthsController
**/
connect() {
subscription(this)
this.subscribe()
this.reconnect()
}
/**
* Handles a repeated Turbo visit to the dashboard page.
*
* @instance
* @memberof Dashboard.MonthsController
**/
reconnect() {
if (this.store("selectedDataVizData")) {
this.storeUpdated("monthSelected", this.storeIdValue)
}
}
/**
* Triggered when a year is set. Uses a document fragment to fully create the
* months buttons before removing the load button and adding all the new months buttons. The last
* button is set as selected
*
* @instance
* @memberof Dashboard.MonthsController
**/
yearSelectedValueChanged() {
if (this.yearSelectedValue !== 0) {
const yearAndMonths = this.store("yearsAndMonths").find(data => data.year === this.yearSelectedValue)
let fragment = document.createDocumentFragment()
yearAndMonths.month_numbers.forEach(monthNumber => {
const buttonClone = this.buttonTarget.cloneNode(false)
const button = fragment.appendChild(buttonClone)
button.innerHTML = monthMapper[monthNumber]
});
this.buttonTargets.forEach(buttonTarget => buttonTarget.remove())
this.buttonGroupTarget.appendChild(fragment)
this.buttonTargets.forEach(buttonTarget => buttonTarget.classList.remove("selected"))
this.buttonTargets[this.buttonTargets.length - 1].classList.add("selected")
}
}
/**
* Ignores month if already clicked. Set the month clicked as selected in the store and gives the class
* selected to the clicked month.
*
* @instance
* @memberof Dashboard.MonthsController
**/
monthClicked(event) {
if (this.store("monthSelected") === parseInt(event.target.innerHTML)) return
this.editStore(
"monthSelected",
parseInt(Object.keys(monthMapper).find(key => monthMapper[key] === event.target.innerHTML))
)
this.buttonTargets.forEach(buttonTarget => buttonTarget.classList.remove("selected"))
event.target.classList.add("selected")
}
/**
* Fetch all of the data for the selected month. If the data for the month is already present
* then it does not fetch again.
*
* @instance
* @memberof Dashboard.MonthsController
**/
fetchDataVizData() {
const year = this.store("yearSelected")
const month =this.store("monthSelected")
const data = this.store("dataVizData")[`${year}${month}`]
if (data) {
this.editStore("selectedDataVizData", data)
} else {
this.editStore("fetchingDataVizData", true)
fetch(`/.netlify/functions/supabase-get-api?year=${year}&month=${month}`, {
headers: { "Function-Name": this.functionValue }
})
.then(responseCheck => {
if (!responseCheck.ok) { throw Error(responseCheck.status); }
return responseCheck;
})
.then(res => res.json())
.then(fetchedData => {
this.editStore("fetchingDataVizData", false)
let dataToUpdate = this.store("dataVizData")
dataToUpdate[`${year}${month}`] = fetchedData
this.editStore("dataVizData", dataToUpdate)
this.editStore("selectedDataVizData", this.store("dataVizData")[`${year}${month}`])
})
.catch(error => {
console.warn(error)
this.editStore("fetchingDataVizData", false)
});
}
}
/**
* Triggered by the store whenever any store data changes. Fetches the relevant data when a month is
* selected
*
* @instance
* @memberof Dashboard.MonthsController
**/
storeUpdated(prop, storeId) {
this.yearSelectedValue = this.store("yearSelected")
if (prop === "monthSelected" && storeId === this.storeIdValue) this.fetchDataVizData()
}
/**
* Unsubscribe from the store
*
* @instance
* @memberof Dashboard.MonthsController
**/
disconnect() {
this.yearSelectedValue = ""
this.unsubscribe()
}
}