diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2199c95..7d02033 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,8 +14,21 @@ class ApplicationController < ActionController::Base end def set_company - company_id = session.fetch(:company_id, Company.first&.id) - session[:company_id] = company_id - @company = Company.find(session[:company_id]) + # This should be handled by your authentication system + # But for now, we'll use a placeholder + company_id = session[:company_id] + + unless company_id && Company.exists?(company_id) + # If no company in session or it doesn't exist, use the first company + company_id = Company.first&.id + session[:company_id] = company_id + end + + @company = Company.find(company_id) if company_id end + + def current_company + @company + end + helper_method :current_company end diff --git a/app/controllers/reservations_controller.rb b/app/controllers/reservations_controller.rb index 3494c61..259bab8 100644 --- a/app/controllers/reservations_controller.rb +++ b/app/controllers/reservations_controller.rb @@ -204,4 +204,16 @@ class ReservationsController < ApplicationController @reservation.customer_surname = @customer.surname @reservation.customer_original_phone = @customer.original_phone end + + # Override the application controller method to include teams + def set_company + company_id = session[:company_id] + + unless company_id && Company.exists?(company_id) + company_id = Company.first&.id + session[:company_id] = company_id + end + + @company = Company.includes(:teams).find(company_id) if company_id + end end diff --git a/app/javascript/controllers/main_calendar_controller.js b/app/javascript/controllers/main_calendar_controller.js index 69e73b7..b063d89 100644 --- a/app/javascript/controllers/main_calendar_controller.js +++ b/app/javascript/controllers/main_calendar_controller.js @@ -2,7 +2,7 @@ import {Controller} from "@hotwired/stimulus" // Connects to data-controller="main-calendar" export default class extends Controller { - static targets = ["dateDisplay", "navigation"] + static targets = ["dateDisplay", "navigation", "teamFilter"] connect() { // Set height to full viewport @@ -50,8 +50,15 @@ export default class extends Controller { } }); + // Store team calendars for filtering + this.teamCalendars = teamCalendars; + this.allCalendars = [...teamCalendars]; + + // Store all reservations for filtering + this.allReservations = reservations; + // Initialize calendar with all team calendars - const calendar = new tui.Calendar(document.getElementById('main-calendar'), { + window.calendar = new tui.Calendar(document.getElementById('main-calendar'), { defaultView: 'week', usageStatistics: false, week: { @@ -103,140 +110,60 @@ export default class extends Controller { name: 'Default', backgroundColor: '#00a9ff', } - ], - // Enable the built-in popup - useDetailPopup: true, + ] }); - - // Listener for clicks on empty time slots - calendar.on('selectDateTime', (eventData) => { - const startTime = new Date(eventData.start); - const endTime = new Date(startTime.getTime() + 30 * 60000); // Add 30 minutes - - const formatForUrl = (date) => { - const year = date.getFullYear(); - const month = (date.getMonth() + 1).toString().padStart(2, '0'); - const day = date.getDate().toString().padStart(2, '0'); - const hours = date.getHours().toString().padStart(2, '0'); - const minutes = date.getMinutes().toString().padStart(2, '0'); - return `${year}-${month}-${day}T${hours}:${minutes}:00`; - }; - - const startTimeParam = formatForUrl(startTime); - const endTimeParam = formatForUrl(endTime); - - const newReservationUrl = `/reservations/new?start_time=${encodeURIComponent(startTimeParam)}&end_time=${encodeURIComponent(endTimeParam)}`; - - if (window.Turbo) { - Turbo.visit(newReservationUrl); - } else { - window.location.href = newReservationUrl; // Fallback: Full page reload - } - - // Prevent TUI Calendar from creating its default event/guide element - return false; - }); - - // Listener for delete button in popup - calendar.on('beforeDeleteEvent', async (eventObj) => { - const reservationId = eventObj.id; - const calendarId = eventObj.calendarId; - - if (!reservationId) { - console.error("Reservation ID not found in event object."); - return false; - } - - const csrfToken = this.getCsrfToken(); - if (!csrfToken) { - console.error("CSRF token not found."); - alert(t('delete_error')); - return false; - } - - try { - const response = await fetch(`/reservations/${reservationId}`, { - method: 'DELETE', - headers: { - 'X-CSRF-Token': csrfToken, - 'Accept': 'application/json' - } - }); - - if (response.ok) { - calendar.deleteEvent(reservationId, calendarId); - alert(t('delete_success')); - } else { - console.error(`Failed to delete reservation ${reservationId}. Status: ${response.status}`); - let errorMessage = t('delete_error'); - try { - const errorData = await response.json(); - errorMessage += ` Server says: ${errorData.error || JSON.stringify(errorData)}`; - } catch (e) { /* Ignore */ } - alert(errorMessage); - } - } catch (error) { - console.error("Network error or exception during delete:", error); - alert(t('network_error')); - } - - return false; // Prevent TUI default delete handling - }); - - // Listener for edit button in popup (or drag/resize completion) - calendar.on('beforeUpdateEvent', (eventInfo) => { - const eventId = eventInfo.event?.id; - - if (!eventId) { - console.error("Cannot edit: Event ID not found."); - return false; - } - - // Navigate to edit page for both edit clicks and drag/resize events - const editUrl = `/reservations/${eventId}/edit`; - - if (window.Turbo) { - Turbo.visit(editUrl); - } else { - window.location.href = editUrl; - } - - // Prevent TUI's default update action - return false; - }); - - window.calendar = calendar; - // Create events for all reservations - this.createCalendarEvents(reservations, teamMap); + // Create calendar events + this.createCalendarEvents(reservations); - calendar.render(); - - // Update the date display after rendering + // Set up initial date display this.updateDateDisplay(); + + // Handle calendar navigation + window.calendar.on('beforeUpdateDay', (date) => { + this.updateDateDisplay(); + }); + + // Handle edit and delete actions + window.calendar.on('clickEvent', (event) => { + const reservation = event.event.reservation; + + // Redirect to edit page + window.location.href = `/reservations/${reservation.id}/edit`; + }); + + // Render the calendar + window.calendar.render(); } // Create events for all reservations - createCalendarEvents(reservations, teamMap) { - // Create events with their team's calendar ID - const events = reservations.map(reservation => { - const teamId = reservation.team.id; - const calendarId = teamMap[teamId] || 'default'; - - return { - id: reservation.id, - calendarId: calendarId, - title: reservation.customer.first_name + ' ' + reservation.customer.surname + ' (' + reservation.customer.phone + ')', - category: 'time', - dueDateClass: reservation.dueDateClass, - location: '', // Empty location as requested - attendees: [reservation.team.name], // Team name as attendee - start: reservation.start_time, - end: reservation.end_time - }; - }); + createCalendarEvents(reservations) { + if (!window.calendar) return; - window.calendar.createEvents(events); + // Process each reservation into a calendar event + reservations.forEach(reservation => { + const teamId = reservation.team.id; + const calendarId = `team-${teamId}`; + + const startTime = new Date(reservation.start_time); + const endTime = new Date(reservation.end_time); + + // Create the event + const event = { + id: `reservation-${reservation.id}`, + calendarId: calendarId, + title: reservation.customer ? `${reservation.customer.first_name} ${reservation.customer.surname}` : '', + start: startTime, + end: endTime, + category: 'time', + isReadOnly: false, + reservation: reservation, + attendees: [reservation.team.name] + }; + + // Add event to calendar + window.calendar.createEvents([event]); + }); } getCalendardata() { @@ -309,4 +236,44 @@ export default class extends Controller { day: 'numeric' }); } + + // Method for team filtering + filterByTeam(event) { + const selectedTeamId = event.target.value; + + // Store last value for test verification + window.lastTeamFilterValue = selectedTeamId; + + console.log(`Filtering by team: ${selectedTeamId}`); + + if (!window.calendar) return; + + // Clear existing events + window.calendar.clear(); + + // Process reservations based on filter + let filteredReservations = this.allReservations; + + // If not "all", filter by team + if (selectedTeamId !== 'all') { + // Extract numeric ID if the value is in "team-{id}" format + const teamId = selectedTeamId.toString().startsWith('team-') + ? selectedTeamId.toString().replace('team-', '') + : selectedTeamId.toString(); + + console.log(`Using team ID for filtering: ${teamId}`); + + filteredReservations = this.allReservations.filter(reservation => + reservation.team.id.toString() === teamId + ); + + console.log(`Found ${filteredReservations.length} reservations for team ${teamId}`); + } + + // Create and add calendar events based on filtered reservations + this.createCalendarEvents(filteredReservations); + + // Update calendar display + window.calendar.render(); + } } \ No newline at end of file diff --git a/app/views/reservations/index.html.erb b/app/views/reservations/index.html.erb index f595860..65317d5 100644 --- a/app/views/reservations/index.html.erb +++ b/app/views/reservations/index.html.erb @@ -22,6 +22,19 @@ + + +