purityselect/resources/js/pages/patient/orders-list.vue
2024-10-25 01:05:27 +05:00

558 lines
18 KiB
Vue

<script setup>
import { computed, onMounted, reactive, ref } from "vue";
import { useStore } from "vuex";
const router = useRouter();
const store = useStore();
const orders = ref([]);
const selectedDate = ref();
const headers = [
{ title: "Order Number", key: "id" },
{ title: "Customer", key: "customer" },
{ title: "Total", key: "total" },
{ title: "Status", key: "status" },
{ title: "Actions", key: "actions" },
];
const loading = ref(false);
const search = ref("");
const filterDialog = ref(false);
const isShown = ref(false);
const startDateMenu = ref(null)
const endDateMenu = ref(null)
const showCustomRangePicker = ref(false);
const dateRange = ref([]);
const filters = reactive({
startDate: null,
endDate: null,
dateRangeText: computed(() => {
if (filters.startDate && filters.endDate) {
return `${formatDateDate(filters.startDate)} - ${formatDateDate(filters.endDate)}`;
}
return 'Select Date';
}),
});
const statusOptions = ["Pending", "Shipped", "Delivered", "Cancelled"];
const getStatusColor = (status) => {
switch (status) {
case "Pending":
return "orange";
case "Shipped":
return "blue";
case "Delivered":
return "green";
case "Cancelled":
return "red";
default:
return "gray";
}
};
const openFilterDialog = () => {
isShown.value = true;
};
const resetFilters = async () => {
filters.search = "";
filters.status = [];
filters.startDate = null
filters.endDate = null
startDateMenu.value = null
endDateMenu.value = null
store.dispatch("updateIsLoading", true);
await store.dispatch("orderPtaientList");
orders.value = store.getters.getPatientOrderList;
console.log(orders.value);
store.dispatch("updateIsLoading", false);
};
const applyFilters = async () => {
search.value = filters.search;
filterDialog.value = false;
await getFilter()
};
const filteredOrders = computed(() => {
let filtered = store.getters.getPatientOrderList;
if (filters.search) {
filtered = filtered.filter((order) =>
order.orderNumber
.toLowerCase()
.includes(filters.search.toLowerCase())
);
}
// if (filters.status.length > 0) {
// filtered = filtered.filter((order) =>
// filters.status.includes(order.status)
// );
// }
// if (filters.startDate) {
// const startDate = new Date(filters.startDate);
// filtered = filtered.filter((order) => {
// const orderDate = new Date(order.created_at);
// return orderDate >= startDate;
// });
// }
// if (filters.endDate) {
// const endDate = new Date(filters.endDate);
// filtered = filtered.filter((order) => {
// const orderDate = new Date(order.created_at);
// return orderDate <= endDate;
// });
// }
filtered.sort((a, b) => {
return b.id - a.id;
});
return filtered;
});
const datepickStart = async () => {
console.log("ppicker", startDateMenu.value);
if (startDateMenu.value) {
const selectedDate = new Date(startDateMenu.value);
const dateWithoutTime = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
// Format the date as needed
console.log("formattedDate",);
// const formattedDate = selectedDate.getFullYear() + '-' + selectedDate.getMonth() + '-' + selectedDate.getDate() //dateWithoutTime.toISOString().slice(0, 10);
const formattedDate = formatDateDate(selectedDate)
console.log("formattedDate", formattedDate);
filters.startDate = formattedDate
showStartDatePicker.value = false;
// await getFilter()
}
}
const formatDateDate = (date) => {
const messageDate = new Date(date);
const options = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
};
return messageDate.toLocaleDateString('en-US', options).replace(/\//g, '-');
};
const datepickendDate = async () => {
console.log("ppicker", filters.endDate);
if (endDateMenu.value) {
const selectedDate = new Date(endDateMenu.value);
const dateWithoutTime = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
// Format the date as needed
console.log("formattedDate", dateWithoutTime);
const formattedDate = formatDateDate(selectedDate)//dateWithoutTime.toISOString().slice(0, 10);
console.log("formattedDate", formattedDate);
filters.endDate = formattedDate
showEndDatePicker.value = false;
//await getFilter()
}
}
const viewOrder = (orderId) => {
router.push({ name: "order-detail", params: { id: orderId } });
};
const formatDate = (date) => {
const messageDate = new Date(date);
const options = {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric", // Change from '2-digit' to 'numeric'
minute: "2-digit",
hour12: true, // Add hour12: true to get 12-hour format with AM/PM
};
const formattedDate = messageDate
.toLocaleString("en-US", options)
.replace(/\//g, "-")
.replace(',', ''); // Remove the comma
return formattedDate.trim();
};
const getFilter = async () => {
console.log("filter", filters.startDate, filters.endDate);
await store.dispatch('orderPtaientListFilter', {
from_date: formatDateDate(filters.startDate),
to_date: formatDateDate(filters.endDate),
})
orders.value = store.getters.getPatientOrderList;
store.dispatch('updateIsLoading', false)
}
onMounted(async () => {
store.dispatch("updateIsLoading", true);
await store.dispatch("orderPtaientList");
orders.value = store.getters.getPatientOrderList;
orders.value.sort((a, b) => {
return b.id - a.id;
});
console.log(orders.value);
});
const selectToday = () => {
const today = new Date().toISOString().split('T')[0];
filters.startDate = today;
filters.endDate = today;
showCustomRangePicker.value = false;
};
const selectYesterday = () => {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
const formattedYesterday = yesterday.toISOString().split('T')[0];
filters.startDate = formattedYesterday;
filters.endDate = formattedYesterday;
showCustomRangePicker.value = false;
};
const selectLast7Days = () => {
const today = new Date();
const sevenDaysAgo = new Date(today);
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 6);
filters.startDate = sevenDaysAgo.toISOString().split('T')[0];
filters.endDate = today.toISOString().split('T')[0];
showCustomRangePicker.value = false;
};
const minDate = computed(() => {
const date = new Date();
date.setFullYear(date.getFullYear() - 1);
return date.toISOString().substr(0, 10);
});
const maxDate = computed(() => {
const date = new Date();
return date.toISOString().substr(0, 10);
});
const applyCustomRange = (dates) => {
console.log(dateRange.value)
dateRange.value.sort();
if (dates.length === 2) {
[filters.startDate, filters.endDate] = dates;
showCustomRangePicker.value = false;
}
};
const showCustomRangePickerFunction = (state) => {
if (state) {
dateRange.value = []
showCustomRangePicker.value = true;
}
}
</script>
<template>
<VDialog v-model="store.getters.getIsLoading" width="110" height="150" color="primary">
<VCardText class="" style="color: white !important">
<div class="demo-space-x">
<VProgressCircular :size="40" color="primary" indeterminate />
</div>
</VCardText>
</VDialog>
<v-container class="pt-0">
<v-row>
<v-col cols="12">
<VCardTitle class="pt-0"><b>ORDERS </b></VCardTitle>
<v-card>
<v-card-title>
<v-row class="px-0 py-4">
<v-col cols="12" md="4">
<VMenu location="bottom" :close-on-content-click="false" :nudge-right="40"
transition="scale-transition" offset-y min-width="auto" density="compact">
<template #activator="{ props }">
<v-text-field v-model="filters.dateRangeText" label="Select Date Range"
v-bind="props" outlined density="compact" readonly></v-text-field>
</template>
<v-card>
<v-list>
<v-list-item @click="selectToday">Today</v-list-item>
<v-list-item @click="selectYesterday">Yesterday</v-list-item>
<v-list-item @click="selectLast7Days">Last 7 Days</v-list-item>
<v-list-item @click="showCustomRangePickerFunction(true)">Custom
Range</v-list-item>
</v-list>
<v-date-picker v-if="showCustomRangePicker" v-model="dateRange" :max="maxDate"
:min="minDate" multiple class="custom-date-picker" mode="range"
@update:model-value="applyCustomRange" hide-header>
</v-date-picker>
</v-card>
</VMenu>
</v-col>
<v-col cols="4">
<v-btn color="primary" class="text-capitalize mr-1" text @click="applyFilters">
Filter
</v-btn>
<v-btn color="primary" class="text-capitalize" text @click="resetFilters">
Reset
</v-btn>
</v-col>
</v-row>
</v-card-title>
</v-card>
</v-col>
</v-row>
<v-row v-if="filteredOrders.length > 0">
<v-col v-for="order in filteredOrders" :key="order.id" cols="12" md="6">
<v-card class="order-card mb-6 rounded-lg elevation-3">
<div class="order-header pa-4">
<v-row no-gutters align="center">
<v-col>
<div class="d-flex align-center">
<v-avatar color="rgb(var(--v-theme-yellow))" size="56"
class="text-grey-800 text-h6 font-weight-bold mr-4">
#{{ order.id }}
</v-avatar>
<div>
<div class="text-subtitle-1 font-weight-medium">{{ formatDate(order.created_at)
}}</div>
</div>
</div>
</v-col>
<v-col cols="auto" class="ml-auto">
<v-chip color="primary" label x-large class="font-weight-bold">
Total: ${{ parseFloat(order.order_total_amount +
order.order_total_shipping).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}) }}
</v-chip>
</v-col>
</v-row>
</div>
<v-divider></v-divider>
<v-card-text class="pa-4">
<h3 class="text-h6 font-weight-bold mb-4">Order Items</h3>
<div class="order-items-container">
<v-list class="order-items-list">
<v-list-item v-for="item in order.order_items" :key="item.id" class="mb-2 rounded-lg"
two-line>
<v-list-item-avatar tile size="80" class="rounded-lg">
<v-img :src="item.image_url" cover></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title class="text-subtitle-1 font-weight-medium">{{
item.title
}}</v-list-item-title>
<v-list-item-subtitle>
<v-chip x-small class="mr-2" outlined>Qty: {{ item.qty }} </v-chip>
<v-chip x-small outlined>${{ parseFloat(item.price).toLocaleString('en-US',
{
minimumFractionDigits: 2, maximumFractionDigits: 2
}) }}
each</v-chip>
<v-chip color="primary" x-small>$ {{ parseFloat(item.qty *
item.price).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
}}</v-chip>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
</v-list-item-action>
</v-list-item>
</v-list>
</div>
</v-card-text>
<v-divider></v-divider>
<v-card-actions class="pa-4">
<v-spacer></v-spacer>
<v-btn @click="viewOrder(order.id)" color="primary" outlined rounded>
<v-icon left>mdi-eye</v-icon>
View Details
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
<v-row v-else>
<v-col cols="12" md="12">
<v-card class="mb-4 rounded">
<v-card-title class="d-flex justify-space-between align-center">
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="12" class="text-center">no data found </v-col>
</v-row>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-dialog v-model="filterDialog" max-width="500">
<v-card>
<v-card-title>
<span class="text-h5">Filter Orders</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12">
<v-text-field v-model="filters.search" label="Search" outlined dense></v-text-field>
</v-col>
<v-col cols="12">
<v-select v-model="filters.status" :items="statusOptions" label="Status" outlined dense
multiple></v-select>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-btn color="primary" text @click="resetFilters">
Reset Filters
</v-btn>
<v-spacer></v-spacer>
<v-btn color="primary" text @click="applyFilters">
Apply
</v-btn>
<v-btn text @click="filterDialog = false"> Cancel </v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<style scoped>
.custom-select {
min-height: 44px;
/* Adjust the minimum height as needed */
padding-top: 8px;
/* Adjust top padding as needed */
padding-bottom: 8px;
/* Adjust bottom padding as needed */
}
.text-primary {
color: rgb(var(--v-theme-yellow-theme-button)) !important;
}
.v-date-picker-month__day .v-btn {
--v-btn-height: 23px !important;
--v-btn-size: 0.85rem;
}
.custom-date-picker {
font-size: 0.85em;
}
.custom-date-picker :deep(.v-date-picker-month) {
width: 100%;
}
.custom-date-picker :deep(.v-date-picker-month__day) {
width: 30px;
height: 30px;
}
.custom-date-picker :deep(.v-date-picker-month) {
min-width: 300px;
}
.custom-date-picker :deep(.v-date-picker-month__day .v-btn) {
--v-btn-height: 20px !important;
}
.order-card {
transition: all 0.3s;
}
.order-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 20px -10px rgba(0, 0, 0, 0.1), 0 4px 20px 0px rgba(0, 0, 0, 0.1), 0 7px 8px -5px rgba(0, 0, 0, 0.1) !important;
}
.order-header {
background-color: #f5f5f5;
}
.order-items-container {
height: 155px;
/* Set a fixed height */
overflow-y: auto;
/* Enable vertical scrolling */
}
.order-items-list {
padding-right: 16px;
/* Add some padding for the scrollbar */
}
.order-card .v-list-item {
border: 1px solid rgba(0, 0, 0, 0.12);
}
/* Custom scrollbar styles */
.order-items-container::-webkit-scrollbar {
width: 8px;
}
.order-items-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.order-items-container::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
.order-items-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
/* Mobile styles */
@media (max-width: 600px) {
.order-header {
flex-direction: column;
}
.order-header .v-avatar {
margin-bottom: 16px;
}
.order-header .v-col {
text-align: center;
}
.order-header .ml-auto {
margin: 16px auto 0 auto;
}
.order-items-container {
height: auto;
}
}
</style>