#71 - annual summary (#113)

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* fix

* lint fix

* cr fix

* fix
This commit is contained in:
Adrian Hopek 2022-04-07 14:33:15 +02:00 committed by GitHub
parent 84403a762a
commit ff8d6aade6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1073 additions and 1206 deletions

View File

@ -187,7 +187,7 @@ class TimesheetPerUserSheet implements WithTitle, WithHeadings, WithEvents, With
{ {
return $user->vacations() return $user->vacations()
->with("vacationRequest") ->with("vacationRequest")
->whereRelation("vacationRequest", fn(Builder $query) => $query->whereIn("type", $this->types)) ->whereRelation("vacationRequest", fn(Builder $query): Builder => $query->whereIn("type", $this->types))
->whereBetween("date", [$period->start, $period->end]) ->whereBetween("date", [$period->start, $period->end])
->approved() ->approved()
->get() ->get()

View File

@ -21,10 +21,10 @@ class UserVacationStatsRetriever
{ {
return $user return $user
->vacations() ->vacations()
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereRelation( ->whereRelation(
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query fn(Builder $query): Builder => $query
->whereIn("type", $this->getLimitableVacationTypes()) ->whereIn("type", $this->getLimitableVacationTypes())
->states(VacationRequestStatesRetriever::successStates()), ->states(VacationRequestStatesRetriever::successStates()),
) )
@ -36,8 +36,8 @@ class UserVacationStatsRetriever
return $user->vacations() return $user->vacations()
->whereRelation( ->whereRelation(
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query fn(Builder $query): Builder => $query
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereIn("type", $this->getLimitableVacationTypes()) ->whereIn("type", $this->getLimitableVacationTypes())
->states(VacationRequestStatesRetriever::successStates()), ->states(VacationRequestStatesRetriever::successStates()),
) )
@ -50,10 +50,10 @@ class UserVacationStatsRetriever
{ {
return $user return $user
->vacations() ->vacations()
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereRelation( ->whereRelation(
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query fn(Builder $query): Builder => $query
->whereIn("type", $this->getLimitableVacationTypes()) ->whereIn("type", $this->getLimitableVacationTypes())
->states(VacationRequestStatesRetriever::pendingStates()), ->states(VacationRequestStatesRetriever::pendingStates()),
) )
@ -64,10 +64,10 @@ class UserVacationStatsRetriever
{ {
return $user return $user
->vacations() ->vacations()
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereRelation( ->whereRelation(
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query fn(Builder $query): Builder => $query
->whereIn("type", $this->getNotLimitableVacationTypes()) ->whereIn("type", $this->getNotLimitableVacationTypes())
->states(VacationRequestStatesRetriever::successStates()), ->states(VacationRequestStatesRetriever::successStates()),
) )
@ -86,7 +86,7 @@ class UserVacationStatsRetriever
public function getVacationDaysLimit(User $user, YearPeriod $yearPeriod): int public function getVacationDaysLimit(User $user, YearPeriod $yearPeriod): int
{ {
$limit = $user->vacationLimits() $limit = $user->vacationLimits()
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->first() ->first()
?->days; ?->days;

View File

@ -41,16 +41,19 @@ class DoesNotExceedLimitRule implements VacationRequestRule
protected function getUserVacationLimit(User $user, YearPeriod $yearPeriod): int protected function getUserVacationLimit(User $user, YearPeriod $yearPeriod): int
{ {
return $user->vacationLimits()->where("year_period_id", $yearPeriod->id)->first()->days ?? 0; return $user->vacationLimits()
->whereBelongsTo($yearPeriod)
->first()
?->days ?? 0;
} }
protected function getVacationDaysWithLimit(User $user, YearPeriod $yearPeriod): int protected function getVacationDaysWithLimit(User $user, YearPeriod $yearPeriod): int
{ {
return $user->vacations() return $user->vacations()
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereRelation( ->whereRelation(
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query fn(Builder $query): Builder => $query
->whereIn("type", $this->getLimitableVacationTypes()) ->whereIn("type", $this->getLimitableVacationTypes())
->noStates(VacationRequestStatesRetriever::failedStates()), ->noStates(VacationRequestStatesRetriever::failedStates()),
) )

View File

@ -91,7 +91,7 @@ class User extends Authenticatable
public function hasVacationLimit(YearPeriod $yearPeriod): bool public function hasVacationLimit(YearPeriod $yearPeriod): bool
{ {
return $this->vacationLimits() return $this->vacationLimits()
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereNotNull("days") ->whereNotNull("days")
->exists(); ->exists();
} }
@ -112,8 +112,8 @@ class User extends Authenticatable
{ {
return $query->whereRelation( return $query->whereRelation(
"vacationlimits", "vacationlimits",
fn(Builder $query) => $query fn(Builder $query): Builder => $query
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereNotNull("days"), ->whereNotNull("days"),
); );
} }

View File

@ -47,7 +47,15 @@ class Vacation extends Model
{ {
return $query->whereRelation( return $query->whereRelation(
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query->states(VacationRequestStatesRetriever::successStates()), fn(Builder $query): Builder => $query->states(VacationRequestStatesRetriever::successStates()),
);
}
public function scopePending(Builder $query): Builder
{
return $query->whereRelation(
"vacationRequest",
fn(Builder $query): Builder => $query->states(VacationRequestStatesRetriever::pendingStates()),
); );
} }
} }

View File

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Toby\Infrastructure\Http\Controllers;
use Illuminate\Http\Request;
use Inertia\Response;
use Toby\Eloquent\Helpers\YearPeriodRetriever;
use Toby\Eloquent\Models\Holiday;
use Toby\Eloquent\Models\Vacation;
use Toby\Infrastructure\Http\Resources\SimpleVacationRequestResource;
class AnnualSummaryController extends Controller
{
public function __invoke(Request $request, YearPeriodRetriever $yearPeriodRetriever): Response
{
$yearPeriod = $yearPeriodRetriever->selected();
$holidays = $yearPeriod->holidays()
->get();
$vacations = $request->user()
->vacations()
->with("vacationRequest.vacations")
->whereBelongsTo($yearPeriod)
->approved()
->get();
$pendingVacations = $request->user()
->vacations()
->with("vacationRequest.vacations")
->whereBelongsTo($yearPeriod)
->pending()
->get();
return inertia("AnnualSummary", [
"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),
],
),
]);
}
}

View File

@ -27,16 +27,16 @@ class CalculateUserUnavailableDaysController extends Controller
$holidays = $yearPeriod->holidays()->pluck("date"); $holidays = $yearPeriod->holidays()->pluck("date");
$vacationDays = $user->vacations() $vacationDays = $user->vacations()
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->whereRelation( ->whereRelation(
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query->noStates(VacationRequestStatesRetriever::failedStates()), fn(Builder $query): Builder => $query->noStates(VacationRequestStatesRetriever::failedStates()),
) )
->pluck("date"); ->pluck("date");
return new JsonResponse([ return new JsonResponse([
...$holidays->map(fn(Carbon $date) => $date->toDateString()), ...$holidays->map(fn(Carbon $date): string => $date->toDateString()),
...$vacationDays->map(fn(Carbon $date) => $date->toDateString()), ...$vacationDays->map(fn(Carbon $date): string => $date->toDateString()),
]); ]);
} }
} }

View File

@ -40,26 +40,26 @@ class VacationRequestController extends Controller
$vacationRequests = $request->user() $vacationRequests = $request->user()
->vacationRequests() ->vacationRequests()
->with("vacations") ->with("vacations")
->where("year_period_id", $yearPeriodRetriever->selected()->id) ->whereBelongsTo($yearPeriodRetriever->selected())
->latest() ->latest()
->states(VacationRequestStatesRetriever::filterByStatusGroup($status, $request->user())) ->states(VacationRequestStatesRetriever::filterByStatusGroup($status, $request->user()))
->paginate(); ->paginate();
$pending = $request->user() $pending = $request->user()
->vacationRequests() ->vacationRequests()
->where("year_period_id", $yearPeriodRetriever->selected()->id) ->whereBelongsTo($yearPeriodRetriever->selected())
->states(VacationRequestStatesRetriever::pendingStates()) ->states(VacationRequestStatesRetriever::pendingStates())
->count(); ->count();
$success = $request->user() $success = $request->user()
->vacationRequests() ->vacationRequests()
->where("year_period_id", $yearPeriodRetriever->selected()->id) ->whereBelongsTo($yearPeriodRetriever->selected())
->states(VacationRequestStatesRetriever::successStates()) ->states(VacationRequestStatesRetriever::successStates())
->count(); ->count();
$failed = $request->user() $failed = $request->user()
->vacationRequests() ->vacationRequests()
->where("year_period_id", $yearPeriodRetriever->selected()->id) ->whereBelongsTo($yearPeriodRetriever->selected())
->states(VacationRequestStatesRetriever::failedStates()) ->states(VacationRequestStatesRetriever::failedStates())
->count(); ->count();
@ -91,11 +91,11 @@ class VacationRequestController extends Controller
$vacationRequests = VacationRequest::query() $vacationRequests = VacationRequest::query()
->with(["user", "vacations"]) ->with(["user", "vacations"])
->where("year_period_id", $yearPeriod->id) ->whereBelongsTo($yearPeriod)
->when($user !== null, fn(Builder $query) => $query->where("user_id", $user)) ->when($user !== null, fn(Builder $query): Builder => $query->where("user_id", $user))
->when( ->when(
$status !== null, $status !== null,
fn(Builder $query) => $query->states( fn(Builder $query): Builder => $query->states(
VacationRequestStatesRetriever::filterByStatusGroup($status, $request->user()), VacationRequestStatesRetriever::filterByStatusGroup($status, $request->user()),
), ),
) )
@ -156,7 +156,7 @@ class VacationRequestController extends Controller
return $pdf->stream(); return $pdf->stream();
} }
public function create(Request $request, YearPeriodRetriever $yearPeriodRetriever): Response public function create(Request $request): Response
{ {
$users = User::query() $users = User::query()
->orderBy("last_name") ->orderBy("last_name")

View File

@ -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(),
];
}
}

1821
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
"flatpickr": "^4.6.11", "flatpickr": "^4.6.11",
"laravel-mix": "^6.0.43", "laravel-mix": "^6.0.43",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"luxon": "^2.3.1",
"postcss": "^8.4.12", "postcss": "^8.4.12",
"tailwindcss": "^3.0.23", "tailwindcss": "^3.0.23",
"vue": "^3.2.31", "vue": "^3.2.31",

View File

@ -68,4 +68,3 @@
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background: #dadce0; background: #dadce0;
} }

