fix
This commit is contained in:
parent
45510a898b
commit
d2babab7a0
@ -35,6 +35,6 @@ class AuthServiceProvider extends ServiceProvider
|
|||||||
Gate::define("manageVacationLimits", fn(User $user): bool => $user->role === Role::AdministrativeApprover);
|
Gate::define("manageVacationLimits", fn(User $user): bool => $user->role === Role::AdministrativeApprover);
|
||||||
Gate::define("generateTimesheet", fn(User $user): bool => $user->role === Role::AdministrativeApprover);
|
Gate::define("generateTimesheet", fn(User $user): bool => $user->role === Role::AdministrativeApprover);
|
||||||
Gate::define("listMonthlyUsage", fn(User $user): bool => $user->role === Role::AdministrativeApprover);
|
Gate::define("listMonthlyUsage", fn(User $user): bool => $user->role === Role::AdministrativeApprover);
|
||||||
Gate::define("manageResumes", fn(User $user): bool => $user->role === Role::AdministrativeApprover);
|
Gate::define("manageResumes", fn(User $user): bool => $user->role === Role::TechnicalApprover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class ResumeGenerator
|
|||||||
|
|
||||||
protected function fillTechnologies(TemplateProcessor $processor, Resume $resume): void
|
protected function fillTechnologies(TemplateProcessor $processor, Resume $resume): void
|
||||||
{
|
{
|
||||||
if ($resume->technologies->count() <= 0) {
|
if ($resume->technologies->isEmpty()) {
|
||||||
$processor->deleteBlock("technologies");
|
$processor->deleteBlock("technologies");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -51,7 +51,7 @@ class ResumeGenerator
|
|||||||
|
|
||||||
protected function fillLanguages(TemplateProcessor $processor, Resume $resume): void
|
protected function fillLanguages(TemplateProcessor $processor, Resume $resume): void
|
||||||
{
|
{
|
||||||
if ($resume->education->count() <= 0) {
|
if ($resume->education->isEmpty()) {
|
||||||
$processor->deleteBlock("languages");
|
$processor->deleteBlock("languages");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -62,7 +62,7 @@ class ResumeGenerator
|
|||||||
|
|
||||||
protected function fillEducation(TemplateProcessor $processor, Resume $resume): void
|
protected function fillEducation(TemplateProcessor $processor, Resume $resume): void
|
||||||
{
|
{
|
||||||
if ($resume->education->count() <= 0) {
|
if ($resume->education->isEmpty()) {
|
||||||
$processor->deleteBlock("education");
|
$processor->deleteBlock("education");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -73,7 +73,7 @@ class ResumeGenerator
|
|||||||
|
|
||||||
protected function fillProjects(TemplateProcessor $processor, Resume $resume): void
|
protected function fillProjects(TemplateProcessor $processor, Resume $resume): void
|
||||||
{
|
{
|
||||||
if ($resume->projects->count() <= 0) {
|
if ($resume->projects->isEmpty()) {
|
||||||
$processor->deleteBlock("projects");
|
$processor->deleteBlock("projects");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -94,7 +94,7 @@ class ResumeGenerator
|
|||||||
return [
|
return [
|
||||||
"index#{$index}" => $index,
|
"index#{$index}" => $index,
|
||||||
"start_date#{$index}" => Carbon::create($project["startDate"])->toDisplayString(),
|
"start_date#{$index}" => Carbon::create($project["startDate"])->toDisplayString(),
|
||||||
"end_date#{$index}" => Carbon::create($project["endDate"])->toDisplayString(),
|
"end_date#{$index}" => $project["current"] ? "present" : Carbon::create($project["endDate"])->format("m.Y"),
|
||||||
"description#{$index}" => $project["description"],
|
"description#{$index}" => $project["description"],
|
||||||
"tasks#{$index}" => $this->withNewLines($project["tasks"]),
|
"tasks#{$index}" => $this->withNewLines($project["tasks"]),
|
||||||
];
|
];
|
||||||
@ -134,7 +134,7 @@ class ResumeGenerator
|
|||||||
{
|
{
|
||||||
return $resume->education->map(fn(array $project, int $index): array => [
|
return $resume->education->map(fn(array $project, int $index): array => [
|
||||||
"start_date" => Carbon::create($project["startDate"])->toDisplayString(),
|
"start_date" => Carbon::create($project["startDate"])->toDisplayString(),
|
||||||
"end_date" => Carbon::create($project["endDate"])->toDisplayString(),
|
"end_date" => $project["current"] ? "present" : Carbon::create($project["endDate"])->format("m.Y"),
|
||||||
"school" => $project["school"],
|
"school" => $project["school"],
|
||||||
"field_of_study" => $project["fieldOfStudy"],
|
"field_of_study" => $project["fieldOfStudy"],
|
||||||
"degree" => $project["degree"],
|
"degree" => $project["degree"],
|
||||||
|
@ -16,6 +16,8 @@ class Technology extends Model
|
|||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
protected static function newFactory(): TechnologyFactory
|
protected static function newFactory(): TechnologyFactory
|
||||||
{
|
{
|
||||||
return TechnologyFactory::new();
|
return TechnologyFactory::new();
|
||||||
|
57
app/Infrastructure/Http/Controllers/TechnologyController.php
Normal file
57
app/Infrastructure/Http/Controllers/TechnologyController.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Toby\Infrastructure\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
use Inertia\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Toby\Eloquent\Models\Technology;
|
||||||
|
use Toby\Infrastructure\Http\Requests\TechnologyRequest;
|
||||||
|
use Toby\Infrastructure\Http\Resources\TechnologyResource;
|
||||||
|
|
||||||
|
class TechnologyController extends Controller
|
||||||
|
{
|
||||||
|
public function index(): Response
|
||||||
|
{
|
||||||
|
$this->authorize("manageResumes");
|
||||||
|
|
||||||
|
$technologies = Technology::query()
|
||||||
|
->orderBy("name")
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return inertia("Technologies", [
|
||||||
|
"technologies" => TechnologyResource::collection($technologies),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AuthorizationException
|
||||||
|
*/
|
||||||
|
public function store(TechnologyRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->authorize("manageResumes");
|
||||||
|
|
||||||
|
$technology = Technology::query()->create($request->data());
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with("success", __("Technology :name has been created.", [
|
||||||
|
"name" => $technology->name,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Technology $technology): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->authorize("manageResumes");
|
||||||
|
|
||||||
|
$technology->delete();
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with("success", __("Technology :name has been deleted.", [
|
||||||
|
"name" => $technology->name,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
@ -20,19 +20,21 @@ class ResumeRequest extends FormRequest
|
|||||||
"education.*.school" => ["required"],
|
"education.*.school" => ["required"],
|
||||||
"education.*.degree" => ["required"],
|
"education.*.degree" => ["required"],
|
||||||
"education.*.fieldOfStudy" => ["required"],
|
"education.*.fieldOfStudy" => ["required"],
|
||||||
"education.*.startDate" => ["required", "date_format:Y-m-d"],
|
"education.*.startDate" => ["required", "date_format:m/Y"],
|
||||||
"education.*.endDate" => ["required", "date_format:Y-m-d", "after:education.*.startDate"],
|
"education.*.current" => ["required", "boolean"],
|
||||||
|
"education.*.endDate" => ["required_if:education.*.current,false", "nullable", "date_format:m/Y", "after:education.*.startDate"],
|
||||||
|
|
||||||
"languages.*.name" => ["required", "distinct"],
|
"languages.*.name" => ["required", "distinct"],
|
||||||
"languages.*.level" => ["required", Rule::in(1, 2, 3, 4, 5, 6)],
|
"languages.*.level" => ["required", Rule::in(1, 2, 3, 4, 5, 6)],
|
||||||
|
|
||||||
"technologies.*.name" => ["required", "exists:technologies,name", "distinct"],
|
"technologies.*.name" => ["required", "distinct"],
|
||||||
"technologies.*.level" => ["required", Rule::in(1, 2, 3, 4, 5)],
|
"technologies.*.level" => ["required", Rule::in(1, 2, 3, 4, 5)],
|
||||||
|
|
||||||
"projects.*.description" => ["required"],
|
"projects.*.description" => ["required"],
|
||||||
"projects.*.technologies" => ["array", "min:1", "exists:technologies,name", "distinct"],
|
"projects.*.technologies" => ["array", "min:1", "distinct"],
|
||||||
"projects.*.startDate" => ["required", "date_format:Y-m-d"],
|
"projects.*.startDate" => ["required", "date_format:m/Y"],
|
||||||
"projects.*.endDate" => ["required", "date_format:Y-m-d", "after:projects.*.startDate"],
|
"projects.*.current" => ["required", "boolean"],
|
||||||
|
"projects.*.endDate" => ["required_if:projects.*.current,false", "nullable", "date_format:m/Y", "after:projects.*.startDate"],
|
||||||
"projects.*.tasks" => ["required"],
|
"projects.*.tasks" => ["required"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
29
app/Infrastructure/Http/Requests/TechnologyRequest.php
Normal file
29
app/Infrastructure/Http/Requests/TechnologyRequest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Toby\Infrastructure\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class TechnologyRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"name" => [
|
||||||
|
"required",
|
||||||
|
Rule::unique("technologies", "name")->ignore($this->technology),
|
||||||
|
"max:255",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function data(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"name" => $this->get("name"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
20
app/Infrastructure/Http/Resources/TechnologyResource.php
Normal file
20
app/Infrastructure/Http/Resources/TechnologyResource.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Toby\Infrastructure\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class TechnologyResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
public function toArray($request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"id" => $this->id,
|
||||||
|
"name" => $this->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Toby\Eloquent\Models\Resume;
|
use Toby\Eloquent\Models\Resume;
|
||||||
use Toby\Eloquent\Models\Technology;
|
use Toby\Eloquent\Models\Technology;
|
||||||
@ -33,8 +34,9 @@ class ResumeFactory extends Factory
|
|||||||
"school" => $this->faker->sentence,
|
"school" => $this->faker->sentence,
|
||||||
"degree" => $this->faker->sentence,
|
"degree" => $this->faker->sentence,
|
||||||
"fieldOfStudy" => $this->faker->sentence,
|
"fieldOfStudy" => $this->faker->sentence,
|
||||||
"startDate" => $this->faker->date,
|
"current" => false,
|
||||||
"endDate" => $this->faker->date,
|
"startDate" => Carbon::create($this->faker->date)->format("m/Y"),
|
||||||
|
"endDate" => Carbon::create($this->faker->date)->format("m/Y"),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +80,9 @@ class ResumeFactory extends Factory
|
|||||||
$items[] = [
|
$items[] = [
|
||||||
"description" => $this->faker->text,
|
"description" => $this->faker->text,
|
||||||
"technologies" => $technologies->random($number)->all(),
|
"technologies" => $technologies->random($number)->all(),
|
||||||
"startDate" => $this->faker->date,
|
"current" => false,
|
||||||
"endDate" => $this->faker->date,
|
"startDate" => Carbon::create($this->faker->date)->format("m/Y"),
|
||||||
|
"endDate" => Carbon::create($this->faker->date)->format("m/Y"),
|
||||||
"tasks" => $this->faker->text,
|
"tasks" => $this->faker->text,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
@import 'flatpickr/dist/themes/light.css';
|
@import 'flatpickr/dist/themes/light.css';
|
||||||
|
@import 'flatpickr/dist/plugins/monthSelect/style.css';
|
||||||
@import 'vue-toastification/dist/index.css';
|
@import 'vue-toastification/dist/index.css';
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
|
@ -207,7 +207,7 @@
|
|||||||
Data rozpoczęcia
|
Data rozpoczęcia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<MonthPicker
|
||||||
v-model="element.startDate"
|
v-model="element.startDate"
|
||||||
placeholder="Wybierz datę"
|
placeholder="Wybierz datę"
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
class="block w-full rounded-md shadow-sm sm:text-sm"
|
||||||
@ -226,12 +226,23 @@
|
|||||||
Data zakończenia
|
Data zakończenia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<div class="space-y-2">
|
||||||
v-model="element.endDate"
|
<label class="block text-sm font-medium text-gray-700 sm:mt-px">
|
||||||
placeholder="Wybierz datę"
|
<input
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
v-model="element.current"
|
||||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.endDate`] }"
|
type="checkbox"
|
||||||
/>
|
class="focus:ring-blumilk-500 h-4 w-4 text-blumilk-600 border-gray-300 rounded mr-1"
|
||||||
|
>
|
||||||
|
W trakcie
|
||||||
|
</label>
|
||||||
|
<MonthPicker
|
||||||
|
v-model="element.endDate"
|
||||||
|
placeholder="Wybierz datę"
|
||||||
|
:disabled="element.current"
|
||||||
|
class="block w-full rounded-md shadow-sm sm:text-sm disabled:bg-gray-100"
|
||||||
|
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.endDate`] }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="form.errors[`education.${index}.endDate`]"
|
v-if="form.errors[`education.${index}.endDate`]"
|
||||||
class="mt-2 text-sm text-red-600"
|
class="mt-2 text-sm text-red-600"
|
||||||
@ -436,12 +447,12 @@
|
|||||||
Data rozpoczęcia
|
Data rozpoczęcia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<MonthPicker
|
||||||
:id="`project-startDate-${index}`"
|
:id="`project-startDate-${index}`"
|
||||||
v-model="element.startDate"
|
v-model="element.startDate"
|
||||||
placeholder="Wybierz datę"
|
placeholder="Wybierz datę"
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
class="block w-full rounded-md shadow-sm sm:text-sm"
|
||||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`educations.${index}.startDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`educations.${index}.startDate`] }"
|
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`projects.${index}.startDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`projects.${index}.startDate`] }"
|
||||||
/>
|
/>
|
||||||
<p
|
<p
|
||||||
v-if="form.errors[`projects.${index}.startDate`]"
|
v-if="form.errors[`projects.${index}.startDate`]"
|
||||||
@ -459,13 +470,24 @@
|
|||||||
Data zakończenia
|
Data zakończenia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<div class="space-y-2">
|
||||||
:id="`project-endDate-${index}`"
|
<label class="block text-sm font-medium text-gray-700 sm:mt-px">
|
||||||
v-model="element.endDate"
|
<input
|
||||||
placeholder="Wybierz datę"
|
v-model="element.current"
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
type="checkbox"
|
||||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`educations.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`educations.${index}.endDate`] }"
|
class="focus:ring-blumilk-500 h-4 w-4 text-blumilk-600 border-gray-300 rounded mr-1"
|
||||||
/>
|
>
|
||||||
|
W trakcie
|
||||||
|
</label>
|
||||||
|
<MonthPicker
|
||||||
|
:id="`project-endDate-${index}`"
|
||||||
|
v-model="element.endDate"
|
||||||
|
placeholder="Wybierz datę"
|
||||||
|
:disabled="element.current"
|
||||||
|
class="block w-full rounded-md shadow-sm sm:text-sm disabled:bg-gray-100"
|
||||||
|
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`projects.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`projects.${index}.endDate`] }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="form.errors[`projects.${index}.endDate`]"
|
v-if="form.errors[`projects.${index}.endDate`]"
|
||||||
class="mt-2 text-sm text-red-600"
|
class="mt-2 text-sm text-red-600"
|
||||||
@ -525,7 +547,7 @@ import { Listbox, ListboxOption, ListboxOptions, ListboxLabel, ListboxButton } f
|
|||||||
import { SelectorIcon, CheckIcon } from '@heroicons/vue/outline'
|
import { SelectorIcon, CheckIcon } from '@heroicons/vue/outline'
|
||||||
import { ExclamationCircleIcon } from '@heroicons/vue/solid'
|
import { ExclamationCircleIcon } from '@heroicons/vue/solid'
|
||||||
import { useForm } from '@inertiajs/inertia-vue3'
|
import { useForm } from '@inertiajs/inertia-vue3'
|
||||||
import FlatPickr from 'vue-flatpickr-component'
|
import MonthPicker from '@/Shared/Forms/MonthPicker'
|
||||||
import DynamicSection from '@/Shared/Forms/DynamicSection'
|
import DynamicSection from '@/Shared/Forms/DynamicSection'
|
||||||
import Combobox from '@/Shared/Forms/Combobox'
|
import Combobox from '@/Shared/Forms/Combobox'
|
||||||
import MultipleCombobox from '@/Shared/Forms/MultipleCombobox'
|
import MultipleCombobox from '@/Shared/Forms/MultipleCombobox'
|
||||||
|
@ -207,7 +207,7 @@
|
|||||||
Data rozpoczęcia
|
Data rozpoczęcia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<MonthPicker
|
||||||
v-model="element.startDate"
|
v-model="element.startDate"
|
||||||
placeholder="Wybierz datę"
|
placeholder="Wybierz datę"
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
class="block w-full rounded-md shadow-sm sm:text-sm"
|
||||||
@ -226,12 +226,23 @@
|
|||||||
Data zakończenia
|
Data zakończenia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<div class="space-y-2">
|
||||||
v-model="element.endDate"
|
<label class="block text-sm font-medium text-gray-700 sm:mt-px">
|
||||||
placeholder="Wybierz datę"
|
<input
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
v-model="element.current"
|
||||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.endDate`] }"
|
type="checkbox"
|
||||||
/>
|
class="focus:ring-blumilk-500 h-4 w-4 text-blumilk-600 border-gray-300 rounded mr-1"
|
||||||
|
>
|
||||||
|
W trakcie
|
||||||
|
</label>
|
||||||
|
<MonthPicker
|
||||||
|
v-model="element.endDate"
|
||||||
|
placeholder="Wybierz datę"
|
||||||
|
:disabled="element.current"
|
||||||
|
class="block w-full rounded-md shadow-sm sm:text-sm disabled:bg-gray-100"
|
||||||
|
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.endDate`] }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="form.errors[`education.${index}.endDate`]"
|
v-if="form.errors[`education.${index}.endDate`]"
|
||||||
class="mt-2 text-sm text-red-600"
|
class="mt-2 text-sm text-red-600"
|
||||||
@ -436,12 +447,12 @@
|
|||||||
Data rozpoczęcia
|
Data rozpoczęcia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<MonthPicker
|
||||||
:id="`project-startDate-${index}`"
|
:id="`project-startDate-${index}`"
|
||||||
v-model="element.startDate"
|
v-model="element.startDate"
|
||||||
placeholder="Wybierz datę"
|
placeholder="Wybierz datę"
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
class="block w-full rounded-md shadow-sm sm:text-sm"
|
||||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`educations.${index}.startDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`educations.${index}.startDate`] }"
|
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`projects.${index}.startDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`projects.${index}.startDate`] }"
|
||||||
/>
|
/>
|
||||||
<p
|
<p
|
||||||
v-if="form.errors[`projects.${index}.startDate`]"
|
v-if="form.errors[`projects.${index}.startDate`]"
|
||||||
@ -459,13 +470,24 @@
|
|||||||
Data zakończenia
|
Data zakończenia
|
||||||
</label>
|
</label>
|
||||||
<div class="mt-1 sm:mt-0">
|
<div class="mt-1 sm:mt-0">
|
||||||
<FlatPickr
|
<div class="space-y-2">
|
||||||
:id="`project-endDate-${index}`"
|
<label class="block text-sm font-medium text-gray-700 sm:mt-px">
|
||||||
v-model="element.endDate"
|
<input
|
||||||
placeholder="Wybierz datę"
|
v-model="element.current"
|
||||||
class="block w-full rounded-md shadow-sm sm:text-sm"
|
type="checkbox"
|
||||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`educations.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`educations.${index}.endDate`] }"
|
class="focus:ring-blumilk-500 h-4 w-4 text-blumilk-600 border-gray-300 rounded mr-1"
|
||||||
/>
|
>
|
||||||
|
W trakcie
|
||||||
|
</label>
|
||||||
|
<MonthPicker
|
||||||
|
:id="`project-endDate-${index}`"
|
||||||
|
v-model="element.endDate"
|
||||||
|
placeholder="Wybierz datę"
|
||||||
|
:disabled="element.current"
|
||||||
|
class="block w-full rounded-md shadow-sm sm:text-sm disabled:bg-gray-100"
|
||||||
|
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`projects.${index}.endDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`projects.${index}.endDate`] }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="form.errors[`projects.${index}.endDate`]"
|
v-if="form.errors[`projects.${index}.endDate`]"
|
||||||
class="mt-2 text-sm text-red-600"
|
class="mt-2 text-sm text-red-600"
|
||||||
@ -525,7 +547,7 @@ import { Listbox, ListboxOption, ListboxOptions, ListboxLabel, ListboxButton } f
|
|||||||
import { SelectorIcon, CheckIcon } from '@heroicons/vue/outline'
|
import { SelectorIcon, CheckIcon } from '@heroicons/vue/outline'
|
||||||
import { ExclamationCircleIcon } from '@heroicons/vue/solid'
|
import { ExclamationCircleIcon } from '@heroicons/vue/solid'
|
||||||
import { useForm } from '@inertiajs/inertia-vue3'
|
import { useForm } from '@inertiajs/inertia-vue3'
|
||||||
import FlatPickr from 'vue-flatpickr-component'
|
import MonthPicker from '@/Shared/Forms/MonthPicker'
|
||||||
import DynamicSection from '@/Shared/Forms/DynamicSection'
|
import DynamicSection from '@/Shared/Forms/DynamicSection'
|
||||||
import Combobox from '@/Shared/Forms/Combobox'
|
import Combobox from '@/Shared/Forms/Combobox'
|
||||||
import MultipleCombobox from '@/Shared/Forms/MultipleCombobox'
|
import MultipleCombobox from '@/Shared/Forms/MultipleCombobox'
|
||||||
@ -552,11 +574,11 @@ const form = useForm(`EditResume:${props.resume.id}`,{
|
|||||||
educations: props.resume.education ?? [],
|
educations: props.resume.education ?? [],
|
||||||
projects: props.resume.projects ?? [],
|
projects: props.resume.projects ?? [],
|
||||||
technologies: props.resume.technologies.map((technology) => ({
|
technologies: props.resume.technologies.map((technology) => ({
|
||||||
name: props.technologies.find((tech) => tech === technology.name),
|
name: technology.name,
|
||||||
level: technologyLevels.find((level) => level.level === technology.level),
|
level: technologyLevels.find((level) => level.level === technology.level),
|
||||||
})) ?? [],
|
})) ?? [],
|
||||||
languages: props.resume.languages.map((language) => ({
|
languages: props.resume.languages.map((language) => ({
|
||||||
name: languages.find((lang) => lang === language.name),
|
name: language.name,
|
||||||
level: languageLevels.find((level) => level.level === language.level),
|
level: languageLevels.find((level) => level.level === language.level),
|
||||||
})) ?? [],
|
})) ?? [],
|
||||||
})
|
})
|
||||||
@ -606,7 +628,10 @@ function submitResume() {
|
|||||||
.transform((data) => ({
|
.transform((data) => ({
|
||||||
user: data.user?.id,
|
user: data.user?.id,
|
||||||
name: data.name,
|
name: data.name,
|
||||||
education: data.educations,
|
education: data.educations.map(education => ({
|
||||||
|
...education,
|
||||||
|
endDate: education.current ? null: education.endDate,
|
||||||
|
})),
|
||||||
languages: data.languages.map(language => ({
|
languages: data.languages.map(language => ({
|
||||||
name: language.name,
|
name: language.name,
|
||||||
level: language.level.level,
|
level: language.level.level,
|
||||||
@ -615,7 +640,10 @@ function submitResume() {
|
|||||||
name: technology.name,
|
name: technology.name,
|
||||||
level: technology.level.level,
|
level: technology.level.level,
|
||||||
})),
|
})),
|
||||||
projects: data.projects,
|
projects: data.projects.map(project => ({
|
||||||
|
...project,
|
||||||
|
endDate: project.current ? null : project.endDate,
|
||||||
|
})),
|
||||||
}))
|
}))
|
||||||
.put(`/resumes/${props.resume.id}`)
|
.put(`/resumes/${props.resume.id}`)
|
||||||
}
|
}
|
||||||
|
222
resources/js/Pages/Technologies.vue
Normal file
222
resources/js/Pages/Technologies.vue
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
<template>
|
||||||
|
<InertiaHead title="Klucze" />
|
||||||
|
<div class="bg-white shadow-md">
|
||||||
|
<div class="flex justify-between items-center p-4 sm:px-6">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-lg font-medium leading-6 text-gray-900">
|
||||||
|
Technologie
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center py-3 px-4 text-sm font-medium leading-4 text-white bg-blumilk-600 hover:bg-blumilk-700 rounded-md border border-transparent focus:outline-none focus:ring-2 focus:ring-blumilk-500 focus:ring-offset-2 shadow-sm"
|
||||||
|
@click="creating = true"
|
||||||
|
>
|
||||||
|
Dodaj technologię
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-200">
|
||||||
|
<div class="overflow-auto xl:overflow-visible">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-4 text-xs font-semibold tracking-wider text-left text-gray-500 uppercase whitespace-nowrap"
|
||||||
|
>
|
||||||
|
Technologia
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-4 text-xs font-semibold tracking-wider text-left text-gray-500 uppercase whitespace-nowrap"
|
||||||
|
/>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-100">
|
||||||
|
<tr
|
||||||
|
v-for="technology in technologies.data"
|
||||||
|
:key="technology.id"
|
||||||
|
class="hover:bg-blumilk-25"
|
||||||
|
>
|
||||||
|
<td class="px-4 py-2 text-sm text-gray-500 whitespace-nowrap">
|
||||||
|
{{ technology.name }}
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-2 text-sm text-right text-gray-500 whitespace-nowrap">
|
||||||
|
<Menu
|
||||||
|
as="div"
|
||||||
|
class="inline-block relative text-left"
|
||||||
|
>
|
||||||
|
<MenuButton
|
||||||
|
class="flex items-center text-gray-400 hover:text-gray-600 rounded-full focus:outline-none focus:ring-2 focus:ring-blumilk-500 focus:ring-offset-2 focus:ring-offset-gray-100"
|
||||||
|
>
|
||||||
|
<DotsVerticalIcon class="w-5 h-5" />
|
||||||
|
</MenuButton>
|
||||||
|
|
||||||
|
<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="absolute right-0 z-10 mt-2 w-56 bg-white rounded-md focus:outline-none ring-1 ring-black ring-opacity-5 shadow-lg origin-top-right"
|
||||||
|
>
|
||||||
|
<div class="py-1">
|
||||||
|
<MenuItem
|
||||||
|
v-slot="{ active }"
|
||||||
|
class="flex"
|
||||||
|
>
|
||||||
|
<InertiaLink
|
||||||
|
as="button"
|
||||||
|
method="delete"
|
||||||
|
preserve-scroll
|
||||||
|
:href="`/technologies/${technology.id}`"
|
||||||
|
:class="[active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', 'block w-full text-left font-medium px-4 py-2 text-sm']"
|
||||||
|
>
|
||||||
|
<TrashIcon class="mr-2 w-5 h-5 text-red-500" />
|
||||||
|
Usuń
|
||||||
|
</InertiaLink>
|
||||||
|
</MenuItem>
|
||||||
|
</div>
|
||||||
|
</MenuItems>
|
||||||
|
</transition>
|
||||||
|
</Menu>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="!technologies.data.length">
|
||||||
|
<td
|
||||||
|
colspan="100%"
|
||||||
|
class="py-4 text-xl leading-5 text-center text-gray-700"
|
||||||
|
>
|
||||||
|
Brak danych
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<TransitionRoot
|
||||||
|
as="template"
|
||||||
|
:show="creating"
|
||||||
|
>
|
||||||
|
<Dialog
|
||||||
|
is="div"
|
||||||
|
class="overflow-y-auto fixed inset-0 z-10"
|
||||||
|
@close="creating = false"
|
||||||
|
>
|
||||||
|
<div class="flex justify-center items-end px-4 pt-4 pb-20 min-h-screen text-center sm:block sm:p-0">
|
||||||
|
<TransitionChild
|
||||||
|
as="template"
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enter-from="opacity-0"
|
||||||
|
enter-to="opacity-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leave-from="opacity-100"
|
||||||
|
leave-to="opacity-0"
|
||||||
|
>
|
||||||
|
<DialogOverlay class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
|
||||||
|
</TransitionChild>
|
||||||
|
|
||||||
|
<span class="hidden sm:inline-block sm:h-screen sm:align-middle">​</span>
|
||||||
|
<TransitionChild
|
||||||
|
as="template"
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
|
enter-to="opacity-100 translate-y-0 sm:scale-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leave-from="opacity-100 translate-y-0 sm:scale-100"
|
||||||
|
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
class="inline-block relative px-4 pt-5 pb-4 text-left align-bottom bg-white rounded-lg shadow-xl transition-all transform sm:p-6 sm:my-8 sm:w-full sm:max-w-sm sm:align-middle"
|
||||||
|
@submit.prevent="submitCreateTechnology"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<DialogTitle
|
||||||
|
as="h3"
|
||||||
|
class="text-lg font-medium leading-6 text-center text-gray-900 font-sembiold"
|
||||||
|
>
|
||||||
|
Dodaj technologię
|
||||||
|
</DialogTitle>
|
||||||
|
<div class="mt-5">
|
||||||
|
<label
|
||||||
|
for="name"
|
||||||
|
class="block text-sm font-medium text-gray-700 sm:mt-px"
|
||||||
|
>
|
||||||
|
Nazwa
|
||||||
|
</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input
|
||||||
|
id="name"
|
||||||
|
v-model="form.name"
|
||||||
|
type="text"
|
||||||
|
class="block w-full max-w-lg rounded-md shadow-sm sm:text-sm"
|
||||||
|
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.name, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.name }"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
v-if="form.errors.name"
|
||||||
|
class="mt-2 text-sm text-red-600"
|
||||||
|
>
|
||||||
|
{{ form.errors.name }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-5 sm:mt-6">
|
||||||
|
<div class="flex justify-end space-x-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="py-2 px-4 text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blumilk-500 focus:ring-offset-2 shadow-sm"
|
||||||
|
@click="creating = false"
|
||||||
|
>
|
||||||
|
Anuluj
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
:disabled="form.processing"
|
||||||
|
class="inline-flex justify-center py-2 px-4 text-base font-medium text-white bg-blumilk-600 hover:bg-blumilk-700 rounded-md border border-transparent focus:outline-none focus:ring-2 focus:ring-blumilk-500 focus:ring-offset-2 shadow-sm sm:text-sm"
|
||||||
|
>
|
||||||
|
Dodaj
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</TransitionChild>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</TransitionRoot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { DotsVerticalIcon, TrashIcon } from '@heroicons/vue/solid'
|
||||||
|
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'
|
||||||
|
import { useForm } from '@inertiajs/inertia-vue3'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
technologies: Object,
|
||||||
|
})
|
||||||
|
|
||||||
|
const creating = ref(false)
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
name: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
function submitCreateTechnology() {
|
||||||
|
form.post('technologies', {
|
||||||
|
preserveState: (page) => Object.keys(page.props.errors).length,
|
||||||
|
preserveScroll: true,
|
||||||
|
onSuccess: () => form.reset(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
18
resources/js/Shared/Forms/MonthPicker.vue
Normal file
18
resources/js/Shared/Forms/MonthPicker.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<FlatPickr :config="config" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FlatPickr from 'vue-flatpickr-component'
|
||||||
|
import monthSelectPlugin from 'flatpickr/dist/plugins/monthSelect'
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
plugins: [
|
||||||
|
new monthSelectPlugin({
|
||||||
|
shorthand: true,
|
||||||
|
dateFormat: 'm/Y',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -6,15 +6,31 @@
|
|||||||
multiple
|
multiple
|
||||||
>
|
>
|
||||||
<div class="flex flex-wrap gap-3">
|
<div class="flex flex-wrap gap-3">
|
||||||
<button
|
<span
|
||||||
v-for="(item, index) in selectedItems"
|
v-for="(item, index) in selectedItems"
|
||||||
:key="index"
|
:key="index"
|
||||||
type="button"
|
class="inline-flex items-center py-1.5 pl-3 pr-1.5 rounded-lg text-sm font-medium bg-blumilk-500 text-white"
|
||||||
class="py-1 px-2 bg-gray-200 rounded-md"
|
|
||||||
@click="selectedItems.splice(index, 1)"
|
|
||||||
>
|
>
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex-shrink-0 ml-0.5 h-5 w-5 rounded-full inline-flex items-center justify-center text-white hover:bg-blumilk-600 focus:outline-none"
|
||||||
|
@click="selectedItems.splice(index, 1)"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="h-2 w-2"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 8 8"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-width="1.5"
|
||||||
|
d="M1 1l6 6m0-6L1 7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative mt-2">
|
<div class="relative mt-2">
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
>
|
>
|
||||||
</InertiaLink>
|
</InertiaLink>
|
||||||
</div>
|
</div>
|
||||||
<nav class="overflow-y-auto shrink-0 mt-5 h-full divide-y divide-blumilk-800">
|
<nav class="overflow-y-auto shrink-0 mt-5 h-full space-y-5">
|
||||||
<div class="px-2 space-y-1">
|
<div class="px-2 space-y-1">
|
||||||
<InertiaLink
|
<InertiaLink
|
||||||
href="/"
|
href="/"
|
||||||
@ -70,28 +70,53 @@
|
|||||||
Strona główna
|
Strona główna
|
||||||
</InertiaLink>
|
</InertiaLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-3 mt-3">
|
<div
|
||||||
<div class="py-1 px-2 space-y-1">
|
v-if="vacationNavigation.length"
|
||||||
<InertiaLink
|
class="py-1 px-2 space-y-1"
|
||||||
v-for="item in navigation"
|
>
|
||||||
:key="item.name"
|
<InertiaLink
|
||||||
:href="item.href"
|
v-for="item in vacationNavigation"
|
||||||
:class="[$page.component.startsWith(item.section) ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 text-base font-medium rounded-md']"
|
:key="item.name"
|
||||||
@click="sidebarOpen = false;"
|
:href="item.href"
|
||||||
|
:class="[$page.component.startsWith(item.section) ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 text-base font-medium rounded-md']"
|
||||||
|
@click="sidebarOpen = false;"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="item.icon"
|
||||||
|
class="shrink-0 mr-4 w-6 h-6 text-blumilk-200"
|
||||||
|
/>
|
||||||
|
{{ item.name }}
|
||||||
|
<span
|
||||||
|
v-if="item.badge"
|
||||||
|
class="py-0.5 px-2.5 ml-3 text-xs font-semibold text-gray-600 bg-gray-100 rounded-full 2xl:inline-block"
|
||||||
>
|
>
|
||||||
<component
|
{{ item.badge }}
|
||||||
:is="item.icon"
|
</span>
|
||||||
class="shrink-0 mr-4 w-6 h-6 text-blumilk-200"
|
</InertiaLink>
|
||||||
/>
|
</div>
|
||||||
{{ item.name }}
|
<div
|
||||||
<span
|
v-if="miscNavigaction.length"
|
||||||
v-if="item.badge"
|
class="py-1 px-2 space-y-1"
|
||||||
class="py-0.5 px-2.5 ml-3 text-xs font-semibold text-gray-600 bg-gray-100 rounded-full 2xl:inline-block"
|
>
|
||||||
>
|
<InertiaLink
|
||||||
{{ item.badge }}
|
v-for="item in miscNavigaction"
|
||||||
</span>
|
:key="item.name"
|
||||||
</InertiaLink>
|
:href="item.href"
|
||||||
</div>
|
:class="[$page.component.startsWith(item.section) ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 text-base font-medium rounded-md']"
|
||||||
|
@click="sidebarOpen = false;"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="item.icon"
|
||||||
|
class="shrink-0 mr-4 w-6 h-6 text-blumilk-200"
|
||||||
|
/>
|
||||||
|
{{ item.name }}
|
||||||
|
<span
|
||||||
|
v-if="item.badge"
|
||||||
|
class="py-0.5 px-2.5 ml-3 text-xs font-semibold text-gray-600 bg-gray-100 rounded-full 2xl:inline-block"
|
||||||
|
>
|
||||||
|
{{ item.badge }}
|
||||||
|
</span>
|
||||||
|
</InertiaLink>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
@ -110,7 +135,7 @@
|
|||||||
>
|
>
|
||||||
</InertiaLink>
|
</InertiaLink>
|
||||||
</div>
|
</div>
|
||||||
<nav class="flex overflow-y-auto flex-col flex-1 px-2 mt-5 divide-y divide-blumilk-800">
|
<nav class="flex overflow-y-auto flex-col flex-1 px-2 mt-5 space-y-4">
|
||||||
<InertiaLink
|
<InertiaLink
|
||||||
href="/"
|
href="/"
|
||||||
:class="[$page.component === 'Dashboard' ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 mt-1 text-sm leading-6 font-medium rounded-md']"
|
:class="[$page.component === 'Dashboard' ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 mt-1 text-sm leading-6 font-medium rounded-md']"
|
||||||
@ -118,9 +143,35 @@
|
|||||||
<HomeIcon class="shrink-0 mr-4 w-6 h-6 text-blumilk-200" />
|
<HomeIcon class="shrink-0 mr-4 w-6 h-6 text-blumilk-200" />
|
||||||
Strona główna
|
Strona główna
|
||||||
</InertiaLink>
|
</InertiaLink>
|
||||||
<div class="pt-1 mt-1 space-y-1">
|
<div
|
||||||
|
v-if="vacationNavigation.length"
|
||||||
|
class="pt-1 mt-1 space-y-1"
|
||||||
|
>
|
||||||
<InertiaLink
|
<InertiaLink
|
||||||
v-for="item in navigation"
|
v-for="item in vacationNavigation"
|
||||||
|
:key="item.name"
|
||||||
|
:href="item.href"
|
||||||
|
:class="[$page.component.startsWith(item.section) ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 text-sm leading-6 font-medium rounded-md']"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="item.icon"
|
||||||
|
class="shrink-0 mr-4 w-6 h-6 text-blumilk-200"
|
||||||
|
/>
|
||||||
|
{{ item.name }}
|
||||||
|
<span
|
||||||
|
v-if="item.badge"
|
||||||
|
class="py-0.5 px-2.5 ml-3 text-xs font-semibold text-gray-600 bg-gray-100 rounded-full 2xl:inline-block"
|
||||||
|
>
|
||||||
|
{{ item.badge }}
|
||||||
|
</span>
|
||||||
|
</InertiaLink>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="miscNavigaction.length"
|
||||||
|
class="pt-1 mt-1 space-y-1"
|
||||||
|
>
|
||||||
|
<InertiaLink
|
||||||
|
v-for="item in miscNavigaction"
|
||||||
:key="item.name"
|
:key="item.name"
|
||||||
:href="item.href"
|
:href="item.href"
|
||||||
:class="[$page.component.startsWith(item.section) ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 text-sm leading-6 font-medium rounded-md']"
|
:class="[$page.component.startsWith(item.section) ? 'bg-blumilk-800 text-white' : 'text-blumilk-100 hover:text-white hover:bg-blumilk-600', 'group flex items-center px-2 py-2 text-sm leading-6 font-medium rounded-md']"
|
||||||
@ -295,7 +346,7 @@ import {
|
|||||||
DocumentTextIcon,
|
DocumentTextIcon,
|
||||||
AdjustmentsIcon,
|
AdjustmentsIcon,
|
||||||
KeyIcon,
|
KeyIcon,
|
||||||
TemplateIcon,
|
TemplateIcon, BeakerIcon,
|
||||||
} from '@heroicons/vue/outline'
|
} from '@heroicons/vue/outline'
|
||||||
import { CheckIcon, ChevronDownIcon } from '@heroicons/vue/solid'
|
import { CheckIcon, ChevronDownIcon } from '@heroicons/vue/solid'
|
||||||
|
|
||||||
@ -307,7 +358,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const sidebarOpen = ref(false)
|
const sidebarOpen = ref(false)
|
||||||
|
|
||||||
const navigation = computed(() =>
|
const vacationNavigation = computed(() =>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: 'Moje wnioski',
|
name: 'Moje wnioski',
|
||||||
@ -359,27 +410,36 @@ const navigation = computed(() =>
|
|||||||
icon: ClipboardListIcon,
|
icon: ClipboardListIcon,
|
||||||
can: true,
|
can: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'Użytkownicy',
|
|
||||||
href: '/users',
|
|
||||||
section: 'Users/',
|
|
||||||
icon: UserGroupIcon,
|
|
||||||
can: props.auth.can.manageUsers,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Klucze',
|
|
||||||
href: '/keys',
|
|
||||||
section: 'Keys',
|
|
||||||
icon: KeyIcon,
|
|
||||||
can: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'CV',
|
|
||||||
href: '/resumes',
|
|
||||||
section: 'Resumes',
|
|
||||||
icon: TemplateIcon,
|
|
||||||
can: props.auth.can.manageResumes,
|
|
||||||
},
|
|
||||||
|
|
||||||
].filter(item => item.can))
|
].filter(item => item.can))
|
||||||
|
|
||||||
|
const miscNavigaction = computed(() => [
|
||||||
|
{
|
||||||
|
name: 'Użytkownicy',
|
||||||
|
href: '/users',
|
||||||
|
section: 'Users/',
|
||||||
|
icon: UserGroupIcon,
|
||||||
|
can: props.auth.can.manageUsers,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Klucze',
|
||||||
|
href: '/keys',
|
||||||
|
section: 'Keys',
|
||||||
|
icon: KeyIcon,
|
||||||
|
can: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Technologie',
|
||||||
|
href: '/technologies',
|
||||||
|
section: 'Technologies',
|
||||||
|
icon: BeakerIcon,
|
||||||
|
can: props.auth.can.manageResumes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CV',
|
||||||
|
href: '/resumes',
|
||||||
|
section: 'Resumes',
|
||||||
|
icon: TemplateIcon,
|
||||||
|
can: props.auth.can.manageResumes,
|
||||||
|
},
|
||||||
|
].filter(item => item.can))
|
||||||
</script>
|
</script>
|
||||||
|
@ -76,5 +76,7 @@
|
|||||||
":recipient takes key no :key from :sender": ":recipient zabiera klucz nr :key :sender",
|
":recipient takes key no :key from :sender": ":recipient zabiera klucz nr :key :sender",
|
||||||
"Resume has been updated.": "CV zostało zaktualizowane.",
|
"Resume has been updated.": "CV zostało zaktualizowane.",
|
||||||
"Resume has been deleted.": "CV zostało usunięte.",
|
"Resume has been deleted.": "CV zostało usunięte.",
|
||||||
"Resume has been created.": "CV zostało utworzone."
|
"Resume has been created.": "CV zostało utworzone.",
|
||||||
|
"Technology :name has been created.": "Technologia :name została utworzona.",
|
||||||
|
"Technology :name has been deleted.": "Technologia :name została usunięta."
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ use Toby\Infrastructure\Http\Controllers\LogoutController;
|
|||||||
use Toby\Infrastructure\Http\Controllers\MonthlyUsageController;
|
use Toby\Infrastructure\Http\Controllers\MonthlyUsageController;
|
||||||
use Toby\Infrastructure\Http\Controllers\ResumeController;
|
use Toby\Infrastructure\Http\Controllers\ResumeController;
|
||||||
use Toby\Infrastructure\Http\Controllers\SelectYearPeriodController;
|
use Toby\Infrastructure\Http\Controllers\SelectYearPeriodController;
|
||||||
|
use Toby\Infrastructure\Http\Controllers\TechnologyController;
|
||||||
use Toby\Infrastructure\Http\Controllers\TimesheetController;
|
use Toby\Infrastructure\Http\Controllers\TimesheetController;
|
||||||
use Toby\Infrastructure\Http\Controllers\UserController;
|
use Toby\Infrastructure\Http\Controllers\UserController;
|
||||||
use Toby\Infrastructure\Http\Controllers\VacationCalendarController;
|
use Toby\Infrastructure\Http\Controllers\VacationCalendarController;
|
||||||
@ -37,6 +38,9 @@ Route::middleware(["auth", TrackUserLastActivity::class])->group(function (): vo
|
|||||||
|
|
||||||
Route::resource("resumes", ResumeController::class)
|
Route::resource("resumes", ResumeController::class)
|
||||||
->whereNumber("resume");
|
->whereNumber("resume");
|
||||||
|
Route::resource("technologies", TechnologyController::class)
|
||||||
|
->only(["index", "store", "destroy"])
|
||||||
|
->whereNumber("technology");
|
||||||
|
|
||||||
Route::get("/keys", [KeysController::class, "index"]);
|
Route::get("/keys", [KeysController::class, "index"]);
|
||||||
Route::post("/keys", [KeysController::class, "store"]);
|
Route::post("/keys", [KeysController::class, "store"]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user