Remove resource calendar mode support

Simplifies calendar configuration and removes resource-specific code paths

Eliminates complexity around resource-based calendar rendering by:
- Removing ResourceCalendarData type
- Removing resource-specific renderers and managers
- Streamlining event and grid management logic
- Consolidating to single date-based calendar implementation
This commit is contained in:
Janus C. H. Knudsen 2025-11-01 01:10:10 +01:00
parent 349e1e8293
commit cda201301c
16 changed files with 65 additions and 323 deletions

View file

@ -1,7 +1,7 @@
// Calendar configuration management // Calendar configuration management
// Pure static configuration class - no dependencies, no events // Pure static configuration class - no dependencies, no events
import { ICalendarConfig, ViewPeriod, CalendarMode } from '../types/CalendarTypes'; import { ICalendarConfig, ViewPeriod } from '../types/CalendarTypes';
import { TimeFormatter, TimeFormatSettings } from '../utils/TimeFormatter'; import { TimeFormatter, TimeFormatSettings } from '../utils/TimeFormatter';
/** /**
@ -61,18 +61,6 @@ interface WorkWeekSettings {
firstWorkDay: number; // ISO: 1 = Monday, 7 = Sunday firstWorkDay: number; // ISO: 1 = Monday, 7 = Sunday
} }
/**
* View settings for resource-based calendar mode
*/
interface ResourceViewSettings {
maxResources: number; // Maximum resources to display
showAvatars: boolean; // Display user avatars
avatarSize: number; // Avatar size in pixels
resourceNameFormat: 'full' | 'short'; // How to display names
showResourceDetails: boolean; // Show additional resource info
showAllDay: boolean; // Show all-day event row
}
/** /**
* Time format configuration settings * Time format configuration settings
*/ */
@ -116,7 +104,6 @@ export class CalendarConfig {
maxEventDuration: 480 // 8 hours maxEventDuration: 480 // 8 hours
}; };
private static calendarMode: CalendarMode = 'date';
private static selectedDate: Date | null = new Date(); private static selectedDate: Date | null = new Date();
private static currentWorkWeek: string = 'standard'; private static currentWorkWeek: string = 'standard';
@ -143,16 +130,6 @@ export class CalendarConfig {
showAllDay: true showAllDay: true
}; };
// Resource view settings
private static resourceViewSettings: ResourceViewSettings = {
maxResources: 10,
showAvatars: true,
avatarSize: 32,
resourceNameFormat: 'full',
showResourceDetails: true,
showAllDay: true
};
// Time format settings - default to Denmark with technical format // Time format settings - default to Denmark with technical format
private static timeFormatConfig: TimeFormatConfig = { private static timeFormatConfig: TimeFormatConfig = {
timezone: 'Europe/Copenhagen', timezone: 'Europe/Copenhagen',
@ -293,28 +270,6 @@ export class CalendarConfig {
return { ...CalendarConfig.dateViewSettings }; return { ...CalendarConfig.dateViewSettings };
} }
/**
* Get resource view settings
*/
static getResourceViewSettings(): ResourceViewSettings {
return { ...CalendarConfig.resourceViewSettings };
}
/**
* Get calendar mode
*/
static getCalendarMode(): CalendarMode {
return CalendarConfig.calendarMode;
}
/**
* Set calendar mode
*/
static setCalendarMode(mode: CalendarMode): void {
CalendarConfig.calendarMode = mode;
}
/** /**
* Get selected date * Get selected date
*/ */
@ -440,7 +395,6 @@ export class CalendarConfig {
const data = JSON.parse(json); const data = JSON.parse(json);
if (data.gridSettings) CalendarConfig.updateGridSettings(data.gridSettings); if (data.gridSettings) CalendarConfig.updateGridSettings(data.gridSettings);
if (data.dateViewSettings) CalendarConfig.dateViewSettings = { ...CalendarConfig.dateViewSettings, ...data.dateViewSettings }; if (data.dateViewSettings) CalendarConfig.dateViewSettings = { ...CalendarConfig.dateViewSettings, ...data.dateViewSettings };
if (data.resourceViewSettings) CalendarConfig.resourceViewSettings = { ...CalendarConfig.resourceViewSettings, ...data.resourceViewSettings };
if (data.timeFormatConfig) { if (data.timeFormatConfig) {
CalendarConfig.timeFormatConfig = { ...CalendarConfig.timeFormatConfig, ...data.timeFormatConfig }; CalendarConfig.timeFormatConfig = { ...CalendarConfig.timeFormatConfig, ...data.timeFormatConfig };
TimeFormatter.configure(CalendarConfig.timeFormatConfig); TimeFormatter.configure(CalendarConfig.timeFormatConfig);
@ -469,9 +423,6 @@ export class CalendarConfig {
getGridSettings() { return CalendarConfig.getGridSettings(); } getGridSettings() { return CalendarConfig.getGridSettings(); }
updateGridSettings(updates: Partial<GridSettings>) { return CalendarConfig.updateGridSettings(updates); } updateGridSettings(updates: Partial<GridSettings>) { return CalendarConfig.updateGridSettings(updates); }
getDateViewSettings() { return CalendarConfig.getDateViewSettings(); } getDateViewSettings() { return CalendarConfig.getDateViewSettings(); }
getResourceViewSettings() { return CalendarConfig.getResourceViewSettings(); }
getCalendarMode() { return CalendarConfig.getCalendarMode(); }
setCalendarMode(mode: CalendarMode) { return CalendarConfig.setCalendarMode(mode); }
getSelectedDate() { return CalendarConfig.getSelectedDate(); } getSelectedDate() { return CalendarConfig.getSelectedDate(); }
setSelectedDate(date: Date) { return CalendarConfig.setSelectedDate(date); } setSelectedDate(date: Date) { return CalendarConfig.setSelectedDate(date); }
getWorkWeekSettings() { return CalendarConfig.getWorkWeekSettings(); } getWorkWeekSettings() { return CalendarConfig.getWorkWeekSettings(); }

View file

@ -22,8 +22,8 @@ import { HeaderManager } from './managers/HeaderManager';
import { ConfigManager } from './managers/ConfigManager'; import { ConfigManager } from './managers/ConfigManager';
// Import renderers // Import renderers
import { DateHeaderRenderer, ResourceHeaderRenderer, type HeaderRenderer } from './renderers/HeaderRenderer'; import { DateHeaderRenderer, type HeaderRenderer } from './renderers/HeaderRenderer';
import { DateColumnRenderer, ResourceColumnRenderer, type ColumnRenderer } from './renderers/ColumnRenderer'; import { DateColumnRenderer, type ColumnRenderer } from './renderers/ColumnRenderer';
import { DateEventRenderer, type EventRendererStrategy } from './renderers/EventRenderer'; import { DateEventRenderer, type EventRendererStrategy } from './renderers/EventRenderer';
import { AllDayEventRenderer } from './renderers/AllDayEventRenderer'; import { AllDayEventRenderer } from './renderers/AllDayEventRenderer';
import { GridRenderer } from './renderers/GridRenderer'; import { GridRenderer } from './renderers/GridRenderer';
@ -86,15 +86,9 @@ async function initializeCalendar(): Promise<void> {
// Bind core services as instances // Bind core services as instances
builder.registerInstance(eventBus).as<IEventBus>(); builder.registerInstance(eventBus).as<IEventBus>();
// Register renderers based on calendar mode // Register renderers
const calendarMode = CalendarConfig.getCalendarMode();
if (calendarMode === 'resource') {
builder.registerType(ResourceHeaderRenderer).as<HeaderRenderer>().singleInstance();
builder.registerType(ResourceColumnRenderer).as<ColumnRenderer>().singleInstance();
} else {
builder.registerType(DateHeaderRenderer).as<HeaderRenderer>().singleInstance(); builder.registerType(DateHeaderRenderer).as<HeaderRenderer>().singleInstance();
builder.registerType(DateColumnRenderer).as<ColumnRenderer>().singleInstance(); builder.registerType(DateColumnRenderer).as<ColumnRenderer>().singleInstance();
}
builder.registerType(DateEventRenderer).as<EventRendererStrategy>().singleInstance(); builder.registerType(DateEventRenderer).as<EventRendererStrategy>().singleInstance();
// Register core services and utilities // Register core services and utilities

View file

@ -169,7 +169,7 @@ export class AllDayManager {
heightDifference: number; heightDifference: number;
} { } {
const root = document.documentElement; const root = document.documentElement;
const targetHeight = targetRows * ALL_DAY_CONSTANTS.SINGLE_ROW_HEIGHT + 2; const targetHeight = targetRows * ALL_DAY_CONSTANTS.SINGLE_ROW_HEIGHT;
// Read CSS variable directly from style property or default to 0 // Read CSS variable directly from style property or default to 0
const currentHeightStr = root.style.getPropertyValue('--all-day-row-height') || '0px'; const currentHeightStr = root.style.getPropertyValue('--all-day-row-height') || '0px';
const currentHeight = parseInt(currentHeightStr) || 0; const currentHeight = parseInt(currentHeightStr) || 0;

View file

@ -47,17 +47,10 @@ export class CalendarManager {
try { try {
// Debug: Check calendar type
const calendarType = this.config.getCalendarMode();
// Step 1: Load data // Step 1: Load data
await this.eventManager.loadData(); await this.eventManager.loadData();
// Step 2: Pass data to GridManager and render grid structure // Step 2: Render grid structure
if (calendarType === 'resource') {
const resourceData = this.eventManager.getResourceData();
this.gridManager.setResourceData(this.eventManager.getRawData() as import('../types/CalendarTypes').ResourceCalendarData);
}
await this.gridManager.render(); await this.gridManager.render();
this.scrollManager.initialize(); this.scrollManager.initialize();

View file

@ -98,21 +98,4 @@ export class ConfigManager {
}); });
} }
} }
/**
* Set calendar mode and emit event
*/
setCalendarMode(mode: 'date' | 'resource'): void {
const oldMode = CalendarConfig.getCalendarMode();
CalendarConfig.setCalendarMode(mode);
// Emit event if changed
if (oldMode !== mode) {
this.eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
key: 'calendarMode',
value: mode,
oldValue: oldMode
});
}
}
} }

