import { Component, OnInit, signal, computed, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Router, RouterModule } from '@angular/router'; export interface Resource { id: string; name: string; type: 'Sala Reuniones' | 'Oficina Flexible' | 'Zona Relax' | 'Evento'; icon: string; desc: string; capacity: number; } @Component({ selector: 'app-calendar-booking', standalone: true, imports: [CommonModule, RouterModule], templateUrl: './calendar-booking.component.html', styleUrls: ['./calendar-booking.component.css'] }) export class CalendarBookingComponent implements OnInit { private router = inject(Router); // Horarios de la captura timeSlots = ['08:00', '09:30', '10:00', '11:30', '12:00', '13:30', '14:00', '15:00']; // Base de datos de recursos por categoría resources = signal([ { id: '1', name: 'SALA LUNA', type: 'Sala Reuniones', icon: '🌙', desc: 'Sala Reuniones resutenias or Sala Luna', capacity: 8 }, { id: '2', name: 'SALA SOL', type: 'Sala Reuniones', icon: '☀️', desc: 'Estables:nación de nuevos luxes', capacity: 12 }, { id: '3', name: 'OFICINA FLEX', type: 'Oficina Flexible', icon: '🏢', desc: 'Resultalioes sala tia r Oficina flexible', capacity: 1 }, { id: '4', name: 'OFICINA FLEX A1', type: 'Oficina Flexible', icon: '🏢', desc: 'Oficina de espacios resutentu-u planetia', capacity: 1 }, { id: '5', name: 'ZONA COFFEE', type: 'Zona Relax', icon: '☕', desc: 'Espacio de café y socialización', capacity: 20 }, { id: '6', name: 'SALA DE JUEGOS', type: 'Zona Relax', icon: '🎮', desc: 'Mesa de ping pong y consolas', capacity: 10 }, { id: '7', name: 'AUDITORIO A', type: 'Evento', icon: '🎤', desc: 'Auditorio principal para presentaciones', capacity: 100 }, { id: '8', name: 'TERRAZA', type: 'Evento', icon: '🌿', desc: 'Espacio abierto para eventos corporativos', capacity: 50 } ]); // Signals para gestionar estado interactivo selectedCategories = signal(['Sala Reuniones', 'Oficina Flexible', 'Zona Relax', 'Evento']); searchQuery = signal(''); // Slot seleccionado para el popup dinámico selectedSlot = signal<{ resource: Resource, time: string } | null>(null); // Ocupación en tiempo real (inicializada con la captura) reservations = signal([ { resourceName: 'SALA LUNA', time: '08:00', author: 'Sistema', date: 'Hace 10h' }, { resourceName: 'SALA LUNA', time: '09:30', author: 'Sistema', date: 'Hace 10h' }, { resourceName: 'SALA LUNA', time: '13:30', author: 'Sistema', date: 'Hace 10h' }, { resourceName: 'SALA LUNA', time: '14:00', author: 'Sistema', date: 'Hace 10h' }, { resourceName: 'SALA SOL', time: '08:00', author: 'Sistema', date: 'Hace 10h' }, { resourceName: 'SALA SOL', time: '09:30', author: 'Sistema', date: 'Hace 10h' } ]); // Notificaciones estáticas de David Chen staticNotifications = [ { title: 'David Chen', detail: 'compartió Resultados del Trimestre', time: 'Hace 15m', type: 'notif', avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=120&q=80' }, { title: 'David Chen', detail: 'compartió Resultados del Trimestre', time: 'Hace 15m', type: 'notif', avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=120&q=80' } ]; // Mini calendar data for June 2026 miniCalendarDays = [ { day: 31, currentMonth: false }, { day: 1, currentMonth: true }, { day: 2, currentMonth: true }, { day: 3, currentMonth: true }, { day: 4, currentMonth: true }, { day: 5, currentMonth: true }, { day: 6, currentMonth: true }, { day: 7, currentMonth: true }, { day: 8, currentMonth: true }, { day: 9, currentMonth: true }, { day: 10, currentMonth: true }, { day: 11, currentMonth: true }, { day: 12, currentMonth: true }, { day: 13, currentMonth: true }, { day: 14, currentMonth: true }, { day: 15, currentMonth: true }, { day: 16, currentMonth: true, active: true }, { day: 17, currentMonth: true }, { day: 18, currentMonth: true }, { day: 19, currentMonth: true }, { day: 20, currentMonth: true }, { day: 21, currentMonth: true }, { day: 22, currentMonth: true }, { day: 23, currentMonth: true }, { day: 24, currentMonth: true }, { day: 25, currentMonth: true }, { day: 26, currentMonth: true }, { day: 27, currentMonth: true }, { day: 28, currentMonth: true }, { day: 29, currentMonth: true }, { day: 30, currentMonth: true }, { day: 1, currentMonth: false }, { day: 2, currentMonth: false }, { day: 3, currentMonth: false }, { day: 4, currentMonth: false }, { day: 5, currentMonth: false }, { day: 6, currentMonth: false }, { day: 7, currentMonth: false }, { day: 8, currentMonth: false }, { day: 9, currentMonth: false }, { day: 10, currentMonth: false }, { day: 11, currentMonth: false } ]; // Computed signals filteredResources = computed(() => { const selectedCats = this.selectedCategories(); const query = this.searchQuery().toLowerCase().trim(); return this.resources().filter(r => selectedCats.includes(r.type) && (!query || r.name.toLowerCase().includes(query) || r.desc.toLowerCase().includes(query)) ); }); recentActivities = computed(() => { // Convertir reservas a actividades const resList = this.reservations().map(res => { let avatar = 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=120&q=80'; if (res.resourceName.includes('LUNA')) { avatar = 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=120&q=80'; } return { title: res.resourceName, detail: `Reservado ${res.time}`, time: res.date, type: 'reserva', avatar: avatar }; }); return [...resList, ...this.staticNotifications]; }); ngOnInit(): void { // Inicializar el popup en Sala Luna de las 10:00 para emular la captura al cargar const luna = this.resources().find(r => r.name === 'SALA LUNA'); if (luna) { this.selectedSlot.set({ resource: luna, time: '11:30' }); } } toggleCategory(cat: string): void { this.selectedCategories.update(prev => { if (prev.includes(cat)) { return prev.filter(c => c !== cat); } else { return [...prev, cat]; } }); this.selectedSlot.set(null); // Reset popup al cambiar filtros } isCategorySelected(cat: string): boolean { return this.selectedCategories().includes(cat); } onSearch(event: Event): void { const value = (event.target as HTMLInputElement).value; this.searchQuery.set(value); } isSlotOccupied(resourceName: string, time: string): boolean { return this.reservations().some(res => res.resourceName === resourceName && res.time === time); } onSlotClick(resource: Resource, time: string): void { if (this.isSlotOccupied(resource.name, time)) { return; } this.selectedSlot.set({ resource, time }); } getEndTime(startTime: string): string { const [h, m] = startTime.split(':').map(Number); let fh = h + 1; let fm = m + 30; if (fm >= 60) { fh += 1; fm -= 60; } return `${String(fh).padStart(2, '0')}:${String(fm).padStart(2, '0')}`; } confirmReserva(): void { const slot = this.selectedSlot(); if (slot) { const newRes = { resourceName: slot.resource.name, time: slot.time, author: 'Jess Miller', date: 'Hace un momento' }; this.reservations.update(prev => [newRes, ...prev]); this.selectedSlot.set(null); } } closePopup(): void { this.selectedSlot.set(null); } navigateToNuevo(): void { const slot = this.selectedSlot(); this.router.navigate(['/reservas/nuevo'], { queryParams: { fecha: new Date().toISOString().split('T')[0], tipo: slot ? (slot.resource.type === 'Sala Reuniones' ? 'room' : 'desk') : 'room', hora: slot ? slot.time : '10:00' } }); } }