View File

@ -14,61 +14,71 @@ const types = [
text: 'Urlop wypoczynkowy', text: 'Urlop wypoczynkowy',
value: 'vacation', value: 'vacation',
icon: WhiteBalanceSunnyIcon, icon: WhiteBalanceSunnyIcon,
color: 'text-amber-500', color: 'text-amber-300',
border: 'border-amber-300',
}, },
{ {
text: 'Urlop na żądanie', text: 'Urlop na żądanie',
value: 'vacation_on_request', value: 'vacation_on_request',
icon: CommentAlertIcon, icon: CommentAlertIcon,
color: 'text-slate-500', color: 'text-slate-500',
border: 'border-slate-500',
}, },
{ {
text: 'Urlop okolicznościowy', text: 'Urlop okolicznościowy',
value: 'special_vacation', value: 'special_vacation',
icon: StarShootingIcon, icon: StarShootingIcon,
color: 'text-orange-500', color: 'text-orange-500',
border: 'border-orange-500',
}, },
{ {
text: 'Opieka nad dzieckiem art 188 kp', text: 'Opieka nad dzieckiem art 188 kp',
value: 'childcare_vacation', value: 'childcare_vacation',
icon: BabyCarriageIcon, icon: BabyCarriageIcon,
color: 'text-purple-500', color: 'text-purple-500',
border: 'border-purple-500',
}, },
{ {
text: 'Urlop szkoleniowy', text: 'Urlop szkoleniowy',
value: 'training_vacation', value: 'training_vacation',
icon: HumanMaleBoardIcon, icon: HumanMaleBoardIcon,
color: 'text-blumilk-500', color: 'text-blumilk-500',
border: 'border-blumilk-500',
}, },
{ {
text: 'Urlop bezpłatny', text: 'Urlop bezpłatny',
value: 'unpaid_vacation', value: 'unpaid_vacation',
icon: CurrencyUsdOffIcon, icon: CurrencyUsdOffIcon,
color: 'text-emerald-500', color: 'text-emerald-500',
border: 'border-emerald-500',
}, },
{ {
text: 'Wolontariat', text: 'Wolontariat',
value: 'volunteering_vacation', value: 'volunteering_vacation',
icon: HandHeartOutlineIcon, icon: HandHeartOutlineIcon,
color: 'text-pink-500', color: 'text-pink-500',
border: 'border-pink-500',
}, },
{ {
text: 'Odbiór za święto', text: 'Odbiór za święto',
value: 'time_in_lieu', value: 'time_in_lieu',
icon: CalendarCheckIcon, icon: CalendarCheckIcon,
color: 'text-stone-500', color: 'text-stone-500',
border: 'border-stone-500',
}, },
{ {
text: 'Zwolnienie lekarskie', text: 'Zwolnienie lekarskie',
value: 'sick_vacation', value: 'sick_vacation',
icon: MedicalBagIcon, icon: MedicalBagIcon,
color: 'text-rose-500', color: 'text-rose-500',
border: 'border-rose-500',
}, },
{ {
text: 'Nieobecność', text: 'Nieobecność',
value: 'absence', value: 'absence',
icon: CalendarRemoveIcon, icon: CalendarRemoveIcon,
color: 'text-cyan-500', color: 'text-cyan-500',
border: 'border-cyan-500',
}, },
] ]

