Skip to content

Commit

Permalink
#327 - handy calendar (#411)
Browse files Browse the repository at this point in the history
* #327 - added handy calendar on request show view, moved them into component also

* #327 - added handy calendar

* #327 - update

* #327 - hidden calendar for employee

* #327 - csf

* #327 - cr fix
  • Loading branch information
kamilpiech97 authored Mar 27, 2024
1 parent b66edef commit 1d7812f
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 179 deletions.
50 changes: 48 additions & 2 deletions app/Infrastructure/Http/Controllers/VacationRequestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Domain\VacationTypeConfigRetriever;
use Toby\Eloquent\Helpers\YearPeriodRetriever;
use Toby\Eloquent\Models\Holiday;
use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\Vacation;
use Toby\Eloquent\Models\VacationRequest;
use Toby\Infrastructure\Http\Requests\VacationRequestRequest;
use Toby\Infrastructure\Http\Resources\SimpleUserResource;
use Toby\Infrastructure\Http\Resources\SimpleVacationRequestResource;
use Toby\Infrastructure\Http\Resources\VacationRequestActivityResource;
use Toby\Infrastructure\Http\Resources\VacationRequestResource;

Expand Down Expand Up @@ -127,8 +130,11 @@ public function indexForApprovers(
/**
* @throws AuthorizationException
*/
public function show(VacationRequest $vacationRequest, UserVacationStatsRetriever $statsRetriever): Response
{
public function show(
VacationRequest $vacationRequest,
UserVacationStatsRetriever $statsRetriever,
YearPeriodRetriever $yearPeriodRetriever,
): Response {
$this->authorize("show", $vacationRequest);

$vacationRequest->load(["vacations.user.profile", "user.permissions", "user.profile", "activities.user.profile"]);
Expand All @@ -137,6 +143,29 @@ public function show(VacationRequest $vacationRequest, UserVacationStatsRetrieve
$pending = $statsRetriever->getPendingVacationDays($vacationRequest->user, $vacationRequest->yearPeriod);
$remaining = $limit - $used - $pending;

$yearPeriod = $yearPeriodRetriever->selected();
$requestFromDateMonth = $vacationRequest->from->month;
$requestToDateMonth = $vacationRequest->to->month;

$holidays = $yearPeriod->holidays()
->get();

$user = $vacationRequest->user;

$vacations = $user
->vacations()
->with("vacationRequest.vacations")
->whereBelongsTo($yearPeriod)
->approved()
->get();

$pendingVacations = $user
->vacations()
->with("vacationRequest.vacations")
->whereBelongsTo($yearPeriod)
->pending()
->get();

return inertia("VacationRequest/Show", [
"request" => new VacationRequestResource($vacationRequest),
"activities" => VacationRequestActivityResource::collection($vacationRequest->activities),
Expand All @@ -146,6 +175,23 @@ public function show(VacationRequest $vacationRequest, UserVacationStatsRetrieve
"pending" => $pending,
"remaining" => $remaining,
],
"handyCalendarData" => [
"holidays" => $holidays->mapWithKeys(
fn(Holiday $holiday): array => [$holiday->date->toDateString() => $holiday->name],
),
"vacations" => $vacations->mapWithKeys(
fn(Vacation $vacation): array => [
$vacation->date->toDateString() => new SimpleVacationRequestResource($vacation->vacationRequest),
],
),
"pendingVacations" => $pendingVacations->mapWithKeys(
fn(Vacation $vacation): array => [
$vacation->date->toDateString() => new SimpleVacationRequestResource($vacation->vacationRequest),
],
),
"startMonth" => $requestFromDateMonth > 1 ? --$requestFromDateMonth : 1,
"endMonth" => $requestToDateMonth < 12 ? ++$requestToDateMonth : 12,
],
]);
}

Expand Down
186 changes: 9 additions & 177 deletions resources/js/Pages/AnnualSummary.vue
Original file line number Diff line number Diff line change
@@ -1,83 +1,12 @@
<script setup>
import { DateTime } from 'luxon'
import useVacationTypeInfo from '@/Composables/vacationTypeInfo.js'
import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo.js'
import Popper from 'vue3-popper'
import VacationPopup from '@/Shared/VacationPopup.vue'
import CalendarComponent from '@/Shared/CalendarComponent.vue'
const props = defineProps({
defineProps({
holidays: Object,
vacations: Object,
pendingVacations: Object,
overButtonDay: String,
})
const { findType } = useVacationTypeInfo()
const { year } = useCurrentYearPeriodInfo()
const months = []
for (let i = 1; i < 13; i++) {
const currentMonth = DateTime.fromObject({ year: year.value, month: i }).startOf('month')
const start = currentMonth.startOf('week')
const end = currentMonth.endOf('month').endOf('week')
const month = {
name: currentMonth.monthLong,
days: [],
}
for (let day = start; day < end; day = day.plus({ day: 1 })) {
const isCurrentMonth = isInCurrentMonth(day, currentMonth)
month.days.push({
date: day,
isCurrentMonth: isCurrentMonth,
isToday: isCurrentMonth && isToday(day),
isWeekend: isWeekend(day),
isVacation: isCurrentMonth && isVacation(day),
isPendingVacation: isCurrentMonth && isPendingVacation(day),
isHoliday: isHoliday(day),
})
}
months.push(month)
}
function isHoliday(date) {
return props.holidays[date.toISODate()] !== undefined
}
function isVacation(date) {
return props.vacations[date.toISODate()] !== undefined
}
function isPendingVacation(date) {
return props.pendingVacations[date.toISODate()] !== undefined
}
function isToday(date) {
return DateTime.now().hasSame(date, 'year') && DateTime.now().hasSame(date, 'day')
}
function isInCurrentMonth(date, currentMonth) {
return currentMonth.hasSame(date, 'month')
}
function isWeekend(date) {
return date.weekday === 6 || date.weekday === 7
}
function getVacationBorder(day) {
const type = findType(getVacationInfo(day).type)
return type.border
}
function getVacationInfo(day) {
return day.isVacation ? props.vacations[day.date.toISODate()] : props.pendingVacations[day.date.toISODate()]
}
</script>

<template>
Expand All @@ -91,110 +20,13 @@ function getVacationInfo(day) {
<div
class="grid grid-cols-1 gap-8 py-8 px-4 mx-auto max-w-3xl border-t border-gray-200 sm:grid-cols-2 sm:px-6 xl:grid-cols-3 xl:px-8 xl:max-w-none 2xl:grid-cols-4"
>
<section
v-for="month in months"
:key="month.name"
class="text-center"
>
<h2 class="font-semibold text-gray-900 capitalize">
{{ month.name }}
</h2>
<div class="grid grid-cols-7 mt-6 text-xs font-semibold leading-6 text-gray-500">
<div>Pn</div>
<div>Wt</div>
<div>Śr</div>
<div>Cz</div>
<div>Pt</div>
<div>Sb</div>
<div>Nd</div>
</div>
<div class="grid grid-cols-7 mt-2 text-sm ring-1 ring-gray-200 shadow">
<template
v-for="(day, dayIdx) in month.days"
:key="dayIdx"
>
<template v-if="day.isCurrentMonth">
<Popper
v-if="day.isVacation || day.isPendingVacation"
open-delay="200"
hover
offset-distance="0"
>
<div :class="[day.isPendingVacation && 'mx-0.5']">
<button :class="[day.isPendingVacation && `border-dashed`, `${getVacationBorder(day)} isolate bg-white w-full hover:bg-blumilk-25 border-b-4 py-1.5 font-medium focus:outline-blumilk-500 cursor-default`]">
<time
:datetime="day.date.toISODate()"
:class="[ day.isToday && 'bg-blumilk-500 font-semibold text-white rounded-full', 'mx-auto flex h-7 w-7 p-4 items-center justify-center']"
>
{{ day.date.day }}
</time>
</button>
</div>
<template #content>
<VacationPopup
:vacation="getVacationInfo(day)"
:see-vacation-details="true"
/>
</template>
</Popper>
<Popper
v-else-if="day.isHoliday"
open-delay="200"
hover
offset-distance="0"
>
<button class="py-1.5 w-full font-medium bg-white hover:bg-blumilk-25 border-b-4 border-transparent focus:outline-blumilk-500 cursor-default">
<time
:datetime="day.date.toISODate()"
:class="[ day.isToday && 'bg-blumilk-500 font-semibold text-white rounded-full', 'text-red-700 font-bold mx-auto flex h-7 w-7 p-4 items-center justify-center']"
>
{{ day.date.day }}
</time>
</button>
<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">
{{ holidays[day.date.toISODate()] }}
</div>
</template>
</Popper>
<button
v-else-if="day.isWeekend"
class="py-1.5 w-full font-medium bg-white hover:bg-blumilk-25 border-b-4 border-transparent focus:outline-blumilk-500 hover:bg-transparent cursor-default"
>
<time
:datetime="day.date.toISODate()"
class="text-red-700 font-bold mx-auto flex h-7 w-7 p-4 items-center justify-center"
>
{{ day.date.day }}
</time>
</button>
<InertiaLink
v-else
href="/vacation/requests/create"
:data="{ 'from_date': day.date.toISODate() }"
class="py-1.5 w-full font-medium bg-white hover:bg-blumilk-25 border-b-4 border-transparent focus:outline-blumilk-500"
>
<time
:datetime="day.date.toISODate()"
:class="[ day.isToday && 'bg-blumilk-500 font-semibold text-white rounded-full', 'mx-auto flex h-7 w-7 p-4 items-center justify-center']"
>
{{ day.date.day }}
</time>
</InertiaLink>
</template>
<div
v-else
class="focus:z-10 py-1.5 w-full font-medium text-gray-400 bg-gray-50 border-b-4 border-transparent"
>
<div class="flex justify-center items-center p-4 mx-auto w-7 h-7">
<time :datetime="day.date.toISODate()">
{{ day.date.day }}
</time>
</div>
</div>
</template>
</div>
</section>
<CalendarComponent
:start-month="1"
:end-month="12"
:vacations="vacations"
:pending-vacations="pendingVacations"
:holidays="holidays"
/>
</div>
</div>
</template>
23 changes: 23 additions & 0 deletions resources/js/Pages/VacationRequest/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import Activity from '@/Shared/Activity.vue'
import Status from '@/Shared/Status.vue'
import VacationType from '@/Shared/VacationType.vue'
import VacationBar from '@/Shared/VacationBar.vue'
import CalendarComponent from '@/Shared/CalendarComponent.vue'
defineProps({
request: Object,
activities: Object,
stats: Object,
auth: Object,
handyCalendarData: Object,
})
</script>

Expand Down Expand Up @@ -271,6 +273,27 @@ defineProps({
</ul>
</div>
</div>
<div
v-if="(auth.can.manageRequestsAsAdministrativeApprover || request.can.manageRequestsAsTechnicalApprover) && request.state !== 'cancelled'"
class="bg-white shadow-md"
>
<div class="py-5 px-4 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900">
Kalendarz pracownika
</h3>
</div>
<div
class="grid grid-cols-1 gap-8 py-8 px-4 mx-auto max-w-3xl border-t border-gray-200 sm:grid-cols-2 sm:px-6"
>
<CalendarComponent
:start-month="handyCalendarData.startMonth"
:end-month="handyCalendarData.endMonth"
:vacations="handyCalendarData.vacations"
:pending-vacations="handyCalendarData.pendingVacations"
:holidays="handyCalendarData.holidays"
/>
</div>
</div>
</div>
</div>
</template>
Loading

0 comments on commit 1d7812f

Please sign in to comment.