Adds work week configuration feature
Implements configurable work week presets, allowing users to customize the days displayed in the calendar. This includes: - Defining work week settings (work days, day names, total days). - Providing predefined work week presets (standard, compressed, weekend, full week). - Adding UI elements to switch between presets. - Updating grid and header rendering logic to reflect the selected work week. - Emitting events when the work week changes, triggering necessary UI updates and data re-renders. This provides a more flexible and personalized calendar experience.
This commit is contained in:
parent
26f0cb8aaa
commit
d017d48bd6
11 changed files with 283 additions and 34 deletions
|
|
@ -13,6 +13,7 @@ export const EventTypes = {
|
|||
CONFIG_UPDATE: 'calendar:configupdate',
|
||||
CALENDAR_TYPE_CHANGED: 'calendar:calendartypechanged',
|
||||
SELECTED_DATE_CHANGED: 'calendar:selecteddatechanged',
|
||||
WORKWEEK_CHANGED: 'calendar:workweekchanged',
|
||||
|
||||
// View change events
|
||||
VIEW_CHANGE: 'calendar:viewchange',
|
||||
|
|
@ -86,7 +87,7 @@ export const EventTypes = {
|
|||
// Management events (legacy - prefer StateEvents)
|
||||
REFRESH_REQUESTED: 'calendar:refreshrequested',
|
||||
RESET_REQUESTED: 'calendar:resetrequested',
|
||||
CALENDAR_REFRESH_REQUESTED: 'calendar:refreshrequested',
|
||||
CALENDAR_REFRESH_REQUESTED: 'calendar:calendarrefreshrequested',
|
||||
CALENDAR_RESET: 'calendar:reset',
|
||||
|
||||
// System events
|
||||
|
|
|
|||
|
|
@ -35,6 +35,17 @@ interface DateViewSettings {
|
|||
showAllDay: boolean; // Show all-day event row
|
||||
}
|
||||
|
||||
/**
|
||||
* Work week configuration settings
|
||||
*/
|
||||
interface WorkWeekSettings {
|
||||
id: string;
|
||||
workDays: number[]; // [1,2,3,4,5] for mon-fri
|
||||
dayNames: string[]; // ['Mon','Tue','Wed','Thu','Fri']
|
||||
totalDays: number; // 5
|
||||
firstWorkDay: number; // 1 = Monday
|
||||
}
|
||||
|
||||
/**
|
||||
* View settings for resource-based calendar mode
|
||||
*/
|
||||
|
|
@ -57,6 +68,7 @@ export class CalendarConfig {
|
|||
private gridSettings: GridSettings;
|
||||
private dateViewSettings: DateViewSettings;
|
||||
private resourceViewSettings: ResourceViewSettings;
|
||||
private currentWorkWeek: string = 'standard';
|
||||
|
||||
constructor() {
|
||||
this.config = {
|
||||
|
|
@ -422,6 +434,83 @@ export class CalendarConfig {
|
|||
date: date
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get work week presets
|
||||
*/
|
||||
private getWorkWeekPresets(): { [key: string]: WorkWeekSettings } {
|
||||
return {
|
||||
'standard': {
|
||||
id: 'standard',
|
||||
workDays: [1,2,3,4,5],
|
||||
dayNames: ['Mon','Tue','Wed','Thu','Fri'],
|
||||
totalDays: 5,
|
||||
firstWorkDay: 1
|
||||
},
|
||||
'compressed': {
|
||||
id: 'compressed',
|
||||
workDays: [1,2,3,4],
|
||||
dayNames: ['Mon','Tue','Wed','Thu'],
|
||||
totalDays: 4,
|
||||
firstWorkDay: 1
|
||||
},
|
||||
'midweek': {
|
||||
id: 'midweek',
|
||||
workDays: [3,4,5],
|
||||
dayNames: ['Wed','Thu','Fri'],
|
||||
totalDays: 3,
|
||||
firstWorkDay: 3
|
||||
},
|
||||
'weekend': {
|
||||
id: 'weekend',
|
||||
workDays: [6,0],
|
||||
dayNames: ['Sat','Sun'],
|
||||
totalDays: 2,
|
||||
firstWorkDay: 6
|
||||
},
|
||||
'fullweek': {
|
||||
id: 'fullweek',
|
||||
workDays: [0,1,2,3,4,5,6],
|
||||
dayNames: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
|
||||
totalDays: 7,
|
||||
firstWorkDay: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current work week settings
|
||||
*/
|
||||
getWorkWeekSettings(): WorkWeekSettings {
|
||||
const presets = this.getWorkWeekPresets();
|
||||
return presets[this.currentWorkWeek] || presets['standard'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set work week preset
|
||||
*/
|
||||
setWorkWeek(workWeekId: string): void {
|
||||
const presets = this.getWorkWeekPresets();
|
||||
if (presets[workWeekId]) {
|
||||
this.currentWorkWeek = workWeekId;
|
||||
|
||||
// Update dateViewSettings to match work week
|
||||
this.dateViewSettings.weekDays = presets[workWeekId].totalDays;
|
||||
|
||||
// Emit work week change event
|
||||
eventBus.emit(EventTypes.WORKWEEK_CHANGED, {
|
||||
workWeekId: workWeekId,
|
||||
settings: presets[workWeekId]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current work week ID
|
||||
*/
|
||||
getCurrentWorkWeek(): string {
|
||||
return this.currentWorkWeek;
|
||||
}
|
||||
}
|
||||
|
||||
// Create singleton instance
|
||||
|
|
|
|||
|
|
@ -264,6 +264,13 @@ export class CalendarManager {
|
|||
this.refresh();
|
||||
});
|
||||
|
||||
// Lyt efter workweek changes
|
||||
this.eventBus.on(EventTypes.WORKWEEK_CHANGED, (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
console.log('CalendarManager: Workweek changed to', customEvent.detail.workWeekId);
|
||||
this.handleWorkweekChange();
|
||||
});
|
||||
|
||||
// Lyt efter reset requests
|
||||
this.eventBus.on(EventTypes.RESET_REQUESTED, () => {
|
||||
this.reset();
|
||||
|
|
@ -281,7 +288,8 @@ export class CalendarManager {
|
|||
nextDate.setDate(nextDate.getDate() + 1);
|
||||
break;
|
||||
case 'week':
|
||||
nextDate.setDate(nextDate.getDate() + 7);
|
||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
||||
nextDate.setDate(nextDate.getDate() + 7); // Move to next calendar week regardless of work days
|
||||
break;
|
||||
case 'month':
|
||||
nextDate.setMonth(nextDate.getMonth() + 1);
|
||||
|
|
@ -302,7 +310,8 @@ export class CalendarManager {
|
|||
previousDate.setDate(previousDate.getDate() - 1);
|
||||
break;
|
||||
case 'week':
|
||||
previousDate.setDate(previousDate.getDate() - 7);
|
||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
||||
previousDate.setDate(previousDate.getDate() - 7); // Move to previous calendar week regardless of work days
|
||||
break;
|
||||
case 'month':
|
||||
previousDate.setMonth(previousDate.getMonth() - 1);
|
||||
|
|
@ -370,4 +379,42 @@ export class CalendarManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle workweek configuration changes
|
||||
*/
|
||||
private handleWorkweekChange(): void {
|
||||
console.log('CalendarManager: Handling workweek change - forcing full grid rebuild');
|
||||
|
||||
// Force a complete grid rebuild by clearing existing structure
|
||||
const container = document.querySelector('swp-calendar-container');
|
||||
if (container) {
|
||||
container.innerHTML = ''; // Clear everything to force full rebuild
|
||||
}
|
||||
|
||||
// Re-render the grid with new workweek settings (will now rebuild everything)
|
||||
this.gridManager.render();
|
||||
|
||||
// Re-initialize scroll manager after grid rebuild
|
||||
this.scrollManager.initialize();
|
||||
|
||||
// Re-render events in the new grid structure
|
||||
this.rerenderEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-render events after grid structure changes
|
||||
*/
|
||||
private rerenderEvents(): void {
|
||||
console.log('CalendarManager: Re-rendering events for new workweek');
|
||||
|
||||
// Get current period data to determine date range
|
||||
const periodData = this.calculateCurrentPeriod();
|
||||
|
||||
// Trigger event rendering for the current date range
|
||||
this.eventRenderer.renderEventsForDateRange(
|
||||
periodData.startDate,
|
||||
periodData.endDate
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { IEventBus } from '../types/CalendarTypes.js';
|
|||
import { DateUtils } from '../utils/DateUtils.js';
|
||||
import { EventTypes } from '../constants/EventTypes.js';
|
||||
import { NavigationRenderer } from '../renderers/NavigationRenderer.js';
|
||||
import { calendarConfig } from '../core/CalendarConfig.js';
|
||||
|
||||
/**
|
||||
* NavigationManager handles calendar navigation (prev/next/today buttons)
|
||||
|
|
@ -17,7 +18,7 @@ export class NavigationManager {
|
|||
constructor(eventBus: IEventBus) {
|
||||
console.log('🧭 NavigationManager: Constructor called');
|
||||
this.eventBus = eventBus;
|
||||
this.navigationRenderer = new NavigationRenderer(eventBus);
|
||||
this.navigationRenderer = new NavigationRenderer(eventBus, calendarConfig);
|
||||
this.currentWeek = DateUtils.getWeekStart(new Date(), 0); // Sunday start like POC
|
||||
this.targetWeek = new Date(this.currentWeek);
|
||||
this.init();
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ export class ViewManager {
|
|||
|
||||
// Setup view button handlers
|
||||
this.setupViewButtonHandlers();
|
||||
|
||||
// Setup workweek preset button handlers
|
||||
this.setupWorkweekButtonHandlers();
|
||||
}
|
||||
|
||||
private setupViewButtonHandlers(): void {
|
||||
|
|
@ -48,8 +51,22 @@ export class ViewManager {
|
|||
});
|
||||
}
|
||||
|
||||
private setupWorkweekButtonHandlers(): void {
|
||||
const workweekButtons = document.querySelectorAll('swp-preset-button[data-workweek]');
|
||||
workweekButtons.forEach(button => {
|
||||
button.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
const workweekId = button.getAttribute('data-workweek');
|
||||
if (workweekId) {
|
||||
this.changeWorkweek(workweekId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private initializeView(): void {
|
||||
this.updateViewButtons();
|
||||
this.updateWorkweekButtons();
|
||||
|
||||
this.eventBus.emit(EventTypes.VIEW_RENDERED, {
|
||||
view: this.currentView
|
||||
|
|
@ -72,6 +89,18 @@ export class ViewManager {
|
|||
});
|
||||
}
|
||||
|
||||
private changeWorkweek(workweekId: string): void {
|
||||
console.log(`ViewManager: Changing workweek to ${workweekId}`);
|
||||
|
||||
// Update the calendar config
|
||||
calendarConfig.setWorkWeek(workweekId);
|
||||
|
||||
// Update button states
|
||||
this.updateWorkweekButtons();
|
||||
|
||||
// Trigger a calendar refresh to apply the new workweek
|
||||
this.eventBus.emit(EventTypes.REFRESH_REQUESTED);
|
||||
}
|
||||
|
||||
private updateViewButtons(): void {
|
||||
const viewButtons = document.querySelectorAll('swp-view-button[data-view]');
|
||||
|
|
@ -85,6 +114,20 @@ export class ViewManager {
|
|||
});
|
||||
}
|
||||
|
||||
private updateWorkweekButtons(): void {
|
||||
const currentWorkweek = calendarConfig.getCurrentWorkWeek();
|
||||
const workweekButtons = document.querySelectorAll('swp-preset-button[data-workweek]');
|
||||
|
||||
workweekButtons.forEach(button => {
|
||||
const buttonWorkweek = button.getAttribute('data-workweek');
|
||||
if (buttonWorkweek === currentWorkweek) {
|
||||
button.setAttribute('data-active', 'true');
|
||||
} else {
|
||||
button.removeAttribute('data-active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private refreshCurrentView(): void {
|
||||
this.eventBus.emit(EventTypes.VIEW_RENDERED, {
|
||||
view: this.currentView
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export class DateColumnRenderer implements ColumnRenderer {
|
|||
render(columnContainer: HTMLElement, context: ColumnRenderContext): void {
|
||||
const { currentWeek, config } = context;
|
||||
|
||||
const dates = this.getWeekDates(currentWeek);
|
||||
const dates = this.getWeekDates(currentWeek, config);
|
||||
const dateSettings = config.getDateViewSettings();
|
||||
const daysToShow = dates.slice(0, dateSettings.weekDays);
|
||||
|
||||
|
|
@ -43,13 +43,20 @@ export class DateColumnRenderer implements ColumnRenderer {
|
|||
});
|
||||
}
|
||||
|
||||
private getWeekDates(weekStart: Date): Date[] {
|
||||
private getWeekDates(weekStart: Date, config: CalendarConfig): Date[] {
|
||||
const dates: Date[] = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const workWeekSettings = config.getWorkWeekSettings();
|
||||
|
||||
// Calculate dates based on actual work days (e.g., [1,2,3,4] for Mon-Thu)
|
||||
workWeekSettings.workDays.forEach(dayOfWeek => {
|
||||
const date = new Date(weekStart);
|
||||
date.setDate(weekStart.getDate() + i);
|
||||
// Set to the start of the week (Sunday = 0)
|
||||
date.setDate(weekStart.getDate() - weekStart.getDay());
|
||||
// Add the specific day of week
|
||||
date.setDate(date.getDate() + dayOfWeek);
|
||||
dates.push(date);
|
||||
}
|
||||
});
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,19 +60,21 @@ export class GridStyleManager {
|
|||
return resourceData.resources.length;
|
||||
} else if (calendarType === 'date') {
|
||||
const dateSettings = this.config.getDateViewSettings();
|
||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
||||
|
||||
switch (dateSettings.period) {
|
||||
case 'day':
|
||||
return 1;
|
||||
case 'week':
|
||||
return dateSettings.weekDays;
|
||||
return workWeekSettings.totalDays;
|
||||
case 'month':
|
||||
return 7;
|
||||
return workWeekSettings.totalDays; // Use work week for month view too
|
||||
default:
|
||||
return dateSettings.weekDays;
|
||||
return workWeekSettings.totalDays;
|
||||
}
|
||||
}
|
||||
|
||||
return 7; // Default
|
||||
return this.config.getWorkWeekSettings().totalDays; // Default to work week
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,18 +27,19 @@ export class DateHeaderRenderer implements HeaderRenderer {
|
|||
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
|
||||
const { currentWeek, config, allDayEvents = [] } = context;
|
||||
|
||||
const dates = this.getWeekDates(currentWeek);
|
||||
const dates = this.getWeekDates(currentWeek, config);
|
||||
const weekDays = config.get('weekDays');
|
||||
const daysToShow = dates.slice(0, weekDays);
|
||||
|
||||
daysToShow.forEach((date) => {
|
||||
const workWeekSettings = config.getWorkWeekSettings();
|
||||
daysToShow.forEach((date, index) => {
|
||||
const header = document.createElement('swp-day-header');
|
||||
if (this.isToday(date)) {
|
||||
(header as any).dataset.today = 'true';
|
||||
}
|
||||
|
||||
header.innerHTML = `
|
||||
<swp-day-name>${this.getDayName(date)}</swp-day-name>
|
||||
<swp-day-name>${workWeekSettings.dayNames[index]}</swp-day-name>
|
||||
<swp-day-date>${date.getDate()}</swp-day-date>
|
||||
`;
|
||||
(header as any).dataset.date = this.formatDate(date);
|
||||
|
|
@ -53,7 +54,7 @@ export class DateHeaderRenderer implements HeaderRenderer {
|
|||
private renderAllDayEvents(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
|
||||
const { currentWeek, config, allDayEvents = [] } = context;
|
||||
|
||||
const dates = this.getWeekDates(currentWeek);
|
||||
const dates = this.getWeekDates(currentWeek, config);
|
||||
const weekDays = config.get('weekDays');
|
||||
const daysToShow = dates.slice(0, weekDays);
|
||||
|
||||
|
|
@ -101,13 +102,20 @@ export class DateHeaderRenderer implements HeaderRenderer {
|
|||
});
|
||||
}
|
||||
|
||||
private getWeekDates(weekStart: Date): Date[] {
|
||||
private getWeekDates(weekStart: Date, config: CalendarConfig): Date[] {
|
||||
const dates: Date[] = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const workWeekSettings = config.getWorkWeekSettings();
|
||||
|
||||
// Calculate dates based on actual work days (e.g., [1,2,3,4] for Mon-Thu)
|
||||
workWeekSettings.workDays.forEach(dayOfWeek => {
|
||||
const date = new Date(weekStart);
|
||||
date.setDate(weekStart.getDate() + i);
|
||||
// Set to the start of the week (Sunday = 0)
|
||||
date.setDate(weekStart.getDate() - weekStart.getDay());
|
||||
// Add the specific day of week
|
||||
date.setDate(date.getDate() + dayOfWeek);
|
||||
dates.push(date);
|
||||
}
|
||||
});
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
|
|
@ -120,10 +128,6 @@ export class DateHeaderRenderer implements HeaderRenderer {
|
|||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
private getDayName(date: Date): string {
|
||||
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||
return days[date.getDay()];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { IEventBus } from '../types/CalendarTypes';
|
||||
import { EventTypes } from '../constants/EventTypes';
|
||||
import { DateUtils } from '../utils/DateUtils';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
|
||||
/**
|
||||
* NavigationRenderer - Handles DOM rendering for navigation containers
|
||||
|
|
@ -8,9 +9,11 @@ import { DateUtils } from '../utils/DateUtils';
|
|||
*/
|
||||
export class NavigationRenderer {
|
||||
private eventBus: IEventBus;
|
||||
private config: CalendarConfig;
|
||||
|
||||
constructor(eventBus: IEventBus) {
|
||||
constructor(eventBus: IEventBus, config: CalendarConfig) {
|
||||
this.eventBus = eventBus;
|
||||
this.config = config;
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
|
|
@ -97,10 +100,13 @@ export class NavigationRenderer {
|
|||
dayColumns.innerHTML = '';
|
||||
|
||||
// Render headers for target week
|
||||
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
||||
workWeekSettings.workDays.forEach((dayOfWeek, i) => {
|
||||
const date = new Date(weekStart);
|
||||
date.setDate(date.getDate() + i);
|
||||
// Set to the start of the week (Sunday = 0)
|
||||
date.setDate(weekStart.getDate() - weekStart.getDay());
|
||||
// Add the specific day of week
|
||||
date.setDate(date.getDate() + dayOfWeek);
|
||||
|
||||
const headerElement = document.createElement('swp-day-header');
|
||||
if (this.isToday(date)) {
|
||||
|
|
@ -108,26 +114,29 @@ export class NavigationRenderer {
|
|||
}
|
||||
|
||||
headerElement.innerHTML = `
|
||||
<swp-day-name>${days[date.getDay()]}</swp-day-name>
|
||||
<swp-day-name>${workWeekSettings.dayNames[i]}</swp-day-name>
|
||||
<swp-day-date>${date.getDate()}</swp-day-date>
|
||||
`;
|
||||
headerElement.dataset.date = this.formatDate(date);
|
||||
|
||||
header.appendChild(headerElement);
|
||||
}
|
||||
});
|
||||
|
||||
// Render day columns for target week
|
||||
for (let i = 0; i < 7; i++) {
|
||||
workWeekSettings.workDays.forEach(dayOfWeek => {
|
||||
const column = document.createElement('swp-day-column');
|
||||
const date = new Date(weekStart);
|
||||
date.setDate(date.getDate() + i);
|
||||
// Set to the start of the week (Sunday = 0)
|
||||
date.setDate(weekStart.getDate() - weekStart.getDay());
|
||||
// Add the specific day of week
|
||||
date.setDate(date.getDate() + dayOfWeek);
|
||||
column.dataset.date = this.formatDate(date);
|
||||
|
||||
const eventsLayer = document.createElement('swp-events-layer');
|
||||
column.appendChild(eventsLayer);
|
||||
|
||||
dayColumns.appendChild(column);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue