This commit is contained in:
Adrian Hopek 2022-01-21 15:17:59 +01:00
parent a62a428781
commit 5a51f24342
23 changed files with 2492 additions and 183 deletions

View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Toby\Helpers;
use Toby\Models\YearPeriod;
class YearPeriodRetriever
{
public const SESSION_KEY = "selected_year_period";
public function selected(): YearPeriod
{
/** @var YearPeriod $yearPeriod */
$yearPeriod = YearPeriod::query()->find(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),
];
}
}

View File

@ -1,40 +0,0 @@
<?php
declare(strict_types=1);
namespace Toby\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Inertia\Response;
use Toby\Http\Resources\VacationLimitResource;
use Toby\Http\Resources\YearPeriodResource;
use Toby\Models\YearPeriod;
class VacationDaysController extends Controller
{
public function edit(Request $request): Response
{
$year = $request->query("year", Carbon::now()->year);
/** @var YearPeriod $yearPeriod */
$yearPeriod = YearPeriod::query()->where("year", $year)->firstOrFail();
$previousYearPeriod = YearPeriod::query()->where("year", $year - 1)->first();
$nextYearPeriod = YearPeriod::query()->where("year", $year + 1)->first();
return inertia("VacationDays", [
"vacationLimits" => VacationLimitResource::collection($yearPeriod->vacationLimits()->with("user")->get()),
"yearPeriods" => [
"prev" => $previousYearPeriod ? new YearPeriodResource($previousYearPeriod) : null,
"current" => new YearPeriodResource($yearPeriod),
"next" => $nextYearPeriod ? new YearPeriodResource($nextYearPeriod) : null,
],
]);
}
public function update(Request $request)
{
dump($request->get("items"));
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Toby\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Arr;
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
{
foreach ($request->data() as $data) {
$limit = VacationLimit::query()->find($data["id"]);
$limit->update(Arr::only($data, ["has_vacation", "days"]));
}
return redirect()
->back()
->with("success", __("Vacation limits have been updated"));
}
}

View File

@ -6,10 +6,15 @@ namespace Toby\Http\Middleware;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Inertia\Middleware; use Inertia\Middleware;
use Toby\Helpers\YearPeriodRetriever;
use Toby\Http\Resources\UserResource; use Toby\Http\Resources\UserResource;
class HandleInertiaRequests extends Middleware class HandleInertiaRequests extends Middleware
{ {
public function __construct(protected YearPeriodRetriever $yearPeriodRetriever)
{
}
public function share(Request $request): array public function share(Request $request): array
{ {
$user = $request->user(); $user = $request->user();
@ -22,6 +27,7 @@ class HandleInertiaRequests extends Middleware
"success" => $request->session()->get("success"), "success" => $request->session()->get("success"),
"error" => $request->session()->get("error"), "error" => $request->session()->get("error"),
], ],
"years" => fn() => $user ? $this->yearPeriodRetriever->links() : [],
]); ]);
} }
} }

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Toby\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Collection;
class VacationLimitRequest extends FormRequest
{
public function rules(): array
{
return [
"items" => ["required", "array"],
"items.*.id" => ["required", "exists:vacation_limits,id"],
"items.*.hasVacation" => ["required", "boolean"],
"items.*.days" => ["exclude_if:items.*.hasVacation,false", "required", "integer", "min:0"],
];
}
public function data(): Collection
{
return $this->collect("items")->map(fn(array $item): array => [
"id" => $item["id"],
"has_vacation" => $item["hasVacation"],
"days" => $item["days"],
]);
}
}

View File

