Working calender/service

This commit is contained in:
2025-08-22 14:48:28 -04:00
parent 7eed45ab32
commit 4bcff598e6
9 changed files with 629 additions and 466 deletions

View File

@@ -7,47 +7,63 @@
<div class=" w-full px-10 ">
<div class="text-sm breadcrumbs mb-10">
<ul>
<li><router-link :to="{ name: 'home' }">Home</router-link></li>
<li>Service Calls</li>
<li>
<router-link :to="{ name: 'home' }">
Home
</router-link>
</li>
<li>
Service Calls
</li>
</ul>
</div>
<div class="flex text-2xl mb-5 font-bold">
Upcoming Service Calls
Service Calls
</div>
<div v-if="isLoading" class="text-center p-10">
<p>Loading upcoming service calls...</p>
<p>Loading service calls...</p>
</div>
<div v-else-if="services.length === 0" class="text-center p-10 bg-gray-100 rounded-md">
<p>No upcoming service calls found.</p>
<div v-else-if="services.length === 0" class="text-center p-10 bg-base-200 rounded-md">
<p>No service calls found.</p>
</div>
<div v-else class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class=" bg-neutral">
<!-- ============================================= -->
<!-- ============== UPDATED TABLE SECTION ============== -->
<!-- ============================================= -->
<div v-else class="overflow-x-auto rounded-lg">
<table class="min-w-full divide-y divide-gray-700">
<thead class="bg-base-200">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Scheduled Date</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Customer Name</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Address</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Service Type</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Description</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-base-content uppercase tracking-wider">Scheduled Date</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-base-content uppercase tracking-wider">Time</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-base-content uppercase tracking-wider">Customer Name</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-base-content uppercase tracking-wider">Address</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-base-content uppercase tracking-wider">Service Type</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-base-content uppercase tracking-wider">Description</th>
</tr>
</thead>
<tbody class=" divide-y bg-neutral">
<tr v-for="service in services" :key="service.id" @click="openEditModal(service)" class="hover:bg-blue-600 hover:text-black cursor-pointer">
<tbody class="bg-base-100 divide-y divide-gray-700">
<!-- The hover color is now a slightly lighter shade of the background -->
<tr v-for="service in services" :key="service.id" @click="openEditModal(service)" class="hover:bg-base-300 cursor-pointer">
<td class="px-6 py-4 whitespace-nowrap">{{ formatDate(service.scheduled_date) }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ formatTime(service.scheduled_date) }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ service.customer_name }}</td>
<td class="px-6 py-4 whitespace-nowrap">{{ service.customer_address }}, {{ service.customer_town }}</td>
<td class="px-6 py-4 whitespace-nowrap font-medium" :style="{ color: getServiceTypeColor(service.type_service_call) }">
{{ getServiceTypeName(service.type_service_call) }}
</td>
<td class="px-6 py-4 whitespace-normal text-sm text-gray-500">{{ service.description }}</td>
<td class="px-6 py-4 whitespace-normal text-sm">{{ service.description }}</td>
</tr>
</tbody>
</table>
</div>
<!-- ============================================= -->
<!-- ============== END UPDATED SECTION ============== -->
<!-- ============================================= -->
</div>
</div>
@@ -63,13 +79,14 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import axios from 'axios';
import authHeader from '../../services/auth.header';
import Header from '../../layouts/headers/headerauth.vue';
import SideBar from '../../layouts/sidebar/sidebar.vue';
import Footer from '../../layouts/footers/footer.vue';
import ServiceEditModal from './ServiceEditModal.vue';
import { defineComponent } from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import ServiceEditModal from './ServiceEditModal.vue'
import dayjs from 'dayjs'; // Import dayjs to handle date/time formatting
interface ServiceCall {
id: number;
@@ -90,7 +107,7 @@ export default defineComponent({
services: [] as ServiceCall[],
isLoading: true,
selectedServiceForEdit: null as ServiceCall | null,
};
}
},
created() {
this.userStatus();
@@ -112,7 +129,7 @@ export default defineComponent({
this.isLoading = false;
}
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
@@ -131,12 +148,53 @@ export default defineComponent({
})
},
// --- HELPER METHODS WITH IMPLEMENTATIONS RESTORED ---
openEditModal(service: ServiceCall) {
this.selectedServiceForEdit = service;
},
closeEditModal() {
this.selectedServiceForEdit = null;
},
async handleSaveChanges(updatedService: ServiceCall) {
try {
const path = `${import.meta.env.VITE_BASE_URL}/service/update/${updatedService.id}`;
const response = await axios.put(path, updatedService, { headers: authHeader(), withCredentials: true });
if (response.data.ok) {
const index = this.services.findIndex(s => s.id === updatedService.id);
if (index !== -1) {
this.services[index] = response.data.service;
}
this.closeEditModal();
}
} catch (error) {
console.error("Failed to save changes:", error);
alert("An error occurred while saving. Please check the console.");
}
},
async handleDeleteService(serviceId: number) {
try {
const path = `${import.meta.env.VITE_BASE_URL}/service/delete/${serviceId}`;
const response = await axios.delete(path, { headers: authHeader(), withCredentials: true });
if (response.data.ok) {
this.services = this.services.filter(s => s.id !== serviceId);
this.closeEditModal();
}
} catch (error) {
console.error("Failed to delete service call:", error);
alert("An error occurred while deleting. Please check the console.");
}
},
formatDate(dateString: string): string {
const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' };
// Adding a timeZone option helps prevent off-by-one-day errors
return new Date(dateString).toLocaleDateString(undefined, { ...options, timeZone: 'UTC' });
if (!dateString) return 'N/A';
return dayjs(dateString).format('MMMM D, YYYY');
},
formatTime(dateString: string): string {
if (!dateString) return 'N/A';
return dayjs(dateString).format('h:mm A');
},
getServiceTypeName(typeId: number): string {
@@ -155,51 +213,11 @@ export default defineComponent({
0: 'blue',
1: 'red',
2: 'green',
3: '#B58900', // A darker yellow for text
3: '#B58900',
4: 'black',
};
return colorMap[typeId] || 'gray';
},
// --- MODAL MANAGEMENT METHODS ---
openEditModal(service: ServiceCall) {
this.selectedServiceForEdit = service;
},
closeEditModal() {
this.selectedServiceForEdit = null;
},
async handleSaveChanges(updatedService: ServiceCall) {
try {
const path = `${import.meta.env.VITE_BASE_URL}/service/update/${updatedService.id}`;
const response = await axios.put(path, updatedService, { headers: authHeader(), withCredentials: true });
if (response.data.ok) {
const index = this.services.findIndex(s => s.id === updatedService.id);
if (index !== -1) {
this.services[index] = response.data.service;
}
this.closeEditModal();
}
} catch (error) {
console.error("Failed to save changes:", error);
alert("An error occurred while saving. Please check the console.");
}
},
async handleDeleteService(serviceId: number) {
try {
const path = `${import.meta.env.VITE_BASE_URL}/service/delete/${serviceId}`;
const response = await axios.delete(path, { headers: authHeader(), withCredentials: true });
if (response.data.ok) {
this.services = this.services.filter(s => s.id !== serviceId);
this.closeEditModal();
}
} catch (error) {
console.error("Failed to delete service call:", error);
alert("An error occurred while deleting. Please check the console.");
}
},
}
},
});
})
</script>