fix
This commit is contained in:
		| @@ -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"> | ||||||
|  |                   <label class="block text-sm font-medium text-gray-700 sm:mt-px"> | ||||||
|  |                     <input | ||||||
|  |                       v-model="element.current" | ||||||
|  |                       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" |                     v-model="element.endDate" | ||||||
|                     placeholder="Wybierz datę" |                     placeholder="Wybierz datę" | ||||||
|                   class="block w-full rounded-md shadow-sm sm:text-sm" |                     :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`] }" |                     :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"> | ||||||
|  |                   <label class="block text-sm font-medium text-gray-700 sm:mt-px"> | ||||||
|  |                     <input | ||||||
|  |                       v-model="element.current" | ||||||
|  |                       type="checkbox" | ||||||
|  |                       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}`" |                     :id="`project-endDate-${index}`" | ||||||
|                     v-model="element.endDate" |                     v-model="element.endDate" | ||||||
|                     placeholder="Wybierz datę" |                     placeholder="Wybierz datę" | ||||||
|                   class="block w-full rounded-md shadow-sm sm:text-sm" |                     :disabled="element.current" | ||||||
|                   :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="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"> | ||||||
|  |                   <label class="block text-sm font-medium text-gray-700 sm:mt-px"> | ||||||
|  |                     <input | ||||||
|  |                       v-model="element.current" | ||||||
|  |                       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" |                     v-model="element.endDate" | ||||||
|                     placeholder="Wybierz datę" |                     placeholder="Wybierz datę" | ||||||
|                   class="block w-full rounded-md shadow-sm sm:text-sm" |                     :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`] }" |                     :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"> | ||||||
|  |                   <label class="block text-sm font-medium text-gray-700 sm:mt-px"> | ||||||
|  |                     <input | ||||||
|  |                       v-model="element.current" | ||||||
|  |                       type="checkbox" | ||||||
|  |                       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}`" |                     :id="`project-endDate-${index}`" | ||||||
|                     v-model="element.endDate" |                     v-model="element.endDate" | ||||||
|                     placeholder="Wybierz datę" |                     placeholder="Wybierz datę" | ||||||
|                   class="block w-full rounded-md shadow-sm sm:text-sm" |                     :disabled="element.current" | ||||||
|                   :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="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 | ||||||
|  |           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> |         </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,10 +70,12 @@ | |||||||
|                 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" | ||||||
|  |               class="py-1 px-2 space-y-1" | ||||||
|  |             > | ||||||
|               <InertiaLink |               <InertiaLink | ||||||
|                   v-for="item in navigation" |                 v-for="item in vacationNavigation" | ||||||
|                 :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-base 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-base font-medium rounded-md']" | ||||||
| @@ -92,6 +94,29 @@ | |||||||
|                 </span> |                 </span> | ||||||
|               </InertiaLink> |               </InertiaLink> | ||||||
|             </div> |             </div> | ||||||
|  |             <div | ||||||
|  |               v-if="miscNavigaction.length" | ||||||
|  |               class="py-1 px-2 space-y-1" | ||||||
|  |             > | ||||||
|  |               <InertiaLink | ||||||
|  |                 v-for="item in miscNavigaction" | ||||||
|  |                 :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-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,6 +410,9 @@ const navigation = computed(() => | |||||||
|       icon: ClipboardListIcon, |       icon: ClipboardListIcon, | ||||||
|       can: true, |       can: true, | ||||||
|     }, |     }, | ||||||
|  |   ].filter(item => item.can)) | ||||||
|  |  | ||||||
|  | const miscNavigaction = computed(() => [ | ||||||
|   { |   { | ||||||
|     name: 'Użytkownicy', |     name: 'Użytkownicy', | ||||||
|     href: '/users', |     href: '/users', | ||||||
| @@ -373,6 +427,13 @@ const navigation = computed(() => | |||||||
|     icon: KeyIcon, |     icon: KeyIcon, | ||||||
|     can: true, |     can: true, | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     name: 'Technologie', | ||||||
|  |     href: '/technologies', | ||||||
|  |     section: 'Technologies', | ||||||
|  |     icon: BeakerIcon, | ||||||
|  |     can: props.auth.can.manageResumes, | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     name: 'CV', |     name: 'CV', | ||||||
|     href: '/resumes', |     href: '/resumes', | ||||||
| @@ -380,6 +441,5 @@ const navigation = computed(() => | |||||||
|     icon: TemplateIcon, |     icon: TemplateIcon, | ||||||
|     can: props.auth.can.manageResumes, |     can: props.auth.can.manageResumes, | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
| ].filter(item => item.can)) | ].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"]); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user