diff --git a/lib/rbui/calendar/calendar_controller.js b/lib/rbui/calendar/calendar_controller.js index d7682b6..bc669a1 100644 --- a/lib/rbui/calendar/calendar_controller.js +++ b/lib/rbui/calendar/calendar_controller.js @@ -1,5 +1,4 @@ import { Controller } from "@hotwired/stimulus"; -import { format } from "date-fns"; // See https://date-fns.org/v2.30.0/docs/format for more options import Mustache from "mustache"; export default class extends Controller { @@ -15,53 +14,53 @@ export default class extends Controller { }, format: { type: String, - default: "yyyy-MM-dd" // See https://date-fns.org/v2.30.0/docs/format for more options + default: "yyyy-MM-dd" // Default format } }; static outlets = ["rbui--calendar-input"] initialize() { - this.updateCalendar() // Initial calendar render + this.updateCalendar(); // Initial calendar render } nextMonth(e) { - e.preventDefault() + e.preventDefault(); this.viewDateValue = this.adjustMonth(1); } prevMonth(e) { - e.preventDefault() + e.preventDefault(); this.viewDateValue = this.adjustMonth(-1); } selectDay(e) { - e.preventDefault() + e.preventDefault(); // Set the selected date value - this.selectedDateValue = e.currentTarget.dataset.day + this.selectedDateValue = e.currentTarget.dataset.day; } selectedDateValueChanged(value, prevValue) { // update the viewDateValue to the first day of month of the selected date (This will trigger updateCalendar() function) - const newViewDate = new Date(this.selectedDateValue) + const newViewDate = new Date(this.selectedDateValue); newViewDate.setDate(2); // set the day to the 2nd (to avoid issues with months with different number of days and timezones) this.viewDateValue = newViewDate.toISOString().slice(0, 10); // Re-render the calendar - this.updateCalendar() + this.updateCalendar(); // update the input value this.rbuiCalendarInputOutlets.forEach(outlet => { - const formattedDate = this.formatDate(this.selectedDate()) - outlet.setValue(formattedDate) - }) + const formattedDate = this.formatDate(this.selectedDate()); + outlet.setValue(formattedDate); + }); } viewDateValueChanged(value, prevValue) { - this.updateCalendar() + this.updateCalendar(); } adjustMonth(adjustment) { - const date = this.viewDate() + const date = this.viewDate(); date.setDate(2); // set the day to the 2nd (to avoid issues with months with different number of days and timezones) date.setMonth(date.getMonth() + adjustment); return date.toISOString().slice(0, 10); @@ -74,44 +73,44 @@ export default class extends Controller { } calendarHTML() { - return this.weekdaysTemplateTarget.innerHTML + this.calendarDays() + return this.weekdaysTemplateTarget.innerHTML + this.calendarDays(); } calendarDays() { - return this.getFullWeeksStartAndEndInMonth().map(week => this.renderWeek(week)).join('') + return this.getFullWeeksStartAndEndInMonth().map(week => this.renderWeek(week)).join(''); } renderWeek(week) { const days = week.map(day => { - return this.renderDay(day) - }).join('') - return `${days}` + return this.renderDay(day); + }).join(''); + return `${days}`; } renderDay(day) { - const today = new Date() - let dateHTML = '' - const data = { day: day, dayDate: day.getDate() } + const today = new Date(); + let dateHTML = ''; + const data = { day: day, dayDate: day.getDate() }; if (day.toDateString() === this.selectedDate().toDateString()) { // selectedDate // Render the selected date template target innerHTML with Mustache - dateHTML = Mustache.render(this.selectedDateTemplateTarget.innerHTML, data) + dateHTML = Mustache.render(this.selectedDateTemplateTarget.innerHTML, data); } else if (day.toDateString() === today.toDateString()) { // todayDate - dateHTML = Mustache.render(this.todayDateTemplateTarget.innerHTML, data) + dateHTML = Mustache.render(this.todayDateTemplateTarget.innerHTML, data); } else if (day.getMonth() === this.viewDate().getMonth()) { - // currentMonthDaTE - dateHTML = Mustache.render(this.currentMonthDateTemplateTarget.innerHTML, data) + // currentMonthDate + dateHTML = Mustache.render(this.currentMonthDateTemplateTarget.innerHTML, data); } else { // otherMonthDate - dateHTML = Mustache.render(this.otherMonthDateTemplateTarget.innerHTML, data) + dateHTML = Mustache.render(this.otherMonthDateTemplateTarget.innerHTML, data); } - return dateHTML + return dateHTML; } monthAndYear() { - const month = this.viewDate().toLocaleString("default", { month: "long" }); + const month = this.viewDate().toLocaleString("en-US", { month: "long" }); const year = this.viewDate().getFullYear(); return `${month} ${year}`; } @@ -121,7 +120,7 @@ export default class extends Controller { } viewDate() { - return this.viewDateValue ? new Date(this.viewDateValue) : this.selectedDate() + return this.viewDateValue ? new Date(this.viewDateValue) : this.selectedDate(); } getFullWeeksStartAndEndInMonth() { @@ -131,26 +130,26 @@ export default class extends Controller { let weeks = [], firstDate = new Date(year, month, 1), lastDate = new Date(year, month + 1, 0), - numDays = lastDate.getDate() + numDays = lastDate.getDate(); - let start = 1 - let end + let start = 1; + let end; if (firstDate.getDay() === 1) { - end = 7 + end = 7; } else if (firstDate.getDay() === 0) { - let preMonthEndDay = new Date(year, month, 0) - start = preMonthEndDay.getDate() - 6 + 1 - end = 1 + let preMonthEndDay = new Date(year, month, 0); + start = preMonthEndDay.getDate() - 6 + 1; + end = 1; } else { - let preMonthEndDay = new Date(year, month, 0) - start = preMonthEndDay.getDate() + 1 - firstDate.getDay() + 1 - end = 7 - firstDate.getDay() + 1 + let preMonthEndDay = new Date(year, month, 0); + start = preMonthEndDay.getDate() + 1 - firstDate.getDay() + 1; + end = 7 - firstDate.getDay() + 1; weeks.push({ start: start, end: end - }) - start = end + 1 - end = end + 7 + }); + start = end + 1; + end = end + 7; } while (start <= numDays) { weeks.push({ @@ -161,12 +160,12 @@ export default class extends Controller { end = end + 7; end = start === 1 && end === 8 ? 1 : end; if (end > numDays && start <= numDays) { - end = end - numDays + end = end - numDays; weeks.push({ start: start, end: end - }) - break + }); + break; } } // *** the magic starts here @@ -176,10 +175,46 @@ export default class extends Controller { const date = new Date(year, month - sub, start + index); return date; }); - })//.flat(Infinity); + }); } formatDate(date) { - return format(date, this.formatValue); + const format = this.formatValue; + const day = date.getDate(); + const month = date.getMonth() + 1; + const year = date.getFullYear(); + const hours = date.getHours(); + const minutes = date.getMinutes(); + const seconds = date.getSeconds(); + const dayOfWeek = date.toLocaleString("en-US", { weekday: "long" }); + const monthName = date.toLocaleString("en-US", { month: "long" }); + const daySuffix = this.getDaySuffix(day); + + + const map = { + 'yyyy': year, + 'MM': ('0' + month).slice(-2), + 'dd': ('0' + day).slice(-2), + 'HH': ('0' + hours).slice(-2), + 'mm': ('0' + minutes).slice(-2), + 'ss': ('0' + seconds).slice(-2), + 'EEEE': dayOfWeek, + 'MMMM': monthName, + 'do': day + daySuffix, + 'PPPP': `${dayOfWeek}, ${monthName} ${day}${daySuffix}, ${year}` + }; + + const formattedDate = format.replace(/yyyy|MM|dd|HH|mm|ss|EEEE|MMMM|do|PPPP/g, matched => map[matched]); + return formattedDate; + } + + getDaySuffix(day) { + if (day > 3 && day < 21) return 'th'; + switch (day % 10) { + case 1: return "st"; + case 2: return "nd"; + case 3: return "rd"; + default: return "th"; + } } -} +} \ No newline at end of file