* wip * wip * wip * wip * wip * wip * wip * wip * wip * fix * lint fix * cr fix * fix
This commit is contained in:
parent
84403a762a
commit
ff8d6aade6
@ -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()
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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()),
|
||||||
)
|
)
|
||||||
|
@ -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"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -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()),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
1823
package-lock.json
generated
1823
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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",
|
||||||
|
@ -68,4 +68,3 @@
|
|||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
background: #dadce0;
|
background: #dadce0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
183
resources/js/Pages/AnnualSummary.vue
Normal file
183
resources/js/Pages/AnnualSummary.vue
Normal 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>
|
@ -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',
|
||||||
|
@ -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"
|
||||||
|
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>
|
@ -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>
|
||||||
|
@ -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");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user