View File

@ -4,9 +4,11 @@ import { usePage } from '@inertiajs/inertia-vue3'
export default function useCurrentYearPeriodInfo() { export default function useCurrentYearPeriodInfo() {
const minDate = computed(() => new Date(usePage().props.value.years.selected.year, 0, 1)) const minDate = computed(() => new Date(usePage().props.value.years.selected.year, 0, 1))
const maxDate = computed(() => new Date(usePage().props.value.years.selected.year, 11, 31)) const maxDate = computed(() => new Date(usePage().props.value.years.selected.year, 11, 31))
const year = computed(() => usePage().props.value.years.selected.year)
return { return {
minDate, minDate,
maxDate, maxDate,
year,
} }
} }

View File

@ -0,0 +1,183 @@
<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="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`]">
<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)" />
</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">
<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
class="py-1.5 w-full font-medium bg-white hover:bg-blumilk-25 border-b-4 border-transparent"
>
<time
:datetime="day.date.toISODate()"
:class="[ day.isToday && 'bg-blumilk-500 font-semibold text-white rounded-full', day.isWeekend && 'text-red-700 font-bold', 'mx-auto flex h-7 w-7 p-4 items-center justify-center']"
>
{{ day.date.day }}
</time>
</button>
</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>
</div>
</div>
</template>
<script setup>
import { DateTime } from 'luxon'
import useVacationTypeInfo from '@/Composables/vacationTypeInfo'
import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo'
import Popper from 'vue3-popper'
import VacationPopup from '@/Shared/VacationPopup'
const props = defineProps({
holidays: Object,
vacations: Object,
pendingVacations: Object,
})
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>

