142 lines
5.1 KiB
Vue
142 lines
5.1 KiB
Vue
<script setup>
|
|
import { ref, onMounted } from 'vue';
|
|
import axios from 'axios';
|
|
import { usePageTitle } from '../composables/Core/usePageTitle';
|
|
import { useNavigate } from '../composables/Core/useNavigate';
|
|
import { useModal } from '../composables/Core/useModal';
|
|
import LoadingSpinner from '../Components/LoadingSpinner.vue';
|
|
import CardSimple from '../Components/Core/CardSimple.vue';
|
|
import InputGroupButton from '../Components/Core/Forms/InputGroupButton.vue';
|
|
|
|
const props = defineProps({
|
|
target: { type: String, required: true }
|
|
});
|
|
|
|
usePageTitle('Shipment Details');
|
|
const { navigate } = useNavigate();
|
|
const modal = useModal();
|
|
|
|
const shipment = ref(null);
|
|
const loading = ref(true);
|
|
|
|
const fetchShipmentDetail = async () => {
|
|
loading.value = true;
|
|
try {
|
|
const response = await axios.post('/Shipments/List', { target: props.target });
|
|
// Simplified: filter from list for now
|
|
if (response.data.success) {
|
|
shipment.value = response.data.data.find(s => s.hashkey === props.target);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch shipment detail:', error);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const updateStatus = async (newStatus) => {
|
|
try {
|
|
const response = await axios.post('/Shipments/Status/Update', {
|
|
target: props.target,
|
|
status: newStatus
|
|
});
|
|
if (response.data.success) {
|
|
shipment.value.status = newStatus;
|
|
}
|
|
} catch (error) {
|
|
modal.open({
|
|
title: 'Error',
|
|
body: 'Failed to update status'
|
|
});
|
|
}
|
|
};
|
|
|
|
onMounted(fetchShipmentDetail);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="shipment-detail-page pb-5">
|
|
<div class="tf-container mt-4">
|
|
<InputGroupButton
|
|
text="Back to Shipments"
|
|
variant="text"
|
|
@click="navigate({ page: 'ShipmentList' })"
|
|
class="mb-4"
|
|
>
|
|
<i class="fas fa-chevron-left me-1"></i> Back to Shipments
|
|
</InputGroupButton>
|
|
|
|
<div v-if="loading" class="text-center py-5">
|
|
<LoadingSpinner />
|
|
</div>
|
|
|
|
<div v-else-if="!shipment" class="alert alert-danger">
|
|
Shipment not found.
|
|
</div>
|
|
|
|
<div v-else>
|
|
<CardSimple title="Track Shipment" class="mb-4">
|
|
<template #headerAction>
|
|
<span class="badge bg-primary px-3 py-2 rounded-pill">{{ shipment.status }}</span>
|
|
</template>
|
|
|
|
<div class="mb-4">
|
|
<div class="small text-muted">Tracking Number</div>
|
|
<div class="fw_5 h5">{{ shipment.tracking_number || 'Pending Assignment' }}</div>
|
|
</div>
|
|
|
|
<div class="row g-4 border-top pt-4">
|
|
<div class="col-6">
|
|
<div class="small text-muted mb-1">Customer</div>
|
|
<div class="fw_5">{{ shipment.customer?.name }}</div>
|
|
<div class="small">{{ shipment.destination_address }}</div>
|
|
</div>
|
|
<div class="col-6 text-end">
|
|
<div class="small text-muted mb-1">Store</div>
|
|
<div class="fw_5">{{ shipment.store?.name }}</div>
|
|
<div class="small">Shipping Fee: ₱{{ shipment.shipping_fee }}</div>
|
|
</div>
|
|
</div>
|
|
</CardSimple>
|
|
|
|
<CardSimple title="Update Progress">
|
|
<div class="d-flex flex-wrap gap-3">
|
|
<InputGroupButton
|
|
v-if="shipment.status === 'PENDING'"
|
|
text="Mark as Picked Up"
|
|
variant="outline"
|
|
size="sm"
|
|
@click="updateStatus('PICKED_UP')"
|
|
/>
|
|
<InputGroupButton
|
|
v-if="shipment.status === 'PICKED_UP'"
|
|
text="Mark as In Transit"
|
|
variant="outline"
|
|
size="sm"
|
|
@click="updateStatus('IN_TRANSIT')"
|
|
/>
|
|
<InputGroupButton
|
|
v-if="shipment.status === 'IN_TRANSIT'"
|
|
text="Mark as Delivered"
|
|
variant="primary"
|
|
size="sm"
|
|
@click="updateStatus('DELIVERED')"
|
|
/>
|
|
<InputGroupButton
|
|
v-if="['PENDING', 'PICKED_UP', 'IN_TRANSIT'].includes(shipment.status)"
|
|
text="Mark as Failed"
|
|
variant="danger"
|
|
size="sm"
|
|
@click="updateStatus('FAILED')"
|
|
/>
|
|
</div>
|
|
</CardSimple>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.fw_5 { font-weight: 500; }
|
|
</style>
|