salix-front/src/pages/Zone/ZoneDeliveryDays.vue

258 lines
7.3 KiB
Vue

<script setup>
import { computed, onMounted, ref, watch, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import ZoneDeliveryPanel from './ZoneDeliveryPanel.vue';
import ZoneDeliveryCalendar from './ZoneDeliveryCalendar.vue';
import { useStateStore } from 'stores/useStateStore';
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
import { useArrayData } from 'src/composables/useArrayData';
const { t } = useI18n();
const stateStore = useStateStore();
const weekdayStore = useWeekdayStore();
const nMonths = ref(4);
const _date = ref(Date.vnNew());
const _data = ref(null);
const firstDay = ref(null);
const lastDay = ref(null);
const months = ref([]);
const days = ref({});
const exclusions = ref({});
const geoExclusions = ref({});
const events = ref([]);
const arrayData = useArrayData('ZoneDeliveryDays', {
url: 'Zones/getEvents',
});
const { store } = arrayData;
const refreshEvents = () => {
days.value = {};
if (!data.value) return;
let day = new Date(firstDay.value.getTime());
while (day <= lastDay.value) {
let stamp = day.getTime();
let wday = day.getDay();
let dayEvents = [];
let _exclusions = exclusions.value[stamp] || [];
if (events.value) {
for (let event of events.value) {
let match;
switch (event.type) {
case 'day':
match = event.dated == stamp;
break;
default:
match =
event.wdays[wday] &&
(!event.started || stamp >= event.started) &&
(!event.ended || stamp <= event.ended);
break;
}
if (match && !_exclusions.find((e) => e.zoneFk == event.zoneFk)) {
dayEvents.push(event);
}
}
}
if (dayEvents.length) days.value[stamp] = dayEvents;
day.setDate(day.getDate() + 1);
}
};
const date = computed({
get: () => _date.value,
set: (value) => {
_date.value = value;
let stamp = value.getTime();
firstDay.value = new Date(stamp);
firstDay.value.setDate(1);
lastDay.value = new Date(stamp);
lastDay.value.setMonth(lastDay.value.getMonth() + nMonths.value);
lastDay.value.setDate(0);
months.value = [];
for (let i = 0; i < nMonths.value; i++) {
let monthDate = new Date(stamp);
monthDate.setMonth(value.getMonth() + i);
months.value.push(monthDate);
}
refreshEvents();
},
});
const data = computed({
get: () => {
return _data.value;
},
set: (value) => {
_data.value = value;
value = value || {};
events.value = value.events;
function toStamp(date) {
return date && new Date(date).setHours(0, 0, 0, 0);
}
exclusions.value = {};
let _exclusions = value.exclusions;
if (_exclusions) {
for (let exclusion of _exclusions) {
let stamp = toStamp(exclusion.dated);
if (!exclusions[stamp]) exclusions.value[stamp] = [];
exclusions.value[stamp].push(exclusion);
}
}
geoExclusions.value = {};
let _geoExclusions = value.geoExclusions;
if (_geoExclusions) {
for (let geoExclusion of _geoExclusions) {
let stamp = toStamp(geoExclusion.dated);
if (!geoExclusions[stamp]) geoExclusions.value[stamp] = [];
geoExclusions.value[stamp].push(geoExclusion);
}
}
let _events = value.events;
if (_events) {
for (let event of _events) {
event.dated = toStamp(event.dated);
event.ended = toStamp(event.ended);
event.started = toStamp(event.started);
event.wdays = weekdayStore.fromSet(event.weekDays || '');
}
}
refreshEvents();
},
});
watch(
() => store.data,
(value) => {
data.value = value;
},
{ immediate: true }
);
const getMonthNameAndYear = (date) => {
const monthName = weekdayStore.getLocaleMonths[date.getMonth()].locale;
const year = date.getFullYear();
return `${monthName} ${year}`;
};
const headerTitle = computed(() => {
if (!months.value?.length) return;
const firstMonth = getMonthNameAndYear(months.value[0]);
const lastMonth = getMonthNameAndYear(months.value[months.value.length - 1]);
return `${firstMonth} - ${lastMonth}`;
});
const step = (direction) => {
const _date = new Date(date.value);
_date.setMonth(_date.getMonth() + nMonths.value * direction);
date.value = _date;
};
onMounted(async () => {
stateStore.rightDrawer = true;
let initialDate = Date.vnNew();
initialDate.setDate(1);
initialDate.setHours(0, 0, 0, 0);
date.value = initialDate;
weekdayStore.initStore();
});
onUnmounted(() => arrayData.destroy());
</script>
<template>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
flat
@click="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</Teleport>
</template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
<QScrollArea class="fit text-grey-8">
<ZoneDeliveryPanel />
</QScrollArea>
</QDrawer>
<QPage class="q-pa-md flex justify-center">
<QCard style="height: max-content">
<div class="calendars-header">
<QBtn
icon="arrow_left"
size="sm"
flat
class="full-height"
@click="step(-1)"
/>
<span>{{ headerTitle }}</span>
<QBtn
icon="arrow_right"
size="sm"
flat
class="full-height"
@click="step(1)"
/>
</div>
<div class="calendars-container">
<ZoneDeliveryCalendar
v-for="(month, index) in months"
:key="index"
:month="month.getMonth() + 1"
:year="month.getFullYear()"
:month-date="month"
:geo-exclusions="geoExclusions"
:exclusions="exclusions"
:days-map="days"
/>
</div>
</QCard>
</QPage>
</template>
<style lang="scss" scoped>
.calendars-header {
height: 45px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: $primary;
font-weight: bold;
font-size: 16px;
}
.calendars-container {
max-width: 800px;
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
</style>