#71 - annual summary #113
@@ -10,6 +10,7 @@ use Inertia\Response;
|
||||
|
|
||||
use Toby\Eloquent\Helpers\YearPeriodRetriever;
|
||||
use Toby\Eloquent\Models\Holiday;
|
||||
use Toby\Eloquent\Models\Vacation;
|
||||
use Toby\Infrastructure\Http\Resources\SimpleVacationRequestResource;
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
|
||||
class AnnualSummaryController extends Controller
|
||||
{
|
||||
@@ -25,22 +26,22 @@ class AnnualSummaryController extends Controller
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
|
||||
$vacations = $request->user()
|
||||
->vacations()
|
||||
->with("vacationRequest")
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
->with("vacationRequest.vacations")
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
->whereBetween("date", [$startDate, $endDate])
|
||||
->approved()
|
||||
->get();
|
||||
|
||||
$pendingVacations = $request->user()
|
||||
->vacations()
|
||||
->with("vacationRequest")
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
->with("vacationRequest.vacations")
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
->whereBetween("date", [$startDate, $endDate])
|
||||
->pending()
|
||||
->get();
|
||||
|
||||
return inertia("AnnualSummary", [
|
||||
"holidays" => $holidays->mapWithKeys(fn(Holiday $holiday) => [$holiday->date->toDateString() => $holiday->name]),
|
||||
"vacations" => $vacations->mapWithKeys(fn(Vacation $vacation) => [$vacation->date->toDateString() => $vacation->vacationRequest->type]),
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
"pendingVacations" => $pendingVacations->mapWithKeys(fn(Vacation $vacation) => [$vacation->date->toDateString() => $vacation->vacationRequest->type]),
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
"vacations" => $vacations->mapWithKeys(fn(Vacation $vacation) => [$vacation->date->toDateString() => new SimpleVacationRequestResource($vacation->vacationRequest)]),
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
"pendingVacations" => $pendingVacations->mapWithKeys(fn(Vacation $vacation) => [$vacation->date->toDateString() => new SimpleVacationRequestResource($vacation->vacationRequest)]),
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Infrastructure\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class SimpleVacationRequestResource extends JsonResource
|
||||
{
|
||||
public static $wrap = null;
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
"id" => $this->id,
|
||||
"name" => $this->name,
|
||||
"type" => $this->type,
|
||||
"state" => $this->state,
|
||||
"from" => $this->from->toDisplayString(),
|
||||
"to" => $this->to->toDisplayString(),
|
||||
"days" => $this->vacations->count(),
|
||||
];
|
||||
}
|
||||
}
|
||||
62
package-lock.json
generated
62
package-lock.json
generated
@@ -20,6 +20,7 @@
|
||||
"echarts": "^5.3.2",
|
||||
"eslit": "^6.0.0",
|
||||
"flatpickr": "^4.6.11",
|
||||
"floating-vue": "^2.0.0-beta.13",
|
||||
"laravel-mix": "^6.0.43",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^2.3.1",
|
||||
@@ -1681,6 +1682,19 @@
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.3.1.tgz",
|
||||
"integrity": "sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g=="
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.1.10.tgz",
|
||||
"integrity": "sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@headlessui/vue": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.5.0.tgz",
|
||||
@@ -4866,6 +4880,18 @@
|
||||
"integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/floating-vue": {
|
||||
"version": "2.0.0-beta.13",
|
||||
"resolved": "https://registry.npmjs.org/floating-vue/-/floating-vue-2.0.0-beta.13.tgz",
|
||||
"integrity": "sha512-C2bGEtdbOXm+2rmkn8W6dTQeh3xJT7YbdHnrbanYDS3vK/1lumdXhYA6j2Qs+9shViNjoVUUND1EhLxLDP2OZA==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^0.1.10",
|
||||
"vue-resize": "^2.0.0-alpha.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
@@ -9029,6 +9055,14 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-material-design-icons/-/vue-material-design-icons-5.0.0.tgz",
|
||||
"integrity": "sha512-lYSJFW/TyQqmg7MvUbEB8ua1mwWy/v8qve7QJuA/UWUAXC4/yVUdAm4pg/sM9+k5n7VLckBv6ucOROuGBsGPDQ=="
|
||||
},
|
||||
"node_modules/vue-resize": {
|
||||
"version": "2.0.0-alpha.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
|
||||
"integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==",
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-style-loader": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
|
||||
@@ -10755,6 +10789,19 @@
|
||||
"strip-json-comments": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"@floating-ui/core": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.3.1.tgz",
|
||||
"integrity": "sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g=="
|
||||
},
|
||||
"@floating-ui/dom": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.1.10.tgz",
|
||||
"integrity": "sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==",
|
||||
"requires": {
|
||||
"@floating-ui/core": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"@headlessui/vue": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.5.0.tgz",
|
||||
@@ -13304,6 +13351,15 @@
|
||||
"integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==",
|
||||
"dev": true
|
||||
},
|
||||
"floating-vue": {
|
||||
"version": "2.0.0-beta.13",
|
||||
"resolved": "https://registry.npmjs.org/floating-vue/-/floating-vue-2.0.0-beta.13.tgz",
|
||||
"integrity": "sha512-C2bGEtdbOXm+2rmkn8W6dTQeh3xJT7YbdHnrbanYDS3vK/1lumdXhYA6j2Qs+9shViNjoVUUND1EhLxLDP2OZA==",
|
||||
"requires": {
|
||||
"@floating-ui/dom": "^0.1.10",
|
||||
"vue-resize": "^2.0.0-alpha.1"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
@@ -16265,6 +16321,12 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-material-design-icons/-/vue-material-design-icons-5.0.0.tgz",
|
||||
"integrity": "sha512-lYSJFW/TyQqmg7MvUbEB8ua1mwWy/v8qve7QJuA/UWUAXC4/yVUdAm4pg/sM9+k5n7VLckBv6ucOROuGBsGPDQ=="
|
||||
},
|
||||
"vue-resize": {
|
||||
"version": "2.0.0-alpha.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz",
|
||||
"integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==",
|
||||
"requires": {}
|
||||
},
|
||||
"vue-style-loader": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"echarts": "^5.3.2",
|
||||
"eslit": "^6.0.0",
|
||||
"flatpickr": "^4.6.11",
|
||||
"floating-vue": "^2.0.0-beta.13",
|
||||
"laravel-mix": "^6.0.43",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^2.3.1",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import 'flatpickr/dist/themes/light.css';
|
||||
@import 'vue-toastification/dist/index.css';
|
||||
@import 'floating-vue/dist/style.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@@ -68,3 +69,16 @@
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #dadce0;
|
||||
}
|
||||
|
||||
.v-popper--theme-tooltip .v-popper__inner {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.v-popper--theme-tooltip .v-popper__arrow-outer {
|
||||
border-color: #527ABA;
|
||||
}
|
||||
|
||||
.v-popper--theme-tooltip:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<InertiaHead title="Podsumowanie roczne" />
|
||||
<div class="bg-white shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg font-medium leading-6 text-gray-900">
|
||||
Podsumowanie roczne
|
||||
</h2>
|
||||
</div>
|
||||
<div class="max-w-md" />
|
||||
<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"
|
||||
@@ -23,32 +25,46 @@
|
||||
<div>Sb</div>
|
||||
<div>Nd</div>
|
||||
</div>
|
||||
<div class="grid isolate grid-cols-7 mt-2 text-sm ring-1 ring-gray-200 shadow">
|
||||
<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"
|
||||
>
|
||||
<button
|
||||
v-if="day.isCurrentMonth"
|
||||
:class="[day.isVacation && `${getVacationBorder(day.date)}`, day.isPendingVacation && `border-dashed mx-0.5 ${getPendingVacationBorder(day.date)}`, !day.isVacation && !day.isPendingVacation && 'border-transparent', 'relative bg-white hover:bg-gray-100 border-b-4 py-1.5 focus:z-10 font-medium']"
|
||||
:class="[day.isVacation && `${getVacationBorder(day.date)}`, day.isPendingVacation && `border-dashed mx-0.5 ${getPendingVacationBorder(day.date)}`, !day.isVacation && !day.isPendingVacation && 'border-transparent', 'relative bg-white hover:bg-blumilk-25 border-b-4 py-1.5 font-medium']"
|
||||
>
|
||||
<div :class="[day.isCurrentMonth && (day.isWeekend || day.isHoliday) && 'text-red-600 font-bold', day.isToday && 'bg-blumilk-500 font-semibold text-white rounded-full', 'mx-auto flex h-7 w-7 p-4 items-center justify-center']">
|
||||
<time :datetime="day.date.toISODate()">
|
||||
{{ day.date.day }}
|
||||
</time>
|
||||
</div>
|
||||
<Popper
|
||||
v-if="day.isHoliday || day.isVacation || day.isPendingVacation"
|
||||
hover
|
||||
<Tooltip
|
||||
v-if="day.isVacation || day.isPendingVacation"
|
||||
:triggers="['click']"
|
||||
placement="bottom"
|
||||
auto-hide
|
||||
>
|
||||
<button class="absolute inset-0" />
|
||||
|
||||
<template #content>
|
||||
<div class="py-2 px-4 text-gray-900 bg-white rounded-md shadow-md text-md">
|
||||
{{ dayIdx }}
|
||||
<div class="absolute inset-0" />
|
||||
<template #popper>
|
||||
<div class="mt-1">
|
||||
<VacationPopup :vacation="getVacationInfo(day)" />
|
||||
</div>
|
||||
</template>
|
||||
</Popper>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
v-else-if="day.isHoliday"
|
||||
:triggers="['click']"
|
||||
placement="bottom"
|
||||
auto-hide
|
||||
>
|
||||
<div class="absolute inset-0" />
|
||||
<template #popper>
|
||||
<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>
|
||||
</Tooltip>
|
||||
</button>
|
||||
<div
|
||||
v-else
|
||||
@@ -71,7 +87,9 @@
|
||||
import { DateTime } from 'luxon'
|
||||
import useVacationTypeInfo from '@/Composables/vacationTypeInfo'
|
||||
import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo'
|
||||
import Popper from 'vue3-popper'
|
||||
import { Tooltip } from 'floating-vue'
|
||||
import VacationPopup from '@/Shared/VacationPopup'
|
||||
|
||||
const props = defineProps({
|
||||
holidays: Object,
|
||||
vacations: Object,
|
||||
@@ -136,14 +154,18 @@ function isWeekend(date) {
|
||||
}
|
||||
|
||||
function getVacationBorder(date) {
|
||||
const type = findType(props.vacations[date.toISODate()])
|
||||
const type = findType(props.vacations[date.toISODate()].type)
|
||||
|
||||
return type.border.approved
|
||||
}
|
||||
|
||||
function getPendingVacationBorder(date) {
|
||||
const type = findType(props.pendingVacations[date.toISODate()])
|
||||
const type = findType(props.pendingVacations[date.toISODate()].type)
|
||||
|
||||
return type.border.approved
|
||||
}
|
||||
|
||||
function getVacationInfo(day) {
|
||||
return day.isVacation ? props.vacations[day.date.toISODate()] : props.pendingVacations[day.date.toISODate()]
|
||||
}
|
||||
</script>
|
||||
62
resources/js/Shared/VacationPopup.vue
Normal file
62
resources/js/Shared/VacationPopup.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="py-2 px-6 text-left text-gray-900 whitespace-nowrap bg-white rounded-lg border border-gray-400">
|
||||
<dl class="divide-y divide-gray-200">
|
||||
<div class="py-2 space-y-1">
|
||||
<dt class="text-sm font-medium text-gray-500">
|
||||
Nr wniosku
|
||||
</dt>
|
||||
<dd class="text-sm text-gray-900">
|
||||
<InertiaLink
|
||||
:href="`/vacation/requests/${vacation.id}`"
|
||||
class="font-semibold text-blumilk-600 hover:text-blumilk-500 hover:underline"
|
||||
>
|
||||
{{ vacation.name }}
|
||||
</InertiaLink>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="py-2 space-y-1">
|
||||
<dt class="text-sm font-medium text-gray-500">
|
||||
Rodzaj urlopu
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<VacationType :type="vacation.type" />
|
||||
</dd>
|
||||
</div>
|
||||
<div class="py-2 space-y-1">
|
||||
<dt class="text-sm font-medium text-gray-500">
|
||||
Obecny status
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<Status :status="vacation.state" />
|
||||
</dd>
|
||||
</div>
|
||||
<div class="py-2 space-y-1">
|
||||
<dt class="text-sm font-medium text-gray-500">
|
||||
Data
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<template v-if="vacation.days > 1">
|
||||
{{ vacation.from }} - {{ vacation.to }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ vacation.from }}
|
||||
</template>
|
||||
<span class="font-semibold">
|
||||
[Liczba dni: {{ vacation.days }}]
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import VacationType from '@/Shared/VacationType'
|
||||
import Status from '@/Shared/Status'
|
||||
|
||||
defineProps({
|
||||
vacation: Object,
|
||||
})
|
||||
|
||||
</script>
|
||||
Reference in New Issue
Block a user
Could you add return types for arrow functions?
Could you add return types for arrow functions?