@ -8,11 +8,12 @@ use Illuminate\Http\Resources\Json\JsonResource;
class VacationLimitResource extends JsonResource class VacationLimitResource extends JsonResource
{ {
public static $wrap = null; public static $wrap = false;
public function toArray($request): array public function toArray($request): array
{ {
return [ return [
"id" => $this->id,
"user" => new UserResource($this->user), "user" => new UserResource($this->user),
"hasVacation" => $this->has_vacation, "hasVacation" => $this->has_vacation,
"days" => $this->days, "days" => $this->days,

View File

@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
namespace Toby\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class YearPeriodResource extends JsonResource
{
public static $wrap = false;
public function toArray($request): array
{
return [
"id" => $this->id,
"year" => $this->year,
];
}
}

View File

@ -19,6 +19,8 @@ class VacationLimit extends Model
{ {
use HasFactory; use HasFactory;
protected $guarded = [];
protected $casts = [ protected $casts = [
"has_vacation" => "boolean", "has_vacation" => "boolean",
]; ];

View File

@ -7,7 +7,9 @@ namespace Toby\Providers;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Toby\Models\User; use Toby\Models\User;
use Toby\Models\VacationLimit;
use Toby\Observers\UserObserver; use Toby\Observers\UserObserver;
use Toby\Scopes\SelectedYearPeriodScope;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {
@ -16,5 +18,7 @@ class AppServiceProvider extends ServiceProvider
User::observe(UserObserver::class); User::observe(UserObserver::class);
Carbon::macro("toDisplayString", fn() => $this->translatedFormat("j F Y")); Carbon::macro("toDisplayString", fn() => $this->translatedFormat("j F Y"));
VacationLimit::addGlobalScope($this->app->make(SelectedYearPeriodScope::class));
} }
} }

View File

@ -0,0 +1,22 @@
<?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);
}
}

View File

@ -14,7 +14,7 @@ class DatabaseSeeder extends Seeder
{ {
public function run(): void public function run(): void
{ {
User::factory(35)->create(); User::factory(14)->create();
User::factory([ User::factory([
"email" => env("LOCAL_EMAIL_FOR_LOGIN_VIA_GOOGLE"), "email" => env("LOCAL_EMAIL_FOR_LOGIN_VIA_GOOGLE"),
])->create(); ])->create();

2129
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,8 @@
"vue-loader": "^17.0.0" "vue-loader": "^17.0.0"
}, },
"devDependencies": { "devDependencies": {
"browser-sync": "^2.27.7",
"browser-sync-webpack-plugin": "^2.3.0",
"eslint": "^8.6.0", "eslint": "^8.6.0",
"eslint-plugin-vue": "^8.2.0" "eslint-plugin-vue": "^8.2.0"
} }

View File

@ -10,45 +10,6 @@
Zarządzaj dostepnymi dniami urlopów dla użytkowników. Zarządzaj dostepnymi dniami urlopów dla użytkowników.
</p> </p>
</div> </div>
<div class="ml-4">
<span class="relative z-0 inline-flex shadow-sm rounded-md">
<InertiaLink
v-if="yearPeriods.prev"
:preserve-scroll="true"
replace
href="/vacation-days"
:data="{year: yearPeriods.prev.year}"
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blumilk-500 focus:border-blumilk-500"
>
<ChevronLeftIcon class="h-5 w-5" />
</InertiaLink>
<span
v-else
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500"
>
<ChevronLeftIcon class="h-5 w-5" />
</span>
<span class="-ml-px relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500">
{{ yearPeriods.current.year }}
</span>
<InertiaLink
v-if="yearPeriods.next"
:preserve-scroll="true"
href="/vacation-days"
replace
:data="{year: yearPeriods.next.year}"
class="-ml-px relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blumilk-500 focus:border-blumilk-500"
>
<ChevronRightIcon class="h-5 w-5" />
</InertiaLink>
<span
v-else
class="-ml-px relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500"
>
<ChevronRightIcon class="h-5 w-5" />
</span>
</span>
</div>
</div> </div>
<div class="border-t border-gray-200"> <div class="border-t border-gray-200">
<div class="overflow-x-auto xl:overflow-x-visible overflow-y-auto xl:overflow-y-visible"> <div class="overflow-x-auto xl:overflow-x-visible overflow-y-auto xl:overflow-y-visible">
@ -84,7 +45,7 @@
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-100"> <tbody class="bg-white divide-y divide-gray-100">
<tr <tr
v-for="item in form.items" v-for="(item, index) in form.items"
:key="item.id" :key="item.id"
class="hover:bg-blumilk-25" class="hover:bg-blumilk-25"
> >
@ -128,14 +89,15 @@
v-model="item.days" v-model="item.days"
type="number" type="number"
min="0" min="0"
class="block w-full shadow-sm rounded-md sm:text-sm" 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"
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" :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 <p
v-if="false" v-if="form.errors[`items.${index}.days`]"
class="mt-2 text-sm text-red-600" class="mt-2 text-sm text-red-600"
> >
{{ form.errors.name }} {{ form.errors[`items.${index}.days`] }}
</p> </p>
</div> </div>
</td> </td>
@ -153,13 +115,6 @@
</tbody> </tbody>
</table> </table>
<div class="flex justify-end py-3 px-4"> <div class="flex justify-end py-3 px-4">
<div class="space-x-3">
<InertiaLink
href="/users"
class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
>
Anuluj
</InertiaLink>
<button <button
type="submit" 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" 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"
@ -167,7 +122,6 @@
Zapisz Zapisz
</button> </button>
</div> </div>
</div>
</form> </form>
</div> </div>
</div> </div>
@ -176,29 +130,26 @@
<script> <script>
import {Switch} from '@headlessui/vue'; import {Switch} from '@headlessui/vue';
import {ChevronLeftIcon, ChevronRightIcon} from '@heroicons/vue/solid';
import {useForm} from '@inertiajs/inertia-vue3'; import {useForm} from '@inertiajs/inertia-vue3';
export default { export default {
name: 'VacationDays', name: 'VacationLimits',
components: { components: {
Switch, Switch,
ChevronLeftIcon,
ChevronRightIcon,
}, },
props: { props: {
vacationLimits: { limits: {
type: Object, type: Object,
default: () => null, default: () => null,
}, },
yearPeriods: { years: {
type: Object, type: Object,
default: () => null, default: () => null,
}, },
}, },
setup(props) { setup(props) {
const form = useForm({ const form = useForm({
items: props.vacationLimits.data, items: props.limits.data,
}); });
return { return {
@ -209,9 +160,16 @@ export default {
submitVacationDays() { submitVacationDays() {
this.form this.form
.transform(data => ({ .transform(data => ({
data, items: data.items.map(item => ({
id: item.id,
hasVacation: item.hasVacation,
days: item.hasVacation ? item.days : null,
})),
})) }))
.put('/vacation-days'); .put('/vacation-days', {
preserveState: (page) => Object.keys(page.props.errors).length,
preserveScroll: true,
});
}, },
}, },
}; };

View File

@ -19,6 +19,53 @@
<!-- Right section on desktop --> <!-- Right section on desktop -->
<div class="hidden lg:ml-4 lg:flex lg:items-center lg:py-5 lg:pr-0.5"> <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 <button
type="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" 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 {BellIcon, MenuIcon, XIcon} from '@heroicons/vue/outline';
import {computed} from 'vue'; import {computed} from 'vue';
import {usePage} from '@inertiajs/inertia-vue3'; import {usePage} from '@inertiajs/inertia-vue3';
import {ChevronDownIcon, CheckIcon} from '@heroicons/vue/solid';
export default { export default {
name: 'MainMenu', name: 'MainMenu',
@ -263,9 +311,12 @@ export default {
BellIcon, BellIcon,
MenuIcon, MenuIcon,
XIcon, XIcon,
ChevronDownIcon,
CheckIcon,
}, },
setup() { setup() {
const user = computed(() => usePage().props.value.auth.user); const user = computed(() => usePage().props.value.auth.user);
const years = computed(() => usePage().props.value.years);
const navigation = [ const navigation = [
{name: 'Strona główna', href: '/', current: true}, {name: 'Strona główna', href: '/', current: true},
@ -282,6 +333,7 @@ export default {
return { return {
user, user,
years,
navigation, navigation,
userNavigation, userNavigation,
}; };

View File

@ -2,11 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Toby\Helpers\YearPeriodRetriever;
use Toby\Http\Controllers\GoogleController; use Toby\Http\Controllers\GoogleController;
use Toby\Http\Controllers\LogoutController; use Toby\Http\Controllers\LogoutController;
use Toby\Http\Controllers\UserController; use Toby\Http\Controllers\UserController;
use Toby\Http\Controllers\VacationDaysController; use Toby\Http\Controllers\VacationLimitController;
use Toby\Models\YearPeriod;
Route::middleware("auth")->group(function (): void { Route::middleware("auth")->group(function (): void {
Route::get("/", fn() => inertia("Dashboard"))->name("dashboard"); Route::get("/", fn() => inertia("Dashboard"))->name("dashboard");
@ -15,8 +18,14 @@ Route::middleware("auth")->group(function (): void {
Route::resource("users", UserController::class); Route::resource("users", UserController::class);
Route::post("users/{user}/restore", [UserController::class, "restore"])->withTrashed(); Route::post("users/{user}/restore", [UserController::class, "restore"])->withTrashed();
Route::get("/vacation-days", [VacationDaysController::class, "edit"])->name("vacation.days"); Route::get("/vacation-days", [VacationLimitController::class, "edit"])->name("vacation.days");
Route::put("/vacation-days", [VacationDaysController::class, "update"]); Route::put("/vacation-days", [VacationLimitController::class, "update"]);
Route::post("year-periods/{yearPeriod}/select", function (Request $request, YearPeriod $yearPeriod) {
$request->session()->put(YearPeriodRetriever::SESSION_KEY, $yearPeriod->id);
return redirect()->back();
})->name("year-periods.select");
}); });
Route::middleware("guest")->group(function (): void { Route::middleware("guest")->group(function (): void {

View File

@ -5,10 +5,10 @@ declare(strict_types=1);
namespace Tests\Feature; namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\TestCase; use Tests\FeatureTestCase;
use Toby\Models\User; use Toby\Models\User;
class AuthenticationTest extends TestCase class AuthenticationTest extends FeatureTestCase
{ {
use DatabaseMigrations; use DatabaseMigrations;

View File

@ -6,10 +6,10 @@ namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseMigrations;
use Inertia\Testing\AssertableInertia as Assert; use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase; use Tests\FeatureTestCase;
use Toby\Models\User; use Toby\Models\User;
class InertiaTest extends TestCase class InertiaTest extends FeatureTestCase
{ {
use DatabaseMigrations; use DatabaseMigrations;

View File

@ -8,11 +8,11 @@ use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Inertia\Testing\AssertableInertia as Assert; use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase; use Tests\FeatureTestCase;
use Toby\Enums\EmploymentForm; use Toby\Enums\EmploymentForm;
use Toby\Models\User; use Toby\Models\User;
class UserTest extends TestCase class UserTest extends FeatureTestCase
{ {
use DatabaseMigrations; use DatabaseMigrations;

21
tests/FeatureTestCase.php Normal file
View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Tests\Traits\InteractsWithYearPeriods;
abstract class FeatureTestCase extends BaseTestCase
{
use CreatesApplication;
use InteractsWithYearPeriods;
protected function setUp(): void
{
parent::setUp();
$this->createCurrentYearPeriod();
}
}

View File

@ -0,0 +1,38 @@
<?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([]);
}
}

View File

@ -7,12 +7,14 @@ namespace Tests\Unit;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Tests\TestCase; use Tests\TestCase;
use Tests\Traits\InteractsWithYearPeriods;
use Toby\Jobs\CheckYearPeriod; use Toby\Jobs\CheckYearPeriod;
use Toby\Models\YearPeriod; use Toby\Models\YearPeriod;
class CheckYearPeriodTest extends TestCase class CheckYearPeriodTest extends TestCase
{ {
use RefreshDatabase; use RefreshDatabase;
use InteractsWithYearPeriods;
public function testYearPeriodsAreCreatedWhenDontExist(): void public function testYearPeriodsAreCreatedWhenDontExist(): void
{ {
@ -54,9 +56,7 @@ class CheckYearPeriodTest extends TestCase
$now = Carbon::now(); $now = Carbon::now();
Carbon::setTestNow($now); Carbon::setTestNow($now);
YearPeriod::factory([ $this->createCurrentYearPeriod();
"year" => $now->year,
]);
$this->assertDatabaseMissing("year_periods", [ $this->assertDatabaseMissing("year_periods", [
"year" => $now->year + 1, "year" => $now->year + 1,
@ -74,12 +74,8 @@ class CheckYearPeriodTest extends TestCase
$now = Carbon::now(); $now = Carbon::now();
Carbon::setTestNow($now); Carbon::setTestNow($now);
YearPeriod::factory([ $this->createCurrentYearPeriod();
"year" => $now->year, $this->createYearPeriod($now->year + 1);
])->create();
YearPeriod::factory([
"year" => $now->year + 1,
])->create();
$this->assertDatabaseCount("year_periods", 2); $this->assertDatabaseCount("year_periods", 2);

View File

@ -0,0 +1,83 @@
<?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;
public function setUp(): void
{
parent::setUp();
$this->current = Carbon::now();
Carbon::setTestNow($this->current);
$this->yearPeriodRetriever = new YearPeriodRetriever();
$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 testRetrievesCurrentYearPeriodWhenNoSelected(): 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());
}
}