|
|
|
|
|
class TimeFilterManager {
|
|
|
constructor() {
|
|
|
this.currentPeriod = 'daily';
|
|
|
this.currentDate = new Date().toISOString().split('T')[0];
|
|
|
this.callbacks = new Set();
|
|
|
this.init();
|
|
|
}
|
|
|
|
|
|
init() {
|
|
|
this.setupEventListeners();
|
|
|
this.initializeFilter();
|
|
|
}
|
|
|
|
|
|
setupEventListeners() {
|
|
|
|
|
|
document.addEventListener('period-changed', (event) => {
|
|
|
const { period, date } = event.detail;
|
|
|
this.handlePeriodChange(period, date);
|
|
|
});
|
|
|
|
|
|
|
|
|
document.addEventListener('keydown', (event) => {
|
|
|
if (event.ctrlKey || event.metaKey) {
|
|
|
switch (event.key) {
|
|
|
case '1':
|
|
|
event.preventDefault();
|
|
|
this.setPeriod('daily');
|
|
|
break;
|
|
|
case '2':
|
|
|
event.preventDefault();
|
|
|
this.setPeriod('weekly');
|
|
|
break;
|
|
|
case '3':
|
|
|
event.preventDefault();
|
|
|
this.setPeriod('monthly');
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
initializeFilter() {
|
|
|
|
|
|
this.triggerCallbacks();
|
|
|
}
|
|
|
|
|
|
handlePeriodChange(period, date) {
|
|
|
const previousPeriod = this.currentPeriod;
|
|
|
const previousDate = this.currentDate;
|
|
|
|
|
|
this.currentPeriod = period;
|
|
|
this.currentDate = date;
|
|
|
|
|
|
|
|
|
if (previousPeriod !== period || previousDate !== date) {
|
|
|
this.triggerCallbacks();
|
|
|
this.updateURL();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
triggerCallbacks() {
|
|
|
const data = {
|
|
|
period: this.currentPeriod,
|
|
|
date: this.currentDate,
|
|
|
timestamp: Date.now()
|
|
|
};
|
|
|
|
|
|
this.callbacks.forEach(callback => {
|
|
|
try {
|
|
|
callback(data);
|
|
|
} catch (error) {
|
|
|
console.error('Error in time filter callback:', error);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
updateURL() {
|
|
|
|
|
|
const url = new URL(window.location);
|
|
|
url.searchParams.set('period', this.currentPeriod);
|
|
|
url.searchParams.set('date', this.currentDate);
|
|
|
|
|
|
window.history.replaceState({}, '', url);
|
|
|
}
|
|
|
|
|
|
|
|
|
setPeriod(period) {
|
|
|
const filterComponent = document.querySelector('[x-data*="timeFilter"]');
|
|
|
if (filterComponent && filterComponent._x_dataStack) {
|
|
|
const alpineData = filterComponent._x_dataStack[0];
|
|
|
if (alpineData && typeof alpineData.setPeriod === 'function') {
|
|
|
alpineData.setPeriod(period);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
setDate(date) {
|
|
|
const filterComponent = document.querySelector('[x-data*="timeFilter"]');
|
|
|
if (filterComponent && filterComponent._x_dataStack) {
|
|
|
const alpineData = filterComponent._x_dataStack[0];
|
|
|
if (alpineData && typeof alpineData.setDate === 'function') {
|
|
|
alpineData.setDate(date);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
getCurrentPeriod() {
|
|
|
return this.currentPeriod;
|
|
|
}
|
|
|
|
|
|
getCurrentDate() {
|
|
|
return this.currentDate;
|
|
|
}
|
|
|
|
|
|
getCurrentSelection() {
|
|
|
return {
|
|
|
period: this.currentPeriod,
|
|
|
date: this.currentDate
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
onPeriodChange(callback) {
|
|
|
if (typeof callback === 'function') {
|
|
|
this.callbacks.add(callback);
|
|
|
|
|
|
|
|
|
callback({
|
|
|
period: this.currentPeriod,
|
|
|
date: this.currentDate,
|
|
|
timestamp: Date.now()
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
this.callbacks.delete(callback);
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
getDateRange() {
|
|
|
const date = new Date(this.currentDate);
|
|
|
|
|
|
switch (this.currentPeriod) {
|
|
|
case 'daily':
|
|
|
return {
|
|
|
start: new Date(date),
|
|
|
end: new Date(date)
|
|
|
};
|
|
|
|
|
|
case 'weekly':
|
|
|
const startOfWeek = new Date(date);
|
|
|
startOfWeek.setDate(date.getDate() - date.getDay());
|
|
|
const endOfWeek = new Date(startOfWeek);
|
|
|
endOfWeek.setDate(startOfWeek.getDate() + 6);
|
|
|
|
|
|
return {
|
|
|
start: startOfWeek,
|
|
|
end: endOfWeek
|
|
|
};
|
|
|
|
|
|
case 'monthly':
|
|
|
const startOfMonth = new Date(date.getFullYear(), date.getMonth(), 1);
|
|
|
const endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
|
|
|
|
return {
|
|
|
start: startOfMonth,
|
|
|
end: endOfMonth
|
|
|
};
|
|
|
|
|
|
default:
|
|
|
return {
|
|
|
start: new Date(date),
|
|
|
end: new Date(date)
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
formatDateForAPI() {
|
|
|
return this.currentDate;
|
|
|
}
|
|
|
|
|
|
getPeriodLabel() {
|
|
|
const labels = {
|
|
|
daily: 'Daily',
|
|
|
weekly: 'Weekly',
|
|
|
monthly: 'Monthly'
|
|
|
};
|
|
|
|
|
|
return labels[this.currentPeriod] || 'Daily';
|
|
|
}
|
|
|
|
|
|
|
|
|
goToPrevious() {
|
|
|
const date = new Date(this.currentDate);
|
|
|
|
|
|
switch (this.currentPeriod) {
|
|
|
case 'daily':
|
|
|
date.setDate(date.getDate() - 1);
|
|
|
break;
|
|
|
case 'weekly':
|
|
|
date.setDate(date.getDate() - 7);
|
|
|
break;
|
|
|
case 'monthly':
|
|
|
date.setMonth(date.getMonth() - 1);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
this.setDate(date.toISOString().split('T')[0]);
|
|
|
}
|
|
|
|
|
|
goToNext() {
|
|
|
const date = new Date(this.currentDate);
|
|
|
|
|
|
switch (this.currentPeriod) {
|
|
|
case 'daily':
|
|
|
date.setDate(date.getDate() + 1);
|
|
|
break;
|
|
|
case 'weekly':
|
|
|
date.setDate(date.getDate() + 7);
|
|
|
break;
|
|
|
case 'monthly':
|
|
|
date.setMonth(date.getMonth() + 1);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
this.setDate(date.toISOString().split('T')[0]);
|
|
|
}
|
|
|
|
|
|
goToToday() {
|
|
|
this.setDate(new Date().toISOString().split('T')[0]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
let timeFilterManager;
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
timeFilterManager = new TimeFilterManager();
|
|
|
|
|
|
|
|
|
window.timeFilterManager = timeFilterManager;
|
|
|
});
|
|
|
|
|
|
export { TimeFilterManager }; |