View File

@ -277,6 +277,7 @@ import {
UserGroupIcon, UserGroupIcon,
XIcon, XIcon,
SunIcon, SunIcon,
ClipboardListIcon,
StarIcon, StarIcon,
CalendarIcon, CalendarIcon,
DocumentTextIcon, DocumentTextIcon,
@ -335,6 +336,14 @@ const navigation = computed(() =>
icon: SunIcon, icon: SunIcon,
can: props.auth.can.manageVacationLimits, can: props.auth.can.manageVacationLimits,
}, },
{
name: 'Podsumowanie roczne',
href: '/vacation/annual-summary',
component: 'AnnualSummary',
icon: ClipboardListIcon,
can: true,
},
{ {
name: 'Użytkownicy', name: 'Użytkownicy',
href: '/users', href: '/users',

View File

@ -1,7 +1,7 @@
<template> <template>
<Popper <Popper
hover hover
class="w-full h-full" class="w-full"
> >
<div class="flex text-white bg-white"> <div class="flex text-white bg-white">
<div <div
@ -27,7 +27,7 @@
</div> </div>
</div> </div>
<template #content> <template #content>
<div class="py-2 px-4 text-gray-900 bg-white rounded-md shadow-md text-md flext"> <div class="py-2 px-4 text-gray-900 bg-white rounded-md shadow-md text-md">
<div class="flex items-center font-normal"> <div class="flex items-center font-normal">
<i <i
class="inline-block mr-3 w-5 h-3" class="inline-block mr-3 w-5 h-3"

View 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>

View File

@ -8,7 +8,7 @@
</div> </div>
</div> </div>
<template #content> <template #content>
<div class="py-1 px-2 text-xs text-gray-900 bg-white shadow-md "> <div class="py-2 px-4 text-xs text-gray-900 bg-white rounded-lg border border-gray-400 ">
{{ typeInfo.text }} {{ typeInfo.text }}
</div> </div>
</template> </template>

View File

@ -3,6 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Toby\Infrastructure\Http\Controllers\AnnualSummaryController;
use Toby\Infrastructure\Http\Controllers\DashboardController; use Toby\Infrastructure\Http\Controllers\DashboardController;
use Toby\Infrastructure\Http\Controllers\GoogleController; use Toby\Infrastructure\Http\Controllers\GoogleController;
use Toby\Infrastructure\Http\Controllers\HolidayController; use Toby\Infrastructure\Http\Controllers\HolidayController;
@ -28,41 +29,43 @@ Route::middleware("auth")->group(function (): void {
Route::post("year-periods/{yearPeriod}/select", SelectYearPeriodController::class) Route::post("year-periods/{yearPeriod}/select", SelectYearPeriodController::class)
->name("year-periods.select"); ->name("year-periods.select");
Route::prefix("/vacation")->group(function (): void { Route::prefix("/vacation")->as("vacation.")->group(function (): void {
Route::get("/limits", [VacationLimitController::class, "edit"]) Route::get("/limits", [VacationLimitController::class, "edit"])
->name("vacation.limits"); ->name("limits");
Route::get("/calendar/{month?}", [VacationCalendarController::class, "index"]) Route::get("/calendar/{month?}", [VacationCalendarController::class, "index"])
->name("vacation.calendar"); ->name("calendar");
Route::get("/timesheet/{month}", TimesheetController::class) Route::get("/timesheet/{month}", TimesheetController::class)
->name("timesheet"); ->name("timesheet");
Route::get("/limits", [VacationLimitController::class, "edit"]) Route::get("/limits", [VacationLimitController::class, "edit"])
->name("vacation.limits"); ->name("limits");
Route::put("/limits", [VacationLimitController::class, "update"]); Route::put("/limits", [VacationLimitController::class, "update"]);
Route::get("/requests", [VacationRequestController::class, "indexForApprovers"]) Route::get("/requests", [VacationRequestController::class, "indexForApprovers"])
->name("vacation.requests.indexForApprovers"); ->name("requests.indexForApprovers");
Route::get("/requests/me", [VacationRequestController::class, "index"]) Route::get("/requests/me", [VacationRequestController::class, "index"])
->name("vacation.requests.index"); ->name("requests.index");
Route::get("/requests/create", [VacationRequestController::class, "create"]) Route::get("/requests/create", [VacationRequestController::class, "create"])
->name("vacation.requests.create"); ->name("requests.create");
Route::post("/requests", [VacationRequestController::class, "store"]) Route::post("/requests", [VacationRequestController::class, "store"])
->name("vacation.requests.store"); ->name("requests.store");
Route::get("/requests/{vacationRequest}", [VacationRequestController::class, "show"]) Route::get("/requests/{vacationRequest}", [VacationRequestController::class, "show"])
->name("vacation.requests.show"); ->name("requests.show");
Route::get("/requests/{vacationRequest}/download", [VacationRequestController::class, "download"]) Route::get("/requests/{vacationRequest}/download", [VacationRequestController::class, "download"])
->name("vacation.requests.download"); ->name("requests.download");
Route::post("/requests/{vacationRequest}/reject", [VacationRequestController::class, "reject"]) Route::post("/requests/{vacationRequest}/reject", [VacationRequestController::class, "reject"])
->name("vacation.requests.reject"); ->name("requests.reject");
Route::post("/requests/{vacationRequest}/cancel", [VacationRequestController::class, "cancel"]) Route::post("/requests/{vacationRequest}/cancel", [VacationRequestController::class, "cancel"])
->name("vacation.requests.cancel"); ->name("requests.cancel");
Route::post("/requests/{vacationRequest}/accept-as-technical", [VacationRequestController::class, "acceptAsTechnical"], ) Route::post("/requests/{vacationRequest}/accept-as-technical", [VacationRequestController::class, "acceptAsTechnical"], )
->name("vacation.requests.accept-as-technical"); ->name("requests.accept-as-technical");
Route::post("/requests/{vacationRequest}/accept-as-administrative", [VacationRequestController::class, "acceptAsAdministrative"], ) Route::post("/requests/{vacationRequest}/accept-as-administrative", [VacationRequestController::class, "acceptAsAdministrative"], )
->name("vacation.requests.accept-as-administrative"); ->name("requests.accept-as-administrative");
Route::get("/monthly-usage", MonthlyUsageController::class) Route::get("/monthly-usage", MonthlyUsageController::class)
->name("vacation.monthly-usage"); ->name("monthly-usage");
Route::get("/annual-summary", AnnualSummaryController::class)
->name("annual-summmary");
}); });
}); });