From d2babab7a0890b7ebccae37ffd376aff2596dc0c Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Tue, 17 May 2022 11:38:16 +0200 Subject: [PATCH] fix --- .../Providers/AuthServiceProvider.php | 2 +- app/Domain/ResumeGenerator.php | 12 +- app/Eloquent/Models/Technology.php | 2 + .../Http/Controllers/TechnologyController.php | 57 +++++ .../Http/Requests/ResumeRequest.php | 14 +- .../Http/Requests/TechnologyRequest.php | 29 +++ .../Http/Resources/TechnologyResource.php | 20 ++ database/factories/ResumeFactory.php | 11 +- resources/css/app.css | 1 + resources/js/Pages/Resumes/Create.vue | 56 +++-- resources/js/Pages/Resumes/Edit.vue | 70 ++++-- resources/js/Pages/Technologies.vue | 222 ++++++++++++++++++ resources/js/Shared/Forms/MonthPicker.vue | 18 ++ .../js/Shared/Forms/MultipleCombobox.vue | 26 +- resources/js/Shared/MainMenu.vue | 158 +++++++++---- resources/lang/pl.json | 4 +- routes/web.php | 4 + 17 files changed, 596 insertions(+), 110 deletions(-) create mode 100644 app/Infrastructure/Http/Controllers/TechnologyController.php create mode 100644 app/Infrastructure/Http/Requests/TechnologyRequest.php create mode 100644 app/Infrastructure/Http/Resources/TechnologyResource.php create mode 100644 resources/js/Pages/Technologies.vue create mode 100644 resources/js/Shared/Forms/MonthPicker.vue diff --git a/app/Architecture/Providers/AuthServiceProvider.php b/app/Architecture/Providers/AuthServiceProvider.php index 7c7631a..3f6d0ae 100644 --- a/app/Architecture/Providers/AuthServiceProvider.php +++ b/app/Architecture/Providers/AuthServiceProvider.php @@ -35,6 +35,6 @@ class AuthServiceProvider extends ServiceProvider Gate::define("manageVacationLimits", 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("manageResumes", fn(User $user): bool => $user->role === Role::AdministrativeApprover); + Gate::define("manageResumes", fn(User $user): bool => $user->role === Role::TechnicalApprover); } } diff --git a/app/Domain/ResumeGenerator.php b/app/Domain/ResumeGenerator.php index 240375d..97900da 100644 --- a/app/Domain/ResumeGenerator.php +++ b/app/Domain/ResumeGenerator.php @@ -40,7 +40,7 @@ class ResumeGenerator protected function fillTechnologies(TemplateProcessor $processor, Resume $resume): void { - if ($resume->technologies->count() <= 0) { + if ($resume->technologies->isEmpty()) { $processor->deleteBlock("technologies"); return; @@ -51,7 +51,7 @@ class ResumeGenerator protected function fillLanguages(TemplateProcessor $processor, Resume $resume): void { - if ($resume->education->count() <= 0) { + if ($resume->education->isEmpty()) { $processor->deleteBlock("languages"); return; @@ -62,7 +62,7 @@ class ResumeGenerator protected function fillEducation(TemplateProcessor $processor, Resume $resume): void { - if ($resume->education->count() <= 0) { + if ($resume->education->isEmpty()) { $processor->deleteBlock("education"); return; @@ -73,7 +73,7 @@ class ResumeGenerator protected function fillProjects(TemplateProcessor $processor, Resume $resume): void { - if ($resume->projects->count() <= 0) { + if ($resume->projects->isEmpty()) { $processor->deleteBlock("projects"); return; @@ -94,7 +94,7 @@ class ResumeGenerator return [ "index#{$index}" => $index, "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"], "tasks#{$index}" => $this->withNewLines($project["tasks"]), ]; @@ -134,7 +134,7 @@ class ResumeGenerator { return $resume->education->map(fn(array $project, int $index): array => [ "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"], "field_of_study" => $project["fieldOfStudy"], "degree" => $project["degree"], diff --git a/app/Eloquent/Models/Technology.php b/app/Eloquent/Models/Technology.php index 218d1d8..3e8aae4 100644 --- a/app/Eloquent/Models/Technology.php +++ b/app/Eloquent/Models/Technology.php @@ -16,6 +16,8 @@ class Technology extends Model { use HasFactory; + protected $guarded = []; + protected static function newFactory(): TechnologyFactory { return TechnologyFactory::new(); diff --git a/app/Infrastructure/Http/Controllers/TechnologyController.php b/app/Infrastructure/Http/Controllers/TechnologyController.php new file mode 100644 index 0000000..cb74fbd --- /dev/null +++ b/app/Infrastructure/Http/Controllers/TechnologyController.php @@ -0,0 +1,57 @@ +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, + ])); + } +} diff --git a/app/Infrastructure/Http/Requests/ResumeRequest.php b/app/Infrastructure/Http/Requests/ResumeRequest.php index e2212a8..7c72840 100644 --- a/app/Infrastructure/Http/Requests/ResumeRequest.php +++ b/app/Infrastructure/Http/Requests/ResumeRequest.php @@ -20,19 +20,21 @@ class ResumeRequest extends FormRequest "education.*.school" => ["required"], "education.*.degree" => ["required"], "education.*.fieldOfStudy" => ["required"], - "education.*.startDate" => ["required", "date_format:Y-m-d"], - "education.*.endDate" => ["required", "date_format:Y-m-d", "after:education.*.startDate"], + "education.*.startDate" => ["required", "date_format:m/Y"], + "education.*.current" => ["required", "boolean"], + "education.*.endDate" => ["required_if:education.*.current,false", "nullable", "date_format:m/Y", "after:education.*.startDate"], "languages.*.name" => ["required", "distinct"], "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)], "projects.*.description" => ["required"], - "projects.*.technologies" => ["array", "min:1", "exists:technologies,name", "distinct"], - "projects.*.startDate" => ["required", "date_format:Y-m-d"], - "projects.*.endDate" => ["required", "date_format:Y-m-d", "after:projects.*.startDate"], + "projects.*.technologies" => ["array", "min:1", "distinct"], + "projects.*.startDate" => ["required", "date_format:m/Y"], + "projects.*.current" => ["required", "boolean"], + "projects.*.endDate" => ["required_if:projects.*.current,false", "nullable", "date_format:m/Y", "after:projects.*.startDate"], "projects.*.tasks" => ["required"], ]; } diff --git a/app/Infrastructure/Http/Requests/TechnologyRequest.php b/app/Infrastructure/Http/Requests/TechnologyRequest.php new file mode 100644 index 0000000..240db50 --- /dev/null +++ b/app/Infrastructure/Http/Requests/TechnologyRequest.php @@ -0,0 +1,29 @@ + [ + "required", + Rule::unique("technologies", "name")->ignore($this->technology), + "max:255", + ], + ]; + } + + public function data(): array + { + return [ + "name" => $this->get("name"), + ]; + } +} diff --git a/app/Infrastructure/Http/Resources/TechnologyResource.php b/app/Infrastructure/Http/Resources/TechnologyResource.php new file mode 100644 index 0000000..c57555c --- /dev/null +++ b/app/Infrastructure/Http/Resources/TechnologyResource.php @@ -0,0 +1,20 @@ + $this->id, + "name" => $this->name, + ]; + } +} diff --git a/database/factories/ResumeFactory.php b/database/factories/ResumeFactory.php index d633f02..1704c6d 100644 --- a/database/factories/ResumeFactory.php +++ b/database/factories/ResumeFactory.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Support\Carbon; use Illuminate\Support\Collection; use Toby\Eloquent\Models\Resume; use Toby\Eloquent\Models\Technology; @@ -33,8 +34,9 @@ class ResumeFactory extends Factory "school" => $this->faker->sentence, "degree" => $this->faker->sentence, "fieldOfStudy" => $this->faker->sentence, - "startDate" => $this->faker->date, - "endDate" => $this->faker->date, + "current" => false, + "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[] = [ "description" => $this->faker->text, "technologies" => $technologies->random($number)->all(), - "startDate" => $this->faker->date, - "endDate" => $this->faker->date, + "current" => false, + "startDate" => Carbon::create($this->faker->date)->format("m/Y"), + "endDate" => Carbon::create($this->faker->date)->format("m/Y"), "tasks" => $this->faker->text, ]; } diff --git a/resources/css/app.css b/resources/css/app.css index 858c5e9..3f550f6 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,4 +1,5 @@ @import 'flatpickr/dist/themes/light.css'; +@import 'flatpickr/dist/plugins/monthSelect/style.css'; @import 'vue-toastification/dist/index.css'; @tailwind base; diff --git a/resources/js/Pages/Resumes/Create.vue b/resources/js/Pages/Resumes/Create.vue index fa33b8c..cd50e0f 100644 --- a/resources/js/Pages/Resumes/Create.vue +++ b/resources/js/Pages/Resumes/Create.vue @@ -207,7 +207,7 @@ Data rozpoczęcia
-
- +
+ + +

-

- +
+ + +

-
- +
+ + +

-

- +
+ + +

({ - name: props.technologies.find((tech) => tech === technology.name), + name: technology.name, level: technologyLevels.find((level) => level.level === technology.level), })) ?? [], languages: props.resume.languages.map((language) => ({ - name: languages.find((lang) => lang === language.name), + name: language.name, level: languageLevels.find((level) => level.level === language.level), })) ?? [], }) @@ -606,7 +628,10 @@ function submitResume() { .transform((data) => ({ user: data.user?.id, name: data.name, - education: data.educations, + education: data.educations.map(education => ({ + ...education, + endDate: education.current ? null: education.endDate, + })), languages: data.languages.map(language => ({ name: language.name, level: language.level.level, @@ -615,7 +640,10 @@ function submitResume() { name: technology.name, level: technology.level.level, })), - projects: data.projects, + projects: data.projects.map(project => ({ + ...project, + endDate: project.current ? null : project.endDate, + })), })) .put(`/resumes/${props.resume.id}`) } diff --git a/resources/js/Pages/Technologies.vue b/resources/js/Pages/Technologies.vue new file mode 100644 index 0000000..b9b0a4a --- /dev/null +++ b/resources/js/Pages/Technologies.vue @@ -0,0 +1,222 @@ + + + diff --git a/resources/js/Shared/Forms/MonthPicker.vue b/resources/js/Shared/Forms/MonthPicker.vue new file mode 100644 index 0000000..c9ba814 --- /dev/null +++ b/resources/js/Shared/Forms/MonthPicker.vue @@ -0,0 +1,18 @@ + + + + diff --git a/resources/js/Shared/Forms/MultipleCombobox.vue b/resources/js/Shared/Forms/MultipleCombobox.vue index 9fa3d8d..87fe585 100644 --- a/resources/js/Shared/Forms/MultipleCombobox.vue +++ b/resources/js/Shared/Forms/MultipleCombobox.vue @@ -6,15 +6,31 @@ multiple >

- + +
-
@@ -110,7 +135,7 @@ >
-