#152 - added holidays
This commit is contained in:
		| @@ -12,6 +12,7 @@ use Toby\Domain\UserVacationStatsRetriever; | |||||||
| use Toby\Domain\VacationRequestStatesRetriever; | use Toby\Domain\VacationRequestStatesRetriever; | ||||||
| use Toby\Domain\VacationTypeConfigRetriever; | use Toby\Domain\VacationTypeConfigRetriever; | ||||||
| use Toby\Eloquent\Helpers\YearPeriodRetriever; | use Toby\Eloquent\Helpers\YearPeriodRetriever; | ||||||
|  | use Toby\Eloquent\Models\Holiday; | ||||||
| use Toby\Eloquent\Models\VacationRequest; | use Toby\Eloquent\Models\VacationRequest; | ||||||
| use Toby\Infrastructure\Http\Resources\HolidayResource; | use Toby\Infrastructure\Http\Resources\HolidayResource; | ||||||
| use Toby\Infrastructure\Http\Resources\VacationRequestResource; | use Toby\Infrastructure\Http\Resources\VacationRequestResource; | ||||||
| @@ -54,6 +55,8 @@ class DashboardController extends Controller | |||||||
|             ->limit(3) |             ->limit(3) | ||||||
|             ->get(); |             ->get(); | ||||||
|  |  | ||||||
|  |         $allHolidays = $yearPeriod->holidays; | ||||||
|  |  | ||||||
|         $limit = $vacationStatsRetriever->getVacationDaysLimit($user, $yearPeriod); |         $limit = $vacationStatsRetriever->getVacationDaysLimit($user, $yearPeriod); | ||||||
|         $used = $vacationStatsRetriever->getUsedVacationDays($user, $yearPeriod); |         $used = $vacationStatsRetriever->getUsedVacationDays($user, $yearPeriod); | ||||||
|         $pending = $vacationStatsRetriever->getPendingVacationDays($user, $yearPeriod); |         $pending = $vacationStatsRetriever->getPendingVacationDays($user, $yearPeriod); | ||||||
| @@ -66,6 +69,9 @@ class DashboardController extends Controller | |||||||
|             "remoteDays" => VacationResource::collection($remoteDays), |             "remoteDays" => VacationResource::collection($remoteDays), | ||||||
|             "vacationRequests" => VacationRequestResource::collection($vacationRequests), |             "vacationRequests" => VacationRequestResource::collection($vacationRequests), | ||||||
|             "holidays" => HolidayResource::collection($holidays), |             "holidays" => HolidayResource::collection($holidays), | ||||||
|  |             "allHolidays" => $allHolidays->mapWithKeys( | ||||||
|  |                 fn(Holiday $holiday): array => [$holiday->date->toDateString() => $holiday->name], | ||||||
|  |             ), | ||||||
|             "stats" => [ |             "stats" => [ | ||||||
|                 "limit" => $limit, |                 "limit" => $limit, | ||||||
|                 "remaining" => $remaining, |                 "remaining" => $remaining, | ||||||
|   | |||||||
| @@ -3,7 +3,9 @@ | |||||||
|   <div class="grid grid-cols-1 gap-4 items-start xl:grid-cols-3 xl:gap-8"> |   <div class="grid grid-cols-1 gap-4 items-start xl:grid-cols-3 xl:gap-8"> | ||||||
|     <div class="grid grid-cols-1 gap-4 xl:col-span-2"> |     <div class="grid grid-cols-1 gap-4 xl:col-span-2"> | ||||||
|       <Welcome :user="auth.user" /> |       <Welcome :user="auth.user" /> | ||||||
|       <VacationCalendar /> |       <VacationCalendar | ||||||
|  |         :holidays="allHolidays" | ||||||
|  |       /> | ||||||
|       <VacationStats :stats="stats" /> |       <VacationStats :stats="stats" /> | ||||||
|     </div> |     </div> | ||||||
|     <div class="grid grid-cols-1 gap-4"> |     <div class="grid grid-cols-1 gap-4"> | ||||||
| @@ -50,5 +52,6 @@ defineProps({ | |||||||
|   can: Object, |   can: Object, | ||||||
|   stats: Object, |   stats: Object, | ||||||
|   years: Object, |   years: Object, | ||||||
|  |   allHolidays: Object, | ||||||
| }) | }) | ||||||
| </script> | </script> | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								resources/js/Shared/ActiveComponent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								resources/js/Shared/ActiveComponent.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | import { h, ref } from 'vue' | ||||||
|  |  | ||||||
|  | const ActiveComponent = function(props, { attrs, slots }) { | ||||||
|  |   const key = props.pkey | ||||||
|  |   const isActive = ref(false) | ||||||
|  |  | ||||||
|  |   function onMouseover() { | ||||||
|  |     console.log('activated ' + key) | ||||||
|  |     isActive.value = true | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   function onMouseleave() { | ||||||
|  |     console.log('disabled ' + key) | ||||||
|  |     isActive.value = false | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return h(props.as, { | ||||||
|  |     ...attrs, | ||||||
|  |     class: 'hello', | ||||||
|  |     onMouseover, | ||||||
|  |     onMouseleave, | ||||||
|  |   }, [ | ||||||
|  |     slots, | ||||||
|  |     slots.default({ isActive }), | ||||||
|  |   ]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ActiveComponent.props = { | ||||||
|  |   as: { | ||||||
|  |     type: String, | ||||||
|  |     default: 'div', | ||||||
|  |   }, | ||||||
|  |   pkey: { | ||||||
|  |     type: Number, | ||||||
|  |     required: true, | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default ActiveComponent | ||||||
							
								
								
									
										70
									
								
								resources/js/Shared/Widgets/Calendar/DateComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								resources/js/Shared/Widgets/Calendar/DateComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | <template> | ||||||
|  |   <template> | ||||||
|  |     <Popper | ||||||
|  |       v-if="day.isHoliday" | ||||||
|  |       as="div" | ||||||
|  |       open-delay="200" | ||||||
|  |       hover | ||||||
|  |       offset-distance="0" | ||||||
|  |       @mouseover.passive="onMouseover" | ||||||
|  |       @mouseleave="onMouseleave" | ||||||
|  |     > | ||||||
|  |       <time | ||||||
|  |         :datetime="day.date" | ||||||
|  |         :class="[ day.isToday && 'flex h-6 w-6 items-center justify-center rounded-full bg-blumilk-500 font-semibold text-white', 'text-red-600' ]" | ||||||
|  |       > | ||||||
|  |         {{ day.dayNumber }} | ||||||
|  |       </time> | ||||||
|  |       <template #content> | ||||||
|  |         <div class="py-2 px-6 text-sm font-semibold text-left text-gray-700 bg-white rounded-lg border border-gray-400"> | ||||||
|  |           {{ getHolidayDescription(day) }} | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </Popper> | ||||||
|  |     <div | ||||||
|  |       v-else | ||||||
|  |       :class="{ 'hello': isActive && !day.isWeekend }" | ||||||
|  |       @mouseover.passive="onMouseover" | ||||||
|  |       @mouseleave="onMouseleave" | ||||||
|  |     > | ||||||
|  |       <time | ||||||
|  |         :datetime="day.date" | ||||||
|  |         :class="{ 'flex h-6 w-6 items-center justify-center rounded-full bg-blumilk-500 font-semibold text-white': day.isToday }" | ||||||
|  |       > | ||||||
|  |         {{ day.dayNumber }} | ||||||
|  |       </time> | ||||||
|  |     </div> | ||||||
|  |   </template> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup> | ||||||
|  | import Popper from 'vue3-popper' | ||||||
|  | import { defineProps, ref } from 'vue' | ||||||
|  |  | ||||||
|  | const props = defineProps({ | ||||||
|  |   day: { | ||||||
|  |     type: Object, | ||||||
|  |     required: true, | ||||||
|  |   }, | ||||||
|  |   holidaydescription: { | ||||||
|  |     type: Function, | ||||||
|  |   }, | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | const isActive = ref(false) | ||||||
|  |  | ||||||
|  | function onMouseover() { | ||||||
|  |   if (!isActive.value) | ||||||
|  |     isActive.value = true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function onMouseleave() { | ||||||
|  |   if (isActive.value) | ||||||
|  |     isActive.value = false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getHolidayDescription(day) { | ||||||
|  |   return props.holidaydescription(day) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | </script> | ||||||
| @@ -120,19 +120,14 @@ | |||||||
|           class="w-full grid grid-cols-7 gap-px" |           class="w-full grid grid-cols-7 gap-px" | ||||||
|           :class="{ 'grid-rows-1': calendarState.viewMode.isWeek }" |           :class="{ 'grid-rows-1': calendarState.viewMode.isWeek }" | ||||||
|         > |         > | ||||||
|           <div |           <DateComponent | ||||||
|             v-for="(day, index) in days" |             v-for="(day, index) in days" | ||||||
|             :key="index" |             :key="index" | ||||||
|  |             :day="day" | ||||||
|             class="flex flex-col relative py-2 px-3" |             class="flex flex-col relative py-2 px-3" | ||||||
|             :class="[day.isCurrentMonth ? 'bg-white' : 'bg-gray-50 text-gray-500', { 'hover:bg-blumilk-25': day.isCurrentMonth && !day.isWeekend }, { 'day': calendarState.viewMode.isWeek }, { 'bg-red-100': day.isCurrentMonth && day.isWeekend }, { 'bg-red-50': !day.isCurrentMonth && day.isWeekend }, { 'text-red-800': day.isWeekend }]" |             :class="[day.isCurrentMonth ? 'bg-white' : 'bg-gray-50 text-gray-500', { 'hover:bg-blumilk-25': day.isCurrentMonth && !day.isWeekend }, { 'day': calendarState.viewMode.isWeek }, { 'bg-red-100': day.isCurrentMonth && day.isWeekend }, { 'bg-red-50': !day.isCurrentMonth && day.isWeekend }, { 'text-red-800': day.isWeekend }]" | ||||||
|           > |             :holidaydescription="getHolidayDescription" | ||||||
|             <time |           /> | ||||||
|               :datetime="day.date" |  | ||||||
|               :class="{ 'flex h-6 w-6 items-center justify-center rounded-full bg-blumilk-500 font-semibold text-white': day.isToday }" |  | ||||||
|             > |  | ||||||
|               {{ day.dayNumber }} |  | ||||||
|             </time> |  | ||||||
|           </div> |  | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
| @@ -147,16 +142,23 @@ import { DateTime } from 'luxon' | |||||||
| import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo' | import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo' | ||||||
| import { useMonthInfo } from '@/Composables/monthInfo' | import { useMonthInfo } from '@/Composables/monthInfo' | ||||||
| import { viewModes, find as findViewMode } from '@/Shared/Widgets/Calendar/ViewModeOptions' | import { viewModes, find as findViewMode } from '@/Shared/Widgets/Calendar/ViewModeOptions' | ||||||
|  | import DateComponent from '@/Shared/Widgets/Calendar/DateComponent' | ||||||
|  |  | ||||||
|  | const props = defineProps({ | ||||||
|  |   holidays: Object, | ||||||
|  | }) | ||||||
|  |  | ||||||
| let days = ref([]) | let days = ref([]) | ||||||
| const months = useMonthInfo().getMonths() |  | ||||||
| function getCurrentDate() { | function getCurrentDate() { | ||||||
|   const { year, month, weekNumber } = DateTime.now() |   const { year, month, weekNumber } = DateTime.now() | ||||||
|   return { year, month, week: weekNumber } |   return { year, month, week: weekNumber } | ||||||
| } | } | ||||||
| const selectedYear = useCurrentYearPeriodInfo().year.value |  | ||||||
| const currentDate = getCurrentDate() | const currentDate = getCurrentDate() | ||||||
|  |  | ||||||
|  | const months = useMonthInfo().getMonths() | ||||||
|  | const selectedYear = useCurrentYearPeriodInfo().year.value | ||||||
|  |  | ||||||
| const calendar = { | const calendar = { | ||||||
|   viewMode: ref('week'), |   viewMode: ref('week'), | ||||||
|   currents: reactive({ |   currents: reactive({ | ||||||
| @@ -227,6 +229,7 @@ const customCalendar = { | |||||||
|       isCurrentMonth: isInCurrentMonth(day), |       isCurrentMonth: isInCurrentMonth(day), | ||||||
|       isToday: isToday(day), |       isToday: isToday(day), | ||||||
|       isWeekend: isWeekend(day), |       isWeekend: isWeekend(day), | ||||||
|  |       isHoliday: isHoliday(day), | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| } | } | ||||||
| @@ -325,6 +328,14 @@ function isWeekend(date) { | |||||||
| function isToday(date) { | function isToday(date) { | ||||||
|   return date.toISODate() === DateTime.local().toISODate() |   return date.toISODate() === DateTime.local().toISODate() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function isHoliday(date) { | ||||||
|  |   return props.holidays[date.toISODate()] !== undefined | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getHolidayDescription(day) { | ||||||
|  |   return props.holidays[day.date] | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="css"> | <style lang="css"> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user