added hot water

This commit is contained in:
2025-10-06 21:13:28 -04:00
parent 91d6d708dc
commit f42444e81d
7 changed files with 77 additions and 41 deletions

View File

@@ -44,6 +44,10 @@
Usage Factor Usage Factor
<span v-if="sortKey === 'house_factor'">{{ sortAsc ? '' : '' }}</span> <span v-if="sortKey === 'house_factor'">{{ sortAsc ? '' : '' }}</span>
</th> </th>
<th @click="sortBy('hot_water_summer')" :class="sortKey === 'hot_water_summer' ? 'cursor-pointer hover:text-white bg-orange-500' : 'cursor-pointer hover:text-white'">
Hot Water Tank
<span v-if="sortKey === 'hot_water_summer'">{{ sortAsc ? '' : '' }}</span>
</th>
<th>Address</th> <th>Address</th>
<th class="text-right">Actions</th> <th class="text-right">Actions</th>
</tr> </tr>
@@ -73,6 +77,7 @@
</router-link> </router-link>
</td> </td>
<td>{{ oil.house_factor }}</td> <td>{{ oil.house_factor }}</td>
<td>{{ oil.hot_water_summer ? 'Yes' : 'No' }}</td>
<td>{{ oil.customer_address }}, {{ oil.customer_town }}</td> <td>{{ oil.customer_address }}, {{ oil.customer_town }}</td>
<td class="text-right"> <td class="text-right">
<div class="flex items-center justify-end gap-2"> <div class="flex items-center justify-end gap-2">
@@ -111,19 +116,31 @@
</div> </div>
<div class="mt-4"> <div class="mt-4">
<label class="label p-0 mb-1"><span class="label-text">Tank Level</span></label> <div class="grid grid-cols-2 gap-4">
<div v-if="oil.last_fill === null" class="text-gray-500 text-sm">New Auto Customer</div> <div>
<div v-else> <label class="label p-0 mb-1"><span class="label-text">Usage Factor</span></label>
<progress class="progress w-full" <div class="text-sm">{{ oil.house_factor }}</div>
:value="oil.estimated_gallons_left" </div>
:max="oil.tank_size" <div>
:class="{ <label class="label p-0 mb-1"><span class="label-text">Hot Water Tank</span></label>
'progress-success': getTankLevelPercentage(oil) > 60, <div class="text-sm">{{ oil.hot_water_summer ? 'Yes' : 'No' }}</div>
'progress-warning': getTankLevelPercentage(oil) >= 25 && getTankLevelPercentage(oil) <= 60, </div>
'progress-error': getTankLevelPercentage(oil) < 25 </div>
}" <div class="mt-4">
></progress> <label class="label p-0 mb-1"><span class="label-text">Tank Level</span></label>
<div class="text-xs text-gray-400 text-right">{{ oil.estimated_gallons_left }} / {{ oil.tank_size }} gal estimated</div> <div v-if="oil.last_fill === null" class="text-gray-500 text-sm">New Auto Customer</div>
<div v-else>
<progress class="progress w-full"
:value="oil.estimated_gallons_left"
:max="oil.tank_size"
:class="{
'progress-success': getTankLevelPercentage(oil) > 60,
'progress-warning': getTankLevelPercentage(oil) >= 25 && getTankLevelPercentage(oil) <= 60,
'progress-error': getTankLevelPercentage(oil) < 25
}"
></progress>
<div class="text-xs text-gray-400 text-right">{{ oil.estimated_gallons_left }} / {{ oil.tank_size }} gal estimated</div>
</div>
</div> </div>
</div> </div>
@@ -169,6 +186,7 @@ interface AutoDelivery {
house_factor: number; house_factor: number;
tank_size: number; tank_size: number;
auto_status: number; auto_status: number;
hot_water_summer: number;
open_ticket_id?: number | null; open_ticket_id?: number | null;
} }
@@ -182,7 +200,7 @@ export default defineComponent({
user: null, user: null,
deliveries: [] as AutoDelivery[], deliveries: [] as AutoDelivery[],
// --- NEW: Data properties for sorting --- // --- NEW: Data properties for sorting ---
sortKey: 'tank_level_percent' as keyof AutoDelivery | 'tank_level_percent', sortKey: 'tank_level_percent' as keyof AutoDelivery | 'tank_level_percent' | 'hot_water_summer',
sortAsc: true, sortAsc: true,
} }
}, },
@@ -212,6 +230,11 @@ export default defineComponent({
} else { } else {
valA = a[this.sortKey as keyof AutoDelivery]; valA = a[this.sortKey as keyof AutoDelivery];
valB = b[this.sortKey as keyof AutoDelivery]; valB = b[this.sortKey as keyof AutoDelivery];
// Special handling for hot_water_summer to ensure it's number
if (this.sortKey === 'hot_water_summer') {
valA = valA || 0;
valB = valB || 0;
}
} }
// Handle nulls or different types if necessary // Handle nulls or different types if necessary
@@ -237,7 +260,7 @@ export default defineComponent({
}, },
methods: { methods: {
// --- NEW: Method to handle sorting --- // --- NEW: Method to handle sorting ---
sortBy(key: keyof AutoDelivery | 'tank_level_percent') { sortBy(key: keyof AutoDelivery | 'tank_level_percent' | 'hot_water_summer') {
if (this.sortKey === key) { if (this.sortKey === key) {
// If clicking the same key, reverse the direction // If clicking the same key, reverse the direction
this.sortAsc = !this.sortAsc; this.sortAsc = !this.sortAsc;
@@ -267,7 +290,7 @@ export default defineComponent({
}); });
}, },
get_oil_orders() { get_oil_orders() {
const path = import.meta.env.VITE_AUTO_URL + '/delivery/all/customers'; const path = import.meta.env.VITE_BASE_URL + '/customer/automatic/deliveries';
axios.get(path, { withCredentials: true, headers: authHeader() }) axios.get(path, { withCredentials: true, headers: authHeader() })
.then((response: any) => { .then((response: any) => {
this.deliveries = response.data; this.deliveries = response.data;

View File

@@ -220,6 +220,17 @@ export default defineComponent({
}) })
.catch(() => { this.user = null; }); .catch(() => { this.user = null; });
}, },
getCustomerTypeList() {
const path = import.meta.env.VITE_BASE_URL + "/query/customertype";
axios.get(path, { withCredentials: true })
.then((response: any) => { this.custList = response.data; });
},
getStatesList() {
const path = import.meta.env.VITE_BASE_URL + "/query/states";
axios.get(path, { withCredentials: true })
.then((response: any) => { this.stateList = response.data; });
},
CreateCustomer(payload: any) { CreateCustomer(payload: any) {
const path = import.meta.env.VITE_BASE_URL + "/customer/create"; const path = import.meta.env.VITE_BASE_URL + "/customer/create";
axios.post(path, payload, { withCredentials: true, headers: authHeader() }) axios.post(path, payload, { withCredentials: true, headers: authHeader() })
@@ -232,7 +243,7 @@ export default defineComponent({
} }
}); });
}, },
onSubmit() { onSubmit() {
this.v$.$validate(); // Trigger validation this.v$.$validate(); // Trigger validation
if (!this.v$.$error) { if (!this.v$.$error) {
// If validation passes, submit the form // If validation passes, submit the form
@@ -243,16 +254,6 @@ export default defineComponent({
console.log("Form validation failed."); console.log("Form validation failed.");
} }
}, },
getCustomerTypeList() {
const path = import.meta.env.VITE_BASE_URL + "/query/customertype";
axios.get(path, { withCredentials: true })
.then((response: any) => { this.custList = response.data; });
},
getStatesList() {
const path = import.meta.env.VITE_BASE_URL + "/query/states";
axios.get(path, { withCredentials: true })
.then((response: any) => { this.stateList = response.data; });
},
}, },
}); });
</script> </script>

