* #23 - wip * #23 - wip * #23 - wip * #23 - wip * #23 - fix * #23 - ecs fix * #23 - fix * #23 - fix * #23 - cr fix
This commit is contained in:
parent
652587dbf1
commit
e147d24365
57
app/Helpers/YearPeriodRetriever.php
Normal file
57
app/Helpers/YearPeriodRetriever.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Helpers;
|
||||
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class YearPeriodRetriever
|
||||
{
|
||||
public const SESSION_KEY = "selected_year_period";
|
||||
|
||||
public function __construct(
|
||||
protected Session $session,
|
||||
) {
|
||||
}
|
||||
|
||||
public function selected(): YearPeriod
|
||||
{
|
||||
/** @var YearPeriod $yearPeriod */
|
||||
$yearPeriod = YearPeriod::query()->find($this->session->get(static::SESSION_KEY));
|
||||
|
||||
return $yearPeriod !== null ? $yearPeriod : $this->current();
|
||||
}
|
||||
|
||||
public function current(): YearPeriod
|
||||
{
|
||||
return YearPeriod::current();
|
||||
}
|
||||
|
||||
public function links(): array
|
||||
{
|
||||
$current = $this->selected();
|
||||
|
||||
$years = YearPeriod::query()->whereIn("year", $this->offset($current->year))->get();
|
||||
$navigation = $years->map(fn(YearPeriod $yearPeriod) => $this->toNavigation($yearPeriod));
|
||||
|
||||
return [
|
||||
"current" => $current->year,
|
||||
"navigation" => $navigation->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function offset(int $year): array
|
||||
{
|
||||
return range($year - 2, $year + 2);
|
||||
}
|
||||
|
||||
protected function toNavigation(YearPeriod $yearPeriod): array
|
||||
{
|
||||
return [
|
||||
"year" => $yearPeriod->year,
|
||||
"link" => route("year-periods.select", $yearPeriod->id),
|
||||
];
|
||||
}
|
||||
}
|
22
app/Http/Controllers/SelectYearPeriodController.php
Normal file
22
app/Http/Controllers/SelectYearPeriodController.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Toby\Helpers\YearPeriodRetriever;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class SelectYearPeriodController extends Controller
|
||||
{
|
||||
public function __invoke(Request $request, YearPeriod $yearPeriod): RedirectResponse
|
||||
{
|
||||
$request->session()->put(YearPeriodRetriever::SESSION_KEY, $yearPeriod->id);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with("success", __("Selected year period has been changed"));
|
||||
}
|
||||
}
|
34
app/Http/Controllers/VacationLimitController.php
Normal file
34
app/Http/Controllers/VacationLimitController.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Inertia\Response;
|
||||
use Toby\Http\Requests\VacationLimitRequest;
|
||||
use Toby\Http\Resources\VacationLimitResource;
|
||||
use Toby\Models\VacationLimit;
|
||||
|
||||
class VacationLimitController extends Controller
|
||||
{
|
||||
public function edit(): Response
|
||||
{
|
||||
return inertia("VacationLimits", [
|
||||
"limits" => VacationLimitResource::collection(VacationLimit::query()->with("user")->get()),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(VacationLimitRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->data();
|
||||
|
||||
foreach ($request->vacationLimits() as $limit) {
|
||||
$limit->update($data[$limit->id]);
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with("success", __("Vacation limits have been updated"));
|
||||
}
|
||||
}
|
@ -6,10 +6,16 @@ namespace Toby\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Middleware;
|
||||
use Toby\Helpers\YearPeriodRetriever;
|
||||
use Toby\Http\Resources\UserResource;
|
||||
|
||||
class HandleInertiaRequests extends Middleware
|
||||
{
|
||||
public function __construct(
|
||||
protected YearPeriodRetriever $yearPeriodRetriever,
|
||||
) {
|
||||
}
|
||||
|
||||
public function share(Request $request): array
|
||||
{
|
||||
$user = $request->user();
|
||||
@ -22,6 +28,7 @@ class HandleInertiaRequests extends Middleware
|
||||
"success" => $request->session()->get("success"),
|
||||
"error" => $request->session()->get("error"),
|
||||
],
|
||||
"years" => fn() => $user ? $this->yearPeriodRetriever->links() : [],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
33
app/Http/Requests/VacationLimitRequest.php
Normal file
33
app/Http/Requests/VacationLimitRequest.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Collection;
|
||||
use Toby\Models\VacationLimit;
|
||||
|
||||
class VacationLimitRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
"items" => ["required", "array"],
|
||||
"items.*.id" => ["required", "exists:vacation_limits,id"],
|
||||
"items.*.days" => ["nullable", "integer", "min:0"],
|
||||
];
|
||||
}
|
||||
|
||||
public function vacationLimits(): Collection
|
||||
{
|
||||
return VacationLimit::query()->find($this->collect("items")->pluck("id"));
|
||||
}
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return $this->collect("items")
|
||||
->keyBy("id")
|
||||
->toArray();
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserFormDataResource extends JsonResource
|
||||
{
|
||||
public static $wrap = false;
|
||||
public static $wrap = null;
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserResource extends JsonResource
|
||||
{
|
||||
public static $wrap = false;
|
||||
public static $wrap = null;
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
|
22
app/Http/Resources/VacationLimitResource.php
Normal file
22
app/Http/Resources/VacationLimitResource.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class VacationLimitResource extends JsonResource
|
||||
{
|
||||
public static $wrap = null;
|
||||
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
"id" => $this->id,
|
||||
"user" => new UserResource($this->user),
|
||||
"hasVacation" => $this->hasVacation(),
|
||||
"days" => $this->days,
|
||||
];
|
||||
}
|
||||
}
|
@ -6,10 +6,12 @@ namespace Toby\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Toby\Enums\EmploymentForm;
|
||||
|
||||
/**
|
||||
@ -19,6 +21,7 @@ use Toby\Enums\EmploymentForm;
|
||||
* @property string $avatar
|
||||
* @property EmploymentForm $employment_form
|
||||
* @property Carbon $employment_date
|
||||
* @property Collection $vacationLimits
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
@ -43,6 +46,11 @@ class User extends Authenticatable
|
||||
"remember_token",
|
||||
];
|
||||
|
||||
public function vacationLimits(): HasMany
|
||||
{
|
||||
return $this->hasMany(VacationLimit::class);
|
||||
}
|
||||
|
||||
public function scopeSearch(Builder $query, ?string $text): Builder
|
||||
{
|
||||
if ($text === null) {
|
||||
@ -53,4 +61,11 @@ class User extends Authenticatable
|
||||
->where("name", "LIKE", "%{$text}%")
|
||||
->orWhere("email", "LIKE", "%{$text}%");
|
||||
}
|
||||
|
||||
public function saveAvatar(string $path): void
|
||||
{
|
||||
$this->avatar = $path;
|
||||
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
37
app/Models/VacationLimit.php
Normal file
37
app/Models/VacationLimit.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property User $user
|
||||
* @property YearPeriod $yearPeriod
|
||||
* @property int $days
|
||||
*/
|
||||
class VacationLimit extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function hasVacation(): bool
|
||||
{
|
||||
return $this->days !== null;
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function yearPeriod(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(YearPeriod::class);
|
||||
}
|
||||
}
|
@ -7,10 +7,13 @@ namespace Toby\Models;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $year
|
||||
* @property Collection $vacationLimits
|
||||
*/
|
||||
class YearPeriod extends Model
|
||||
{
|
||||
@ -27,4 +30,9 @@ class YearPeriod extends Model
|
||||
|
||||
return $year;
|
||||
}
|
||||
|
||||
public function vacationLimits(): HasMany
|
||||
{
|
||||
return $this->hasMany(VacationLimit::class);
|
||||
}
|
||||
}
|
||||
|
@ -6,20 +6,24 @@ namespace Toby\Observers;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Toby\Helpers\UserAvatarGenerator;
|
||||
use Toby\Helpers\YearPeriodRetriever;
|
||||
use Toby\Models\User;
|
||||
|
||||
class UserObserver
|
||||
{
|
||||
public function __construct(
|
||||
protected UserAvatarGenerator $generator,
|
||||
protected YearPeriodRetriever $yearPeriodRetriever,
|
||||
) {
|
||||
}
|
||||
|
||||
public function created(User $user): void
|
||||
{
|
||||
$user->avatar = $this->generator->generateFor($user);
|
||||
$user->saveAvatar($this->generator->generateFor($user));
|
||||
|
||||
$user->save();
|
||||
$user->vacationLimits()->create([
|
||||
"year_period_id" => $this->yearPeriodRetriever->current()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function updating(User $user): void
|
||||
|
28
app/Observers/YearPeriodObserver.php
Normal file
28
app/Observers/YearPeriodObserver.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Observers;
|
||||
|
||||
use Toby\Helpers\UserAvatarGenerator;
|
||||
use Toby\Models\User;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class YearPeriodObserver
|
||||
{
|
||||
public function __construct(
|
||||
protected UserAvatarGenerator $generator,
|
||||
) {
|
||||
}
|
||||
|
||||
public function created(YearPeriod $yearPeriod): void
|
||||
{
|
||||
$users = User::all();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$yearPeriod->vacationLimits()->create([
|
||||
"user_id" => $user->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,15 +6,15 @@ namespace Toby\Providers;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Toby\Models\User;
|
||||
use Toby\Observers\UserObserver;
|
||||
use Toby\Models\VacationLimit;
|
||||
use Toby\Scopes\SelectedYearPeriodScope;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
User::observe(UserObserver::class);
|
||||
|
||||
Carbon::macro("toDisplayString", fn() => $this->translatedFormat("j F Y"));
|
||||
|
||||
VacationLimit::addGlobalScope($this->app->make(SelectedYearPeriodScope::class));
|
||||
}
|
||||
}
|
||||
|
20
app/Providers/ObserverServiceProvider.php
Normal file
20
app/Providers/ObserverServiceProvider.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Toby\Models\User;
|
||||
use Toby\Models\YearPeriod;
|
||||
use Toby\Observers\UserObserver;
|
||||
use Toby\Observers\YearPeriodObserver;
|
||||
|
||||
class ObserverServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
User::observe(UserObserver::class);
|
||||
YearPeriod::observe(YearPeriodObserver::class);
|
||||
}
|
||||
}
|
23
app/Scopes/SelectedYearPeriodScope.php
Normal file
23
app/Scopes/SelectedYearPeriodScope.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Toby\Scopes;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Scope;
|
||||
use Toby\Helpers\YearPeriodRetriever;
|
||||
|
||||
class SelectedYearPeriodScope implements Scope
|
||||
{
|
||||
public function __construct(
|
||||
protected YearPeriodRetriever $yearPeriodRetriever,
|
||||
) {
|
||||
}
|
||||
|
||||
public function apply(Builder $builder, Model $model): Builder
|
||||
{
|
||||
return $builder->where("year_period_id", $this->yearPeriodRetriever->selected()->id);
|
||||
}
|
||||
}
|
@ -42,5 +42,6 @@ return [
|
||||
Toby\Providers\EventServiceProvider::class,
|
||||
Toby\Providers\RouteServiceProvider::class,
|
||||
Toby\Providers\TelescopeServiceProvider::class,
|
||||
Toby\Providers\ObserverServiceProvider::class,
|
||||
],
|
||||
];
|
||||
|
24
database/factories/VacationLimitFactory.php
Normal file
24
database/factories/VacationLimitFactory.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Toby\Models\User;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class VacationLimitFactory extends Factory
|
||||
{
|
||||
public function definition(): array
|
||||
{
|
||||
$hasVacation = $this->faker->boolean(75);
|
||||
|
||||
return [
|
||||
"user_id" => User::factory(),
|
||||
"year_period_id" => YearPeriod::factory(),
|
||||
"has_vacation" => $hasVacation,
|
||||
"days" => $hasVacation ? $this->faker->numberBetween(20, 26) : null,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Toby\Models\User;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
return new class() extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create("vacation_limits", function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignIdFor(User::class)->constrained()->cascadeOnDelete();
|
||||
$table->foreignIdFor(YearPeriod::class)->constrained()->cascadeOnDelete();
|
||||
$table->integer("days")->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists("vacation_limits");
|
||||
}
|
||||
};
|
@ -6,23 +6,61 @@ namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Toby\Helpers\UserAvatarGenerator;
|
||||
use Toby\Models\User;
|
||||
use Toby\Models\VacationLimit;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
public function __construct(
|
||||
protected UserAvatarGenerator $avatarGenerator,
|
||||
) {
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
User::factory(35)->create();
|
||||
User::unsetEventDispatcher();
|
||||
YearPeriod::unsetEventDispatcher();
|
||||
|
||||
User::factory(9)->create();
|
||||
User::factory([
|
||||
"email" => env("LOCAL_EMAIL_FOR_LOGIN_VIA_GOOGLE"),
|
||||
])->create();
|
||||
|
||||
YearPeriod::factory([
|
||||
"year" => Carbon::now()->year,
|
||||
])->create();
|
||||
YearPeriod::factory([
|
||||
"year" => Carbon::now()->year + 1,
|
||||
])->create();
|
||||
$users = User::all();
|
||||
|
||||
$this->generateAvatarsForUsers($users);
|
||||
|
||||
YearPeriod::factory()
|
||||
->count(3)
|
||||
->sequence(
|
||||
[
|
||||
"year" => Carbon::now()->year - 1,
|
||||
],
|
||||
[
|
||||
"year" => Carbon::now()->year,
|
||||
],
|
||||
[
|
||||
"year" => Carbon::now()->year + 1,
|
||||
],
|
||||
)
|
||||
->afterCreating(function (YearPeriod $yearPeriod) use ($users): void {
|
||||
foreach ($users as $user) {
|
||||
VacationLimit::factory()
|
||||
->for($yearPeriod)
|
||||
->for($user)
|
||||
->create();
|
||||
}
|
||||
})
|
||||
->create();
|
||||
}
|
||||
|
||||
protected function generateAvatarsForUsers(Collection $users): void
|
||||
{
|
||||
foreach ($users as $user) {
|
||||
$user->saveAvatar($this->avatarGenerator->generateFor($user));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "application",
|
||||
"name": "toby",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
175
resources/js/Pages/VacationLimits.vue
Normal file
175
resources/js/Pages/VacationLimits.vue
Normal file
@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<InertiaHead title="Użytkownicy" />
|
||||
<div class="bg-white sm:rounded-lg shadow-md">
|
||||
<div class="flex justify-between items-center p-4 sm:px-6">
|
||||
<div>
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Dostępne dni urlopu dla użytkowników
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
Zarządzaj dostepnymi dniami urlopów dla użytkowników.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200">
|
||||
<div class="overflow-x-auto xl:overflow-x-visible overflow-y-auto xl:overflow-y-visible">
|
||||
<form @submit.prevent="submitVacationDays">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
Imię i nazwisko
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
Forma zatrudnienia
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
Posiada urlop?
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
Dostępne dni w roku
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-100">
|
||||
<tr
|
||||
v-for="(item, index) in form.items"
|
||||
:key="item.id"
|
||||
class="hover:bg-blumilk-25"
|
||||
>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
<div class="flex">
|
||||
<span
|
||||
class="inline-flex items-center justify-center h-10 w-10 rounded-full"
|
||||
>
|
||||
<img
|
||||
class="h-10 w-10 rounded-full"
|
||||
:src="item.user.avatar"
|
||||
alt=""
|
||||
>
|
||||
</span>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium break-all text-gray-900">
|
||||
{{ item.user.name }}
|
||||
</p>
|
||||
<p class="text-sm break-all text-gray-500">
|
||||
{{ item.user.email }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ item.user.employmentForm }}
|
||||
</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
<Switch
|
||||
v-model="item.hasVacation"
|
||||
:class="[item.hasVacation ? 'bg-blumilk-500' : 'bg-gray-200', 'relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500']"
|
||||
>
|
||||
<span
|
||||
:class="[item.hasVacation ? 'translate-x-5' : 'translate-x-0', 'pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200']"
|
||||
/>
|
||||
</Switch>
|
||||
</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<input
|
||||
v-model="item.days"
|
||||
type="number"
|
||||
min="0"
|
||||
class="block w-full shadow-sm rounded-md sm:text-sm disabled:bg-slate-50 disabled:text-slate-500 disabled:border-slate-200 disabled:shadow-none disabled:cursor-not-allowed"
|
||||
:disabled="!item.hasVacation"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`items.${index}.days`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`items.${index}.days`] }"
|
||||
>
|
||||
<p
|
||||
v-if="form.errors[`items.${index}.days`]"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors[`items.${index}.days`] }}
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="!form.items.length"
|
||||
>
|
||||
<td
|
||||
colspan="100%"
|
||||
class="text-center py-4 text-xl leading-5 text-gray-700"
|
||||
>
|
||||
Brak danych
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="flex justify-end py-3 px-4">
|
||||
<button
|
||||
type="submit"
|
||||
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Zapisz
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Switch} from '@headlessui/vue';
|
||||
import {useForm} from '@inertiajs/inertia-vue3';
|
||||
|
||||
export default {
|
||||
name: 'VacationLimits',
|
||||
components: {
|
||||
Switch,
|
||||
},
|
||||
props: {
|
||||
limits: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
years: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const form = useForm({
|
||||
items: props.limits.data,
|
||||
});
|
||||
|
||||
return {
|
||||
form,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submitVacationDays() {
|
||||
this.form
|
||||
.transform(data => ({
|
||||
items: data.items.map(item => ({
|
||||
id: item.id,
|
||||
days: item.hasVacation ? item.days : null,
|
||||
})),
|
||||
}))
|
||||
.put('/vacation-limits', {
|
||||
preserveState: (page) => Object.keys(page.props.errors).length,
|
||||
preserveScroll: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -19,6 +19,53 @@
|
||||
|
||||
<!-- Right section on desktop -->
|
||||
<div class="hidden lg:ml-4 lg:flex lg:items-center lg:py-5 lg:pr-0.5">
|
||||
<div class="mr-4">
|
||||
<Menu
|
||||
as="div"
|
||||
class="relative inline-block text-left"
|
||||
>
|
||||
<div>
|
||||
<MenuButton class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-1 focus:ring-gray-300">
|
||||
{{ years.current }}
|
||||
<ChevronDownIcon class="-mr-1 ml-2 h-5 w-5" />
|
||||
</MenuButton>
|
||||
</div>
|
||||
|
||||
<transition
|
||||
enter-active-class="transition ease-out duration-100"
|
||||
enter-from-class="transform opacity-0 scale-95"
|
||||
enter-to-class="transform opacity-100 scale-100"
|
||||
leave-active-class="transition ease-in duration-75"
|
||||
leave-from-class="transform opacity-100 scale-100"
|
||||
leave-to-class="transform opacity-0 scale-95"
|
||||
>
|
||||
<MenuItems class="origin-top-right absolute right-0 mt-2 w-32 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||
<div class="py-1">
|
||||
<MenuItem
|
||||
v-for="(item, index) in years.navigation"
|
||||
:key="index"
|
||||
v-slot="{ active }"
|
||||
>
|
||||
<InertiaLink
|
||||
:href="item.link"
|
||||
as="button"
|
||||
method="post"
|
||||
:preserve-state="false"
|
||||
:class="[active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', 'flex w-full px-4 py-2 text-sm']"
|
||||
>
|
||||
{{ item.year }}
|
||||
<CheckIcon
|
||||
v-if="item.year === years.current"
|
||||
class="h-5 w-5 text-blumilk-500 ml-2"
|
||||
/>
|
||||
</InertiaLink>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</MenuItems>
|
||||
</transition>
|
||||
</Menu>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="flex-shrink-0 p-1 text-cyan-200 rounded-full hover:text-white hover:bg-white hover:bg-opacity-10 focus:outline-none focus:ring-2 focus:ring-white"
|
||||
@ -246,6 +293,7 @@ import {
|
||||
import {BellIcon, MenuIcon, XIcon} from '@heroicons/vue/outline';
|
||||
import {computed} from 'vue';
|
||||
import {usePage} from '@inertiajs/inertia-vue3';
|
||||
import {ChevronDownIcon, CheckIcon} from '@heroicons/vue/solid';
|
||||
|
||||
export default {
|
||||
name: 'MainMenu',
|
||||
@ -263,13 +311,17 @@ export default {
|
||||
BellIcon,
|
||||
MenuIcon,
|
||||
XIcon,
|
||||
ChevronDownIcon,
|
||||
CheckIcon,
|
||||
},
|
||||
setup() {
|
||||
const user = computed(() => usePage().props.value.auth.user);
|
||||
const years = computed(() => usePage().props.value.years);
|
||||
|
||||
const navigation = [
|
||||
{name: 'Strona główna', href: '/', current: true},
|
||||
{name: 'Użytkownicy', href: '/users', current: false},
|
||||
{name: 'Resources', href: '#', current: false},
|
||||
{name: 'Dostępne urlopy', href: '/vacation-limits', current: false},
|
||||
{name: 'Company Directory', href: '#', current: false},
|
||||
{name: 'Openings', href: '#', current: false},
|
||||
];
|
||||
@ -281,6 +333,7 @@ export default {
|
||||
|
||||
return {
|
||||
user,
|
||||
years,
|
||||
navigation,
|
||||
userNavigation,
|
||||
};
|
||||
|
@ -5,7 +5,9 @@ declare(strict_types=1);
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Toby\Http\Controllers\GoogleController;
|
||||
use Toby\Http\Controllers\LogoutController;
|
||||
use Toby\Http\Controllers\SelectYearPeriodController;
|
||||
use Toby\Http\Controllers\UserController;
|
||||
use Toby\Http\Controllers\VacationLimitController;
|
||||
|
||||
Route::middleware("auth")->group(function (): void {
|
||||
Route::get("/", fn() => inertia("Dashboard"))->name("dashboard");
|
||||
@ -13,6 +15,11 @@ Route::middleware("auth")->group(function (): void {
|
||||
|
||||
Route::resource("users", UserController::class);
|
||||
Route::post("users/{user}/restore", [UserController::class, "restore"])->withTrashed();
|
||||
|
||||
Route::get("/vacation-limits", [VacationLimitController::class, "edit"])->name("vacation.limits");
|
||||
Route::put("/vacation-limits", [VacationLimitController::class, "update"]);
|
||||
|
||||
Route::post("year-periods/{yearPeriod}/select", SelectYearPeriodController::class)->name("year-periods.select");
|
||||
});
|
||||
|
||||
Route::middleware("guest")->group(function (): void {
|
||||
|
@ -5,10 +5,10 @@ declare(strict_types=1);
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Tests\TestCase;
|
||||
use Tests\FeatureTestCase;
|
||||
use Toby\Models\User;
|
||||
|
||||
class AuthenticationTest extends TestCase
|
||||
class AuthenticationTest extends FeatureTestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
|
@ -6,10 +6,10 @@ namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Tests\TestCase;
|
||||
use Tests\FeatureTestCase;
|
||||
use Toby\Models\User;
|
||||
|
||||
class InertiaTest extends TestCase
|
||||
class InertiaTest extends FeatureTestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
|
53
tests/Feature/SelectYearPeriodTest.php
Normal file
53
tests/Feature/SelectYearPeriodTest.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\FeatureTestCase;
|
||||
use Toby\Helpers\YearPeriodRetriever;
|
||||
use Toby\Models\User;
|
||||
|
||||
class SelectYearPeriodTest extends FeatureTestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
protected YearPeriodRetriever $yearPeriodRetriever;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->yearPeriodRetriever = $this->app->make(YearPeriodRetriever::class);
|
||||
}
|
||||
|
||||
public function testUserCanSelectNextYearPeriod(): void
|
||||
{
|
||||
$nextYearPeriod = $this->createYearPeriod(Carbon::now()->year + 1);
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->post("/year-periods/{$nextYearPeriod->id}/select")
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertSame($nextYearPeriod->id, $this->yearPeriodRetriever->selected()->id);
|
||||
}
|
||||
|
||||
public function testUserCannotSelectNextYearPeriodIfDoesntExist(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->post("/year-periods/25/select")
|
||||
->assertNotFound();
|
||||
}
|
||||
|
||||
public function testIfUserDoesntSelectAnyYearPeriodCurrentActsAsSelected(): void
|
||||
{
|
||||
$currentYearPeriod = $this->yearPeriodRetriever->current();
|
||||
|
||||
$this->assertSame($currentYearPeriod->id, $this->yearPeriodRetriever->selected()->id);
|
||||
}
|
||||
}
|
@ -6,23 +6,15 @@ namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Tests\TestCase;
|
||||
use Tests\FeatureTestCase;
|
||||
use Toby\Enums\EmploymentForm;
|
||||
use Toby\Models\User;
|
||||
|
||||
class UserTest extends TestCase
|
||||
class UserTest extends FeatureTestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Storage::fake();
|
||||
}
|
||||
|
||||
public function testAdminCanSeeUsersList(): void
|
||||
{
|
||||
User::factory()->count(10)->create();
|
||||
|
77
tests/Feature/VacationLimitTest.php
Normal file
77
tests/Feature/VacationLimitTest.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Tests\FeatureTestCase;
|
||||
use Toby\Models\User;
|
||||
use Toby\Models\VacationLimit;
|
||||
|
||||
class VacationLimitTest extends FeatureTestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
public function testAdminCanSeeVacationLimits(): void
|
||||
{
|
||||
$admin = User::factory()->createQuietly();
|
||||
|
||||
User::factory(10)->create();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->get("/vacation-limits")
|
||||
->assertOk()
|
||||
->assertInertia(
|
||||
fn(Assert $page) => $page
|
||||
->component("VacationLimits")
|
||||
->has("limits.data", 10),
|
||||
);
|
||||
}
|
||||
|
||||
public function testAdminCanUpdateVacationLimits(): void
|
||||
{
|
||||
$admin = User::factory()->createQuietly();
|
||||
|
||||
User::factory(3)->create();
|
||||
|
||||
[$limit1, $limit2, $limit3] = VacationLimit::all();
|
||||
|
||||
$data = [
|
||||
[
|
||||
"id" => $limit1->id,
|
||||
"days" => 25,
|
||||
],
|
||||
[
|
||||
"id" => $limit2->id,
|
||||
"days" => null,
|
||||
],
|
||||
[
|
||||
"id" => $limit3->id,
|
||||
"days" => 20,
|
||||
],
|
||||
];
|
||||
|
||||
$this->actingAs($admin)
|
||||
->put("/vacation-limits", [
|
||||
"items" => $data,
|
||||
])
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertDatabaseHas("vacation_limits", [
|
||||
"id" => $limit1->id,
|
||||
"days" => 25,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas("vacation_limits", [
|
||||
"id" => $limit2->id,
|
||||
"days" => null,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas("vacation_limits", [
|
||||
"id" => $limit3->id,
|
||||
"days" => 20,
|
||||
]);
|
||||
}
|
||||
}
|
23
tests/FeatureTestCase.php
Normal file
23
tests/FeatureTestCase.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\Traits\InteractsWithYearPeriods;
|
||||
|
||||
abstract class FeatureTestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication;
|
||||
use InteractsWithYearPeriods;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Carbon::setTestNow(Carbon::now());
|
||||
$this->createCurrentYearPeriod();
|
||||
}
|
||||
}
|
49
tests/Traits/InteractsWithYearPeriods.php
Normal file
49
tests/Traits/InteractsWithYearPeriods.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Traits;
|
||||
|
||||
use Illuminate\Foundation\Testing\Concerns\InteractsWithSession;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Toby\Helpers\YearPeriodRetriever;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
trait InteractsWithYearPeriods
|
||||
{
|
||||
use InteractsWithSession;
|
||||
|
||||
public function createYearPeriod(int $year): YearPeriod
|
||||
{
|
||||
/** @var YearPeriod $yearPeriod */
|
||||
$yearPeriod = YearPeriod::factory()->create([
|
||||
"year" => $year,
|
||||
]);
|
||||
|
||||
return $yearPeriod;
|
||||
}
|
||||
|
||||
public function createCurrentYearPeriod(): YearPeriod
|
||||
{
|
||||
return $this->createYearPeriod(Carbon::now()->year);
|
||||
}
|
||||
|
||||
public function markYearPeriodAsSelected(YearPeriod $yearPeriod): void
|
||||
{
|
||||
$this->session([
|
||||
YearPeriodRetriever::SESSION_KEY => $yearPeriod->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function clearSelectedYearPeriod(): void
|
||||
{
|
||||
$this->session([]);
|
||||
}
|
||||
|
||||
public function cleanYearPeriods(): void
|
||||
{
|
||||
$this->clearSelectedYearPeriod();
|
||||
|
||||
YearPeriod::query()->delete();
|
||||
}
|
||||
}
|
@ -7,16 +7,19 @@ namespace Tests\Unit;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
use Tests\Traits\InteractsWithYearPeriods;
|
||||
use Toby\Models\User;
|
||||
|
||||
class AvatarTest extends TestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
use InteractsWithYearPeriods;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->createCurrentYearPeriod();
|
||||
Storage::fake();
|
||||
}
|
||||
|
||||
|
@ -7,12 +7,13 @@ namespace Tests\Unit;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\TestCase;
|
||||
use Tests\Traits\InteractsWithYearPeriods;
|
||||
use Toby\Jobs\CheckYearPeriod;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class CheckYearPeriodTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
use InteractsWithYearPeriods;
|
||||
|
||||
public function testYearPeriodsAreCreatedWhenDontExist(): void
|
||||
{
|
||||
@ -54,9 +55,7 @@ class CheckYearPeriodTest extends TestCase
|
||||
$now = Carbon::now();
|
||||
Carbon::setTestNow($now);
|
||||
|
||||
YearPeriod::factory([
|
||||
"year" => $now->year,
|
||||
]);
|
||||
$this->createCurrentYearPeriod();
|
||||
|
||||
$this->assertDatabaseMissing("year_periods", [
|
||||
"year" => $now->year + 1,
|
||||
@ -74,12 +73,8 @@ class CheckYearPeriodTest extends TestCase
|
||||
$now = Carbon::now();
|
||||
Carbon::setTestNow($now);
|
||||
|
||||
YearPeriod::factory([
|
||||
"year" => $now->year,
|
||||
])->create();
|
||||
YearPeriod::factory([
|
||||
"year" => $now->year + 1,
|
||||
])->create();
|
||||
$this->createCurrentYearPeriod();
|
||||
$this->createYearPeriod($now->year + 1);
|
||||
|
||||
$this->assertDatabaseCount("year_periods", 2);
|
||||
|
||||
|
50
tests/Unit/VacationLimitTest.php
Normal file
50
tests/Unit/VacationLimitTest.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Tests\TestCase;
|
||||
use Tests\Traits\InteractsWithYearPeriods;
|
||||
use Toby\Models\User;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class VacationLimitTest extends TestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
use InteractsWithYearPeriods;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->createCurrentYearPeriod();
|
||||
}
|
||||
|
||||
public function testWhenUserIsCreatedThenVacationLimitIsCreatedForCurrentYearPeriod(): void
|
||||
{
|
||||
$this->assertDatabaseCount("vacation_limits", 0);
|
||||
|
||||
$currentYearPeriod = YearPeriod::current();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->assertDatabaseCount("vacation_limits", 1);
|
||||
|
||||
$this->assertDatabaseHas("vacation_limits", [
|
||||
"user_id" => $user->id,
|
||||
"year_period_id" => $currentYearPeriod->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testWhenYearPeriodIsCreatedThenVacationLimitsForThisYearPeriodAreCreated(): void
|
||||
{
|
||||
$this->assertDatabaseCount("vacation_limits", 0);
|
||||
|
||||
User::factory(10)->createQuietly();
|
||||
|
||||
YearPeriod::factory()->create();
|
||||
|
||||
$this->assertDatabaseCount("vacation_limits", 10);
|
||||
}
|
||||
}
|
82
tests/Unit/YearPeriodRetrieverTest.php
Normal file
82
tests/Unit/YearPeriodRetrieverTest.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use Illuminate\Foundation\Testing\Concerns\InteractsWithSession;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\TestCase;
|
||||
use Tests\Traits\InteractsWithYearPeriods;
|
||||
use Toby\Helpers\YearPeriodRetriever;
|
||||
use Toby\Models\YearPeriod;
|
||||
|
||||
class YearPeriodRetrieverTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
use InteractsWithSession;
|
||||
use InteractsWithYearPeriods;
|
||||
|
||||
public Carbon $current;
|
||||
public YearPeriod $previousYearPeriod;
|
||||
public YearPeriod $currentYearPeriod;
|
||||
public YearPeriod $nextYearPeriod;
|
||||
public YearPeriodRetriever $yearPeriodRetriever;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->current = Carbon::now();
|
||||
Carbon::setTestNow($this->current);
|
||||
|
||||
$this->yearPeriodRetriever = $this->app->make(YearPeriodRetriever::class);
|
||||
|
||||
$this->previousYearPeriod = $this->createYearPeriod($this->current->year - 1);
|
||||
$this->currentYearPeriod = $this->createCurrentYearPeriod();
|
||||
$this->nextYearPeriod = $this->createYearPeriod($this->current->year + 1);
|
||||
}
|
||||
|
||||
public function testRetrievesCorrectCurrentYearPeriod(): void
|
||||
{
|
||||
$this->assertSame($this->currentYearPeriod->id, $this->yearPeriodRetriever->current()->id);
|
||||
}
|
||||
|
||||
public function testRetrievesCurrentYearPeriodWhenNoneIsSelected(): void
|
||||
{
|
||||
$this->clearSelectedYearPeriod();
|
||||
|
||||
$this->assertSame($this->currentYearPeriod->id, $this->yearPeriodRetriever->selected()->id);
|
||||
}
|
||||
|
||||
public function testRetrievesCorrectYearPeriodWhenSelected(): void
|
||||
{
|
||||
$this->markYearPeriodAsSelected($this->nextYearPeriod);
|
||||
|
||||
$this->assertSame($this->nextYearPeriod->id, $this->yearPeriodRetriever->selected()->id);
|
||||
}
|
||||
|
||||
public function testLinks(): void
|
||||
{
|
||||
$expected = [
|
||||
"current" => $this->current->year,
|
||||
"navigation" => [
|
||||
[
|
||||
"year" => $this->previousYearPeriod->year,
|
||||
"link" => route("year-periods.select", $this->previousYearPeriod),
|
||||
],
|
||||
[
|
||||
"year" => $this->currentYearPeriod->year,
|
||||
"link" => route("year-periods.select", $this->currentYearPeriod),
|
||||
],
|
||||
[
|
||||
"year" => $this->nextYearPeriod->year,
|
||||
"link" => route("year-periods.select", $this->nextYearPeriod),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$this->assertSame($expected, $this->yearPeriodRetriever->links());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user