Working time
This commit is contained in:
@@ -23,7 +23,13 @@
|
|||||||
<div class="flex-1 p-4 overflow-auto">
|
<div class="flex-1 p-4 overflow-auto">
|
||||||
<FullCalendar ref="fullCalendar" :options="calendarOptions" />
|
<FullCalendar ref="fullCalendar" :options="calendarOptions" />
|
||||||
</div>
|
</div>
|
||||||
<EventModal v-if="selectedEvent" :event="selectedEvent" @close-modal="selectedEvent = null" @delete-event="handleEventDelete" />
|
|
||||||
|
<EventModal
|
||||||
|
v-if="selectedEvent"
|
||||||
|
:event="selectedEvent"
|
||||||
|
@close-modal="selectedEvent = null"
|
||||||
|
@delete-event="handleEventDelete"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,10 +45,12 @@ import { CalendarOptions, EventApi, EventClickArg } from '@fullcalendar/core';
|
|||||||
import EventSidebar from './EventSidebar.vue';
|
import EventSidebar from './EventSidebar.vue';
|
||||||
import EventModal from './EventModal.vue';
|
import EventModal from './EventModal.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import authHeader from '../../../services/auth.header'; // Assuming you have this service
|
import authHeader from '../../../services/auth.header';
|
||||||
|
|
||||||
// --- Interfaces (no changes) ---
|
// --- Interfaces ---
|
||||||
interface Customer { id: number; customer_last_name: string; customer_first_name: string; customer_town: string; customer_state: number; customer_zip: string; customer_phone_number: string; customer_address: string; customer_home_type: number; customer_apt: string; }
|
interface Customer { id: number; customer_last_name: string; customer_first_name: string; customer_town: string; customer_state: number; customer_zip: string; customer_phone_number: string; customer_address: string; customer_home_type: number; customer_apt: string; }
|
||||||
|
interface EventExtendedProps { description: string; type_service_call: number; }
|
||||||
|
interface AppEvent { id?: string; title: string; start: string; end?: string; extendedProps: EventExtendedProps; }
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CalendarCustomer',
|
name: 'CalendarCustomer',
|
||||||
@@ -71,19 +79,19 @@ export default defineComponent({
|
|||||||
events: [],
|
events: [],
|
||||||
eventClick: this.handleEventClick,
|
eventClick: this.handleEventClick,
|
||||||
};
|
};
|
||||||
// --- KEY CHANGE: Fetch ALL events when the component is created ---
|
|
||||||
this.fetchEvents();
|
this.fetchEvents();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// --- METHOD IMPLEMENTATIONS RESTORED ---
|
||||||
|
|
||||||
async getCustomer(customerId: string): Promise<void> {
|
async getCustomer(customerId: string): Promise<void> {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.customer = null;
|
this.customer = null;
|
||||||
try {
|
try {
|
||||||
const path = `${import.meta.env.VITE_BASE_URL}/customer/${customerId}`;
|
const path = `${import.meta.env.VITE_BASE_URL}/customer/${customerId}`;
|
||||||
const response = await axios.get(path, { withCredentials: true });
|
const response = await axios.get(path, { withCredentials: true, headers: authHeader() });
|
||||||
if (response.data && response.data.id) {
|
if (response.data && response.data.id) {
|
||||||
this.customer = response.data;
|
this.customer = response.data;
|
||||||
// --- REMOVED: No longer need to fetch events from here ---
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("API call to get customer FAILED:", error);
|
console.error("API call to get customer FAILED:", error);
|
||||||
@@ -92,15 +100,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// --- KEY CHANGE: This method now fetches ALL events and is independent ---
|
|
||||||
async fetchEvents(): Promise<void> {
|
async fetchEvents(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log("fetchEvents: Fetching ALL events for the master calendar.");
|
|
||||||
// Call the new '/service/all' endpoint
|
|
||||||
const path = `${import.meta.env.VITE_BASE_URL}/service/all`;
|
const path = `${import.meta.env.VITE_BASE_URL}/service/all`;
|
||||||
const response = await axios.get(path, { headers: authHeader(), withCredentials: true });
|
const response = await axios.get(path, { headers: authHeader(), withCredentials: true });
|
||||||
|
|
||||||
console.log("fetchEvents: Received all events from API:", response.data);
|
|
||||||
this.calendarOptions.events = response.data;
|
this.calendarOptions.events = response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching all calendar events:", error);
|
console.error("Error fetching all calendar events:", error);
|
||||||
@@ -125,7 +128,6 @@ export default defineComponent({
|
|||||||
const response = await axios.post(path, payload, { withCredentials: true, headers: authHeader() });
|
const response = await axios.post(path, payload, { withCredentials: true, headers: authHeader() });
|
||||||
|
|
||||||
if (response.data.ok === true) {
|
if (response.data.ok === true) {
|
||||||
// After creating a new event, refresh the entire master calendar
|
|
||||||
await this.fetchEvents();
|
await this.fetchEvents();
|
||||||
} else {
|
} else {
|
||||||
console.error("Failed to create event:", response.data.error);
|
console.error("Failed to create event:", response.data.error);
|
||||||
@@ -136,7 +138,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async handleEventDelete(eventId: string): Promise<void> {
|
async handleEventDelete(eventId: string): Promise<void> {
|
||||||
// ... (no changes needed in this method)
|
|
||||||
try {
|
try {
|
||||||
const path = `${import.meta.env.VITE_BASE_URL}/service/delete/${eventId}`;
|
const path = `${import.meta.env.VITE_BASE_URL}/service/delete/${eventId}`;
|
||||||
const response = await axios.delete(path, { withCredentials: true, headers: authHeader() });
|
const response = await axios.delete(path, { withCredentials: true, headers: authHeader() });
|
||||||
@@ -145,8 +146,12 @@ export default defineComponent({
|
|||||||
const eventToRemove = calendarApi.getEventById(eventId);
|
const eventToRemove = calendarApi.getEventById(eventId);
|
||||||
if (eventToRemove) eventToRemove.remove();
|
if (eventToRemove) eventToRemove.remove();
|
||||||
this.selectedEvent = null;
|
this.selectedEvent = null;
|
||||||
|
} else {
|
||||||
|
console.error("Failed to delete event:", response.data.error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error deleting event:", error);
|
||||||
}
|
}
|
||||||
} catch (error) { console.error("Error deleting event:", error); }
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 bg-gray-800 bg-opacity-75 flex items-center justify-center z-50">
|
<div class="fixed inset-0 bg-gray-800 bg-opacity-75 flex items-center justify-center z-50">
|
||||||
<div class="relative bg-white p-6 rounded-lg shadow-xl w-full max-w-md">
|
<div class="relative bg-white p-6 rounded-lg shadow-xl w-full max-w-md">
|
||||||
|
|
||||||
<div class="text-left">
|
<div class="text-left">
|
||||||
<h3 class="text-2xl leading-6 font-bold text-gray-900 mb-2">{{ event?.title }}</h3>
|
<h3 class="text-2xl leading-6 font-bold text-gray-900 mb-2">{{ event?.title }}</h3>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<p class="text-sm text-gray-600 whitespace-pre-wrap">{{ event?.extendedProps.description }}</p>
|
<p class="text-sm text-gray-600 whitespace-pre-wrap">{{ event?.extendedProps.description }}</p>
|
||||||
<p class="text-sm text-gray-500 mt-4">
|
<p class="text-sm text-gray-500 mt-4">
|
||||||
<strong>Start:</strong> {{ formatEventDate(event?.start) }}
|
<strong>When:</strong> {{ formatEventDate(event?.start) }}
|
||||||
</p>
|
|
||||||
<p v-if="event?.end" class="text-sm text-gray-500">
|
|
||||||
<strong>End:</strong> {{ formatEventDate(event?.end, true) }}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 flex justify-end space-x-3">
|
|
||||||
<button @click="confirmDelete" class="px-4 py-2 bg-red-600 text-white text-base font-medium rounded-md shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
|
<button @click="$emit('close-modal')" type="button" class="absolute top-0 right-0 mt-4 mr-4 text-gray-400 hover:text-gray-600 focus:outline-none" aria-label="Close modal">
|
||||||
Delete
|
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>
|
||||||
</button>
|
</button>
|
||||||
<button @click="$emit('close-modal')" class="px-4 py-2 bg-gray-200 text-gray-800 text-base font-medium rounded-md shadow-sm hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400">
|
|
||||||
|
<div class="mt-6 flex justify-between items-center">
|
||||||
|
<button @click="confirmDelete" class="px-4 py-2 bg-red-600 text-white text-base font-medium rounded-md shadow-sm hover:bg-red-700">
|
||||||
|
Delete Event
|
||||||
|
</button>
|
||||||
|
<button @click="$emit('close-modal')" class="px-4 py-2 bg-gray-200 text-gray-800 text-base font-medium rounded-md shadow-sm hover:bg-gray-300">
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -32,6 +35,7 @@ import dayjs from 'dayjs';
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'EventModal',
|
name: 'EventModal',
|
||||||
|
// This modal correctly expects a prop named 'event' of type 'EventApi'
|
||||||
props: {
|
props: {
|
||||||
event: {
|
event: {
|
||||||
type: Object as PropType<EventApi | null>,
|
type: Object as PropType<EventApi | null>,
|
||||||
@@ -44,15 +48,10 @@ export default defineComponent({
|
|||||||
this.$emit('delete-event', this.event.id);
|
this.$emit('delete-event', this.event.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
formatEventDate(date: Date | string | null | undefined, isEndDate: boolean = false): string {
|
formatEventDate(date: Date | string | null | undefined): string {
|
||||||
if (!date) return 'N/A';
|
if (!date) return 'N/A';
|
||||||
|
// Format the date and time from the FullCalendar event object
|
||||||
let dateObj = dayjs(date);
|
return dayjs(date).format('MMMM D, YYYY [at] h:mm A');
|
||||||
if (isEndDate) {
|
|
||||||
dateObj = dateObj.subtract(1, 'day');
|
|
||||||
}
|
|
||||||
|
|
||||||
return dateObj.format('MMMM D, YYYY');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user