corrad-bp/components/RSCalendar.vue
2025-04-09 11:16:18 +08:00

244 lines
6.4 KiB
Vue

<script setup>
import { DateTime } from "luxon";
const props = defineProps({
events: {
type: Array,
default: () => [],
},
});
const dateNow = ref(DateTime.now());
const arrDate = ref([]);
const dayInWeek = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const monthInYear = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const label = (date) => {
// console.log(date.toString());
return date.toFormat("d");
};
const nextMonth = () => {
dateNow.value = DateTime.local(
dateNow.value.year,
dateNow.value.month,
dateNow.value.day
).plus({
months: 1,
});
};
const prevMonth = () => {
dateNow.value = DateTime.local(
dateNow.value.year,
dateNow.value.month,
dateNow.value.day
).minus({
months: 1,
});
};
const getDateInMonth = () => {
const date = DateTime.local(dateNow.value.year, dateNow.value.month);
const dayInMonth = date.daysInMonth;
arrDate.value = [];
for (let i = 0; i < dayInMonth; i++) {
const day = i + 1;
const date = DateTime.local(dateNow.value.year, dateNow.value.month, day);
const toDay = date.toFormat("ccc");
// Start of the Date
if (i == 0) {
const toDayIndex = dayInWeek.indexOf(toDay);
for (let i = 0; i < toDayIndex; i++) {
const dayBefore = toDayIndex - i;
const dateBefore = date.minus({ days: dayBefore });
updateArrDate(dateBefore, false, false);
}
if (DateTime.now().toISODate() == date.toISODate())
updateArrDate(date, true, true);
else updateArrDate(date, true, false);
}
// End of the Date
else if (i == dayInMonth - 1) {
const toDayIndex = dayInWeek.length - dayInWeek.indexOf(toDay) - 1;
if (DateTime.now().toISODate() == date.toISODate())
updateArrDate(date, true, true);
else updateArrDate(date, true, false);
for (let i = 0; i < toDayIndex; i++) {
const dayAfter = i + 1;
const dateAfter = date.plus({ days: dayAfter });
updateArrDate(dateAfter, false, false);
}
} else {
if (DateTime.now().toISODate() == date.toISODate())
updateArrDate(date, true, true);
else updateArrDate(date, true, false);
}
}
// console.log(arrDate.value);
};
const updateArrDate = (date, currentMonth, isToday) => {
arrDate.value.push({
date: date,
isCurrentMonth: currentMonth,
isToday: isToday,
event: checkEvent(date),
});
};
// Check props.event start and end date with date given
const checkEvent = (date) => {
let result = false;
props.events.forEach((event) => {
if (event.startDate) {
let startDate = "";
let endDate = "";
startDate = DateTime.fromISO(event.startDate);
if (event.endDate) {
endDate = DateTime.fromISO(event.endDate);
}
if (date.toISODate() == startDate.toISODate())
result = [
{
position: "start",
title: event.title,
},
];
else if (
date.toISODate() > startDate.toISODate() &&
date.toISODate() < endDate.toISODate()
)
result = [
{
position: "between",
title: event.title,
},
];
else if (date.toISODate() == endDate.toISODate())
result = [
{
position: "end",
title: event.title,
},
];
else result = false;
}
});
return result; // return result
};
onMounted(() => {
getDateInMonth();
});
watch(dateNow, () => {
getDateInMonth();
});
</script>
<template>
<div class="calendar">
<div class="calendar-header">
<!-- <div class="flex">1</div> -->
<div class="flex justify-between items-center my-4">
<h5>
{{ date.toFormat("LLLL yyyy") }}
</h5>
<div class="flex gap-5">
<button
@click="prevMonth"
class="flex items-center px-2 py-2 rounded-md shadow-md bg-white text-primary hover:bg-primary/80 hover:text-white"
>
<Icon size="20px" name="ic:round-keyboard-arrow-left"></Icon>
</button>
<button
@click="nextMonth"
class="flex items-center px-2 py-2 rounded-md shadow-md bg-white text-primary hover:bg-primary/80 hover:text-white"
>
<Icon size="20px" name="ic:round-keyboard-arrow-right"></Icon>
</button>
</div>
</div>
</div>
<div class="calendar-body rounded-md border border-primary/20">
<div class="calendar-body-header max-w-full">
<ul
class="grid grid-cols-7 list-none bg-primary/50 text-primary rounded-t-md"
>
<li
class="flex justify-center items-center p-5"
v-for="(val, index) in dayInWeek"
:key="index"
>
<span class="font-semibold text-base">{{ val }}</span>
</li>
</ul>
</div>
<div class="calendar-body-content">
<ul class="grid grid-cols-7 list-none">
<li
class="relative flex justify-center items-center h-30 border border-primary/10 whitespace-nowrap"
:class="{
'bg-primary/5': val.isToday,
}"
v-for="(val, index) in allDate"
:key="index"
>
<div class="flex-1">
<label
class="absolute top-2 right-3 font-semibold"
:class="{
'text-primary/20': !val.isCurrentMonth,
'text-primary/70': val.isCurrentMonth,
}"
for="day"
>{{ label(val.date) }}</label
>
<div class="event" v-if="val.event">
<div
class="font-semibold p-5 bg-primary text-white rounded-md"
style="min-height: 5rem"
:class="{
'rounded-r-none ml-5': event.position === 'start',
'rounded-r-none rounded-l-none':
event.position === 'between',
'rounded-l-none mr-5': event.position === 'end',
}"
v-for="(event, index) in val.event"
:key="index"
>
{{ event.position == "start" ? event.title : " " }}
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</template>