#71 - annual summary #113
@@ -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 @@
|
|||||||
|
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?
|
|||||||
|
<?php
|
||||||
|
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?
|
|||||||
|
declare(strict_types=1);
|
||||||
|
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?
|
|||||||
|
namespace Toby\Infrastructure\Http\Controllers;
|
||||||
|
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?
|
|||||||
|
use Illuminate\Http\Request;
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
use Inertia\Response;
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
use Toby\Eloquent\Helpers\YearPeriodRetriever;
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
use Toby\Eloquent\Models\Holiday;
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
use Toby\Eloquent\Models\Vacation;
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
use Toby\Infrastructure\Http\Resources\SimpleVacationRequestResource;
|
||||||
|
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?
|
|||||||
|
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?
|
|||||||
|
public function __invoke(Request $request, YearPeriodRetriever $yearPeriodRetriever): Response
|
||||||
|
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?
|
|||||||
|
$yearPeriod = $yearPeriodRetriever->selected();
|
||||||
|
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?
|
|||||||
|
$holidays = $yearPeriod->holidays()
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
->get();
|
||||||
|
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()
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
->vacations()
|
||||||
|
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?
|
|||||||
|
->whereBelongsTo($yearPeriod)
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
->approved()
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
->get();
|
||||||
|
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?
|
|||||||
|
$pendingVacations = $request->user()
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
->vacations()
|
||||||
|
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?
|
|||||||
|
->whereBelongsTo($yearPeriod)
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
->pending()
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
->get();
|
||||||
|
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?
|
|||||||
|
return inertia("AnnualSummary", [
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
"holidays" => $holidays->mapWithKeys(
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
fn(Holiday $holiday): array => [$holiday->date->toDateString() => $holiday->name],
|
||||||
|
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" => $vacations->mapWithKeys(
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
fn(Vacation $vacation): array => [
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
$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?
|
|||||||
|
"pendingVacations" => $pendingVacations->mapWithKeys(
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
fn(Vacation $vacation): array => [
|
||||||
|
Could you add return types for arrow functions? Could you add return types for arrow functions?
|
|||||||
|
$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?
|
|||||||
|
]);
|
||||||
|
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?
|
|||||||
@@ -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(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
1821
package-lock.json
generated
@@ -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
@@ -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
@@ -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");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Could you add return type of arrow function?