View File

@@ -339,6 +339,7 @@ interface ServiceParts {
oil_filter_2: string; oil_filter_2: string;
oil_nozzle: string; oil_nozzle: string;
oil_nozzle_2: string; oil_nozzle_2: string;
hot_water_tank: number;
} }
interface ServicePlan { interface ServicePlan {

View File

@@ -28,6 +28,10 @@
<div class="font-bold">Oil Nozzle 2:</div> <div class="font-bold">Oil Nozzle 2:</div>
<div :style="{ color: getNozzleColor(parts.oil_nozzle_2), fontWeight: 'bold' }">{{ parts.oil_nozzle_2 }}</div> <div :style="{ color: getNozzleColor(parts.oil_nozzle_2), fontWeight: 'bold' }">{{ parts.oil_nozzle_2 }}</div>
</div> </div>
<div class="col-span-2" v-if="parts.hot_water_tank !== undefined">
<div class="font-bold">Hot Water Tank:</div>
<div>{{ parts.hot_water_tank ? 'Yes' : 'No' }}</div>
</div>
</div> </div>
<div v-else> <div v-else>
<p class="text-xs opacity-70">No equipment parts information available.</p> <p class="text-xs opacity-70">No equipment parts information available.</p>
@@ -51,6 +55,7 @@ interface ServiceParts {
oil_filter_2: string; oil_filter_2: string;
oil_nozzle: string; oil_nozzle: string;
oil_nozzle_2: string; oil_nozzle_2: string;
hot_water_tank: number;
} }
// 2. Define the Props interface, explicitly allowing 'null'. // 2. Define the Props interface, explicitly allowing 'null'.
@@ -65,7 +70,7 @@ defineEmits(['open-parts-modal']);
const hasPartsData = computed(() => { const hasPartsData = computed(() => {
if (!props.parts) return false; if (!props.parts) return false;
return !!(props.parts.oil_filter || props.parts.oil_filter_2 || props.parts.oil_nozzle || props.parts.oil_nozzle_2); return !!(props.parts.oil_filter || props.parts.oil_filter_2 || props.parts.oil_nozzle || props.parts.oil_nozzle_2 || (props.parts.hot_water_tank !== undefined && props.parts.hot_water_tank !== null));
}); });
const getNozzleColor = (nozzleString: string): string => { const getNozzleColor = (nozzleString: string): string => {

View File

@@ -7,7 +7,7 @@
<!-- Modal Header --> <!-- Modal Header -->
<div class="flex justify-between items-center border-b border-gray-700 pb-3 mb-4"> <div class="flex justify-between items-center border-b border-gray-700 pb-3 mb-4">
<h3 class="text-2xl font-bold">Edit Oil Filters & Nozzles</h3> <h3 class="text-2xl font-bold">Edit Equipment Parts</h3>
<button @click="$emit('close-modal')" type="button" class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button> <button @click="$emit('close-modal')" type="button" class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</div> </div>
@@ -32,6 +32,21 @@
</select> </select>
</div> </div>
<!-- Hot Water Tank Section -->
<div class="md:col-span-2 border-t border-gray-700 pt-4">
<label class="block text-sm font-medium mb-2">Hot Water Tank</label>
<div class="flex space-x-6">
<label class="cursor-pointer">
<input type="radio" :value="1" v-model="editableParts.hot_water_tank" class="radio radio-primary" />
<span class="ml-2">Yes</span>
</label>
<label class="cursor-pointer">
<input type="radio" :value="0" v-model="editableParts.hot_water_tank" class="radio radio-primary" />
<span class="ml-2">No</span>
</label>
</div>
</div>
<!-- Oil Nozzle 1 Section --> <!-- Oil Nozzle 1 Section -->
<div class="md:col-span-2 border-t border-gray-700 pt-4"> <div class="md:col-span-2 border-t border-gray-700 pt-4">
<label class="block text-sm font-medium mb-2">Oil Nozzle 1</label> <label class="block text-sm font-medium mb-2">Oil Nozzle 1</label>
@@ -92,6 +107,7 @@ interface ServiceParts {
oil_filter_2: string; oil_filter_2: string;
oil_nozzle: string; oil_nozzle: string;
oil_nozzle_2: string; oil_nozzle_2: string;
hot_water_tank: number;
} }
interface NozzleParts { interface NozzleParts {

View File

@@ -82,18 +82,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-span-6 "> <div class="col-span-6 ">
<div class="col-span-4 "> <div class="col-span-4 ">
<div class="grid grid-cols-12 "> <div class="grid grid-cols-12 ">