#36 - wip
This commit is contained in:
		
							
								
								
									
										42
									
								
								app/Domain/VacationDaysCalculator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								app/Domain/VacationDaysCalculator.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Toby\Domain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Carbon\CarbonInterface;
 | 
				
			||||||
 | 
					use Carbon\CarbonPeriod;
 | 
				
			||||||
 | 
					use Illuminate\Support\Collection;
 | 
				
			||||||
 | 
					use Toby\Eloquent\Models\YearPeriod;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VacationDaysCalculator
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function calculateDays(YearPeriod $yearPeriod, CarbonInterface $from, CarbonInterface $to): Collection
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $period = CarbonPeriod::create($from, $to);
 | 
				
			||||||
 | 
					        $holidays = $yearPeriod->holidays()->pluck("date");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $validDays = collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($period as $day) {
 | 
				
			||||||
 | 
					            if ($this->passes($day, $holidays)) {
 | 
				
			||||||
 | 
					                $validDays->add($day);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $validDays;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected function passes(CarbonInterface $day, Collection $holidays): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($day->isWeekend()) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($holidays->contains($day)) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
declare(strict_types=1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Toby\Domain\Validation\Rules;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Closure;
 | 
					 | 
				
			||||||
use Toby\Eloquent\Models\VacationRequest;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ApprovedVacationDaysInSameRange implements VacationRequestRule
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function check(VacationRequest $vacationRequest, Closure $next)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $next($vacationRequest);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -4,13 +4,22 @@ declare(strict_types=1);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Toby\Domain\Validation\Rules;
 | 
					namespace Toby\Domain\Validation\Rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Closure;
 | 
					use Toby\Domain\VacationTypeConfigRetriever;
 | 
				
			||||||
use Toby\Eloquent\Models\VacationRequest;
 | 
					use Toby\Eloquent\Models\VacationRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DoesNotExceedLimitRule implements VacationRequestRule
 | 
					class DoesNotExceedLimitRule extends VacationRequestRule
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public function check(VacationRequest $vacationRequest, Closure $next)
 | 
					    public function __construct(protected VacationTypeConfigRetriever $configRetriever)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $next($vacationRequest);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function passes(VacationRequest $vacationRequest): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function errorMessage(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return __("You have exceeded your vacation limit.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,13 +4,24 @@ declare(strict_types=1);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Toby\Domain\Validation\Rules;
 | 
					namespace Toby\Domain\Validation\Rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Closure;
 | 
					use Toby\Domain\VacationDaysCalculator;
 | 
				
			||||||
use Toby\Eloquent\Models\VacationRequest;
 | 
					use Toby\Eloquent\Models\VacationRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MinimumOneVacationDayRule implements VacationRequestRule
 | 
					class MinimumOneVacationDayRule extends VacationRequestRule
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public function check(VacationRequest $vacationRequest, Closure $next)
 | 
					    public function __construct(protected VacationDaysCalculator $vacationDaysCalculator)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $next($vacationRequest);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function passes(VacationRequest $vacationRequest): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->vacationDaysCalculator
 | 
				
			||||||
 | 
					            ->calculateDays($vacationRequest->yearPeriod, $vacationRequest->from, $vacationRequest->to)
 | 
				
			||||||
 | 
					            ->isNotEmpty();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function errorMessage(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return __("Vacation needs minimum one day.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Toby\Domain\Validation\Rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Toby\Domain\Enums\VacationRequestState;
 | 
				
			||||||
 | 
					use Toby\Eloquent\Models\VacationRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoApprovedVacationRequestsInRange extends VacationRequestRule
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function passes(VacationRequest $vacationRequest): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $vacationRequest
 | 
				
			||||||
 | 
					            ->user
 | 
				
			||||||
 | 
					            ->vacationRequests()
 | 
				
			||||||
 | 
					            ->overlapsWith($vacationRequest)
 | 
				
			||||||
 | 
					            ->states(VacationRequestState::successStates())
 | 
				
			||||||
 | 
					            ->exists();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function errorMessage(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return __("You have approved vacation request in this range.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Toby\Domain\Validation\Rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Toby\Domain\Enums\VacationRequestState;
 | 
				
			||||||
 | 
					use Toby\Eloquent\Models\VacationRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoPendingVacationRequestInRange extends VacationRequestRule
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function passes(VacationRequest $vacationRequest): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $vacationRequest
 | 
				
			||||||
 | 
					            ->user
 | 
				
			||||||
 | 
					            ->vacationRequests()
 | 
				
			||||||
 | 
					            ->overlapsWith($vacationRequest)
 | 
				
			||||||
 | 
					            ->states(VacationRequestState::pendingStates())
 | 
				
			||||||
 | 
					            ->exists();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function errorMessage(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return __("You have pending vacation request in this range.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
declare(strict_types=1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Toby\Domain\Validation\Rules;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Closure;
 | 
					 | 
				
			||||||
use Toby\Eloquent\Models\VacationRequest;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PendingVacationRequestInSameRange implements VacationRequestRule
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function check(VacationRequest $vacationRequest, Closure $next)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $next($vacationRequest);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
declare(strict_types=1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Toby\Domain\Validation\Rules;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Closure;
 | 
					 | 
				
			||||||
use Toby\Eloquent\Models\VacationRequest;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class UsedVacationDaysInSameRange
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function check(VacationRequest $vacationRequest, Closure $next)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $next($vacationRequest);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Toby\Domain\Validation\Rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Toby\Eloquent\Models\VacationRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VacationRangeIsInTheSameYearRule extends VacationRequestRule
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function passes(VacationRequest $vacationRequest): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $vacationRequest->from->isSameYear($vacationRequest->to);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function errorMessage(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return __("The vacation request cannot be created at the turn of the year.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,10 +4,18 @@ declare(strict_types=1);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Toby\Domain\Validation\Rules;
 | 
					namespace Toby\Domain\Validation\Rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Closure;
 | 
					use Illuminate\Validation\ValidationException;
 | 
				
			||||||
use Toby\Eloquent\Models\VacationRequest;
 | 
					use Toby\Eloquent\Models\VacationRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface VacationRequestRule
 | 
					abstract class VacationRequestRule
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public function check(VacationRequest $vacationRequest, Closure $next);
 | 
					    public function check(VacationRequest $vacationRequest): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (! $this->passes($vacationRequest)) {
 | 
				
			||||||
 | 
					            throw ValidationException::withMessages(["vacationRequest" => $this->errorMessage()]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public abstract function passes(VacationRequest $vacationRequest): bool;
 | 
				
			||||||
 | 
					    public abstract function errorMessage(): string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,19 +5,21 @@ declare(strict_types=1);
 | 
				
			|||||||
namespace Toby\Domain\Validation;
 | 
					namespace Toby\Domain\Validation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Illuminate\Pipeline\Pipeline;
 | 
					use Illuminate\Pipeline\Pipeline;
 | 
				
			||||||
use Toby\Domain\Validation\Rules\ApprovedVacationDaysInSameRange;
 | 
					use Toby\Domain\Validation\Rules\NoApprovedVacationRequestsInRange;
 | 
				
			||||||
use Toby\Domain\Validation\Rules\DoesNotExceedLimitRule;
 | 
					use Toby\Domain\Validation\Rules\DoesNotExceedLimitRule;
 | 
				
			||||||
use Toby\Domain\Validation\Rules\MinimumOneVacationDayRule;
 | 
					use Toby\Domain\Validation\Rules\MinimumOneVacationDayRule;
 | 
				
			||||||
use Toby\Domain\Validation\Rules\PendingVacationRequestInSameRange;
 | 
					use Toby\Domain\Validation\Rules\NoPendingVacationRequestInRange;
 | 
				
			||||||
 | 
					use Toby\Domain\Validation\Rules\VacationRangeIsInTheSameYearRule;
 | 
				
			||||||
use Toby\Eloquent\Models\VacationRequest;
 | 
					use Toby\Eloquent\Models\VacationRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VacationRequestValidator
 | 
					class VacationRequestValidator
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected array $rules = [
 | 
					    protected array $rules = [
 | 
				
			||||||
 | 
					        VacationRangeIsInTheSameYearRule::class,
 | 
				
			||||||
        MinimumOneVacationDayRule::class,
 | 
					        MinimumOneVacationDayRule::class,
 | 
				
			||||||
        DoesNotExceedLimitRule::class,
 | 
					        DoesNotExceedLimitRule::class,
 | 
				
			||||||
        PendingVacationRequestInSameRange::class,
 | 
					        NoPendingVacationRequestInRange::class,
 | 
				
			||||||
        ApprovedVacationDaysInSameRange::class,
 | 
					        NoApprovedVacationRequestsInRange::class,
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct(
 | 
					    public function __construct(
 | 
				
			||||||
@@ -27,9 +29,8 @@ class VacationRequestValidator
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public function validate(VacationRequest $vacationRequest): void
 | 
					    public function validate(VacationRequest $vacationRequest): void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->pipeline
 | 
					        foreach ($this->rules as $rule) {
 | 
				
			||||||
            ->send($vacationRequest)
 | 
					            app($rule)->check($vacationRequest);
 | 
				
			||||||
            ->through($this->rules)
 | 
					        }
 | 
				
			||||||
            ->via("check");
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Toby\Eloquent\Models;
 | 
					namespace Toby\Eloquent\Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Carbon\CarbonInterface;
 | 
				
			||||||
use Database\Factories\VacationRequestFactory;
 | 
					use Database\Factories\VacationRequestFactory;
 | 
				
			||||||
use Illuminate\Database\Eloquent\Builder;
 | 
					use Illuminate\Database\Eloquent\Builder;
 | 
				
			||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
 | 
					use Illuminate\Database\Eloquent\Factories\HasFactory;
 | 
				
			||||||
@@ -68,6 +69,12 @@ class VacationRequest extends Model
 | 
				
			|||||||
        return $query->whereIn("state", $states);
 | 
					        return $query->whereIn("state", $states);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function scopeOverlapsWith(Builder $query, VacationRequest $vacationRequest): Builder
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $query->where("from", '<=', $vacationRequest->to)
 | 
				
			||||||
 | 
					            ->where("to", '>=', $vacationRequest->from);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected static function newFactory(): VacationRequestFactory
 | 
					    protected static function newFactory(): VacationRequestFactory
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return VacationRequestFactory::new();
 | 
					        return VacationRequestFactory::new();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Toby\Infrastructure\Http\Controllers\Api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Http\JsonResponse;
 | 
				
			||||||
 | 
					use Toby\Domain\VacationDaysCalculator;
 | 
				
			||||||
 | 
					use Toby\Infrastructure\Http\Controllers\Controller;
 | 
				
			||||||
 | 
					use Toby\Infrastructure\Http\Requests\Api\CalculateVacationDaysRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CalculateVacationDaysController extends Controller
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __invoke(CalculateVacationDaysRequest $request, VacationDaysCalculator $calculator): JsonResponse
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $days = $calculator->calculateDays($request->yearPeriod(), $request->from(), $request->to());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new JsonResponse($days->all());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
 | 
				
			|||||||
namespace Toby\Infrastructure\Http\Controllers;
 | 
					namespace Toby\Infrastructure\Http\Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Barryvdh\DomPDF\Facade\Pdf;
 | 
					use Barryvdh\DomPDF\Facade\Pdf;
 | 
				
			||||||
 | 
					use Carbon\Carbon;
 | 
				
			||||||
use Illuminate\Http\RedirectResponse;
 | 
					use Illuminate\Http\RedirectResponse;
 | 
				
			||||||
use Illuminate\Http\Request;
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
use Illuminate\Http\Response as LaravelResponse;
 | 
					use Illuminate\Http\Response as LaravelResponse;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Toby\Infrastructure\Http\Requests\Api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Foundation\Http\FormRequest;
 | 
				
			||||||
 | 
					use Illuminate\Support\Carbon;
 | 
				
			||||||
 | 
					use Toby\Eloquent\Models\YearPeriod;
 | 
				
			||||||
 | 
					use Toby\Infrastructure\Http\Rules\YearPeriodExists;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CalculateVacationDaysRequest extends FormRequest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function rules(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            "from" => ["required", "date_format:Y-m-d", new YearPeriodExists()],
 | 
				
			||||||
 | 
					            "to" => ["required", "date_format:Y-m-d", new YearPeriodExists()],
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function from(): Carbon
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Carbon::create($this->request->get("from"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function to(): Carbon
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Carbon::create($this->request->get("to"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function yearPeriod(): YearPeriod
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return YearPeriod::findByYear(Carbon::create($this->request->get("from"))->year);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,5 +10,5 @@ return [
 | 
				
			|||||||
    "allowed_headers" => ["*"],
 | 
					    "allowed_headers" => ["*"],
 | 
				
			||||||
    "exposed_headers" => [],
 | 
					    "exposed_headers" => [],
 | 
				
			||||||
    "max_age" => 0,
 | 
					    "max_age" => 0,
 | 
				
			||||||
    "supports_credentials" => false,
 | 
					    "supports_credentials" => true,
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,8 @@ class VacationRequestFactory extends Factory
 | 
				
			|||||||
            ->whereYear("from", $year)
 | 
					            ->whereYear("from", $year)
 | 
				
			||||||
            ->count() + 1;
 | 
					            ->count() + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dump($user->vacationRequests()->count());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return "{$number}/{$year}";
 | 
					        return "{$number}/{$year}";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										37
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "name": "application",
 | 
					    "name": "toby",
 | 
				
			||||||
    "lockfileVersion": 2,
 | 
					    "lockfileVersion": 2,
 | 
				
			||||||
    "requires": true,
 | 
					    "requires": true,
 | 
				
			||||||
    "packages": {
 | 
					    "packages": {
 | 
				
			||||||
@@ -15,6 +15,7 @@
 | 
				
			|||||||
                "@tailwindcss/typography": "^0.5.0",
 | 
					                "@tailwindcss/typography": "^0.5.0",
 | 
				
			||||||
                "@vue/compiler-sfc": "^3.2.26",
 | 
					                "@vue/compiler-sfc": "^3.2.26",
 | 
				
			||||||
                "autoprefixer": "^10.4.2",
 | 
					                "autoprefixer": "^10.4.2",
 | 
				
			||||||
 | 
					                "axios": "^0.25.0",
 | 
				
			||||||
                "echarts": "^5.2.2",
 | 
					                "echarts": "^5.2.2",
 | 
				
			||||||
                "flatpickr": "^4.6.9",
 | 
					                "flatpickr": "^4.6.9",
 | 
				
			||||||
                "laravel-mix": "^6.0.6",
 | 
					                "laravel-mix": "^6.0.6",
 | 
				
			||||||
@@ -1741,6 +1742,14 @@
 | 
				
			|||||||
                "vue": "^3.0.0"
 | 
					                "vue": "^3.0.0"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        "node_modules/@inertiajs/inertia/node_modules/axios": {
 | 
				
			||||||
 | 
					            "version": "0.21.4",
 | 
				
			||||||
 | 
					            "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
 | 
				
			||||||
 | 
					            "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
 | 
				
			||||||
 | 
					            "dependencies": {
 | 
				
			||||||
 | 
					                "follow-redirects": "^1.14.0"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "node_modules/@inertiajs/progress": {
 | 
					        "node_modules/@inertiajs/progress": {
 | 
				
			||||||
            "version": "0.2.7",
 | 
					            "version": "0.2.7",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@inertiajs/progress/-/progress-0.2.7.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@inertiajs/progress/-/progress-0.2.7.tgz",
 | 
				
			||||||
@@ -2642,11 +2651,11 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/axios": {
 | 
					        "node_modules/axios": {
 | 
				
			||||||
            "version": "0.21.4",
 | 
					            "version": "0.25.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
 | 
					            "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "follow-redirects": "^1.14.0"
 | 
					                "follow-redirects": "^1.14.7"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/babel-loader": {
 | 
					        "node_modules/babel-loader": {
 | 
				
			||||||
@@ -10664,6 +10673,16 @@
 | 
				
			|||||||
                "axios": "^0.21.1",
 | 
					                "axios": "^0.21.1",
 | 
				
			||||||
                "deepmerge": "^4.0.0",
 | 
					                "deepmerge": "^4.0.0",
 | 
				
			||||||
                "qs": "^6.9.0"
 | 
					                "qs": "^6.9.0"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "dependencies": {
 | 
				
			||||||
 | 
					                "axios": {
 | 
				
			||||||
 | 
					                    "version": "0.21.4",
 | 
				
			||||||
 | 
					                    "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
 | 
				
			||||||
 | 
					                    "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
 | 
				
			||||||
 | 
					                    "requires": {
 | 
				
			||||||
 | 
					                        "follow-redirects": "^1.14.0"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "@inertiajs/inertia-vue3": {
 | 
					        "@inertiajs/inertia-vue3": {
 | 
				
			||||||
@@ -11468,11 +11487,11 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "axios": {
 | 
					        "axios": {
 | 
				
			||||||
            "version": "0.21.4",
 | 
					            "version": "0.25.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
 | 
					            "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
 | 
				
			||||||
            "requires": {
 | 
					            "requires": {
 | 
				
			||||||
                "follow-redirects": "^1.14.0"
 | 
					                "follow-redirects": "^1.14.7"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "babel-loader": {
 | 
					        "babel-loader": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@
 | 
				
			|||||||
        "@tailwindcss/typography": "^0.5.0",
 | 
					        "@tailwindcss/typography": "^0.5.0",
 | 
				
			||||||
        "@vue/compiler-sfc": "^3.2.26",
 | 
					        "@vue/compiler-sfc": "^3.2.26",
 | 
				
			||||||
        "autoprefixer": "^10.4.2",
 | 
					        "autoprefixer": "^10.4.2",
 | 
				
			||||||
 | 
					        "axios": "^0.25.0",
 | 
				
			||||||
        "echarts": "^5.2.2",
 | 
					        "echarts": "^5.2.2",
 | 
				
			||||||
        "flatpickr": "^4.6.9",
 | 
					        "flatpickr": "^4.6.9",
 | 
				
			||||||
        "laravel-mix": "^6.0.6",
 | 
					        "laravel-mix": "^6.0.6",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,26 @@
 | 
				
			|||||||
      class="border-t border-gray-200 px-6"
 | 
					      class="border-t border-gray-200 px-6"
 | 
				
			||||||
      @submit.prevent="createForm"
 | 
					      @submit.prevent="createForm"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        v-if="form.errors.vacationRequest"
 | 
				
			||||||
 | 
					        class="rounded-md bg-red-50 p-4 mt-2"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <div class="flex">
 | 
				
			||||||
 | 
					          <div class="flex-shrink-0">
 | 
				
			||||||
 | 
					            <XCircleIcon class="h-5 w-5 text-red-400" />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="ml-3">
 | 
				
			||||||
 | 
					            <h3 class="text-sm font-medium text-red-800">
 | 
				
			||||||
 | 
					              Wniosek nie mógł zostać utworzony
 | 
				
			||||||
 | 
					            </h3>
 | 
				
			||||||
 | 
					            <div class="mt-2 text-sm text-red-700">
 | 
				
			||||||
 | 
					              <span>{{ form.errors.vacationRequest }}</span>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
      <Listbox
 | 
					      <Listbox
 | 
				
			||||||
        v-model="form.vacationType"
 | 
					        v-model="form.type"
 | 
				
			||||||
        as="div"
 | 
					        as="div"
 | 
				
			||||||
        class="sm:grid sm:grid-cols-3 py-4 items-center"
 | 
					        class="sm:grid sm:grid-cols-3 py-4 items-center"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
@@ -21,9 +39,9 @@
 | 
				
			|||||||
        <div class="mt-1 relative sm:mt-0 sm:col-span-2">
 | 
					        <div class="mt-1 relative sm:mt-0 sm:col-span-2">
 | 
				
			||||||
          <ListboxButton
 | 
					          <ListboxButton
 | 
				
			||||||
            class="bg-white relative w-full max-w-lg border rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default sm:text-sm focus:ring-1"
 | 
					            class="bg-white relative w-full max-w-lg border rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default sm:text-sm focus:ring-1"
 | 
				
			||||||
            :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.vacationType, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.vacationType }"
 | 
					            :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.type, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.type }"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <span class="block truncate">{{ form.vacationType.label }}</span>
 | 
					            <span class="block truncate">{{ form.type.label }}</span>
 | 
				
			||||||
            <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
 | 
					            <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
 | 
				
			||||||
              <SelectorIcon class="h-5 w-5 text-gray-400" />
 | 
					              <SelectorIcon class="h-5 w-5 text-gray-400" />
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
@@ -38,15 +56,15 @@
 | 
				
			|||||||
              class="absolute z-10 mt-1 w-full max-w-lg bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
 | 
					              class="absolute z-10 mt-1 w-full max-w-lg bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <ListboxOption
 | 
					              <ListboxOption
 | 
				
			||||||
                v-for="vacationType in vacationTypes"
 | 
					                v-for="type in vacationTypes"
 | 
				
			||||||
                :key="vacationType.value"
 | 
					                :key="type.value"
 | 
				
			||||||
                v-slot="{ active, selected }"
 | 
					                v-slot="{ active, selected }"
 | 
				
			||||||
                as="template"
 | 
					                as="template"
 | 
				
			||||||
                :value="vacationType"
 | 
					                :value="type"
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                <li :class="[active ? 'text-white bg-blumilk-600' : 'text-gray-900', 'cursor-default select-none relative py-2 pl-3 pr-9']">
 | 
					                <li :class="[active ? 'text-white bg-blumilk-600' : 'text-gray-900', 'cursor-default select-none relative py-2 pl-3 pr-9']">
 | 
				
			||||||
                  <span :class="[selected ? 'font-semibold' : 'font-normal', 'block truncate']">
 | 
					                  <span :class="[selected ? 'font-semibold' : 'font-normal', 'block truncate']">
 | 
				
			||||||
                    {{ vacationType.label }}
 | 
					                    {{ type.label }}
 | 
				
			||||||
                  </span>
 | 
					                  </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  <span
 | 
					                  <span
 | 
				
			||||||
@@ -60,10 +78,10 @@
 | 
				
			|||||||
            </ListboxOptions>
 | 
					            </ListboxOptions>
 | 
				
			||||||
          </transition>
 | 
					          </transition>
 | 
				
			||||||
          <p
 | 
					          <p
 | 
				
			||||||
            v-if="form.errors.vacationType"
 | 
					            v-if="form.errors.type"
 | 
				
			||||||
            class="mt-2 text-sm text-red-600"
 | 
					            class="mt-2 text-sm text-red-600"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            {{ form.errors.vacationType }}
 | 
					            {{ form.errors.type }}
 | 
				
			||||||
          </p>
 | 
					          </p>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </Listbox>
 | 
					      </Listbox>
 | 
				
			||||||
@@ -77,18 +95,18 @@
 | 
				
			|||||||
        <div class="mt-1 sm:mt-0 sm:col-span-2">
 | 
					        <div class="mt-1 sm:mt-0 sm:col-span-2">
 | 
				
			||||||
          <FlatPickr
 | 
					          <FlatPickr
 | 
				
			||||||
            id="date_from"
 | 
					            id="date_from"
 | 
				
			||||||
            v-model="form.dateFrom"
 | 
					            v-model="form.from"
 | 
				
			||||||
            :config="fromInputConfig"
 | 
					            :config="fromInputConfig"
 | 
				
			||||||
            placeholder="Wybierz datę"
 | 
					            placeholder="Wybierz datę"
 | 
				
			||||||
            class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
 | 
					            class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
 | 
				
			||||||
            :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.dateFrom, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.dateFrom }"
 | 
					            :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.from, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.from }"
 | 
				
			||||||
            @on-change="onFromChange"
 | 
					            @on-change="onFromChange"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          <p
 | 
					          <p
 | 
				
			||||||
            v-if="form.errors.dateFrom"
 | 
					            v-if="form.errors.from"
 | 
				
			||||||
            class="mt-2 text-sm text-red-600"
 | 
					            class="mt-2 text-sm text-red-600"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            {{ form.errors.dateFrom }}
 | 
					            {{ form.errors.from }}
 | 
				
			||||||
          </p>
 | 
					          </p>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
@@ -102,25 +120,25 @@
 | 
				
			|||||||
        <div class="mt-1 sm:mt-0 sm:col-span-2">
 | 
					        <div class="mt-1 sm:mt-0 sm:col-span-2">
 | 
				
			||||||
          <FlatPickr
 | 
					          <FlatPickr
 | 
				
			||||||
            id="date_to"
 | 
					            id="date_to"
 | 
				
			||||||
            v-model="form.dateTo"
 | 
					            v-model="form.to"
 | 
				
			||||||
            :config="toInputConfig"
 | 
					            :config="toInputConfig"
 | 
				
			||||||
            placeholder="Wybierz datę"
 | 
					            placeholder="Wybierz datę"
 | 
				
			||||||
            class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
 | 
					            class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
 | 
				
			||||||
            :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.dateTo, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.dateTo }"
 | 
					            :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.to, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.to }"
 | 
				
			||||||
            @on-change="onToChange"
 | 
					            @on-change="onToChange"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          <p
 | 
					          <p
 | 
				
			||||||
            v-if="form.errors.dateTo"
 | 
					            v-if="form.errors.to"
 | 
				
			||||||
            class="mt-2 text-sm text-red-600"
 | 
					            class="mt-2 text-sm text-red-600"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            {{ form.errors.dateTo }}
 | 
					            {{ form.errors.to }}
 | 
				
			||||||
          </p>
 | 
					          </p>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="sm:grid sm:grid-cols-3 py-4 items-center">
 | 
					      <div class="sm:grid sm:grid-cols-3 py-4 items-center">
 | 
				
			||||||
        <span class="block text-sm font-medium text-gray-700 sm:mt-px">Liczba dni urlopu</span>
 | 
					        <span class="block text-sm font-medium text-gray-700 sm:mt-px">Liczba dni urlopu</span>
 | 
				
			||||||
        <div class="mt-1 sm:mt-0 sm:col-span-2 w-full max-w-lg bg-gray-50 border border-gray-300 rounded-md px-4 py-2 inline-flex items-center text-gray-500 sm:text-sm">
 | 
					        <div class="mt-1 sm:mt-0 sm:col-span-2 w-full max-w-lg bg-gray-50 border border-gray-300 rounded-md px-4 py-2 inline-flex items-center text-gray-500 sm:text-sm">
 | 
				
			||||||
          1
 | 
					          {{ estimatedDays.length }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="sm:grid sm:grid-cols-3 py-4 items-center">
 | 
					      <div class="sm:grid sm:grid-cols-3 py-4 items-center">
 | 
				
			||||||
@@ -164,8 +182,9 @@
 | 
				
			|||||||
import {useForm} from '@inertiajs/inertia-vue3'
 | 
					import {useForm} from '@inertiajs/inertia-vue3'
 | 
				
			||||||
import FlatPickr from 'vue-flatpickr-component'
 | 
					import FlatPickr from 'vue-flatpickr-component'
 | 
				
			||||||
import {Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions} from '@headlessui/vue'
 | 
					import {Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions} from '@headlessui/vue'
 | 
				
			||||||
import {CheckIcon, SelectorIcon} from '@heroicons/vue/solid'
 | 
					import {CheckIcon, SelectorIcon, XCircleIcon} from '@heroicons/vue/solid'
 | 
				
			||||||
import {reactive} from 'vue'
 | 
					import {reactive, ref} from 'vue'
 | 
				
			||||||
 | 
					import axios from 'axios'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  name: 'VacationRequestCreate',
 | 
					  name: 'VacationRequestCreate',
 | 
				
			||||||
@@ -178,6 +197,7 @@ export default {
 | 
				
			|||||||
    ListboxOptions,
 | 
					    ListboxOptions,
 | 
				
			||||||
    CheckIcon,
 | 
					    CheckIcon,
 | 
				
			||||||
    SelectorIcon,
 | 
					    SelectorIcon,
 | 
				
			||||||
 | 
					    XCircleIcon,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  props: {
 | 
					  props: {
 | 
				
			||||||
    vacationTypes: {
 | 
					    vacationTypes: {
 | 
				
			||||||
@@ -191,12 +211,14 @@ export default {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  setup(props) {
 | 
					  setup(props) {
 | 
				
			||||||
    const form = useForm({
 | 
					    const form = useForm({
 | 
				
			||||||
      dateFrom: null,
 | 
					      from: null,
 | 
				
			||||||
      dateTo: null,
 | 
					      to: null,
 | 
				
			||||||
      vacationType: props.vacationTypes[0],
 | 
					      type: props.vacationTypes[0],
 | 
				
			||||||
      comment: null,
 | 
					      comment: null,
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const estimatedDays = ref([])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const disableDates = [
 | 
					    const disableDates = [
 | 
				
			||||||
      date => (date.getDay() === 0 || date.getDay() === 6),
 | 
					      date => (date.getDay() === 0 || date.getDay() === 6),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
@@ -213,6 +235,7 @@ export default {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      form,
 | 
					      form,
 | 
				
			||||||
 | 
					      estimatedDays,
 | 
				
			||||||
      fromInputConfig,
 | 
					      fromInputConfig,
 | 
				
			||||||
      toInputConfig,
 | 
					      toInputConfig,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -221,18 +244,26 @@ export default {
 | 
				
			|||||||
    createForm() {
 | 
					    createForm() {
 | 
				
			||||||
      this.form
 | 
					      this.form
 | 
				
			||||||
        .transform(data => ({
 | 
					        .transform(data => ({
 | 
				
			||||||
          from: data.dateFrom,
 | 
					          ...data,
 | 
				
			||||||
          to: data.dateTo,
 | 
					          type: data.type.value,
 | 
				
			||||||
          type: data.vacationType.value,
 | 
					 | 
				
			||||||
          comment: data.comment,
 | 
					 | 
				
			||||||
        }))
 | 
					        }))
 | 
				
			||||||
        .post('/vacation-requests')
 | 
					        .post('/vacation-requests')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    onFromChange(selectedDates, dateStr) {
 | 
					    onFromChange(selectedDates, dateStr) {
 | 
				
			||||||
      this.toInputConfig.minDate = dateStr
 | 
					      this.toInputConfig.minDate = dateStr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.refreshEstimatedDays(this.form.from, this.form.to)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    onToChange(selectedDates, dateStr) {
 | 
					    onToChange(selectedDates, dateStr) {
 | 
				
			||||||
      this.fromInputConfig.maxDate = dateStr
 | 
					      this.fromInputConfig.maxDate = dateStr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.refreshEstimatedDays(this.form.from, this.form.to)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    refreshEstimatedDays(from, to) {
 | 
				
			||||||
 | 
					      if (from && to) {
 | 
				
			||||||
 | 
					        axios.post('/api/calculate-vacation-days', {from, to})
 | 
				
			||||||
 | 
					          .then(res => this.estimatedDays = res.data)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,10 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare(strict_types=1);
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Route;
 | 
				
			||||||
 | 
					use Toby\Infrastructure\Http\Controllers\Api\CalculateVacationDaysController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Route::middleware("auth:sanctum")->group(function (): void {
 | 
				
			||||||
 | 
					    Route::post("calculate-vacation-days", CalculateVacationDaysController::class);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user