View file

@ -1,8 +1,7 @@
import { IEventBus, CalendarEvent, ResourceCalendarData } from '../types/CalendarTypes'; import { IEventBus, CalendarEvent } from '../types/CalendarTypes';
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
import { CalendarConfig } from '../core/CalendarConfig'; import { CalendarConfig } from '../core/CalendarConfig';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
import { ResourceData } from '../types/ManagerTypes';
interface RawEventData { interface RawEventData {
id: string; id: string;
@ -22,7 +21,7 @@ interface RawEventData {
export class EventManager { export class EventManager {
private events: CalendarEvent[] = []; private events: CalendarEvent[] = [];
private rawData: ResourceCalendarData | RawEventData[] | null = null; private rawData: RawEventData[] | null = null;
private eventCache = new Map<string, CalendarEvent[]>(); // Cache for period queries private eventCache = new Map<string, CalendarEvent[]>(); // Cache for period queries
private lastCacheKey: string = ''; private lastCacheKey: string = '';
private dateService: DateService; private dateService: DateService;
@ -52,13 +51,10 @@ export class EventManager {
} }
/** /**
* Optimized mock data loading with better resource handling * Optimized mock data loading
*/ */
private async loadMockData(): Promise<void> { private async loadMockData(): Promise<void> {
const calendarType = this.config.getCalendarMode(); const jsonFile = 'data/mock-events.json';
const jsonFile = calendarType === 'resource'
? '/data/mock-resource-events.json'
: '/data/mock-events.json';
const response = await fetch(jsonFile); const response = await fetch(jsonFile);
if (!response.ok) { if (!response.ok) {
@ -69,29 +65,14 @@ export class EventManager {
// Store raw data and process in one operation // Store raw data and process in one operation
this.rawData = data; this.rawData = data;
this.events = this.processCalendarData(calendarType, data); this.events = this.processCalendarData(data);
} }
/** /**
* Optimized data processing with better type safety * Optimized data processing with better type safety
*/ */
private processCalendarData(calendarType: string, data: ResourceCalendarData | RawEventData[]): CalendarEvent[] { private processCalendarData(data: RawEventData[]): CalendarEvent[] {
if (calendarType === 'resource') { return data.map((event): CalendarEvent => ({
const resourceData = data as ResourceCalendarData;
return resourceData.resources.flatMap(resource =>
resource.events.map(event => ({
...event,
start: new Date(event.start),
end: new Date(event.end),
resourceName: resource.name,
resourceDisplayName: resource.displayName,
resourceEmployeeId: resource.employeeId
}))
);
}
const eventData = data as RawEventData[];
return eventData.map((event): CalendarEvent => ({
...event, ...event,
start: new Date(event.start), start: new Date(event.start),
end: new Date(event.end), end: new Date(event.end),
@ -116,30 +97,6 @@ export class EventManager {
return copy ? [...this.events] : this.events; return copy ? [...this.events] : this.events;
} }
/**
* Get raw resource data for resource calendar mode
*/
public getResourceData(): ResourceData | null {
if (!this.rawData || !('resources' in this.rawData)) {
return null;
}
return {
resources: this.rawData.resources.map(r => ({
id: r.employeeId || r.name, // Use employeeId as id, fallback to name
name: r.name,
type: r.employeeId ? 'employee' : 'resource',
color: 'blue' // Default color since Resource interface doesn't have color
}))
};
}
/**
* Get raw data for compatibility
*/
public getRawData(): ResourceCalendarData | RawEventData[] | null {
return this.rawData;
}
/** /**
* Optimized event lookup with early return * Optimized event lookup with early return
*/ */

View file

@ -5,7 +5,7 @@
import { eventBus } from '../core/EventBus'; import { eventBus } from '../core/EventBus';
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes'; import { CalendarView } from '../types/CalendarTypes';
import { GridRenderer } from '../renderers/GridRenderer'; import { GridRenderer } from '../renderers/GridRenderer';
import { GridStyleManager } from '../renderers/GridStyleManager'; import { GridStyleManager } from '../renderers/GridStyleManager';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
@ -16,7 +16,6 @@ import { DateService } from '../utils/DateService';
export class GridManager { export class GridManager {
private container: HTMLElement | null = null; private container: HTMLElement | null = null;
private currentDate: Date = new Date(); private currentDate: Date = new Date();
private resourceData: ResourceCalendarData | null = null;
private currentView: CalendarView = 'week'; private currentView: CalendarView = 'week';
private gridRenderer: GridRenderer; private gridRenderer: GridRenderer;
private styleManager: GridStyleManager; private styleManager: GridStyleManager;
@ -84,14 +83,6 @@ export class GridManager {
this.render(); this.render();
} }
/**
* Set resource data for resource calendar mode
*/
public setResourceData(resourceData: ResourceCalendarData | null): void {
this.resourceData = resourceData;
this.render();
}
/** /**
* Main render method - delegates to GridRenderer * Main render method - delegates to GridRenderer
*/ */
@ -101,13 +92,12 @@ export class GridManager {
} }
// Update CSS variables first // Update CSS variables first
this.styleManager.updateGridStyles(this.resourceData); this.styleManager.updateGridStyles();
// Delegate to GridRenderer with current view context // Delegate to GridRenderer with current view context
this.gridRenderer.renderGrid( this.gridRenderer.renderGrid(
this.container, this.container,
this.currentDate, this.currentDate
this.resourceData
); );
// Calculate period range // Calculate period range

View file

@ -2,7 +2,6 @@ import { eventBus } from '../core/EventBus';
import { CalendarConfig } from '../core/CalendarConfig'; import { CalendarConfig } from '../core/CalendarConfig';
import { CoreEvents } from '../constants/CoreEvents'; import { CoreEvents } from '../constants/CoreEvents';
import { HeaderRenderer, HeaderRenderContext } from '../renderers/HeaderRenderer'; import { HeaderRenderer, HeaderRenderContext } from '../renderers/HeaderRenderer';
import { ResourceCalendarData } from '../types/CalendarTypes';
import { DragMouseEnterHeaderEventPayload, DragMouseLeaveHeaderEventPayload, HeaderReadyEventPayload } from '../types/EventTypes'; import { DragMouseEnterHeaderEventPayload, DragMouseLeaveHeaderEventPayload, HeaderReadyEventPayload } from '../types/EventTypes';
import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils'; import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
@ -30,8 +29,8 @@ export class HeaderManager {
/** /**
* Initialize header with initial date * Initialize header with initial date
*/ */
public initializeHeader(currentDate: Date, resourceData: ResourceCalendarData | null = null): void { public initializeHeader(currentDate: Date): void {
this.updateHeader(currentDate, resourceData); this.updateHeader(currentDate);
} }
/** /**
@ -89,20 +88,20 @@ export class HeaderManager {
*/ */
private setupNavigationListener(): void { private setupNavigationListener(): void {
eventBus.on(CoreEvents.NAVIGATION_COMPLETED, (event) => { eventBus.on(CoreEvents.NAVIGATION_COMPLETED, (event) => {
const { currentDate, resourceData } = (event as CustomEvent).detail; const { currentDate } = (event as CustomEvent).detail;
this.updateHeader(currentDate, resourceData); this.updateHeader(currentDate);
}); });
// Also listen for date changes (including initial setup) // Also listen for date changes (including initial setup)
eventBus.on(CoreEvents.DATE_CHANGED, (event) => { eventBus.on(CoreEvents.DATE_CHANGED, (event) => {
const { currentDate } = (event as CustomEvent).detail; const { currentDate } = (event as CustomEvent).detail;
this.updateHeader(currentDate, null); this.updateHeader(currentDate);
}); });
// Listen for workweek header updates after grid rebuild // Listen for workweek header updates after grid rebuild
eventBus.on('workweek:header-update', (event) => { eventBus.on('workweek:header-update', (event) => {
const { currentDate } = (event as CustomEvent).detail; const { currentDate } = (event as CustomEvent).detail;
this.updateHeader(currentDate, null); this.updateHeader(currentDate);
}); });
} }
@ -110,10 +109,9 @@ export class HeaderManager {
/** /**
* Update header content for navigation * Update header content for navigation
*/ */
private updateHeader(currentDate: Date, resourceData: ResourceCalendarData | null = null): void { private updateHeader(currentDate: Date): void {
console.log('🎯 HeaderManager.updateHeader called', { console.log('🎯 HeaderManager.updateHeader called', {
currentDate, currentDate,
hasResourceData: !!resourceData,
rendererType: this.headerRenderer.constructor.name rendererType: this.headerRenderer.constructor.name
}); });
@ -129,8 +127,7 @@ export class HeaderManager {
// Render new header content using injected renderer // Render new header content using injected renderer
const context: HeaderRenderContext = { const context: HeaderRenderContext = {
currentWeek: currentDate, currentWeek: currentDate,
config: this.config, config: this.config
resourceData: resourceData
}; };
console.log('🎨 HeaderManager: Calling renderer.render()', context); console.log('🎨 HeaderManager: Calling renderer.render()', context);

View file

@ -1,7 +1,6 @@
// Column rendering strategy interface and implementations // Column rendering strategy interface and implementations
import { CalendarConfig } from '../core/CalendarConfig'; import { CalendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData } from '../types/CalendarTypes';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
import { WorkHoursManager } from '../managers/WorkHoursManager'; import { WorkHoursManager } from '../managers/WorkHoursManager';
@ -18,7 +17,6 @@ export interface ColumnRenderer {
export interface ColumnRenderContext { export interface ColumnRenderContext {
currentWeek: Date; currentWeek: Date;
config: CalendarConfig; config: CalendarConfig;
resourceData?: ResourceCalendarData | null;
} }
/** /**
@ -80,29 +78,3 @@ export class DateColumnRenderer implements ColumnRenderer {
} }
} }
/**
* Resource-based column renderer
*/
export class ResourceColumnRenderer implements ColumnRenderer {
render(columnContainer: HTMLElement, context: ColumnRenderContext): void {
const { resourceData } = context;
if (!resourceData) {
return;
}
resourceData.resources.forEach((resource) => {
const column = document.createElement('swp-resource-column');
(column as any).dataset.resource = resource.name;
(column as any).dataset.employeeId = resource.employeeId;
(column as any).dataset.date = resourceData.date;
const eventsLayer = document.createElement('swp-events-layer');
column.appendChild(eventsLayer);
columnContainer.appendChild(column);
});
}
}

View file

@ -1,5 +1,5 @@
import { CalendarConfig } from '../core/CalendarConfig'; import { CalendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes'; import { CalendarView } from '../types/CalendarTypes';
import { ColumnRenderer, ColumnRenderContext } from './ColumnRenderer'; import { ColumnRenderer, ColumnRenderContext } from './ColumnRenderer';
import { eventBus } from '../core/EventBus'; import { eventBus } from '../core/EventBus';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
@ -30,7 +30,6 @@ export class GridRenderer {
public renderGrid( public renderGrid(
grid: HTMLElement, grid: HTMLElement,
currentDate: Date, currentDate: Date,
resourceData: ResourceCalendarData | null,
view: CalendarView = 'week' view: CalendarView = 'week'
): void { ): void {
@ -43,12 +42,12 @@ export class GridRenderer {
// Only clear and rebuild if grid is empty (first render) // Only clear and rebuild if grid is empty (first render)
if (grid.children.length === 0) { if (grid.children.length === 0) {
this.createCompleteGridStructure(grid, currentDate, resourceData, view); this.createCompleteGridStructure(grid, currentDate, view);
// Setup grid-related event listeners on first render // Setup grid-related event listeners on first render
// this.setupGridEventListeners(); // this.setupGridEventListeners();
} else { } else {
// Optimized update - only refresh dynamic content // Optimized update - only refresh dynamic content
this.updateGridContent(grid, currentDate, resourceData, view); this.updateGridContent(grid, currentDate, view);
} }
} }
@ -58,7 +57,6 @@ export class GridRenderer {
private createCompleteGridStructure( private createCompleteGridStructure(
grid: HTMLElement, grid: HTMLElement,
currentDate: Date, currentDate: Date,
resourceData: ResourceCalendarData | null,
view: CalendarView view: CalendarView
): void { ): void {
// Create all elements in memory first for better performance // Create all elements in memory first for better performance
@ -74,7 +72,7 @@ export class GridRenderer {
fragment.appendChild(timeAxis); fragment.appendChild(timeAxis);
// Create grid container with caching // Create grid container with caching
const gridContainer = this.createOptimizedGridContainer(currentDate, resourceData, view); const gridContainer = this.createOptimizedGridContainer(currentDate, view);
this.cachedGridContainer = gridContainer; this.cachedGridContainer = gridContainer;
fragment.appendChild(gridContainer); fragment.appendChild(gridContainer);
@ -105,7 +103,6 @@ export class GridRenderer {
private createOptimizedGridContainer( private createOptimizedGridContainer(
currentDate: Date, currentDate: Date,
resourceData: ResourceCalendarData | null,
view: CalendarView view: CalendarView
): HTMLElement { ): HTMLElement {
const gridContainer = document.createElement('swp-grid-container'); const gridContainer = document.createElement('swp-grid-container');
@ -124,7 +121,7 @@ export class GridRenderer {
// Create column container // Create column container
const columnContainer = document.createElement('swp-day-columns'); const columnContainer = document.createElement('swp-day-columns');
this.renderColumnContainer(columnContainer, currentDate, resourceData, view); this.renderColumnContainer(columnContainer, currentDate, view);
timeGrid.appendChild(columnContainer); timeGrid.appendChild(columnContainer);
scrollableContent.appendChild(timeGrid); scrollableContent.appendChild(timeGrid);
@ -142,13 +139,11 @@ export class GridRenderer {
private renderColumnContainer( private renderColumnContainer(
columnContainer: HTMLElement, columnContainer: HTMLElement,
currentDate: Date, currentDate: Date,
resourceData: ResourceCalendarData | null,
view: CalendarView view: CalendarView
): void { ): void {
const context: ColumnRenderContext = { const context: ColumnRenderContext = {
currentWeek: currentDate, // ColumnRenderer expects currentWeek property currentWeek: currentDate, // ColumnRenderer expects currentWeek property
config: this.config, config: this.config
resourceData: resourceData
}; };
this.columnRenderer.render(columnContainer, context); this.columnRenderer.render(columnContainer, context);
@ -160,14 +155,13 @@ export class GridRenderer {
private updateGridContent( private updateGridContent(
grid: HTMLElement, grid: HTMLElement,
currentDate: Date, currentDate: Date,
resourceData: ResourceCalendarData | null,
view: CalendarView view: CalendarView
): void { ): void {
// Update column container if needed // Update column container if needed
const columnContainer = grid.querySelector('swp-day-columns'); const columnContainer = grid.querySelector('swp-day-columns');
if (columnContainer) { if (columnContainer) {
columnContainer.innerHTML = ''; columnContainer.innerHTML = '';
this.renderColumnContainer(columnContainer as HTMLElement, currentDate, resourceData, view); this.renderColumnContainer(columnContainer as HTMLElement, currentDate, view);
} }
} }
/** /**
@ -182,8 +176,8 @@ export class GridRenderer {
const weekEnd = this.dateService.addDays(weekStart, 6); const weekEnd = this.dateService.addDays(weekStart, 6);
// Use SAME method as initial load - respects workweek and resource settings // Use SAME method as initial load - respects workweek settings
const newGrid = this.createOptimizedGridContainer(weekStart, null, 'week'); const newGrid = this.createOptimizedGridContainer(weekStart, 'week');
// Position new grid for animation - NO transform here, let Animation API handle it // Position new grid for animation - NO transform here, let Animation API handle it
newGrid.style.position = 'absolute'; newGrid.style.position = 'absolute';

View file

@ -1,5 +1,4 @@
import { CalendarConfig } from '../core/CalendarConfig'; import { CalendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData } from '../types/CalendarTypes';
interface GridSettings { interface GridSettings {
hourHeight: number; hourHeight: number;
@ -25,17 +24,16 @@ export class GridStyleManager {
/** /**
* Update all grid CSS variables * Update all grid CSS variables
*/ */
public updateGridStyles(resourceData: ResourceCalendarData | null = null): void { public updateGridStyles(): void {
const root = document.documentElement; const root = document.documentElement;
const gridSettings = this.config.getGridSettings(); const gridSettings = this.config.getGridSettings();
const calendar = document.querySelector('swp-calendar') as HTMLElement; const calendar = document.querySelector('swp-calendar') as HTMLElement;
const calendarType = this.config.getCalendarMode();
// Set CSS variables for time and grid measurements // Set CSS variables for time and grid measurements
this.setTimeVariables(root, gridSettings); this.setTimeVariables(root, gridSettings);
// Set column count based on calendar type // Set column count based on view
const columnCount = this.calculateColumnCount(calendarType, resourceData); const columnCount = this.calculateColumnCount();
root.style.setProperty('--grid-columns', columnCount.toString()); root.style.setProperty('--grid-columns', columnCount.toString());
// Set column width based on fitToWidth setting // Set column width based on fitToWidth setting
@ -63,12 +61,9 @@ export class GridStyleManager {
} }
/** /**
* Calculate number of columns based on calendar type and view * Calculate number of columns based on view
*/ */
private calculateColumnCount(calendarType: string, resourceData: ResourceCalendarData | null): number { private calculateColumnCount(): number {
if (calendarType === 'resource' && resourceData) {
return resourceData.resources.length;
} else if (calendarType === 'date') {
const dateSettings = this.config.getDateViewSettings(); const dateSettings = this.config.getDateViewSettings();
const workWeekSettings = this.config.getWorkWeekSettings(); const workWeekSettings = this.config.getWorkWeekSettings();
@ -84,9 +79,6 @@ export class GridStyleManager {
} }
} }
return this.config.getWorkWeekSettings().totalDays; // Default to work week
}
/** /**
* Set column width based on fitToWidth setting * Set column width based on fitToWidth setting
*/ */

View file

@ -1,7 +1,6 @@
// Header rendering strategy interface and implementations // Header rendering strategy interface and implementations
import { CalendarConfig } from '../core/CalendarConfig'; import { CalendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData } from '../types/CalendarTypes';
import { DateService } from '../utils/DateService'; import { DateService } from '../utils/DateService';
/** /**
@ -18,7 +17,6 @@ export interface HeaderRenderer {
export interface HeaderRenderContext { export interface HeaderRenderContext {
currentWeek: Date; currentWeek: Date;
config: CalendarConfig; config: CalendarConfig;
resourceData?: ResourceCalendarData | null;
} }
/** /**
@ -62,31 +60,3 @@ export class DateHeaderRenderer implements HeaderRenderer {
}); });
} }
} }
/**
* Resource-based header renderer
*/
export class ResourceHeaderRenderer implements HeaderRenderer {
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
const { resourceData } = context;
if (!resourceData) {
return;
}
resourceData.resources.forEach((resource) => {
const header = document.createElement('swp-resource-header');
header.setAttribute('data-resource', resource.name);
header.setAttribute('data-employee-id', resource.employeeId);
header.innerHTML = `
<swp-resource-avatar>
<img src="${resource.avatarUrl}" alt="${resource.displayName}" onerror="this.style.display='none'">
</swp-resource-avatar>
<swp-resource-name>${resource.displayName}</swp-resource-name>
`;
calendarHeader.appendChild(header);
});
}
}

View file

@ -3,15 +3,12 @@
* Allows clean separation between week view, month view, day view etc. * Allows clean separation between week view, month view, day view etc.
*/ */
import { ResourceCalendarData } from '../types/CalendarTypes';
/** /**
* Context object passed to strategy methods * Context object passed to strategy methods
*/ */
export interface ViewContext { export interface ViewContext {
currentDate: Date; currentDate: Date;
container: HTMLElement; container: HTMLElement;
resourceData: ResourceCalendarData | null;
} }
/** /**

View file

@ -3,27 +3,11 @@
// Time period view types (how much time to display) // Time period view types (how much time to display)
export type ViewPeriod = 'day' | 'week' | 'month'; export type ViewPeriod = 'day' | 'week' | 'month';
// Calendar mode types (how to organize the data)
export type CalendarMode = 'date' | 'resource';
// Type aliases // Type aliases
export type CalendarView = ViewPeriod; export type CalendarView = ViewPeriod;
export type SyncStatus = 'synced' | 'pending' | 'error'; export type SyncStatus = 'synced' | 'pending' | 'error';
export interface Resource {
name: string;
displayName: string;
avatarUrl: string;
employeeId: string;
events: CalendarEvent[];
}
export interface ResourceCalendarData {
date: string;
resources: Resource[];
}
export interface RenderContext { export interface RenderContext {
container: HTMLElement; container: HTMLElement;
startDate: Date; startDate: Date;
@ -39,13 +23,6 @@ export interface CalendarEvent {
allDay: boolean; allDay: boolean;
syncStatus: SyncStatus; syncStatus: SyncStatus;
// Resource information (only present in resource calendar mode)
resource?: {
name: string;
displayName: string;
employeeId: string;
};
recurringId?: string; recurringId?: string;
metadata?: Record<string, any>; metadata?: Record<string, any>;
} }

View file

@ -31,7 +31,6 @@ export interface EventManager extends IManager {
loadData(): Promise<void>; loadData(): Promise<void>;
getEvents(): CalendarEvent[]; getEvents(): CalendarEvent[];
getEventsForPeriod(startDate: Date, endDate: Date): CalendarEvent[]; getEventsForPeriod(startDate: Date, endDate: Date): CalendarEvent[];
getResourceData(): ResourceData | null;
navigateToEvent(eventId: string): boolean; navigateToEvent(eventId: string): boolean;
} }
@ -42,7 +41,6 @@ export interface EventRenderingService extends IManager {
export interface GridManager extends IManager { export interface GridManager extends IManager {
render(): Promise<void>; render(): Promise<void>;
getDisplayDates(): Date[]; getDisplayDates(): Date[];
setResourceData(resourceData: import('./CalendarTypes').ResourceCalendarData | null): void;
} }
export interface ScrollManager extends IManager { export interface ScrollManager extends IManager {
@ -76,20 +74,3 @@ export interface AllDayManager extends IManager {
export interface ResizeHandleManager extends IManager { export interface ResizeHandleManager extends IManager {
// ResizeHandleManager handles hover effects for resize handles // ResizeHandleManager handles hover effects for resize handles
} }
export interface ResourceData {
resources: Resource[];
assignments?: ResourceAssignment[];
}
export interface Resource {
id: string;
name: string;
type?: string;
color?: string;
}
export interface ResourceAssignment {
resourceId: string;
eventId: string;
}

View file

@ -186,7 +186,6 @@ swp-calendar-header {
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width)); min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width));
/* Dynamic width */ /* Dynamic width */
background: var(--color-surface); background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 3; z-index: 3;
@ -198,9 +197,6 @@ swp-calendar-header {
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
/* Firefox - hide scrollbar but keep space */
scrollbar-width: auto;
/* Normal width to match content scrollbar */
/* All-day events container */ /* All-day events container */
swp-allday-container { swp-allday-container {
@ -211,12 +207,10 @@ swp-calendar-header {
grid-auto-rows: var(--single-row-height); grid-auto-rows: var(--single-row-height);
/* Each row is exactly SINGLE_ROW_HEIGHT */ /* Each row is exactly SINGLE_ROW_HEIGHT */
gap: 2px 0px; gap: 2px 0px;
padding: 2px 0px 5px 0px;
align-items: center; align-items: center;
overflow: hidden; overflow: hidden;
} }
scrollbar-color: transparent transparent;
} }
/* WebKit browsers (Chrome, Safari, Edge) - hide scrollbar but keep space */ /* WebKit browsers (Chrome, Safari, Edge) - hide scrollbar but keep space */