wip
This commit is contained in:
		| @@ -44,12 +44,12 @@ class ResumeFactory extends Factory | ||||
|  | ||||
|     protected function generateLanguages(): array | ||||
|     { | ||||
|         $languages = new Collection(["english", "polish", "germany"]); | ||||
|         $languages = new Collection(["English", "Polish", "German"]); | ||||
|         $number = $this->faker->numberBetween(1, $languages->count()); | ||||
|  | ||||
|         return $languages->random($number) | ||||
|             ->map(fn(string $language): array => [ | ||||
|                 "language" => $language, | ||||
|                 "name" => $language, | ||||
|                 "level" => $this->faker->numberBetween(1, 6), | ||||
|             ]) | ||||
|             ->all(); | ||||
| @@ -57,12 +57,12 @@ class ResumeFactory extends Factory | ||||
|  | ||||
|     protected function generateTechnologies(): array | ||||
|     { | ||||
|         $technologies = Technology::all(); | ||||
|         $technologies = Technology::all()->pluck("name"); | ||||
|         $number = $this->faker->numberBetween(2, $technologies->count()); | ||||
|  | ||||
|         return $technologies->random($number) | ||||
|             ->map(fn(string $technology): array => [ | ||||
|                 "technology" => $technology, | ||||
|                 "name" => $technology, | ||||
|                 "level" => $this->faker->numberBetween(1, 5), | ||||
|             ]) | ||||
|             ->all(); | ||||
| @@ -71,7 +71,7 @@ class ResumeFactory extends Factory | ||||
|     protected function generateProjects(): array | ||||
|     { | ||||
|         $items = []; | ||||
|         $technologies = Technology::all(); | ||||
|         $technologies = Technology::all()->pluck("name"); | ||||
|  | ||||
|         for ($i = 0; $i < $this->faker->numberBetween(1, 3); $i++) { | ||||
|             $number = $this->faker->numberBetween(2, $technologies->count()); | ||||
|   | ||||
| @@ -1,34 +1,34 @@ | ||||
| const technologyLevels = [ | ||||
|   { | ||||
|     level: 0, | ||||
|     level: 1, | ||||
|     name: 'Beginner', | ||||
|     activeColor: 'bg-rose-400', | ||||
|     backgroundColor: 'bg-rose-100', | ||||
|     textColor: 'text-rose-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 1, | ||||
|     level: 2, | ||||
|     name: 'Junior', | ||||
|     activeColor: 'bg-orange-400', | ||||
|     backgroundColor: 'bg-orange-100', | ||||
|     textColor: 'text-orange-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 2, | ||||
|     level: 3, | ||||
|     name: 'Regular', | ||||
|     activeColor: 'bg-amber-400', | ||||
|     backgroundColor: 'bg-amber-100', | ||||
|     textColor: 'text-yellow-500', | ||||
|   }, | ||||
|   { | ||||
|     level: 3, | ||||
|     level: 4, | ||||
|     name: 'Advanced', | ||||
|     activeColor: 'bg-emerald-400', | ||||
|     backgroundColor: 'bg-emerald-100', | ||||
|     textColor: 'text-emerald-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 4, | ||||
|     level: 5, | ||||
|     name: 'Master', | ||||
|     activeColor: 'bg-blumilk-400', | ||||
|     backgroundColor: 'bg-blumilk-100', | ||||
| @@ -37,42 +37,42 @@ const technologyLevels = [ | ||||
| ] | ||||
| const languageLevels = [ | ||||
|   { | ||||
|     level: 0, | ||||
|     level: 1, | ||||
|     name: 'A1', | ||||
|     activeColor: 'bg-rose-400', | ||||
|     backgroundColor: 'bg-rose-100', | ||||
|     textColor: 'text-rose-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 1, | ||||
|     level: 2, | ||||
|     name: 'A2', | ||||
|     activeColor: 'bg-orange-400', | ||||
|     backgroundColor: 'bg-orange-100', | ||||
|     textColor: 'text-orange-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 2, | ||||
|     level: 3, | ||||
|     name: 'B1', | ||||
|     activeColor: 'bg-amber-400', | ||||
|     backgroundColor: 'bg-amber-100', | ||||
|     textColor: 'text-yellow-500', | ||||
|   }, | ||||
|   { | ||||
|     level: 3, | ||||
|     level: 4, | ||||
|     name: 'B2', | ||||
|     activeColor: 'bg-emerald-400', | ||||
|     backgroundColor: 'bg-emerald-100', | ||||
|     textColor: 'text-emerald-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 4, | ||||
|     level: 5, | ||||
|     name: 'C1', | ||||
|     activeColor: 'bg-blumilk-400', | ||||
|     backgroundColor: 'bg-blumilk-100', | ||||
|     textColor: 'text-blumilk-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 5, | ||||
|     level: 6, | ||||
|     name: 'C2', | ||||
|     activeColor: 'bg-gray-600', | ||||
|     backgroundColor: 'bg-gray-200', | ||||
|   | ||||
| @@ -138,10 +138,13 @@ | ||||
|           @add-item="addEducation" | ||||
|           @remove-item="(index) => form.educations.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('education', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             {{ element.school ? element.school : '(Nieokreślony)' }} | ||||
|           </template> | ||||
|           <template #form="{ element }"> | ||||
|           <template #form="{ element, index }"> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
|               <label class="block text-sm font-medium text-gray-700 sm:mt-px"> | ||||
|                 Szkoła | ||||
| @@ -151,8 +154,14 @@ | ||||
|                   v-model="element.school" | ||||
|                   type="text" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.school`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.school`] }" | ||||
|                 > | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.school`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.school`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -164,8 +173,14 @@ | ||||
|                   v-model="element.degree" | ||||
|                   type="text" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.degree`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.degree`] }" | ||||
|                 > | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.degree`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.degree`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -177,8 +192,14 @@ | ||||
|                   v-model="element.fieldOfStudy" | ||||
|                   type="text" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.fieldOfStudy`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.fieldOfStudy`] }" | ||||
|                 > | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.fieldOfStudy`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.fieldOfStudy`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -190,8 +211,14 @@ | ||||
|                   v-model="element.startDate" | ||||
|                   placeholder="Wybierz datę" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.startDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.startDate`] }" | ||||
|                 /> | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.startDate`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.startDate`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -203,8 +230,14 @@ | ||||
|                   v-model="element.endDate" | ||||
|                   placeholder="Wybierz datę" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :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`] }" | ||||
|                 /> | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.endDate`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.endDate`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|           </template> | ||||
| @@ -216,7 +249,10 @@ | ||||
|           @add-item="addLanguage" | ||||
|           @remove-item="(index) => form.languages.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('languages', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             <template v-if="element.name"> | ||||
|               {{ element.name }} - <span :class="element.level.textColor">{{ element.level.name }}</span> | ||||
|             </template> | ||||
| @@ -263,7 +299,10 @@ | ||||
|           @add-item="addTechnology" | ||||
|           @remove-item="(index) => form.technologies.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('technologies', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             <template v-if="element.name"> | ||||
|               {{ element.name }} - <span :class="element.level.textColor">{{ element.level.name }}</span> | ||||
|             </template> | ||||
| @@ -310,7 +349,10 @@ | ||||
|           @add-item="addProject" | ||||
|           @remove-item="(index) => form.projects.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('projects', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             {{ element.description ? element.description : '(Nieokreślony)' }} | ||||
|           </template> | ||||
|           <template #form="{ element, index }"> | ||||
| @@ -413,13 +455,12 @@ | ||||
|                 Zadania | ||||
|               </label> | ||||
|               <div class="mt-1 sm:mt-0"> | ||||
|                 <input | ||||
|                 <textarea | ||||
|                   :id="`project-tasks-${index}`" | ||||
|                   v-model="element.tasks" | ||||
|                   type="text" | ||||
|                   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[`projects.${index}.tasks`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`projects.${index}.tasks`] }" | ||||
|                 > | ||||
|                 /> | ||||
|                 <p | ||||
|                   v-if="form.errors[`projects.${index}.tasks`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
| @@ -469,9 +510,9 @@ const props = defineProps({ | ||||
| const { technologyLevels, languageLevels } = useLevels() | ||||
|  | ||||
| const languages = [ | ||||
|   'Język polski', | ||||
|   'Język angielski', | ||||
|   'Język niemiecki', | ||||
|   'Polish', | ||||
|   'English', | ||||
|   'German', | ||||
| ] | ||||
|  | ||||
| const form = useForm({ | ||||
| @@ -517,6 +558,12 @@ function addLanguage() { | ||||
|   }) | ||||
| } | ||||
|  | ||||
| function hasAnyErrorInSection(section, index) { | ||||
|   return Object | ||||
|     .keys(form.errors) | ||||
|     .some((error) => error.startsWith(`${section}.${index}.`)) | ||||
| } | ||||
|  | ||||
| function submitResume() { | ||||
|   form | ||||
|     .transform((data) => ({ | ||||
|   | ||||
| @@ -138,10 +138,13 @@ | ||||
|           @add-item="addEducation" | ||||
|           @remove-item="(index) => form.educations.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('education', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             {{ element.school ? element.school : '(Nieokreślony)' }} | ||||
|           </template> | ||||
|           <template #form="{ element }"> | ||||
|           <template #form="{ element, index }"> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
|               <label class="block text-sm font-medium text-gray-700 sm:mt-px"> | ||||
|                 Szkoła | ||||
| @@ -151,8 +154,14 @@ | ||||
|                   v-model="element.school" | ||||
|                   type="text" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.school`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.school`] }" | ||||
|                 > | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.school`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.school`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -164,8 +173,14 @@ | ||||
|                   v-model="element.degree" | ||||
|                   type="text" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.degree`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.degree`] }" | ||||
|                 > | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.degree`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.degree`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -177,8 +192,14 @@ | ||||
|                   v-model="element.fieldOfStudy" | ||||
|                   type="text" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.fieldOfStudy`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.fieldOfStudy`] }" | ||||
|                 > | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.fieldOfStudy`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.fieldOfStudy`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -190,8 +211,14 @@ | ||||
|                   v-model="element.startDate" | ||||
|                   placeholder="Wybierz datę" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors[`education.${index}.startDate`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`education.${index}.startDate`] }" | ||||
|                 /> | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.startDate`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.startDate`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="items-center py-4 sm:grid sm:grid-cols-2"> | ||||
| @@ -203,8 +230,14 @@ | ||||
|                   v-model="element.endDate" | ||||
|                   placeholder="Wybierz datę" | ||||
|                   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': false, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': true }" | ||||
|                   :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`] }" | ||||
|                 /> | ||||
|                 <p | ||||
|                   v-if="form.errors[`education.${index}.endDate`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
|                 > | ||||
|                   {{ form.errors[`education.${index}.endDate`] }} | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|           </template> | ||||
| @@ -216,7 +249,10 @@ | ||||
|           @add-item="addLanguage" | ||||
|           @remove-item="(index) => form.languages.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('languages', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             <template v-if="element.name"> | ||||
|               {{ element.name }} - <span :class="element.level.textColor">{{ element.level.name }}</span> | ||||
|             </template> | ||||
| @@ -269,7 +305,10 @@ | ||||
|           @add-item="addTechnology" | ||||
|           @remove-item="(index) => form.technologies.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('technologies', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             <template v-if="element.name"> | ||||
|               {{ element.name }} - <span :class="element.level.textColor">{{ element.level.name }}</span> | ||||
|             </template> | ||||
| @@ -322,7 +361,10 @@ | ||||
|           @add-item="addProject" | ||||
|           @remove-item="(index) => form.projects.splice(index, 1)" | ||||
|         > | ||||
|           <template #itemHeader="{ element }"> | ||||
|           <template #itemHeader="{ element, index }"> | ||||
|             <template v-if="hasAnyErrorInSection('projects', index)"> | ||||
|               <ExclamationCircleIcon class="h-6 w-6 mr-2 text-red-600 inline-block" /> | ||||
|             </template> | ||||
|             {{ element.description ? element.description : '(Nieokreślony)' }} | ||||
|           </template> | ||||
|           <template #form="{ element, index }"> | ||||
| @@ -425,13 +467,13 @@ | ||||
|                 Zadania | ||||
|               </label> | ||||
|               <div class="mt-1 sm:mt-0"> | ||||
|                 <input | ||||
|                 <textarea | ||||
|                   :id="`project-tasks-${index}`" | ||||
|                   v-model="element.tasks" | ||||
|                   type="text" | ||||
|                   rows="3" | ||||
|                   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[`projects.${index}.tasks`], 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors[`projects.${index}.tasks`] }" | ||||
|                 > | ||||
|                 /> | ||||
|                 <p | ||||
|                   v-if="form.errors[`projects.${index}.tasks`]" | ||||
|                   class="mt-2 text-sm text-red-600" | ||||
| @@ -466,11 +508,13 @@ | ||||
| <script setup> | ||||
| import { Listbox, ListboxOption, ListboxOptions, ListboxLabel, ListboxButton } from '@headlessui/vue' | ||||
| import { SelectorIcon, CheckIcon } from '@heroicons/vue/outline' | ||||
| import { ExclamationCircleIcon } from '@heroicons/vue/solid' | ||||
| import { useForm } from '@inertiajs/inertia-vue3' | ||||
| import FlatPickr from 'vue-flatpickr-component' | ||||
| import DynamicSection from '@/Shared/Forms/DynamicSection' | ||||
| import Combobox from '@/Shared/Forms/Combobox' | ||||
| import LevelPicker from '@/Shared/Forms/LevelPicker' | ||||
| import useLevels from '@/Composables/useLevels' | ||||
|  | ||||
| const props = defineProps({ | ||||
|   users: Object, | ||||
| @@ -478,106 +522,25 @@ const props = defineProps({ | ||||
|   resume: Object, | ||||
| }) | ||||
|  | ||||
| const technologyLevels = [ | ||||
|   { | ||||
|     level: 1, | ||||
|     name: 'Poczatkujący', | ||||
|     activeColor: 'bg-rose-400', | ||||
|     backgroundColor: 'bg-rose-100', | ||||
|     textColor: 'text-rose-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 2, | ||||
|     name: 'Zaawansowany', | ||||
|     activeColor: 'bg-orange-400', | ||||
|     backgroundColor: 'bg-orange-100', | ||||
|     textColor: 'text-orange-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 3, | ||||
|     name: 'Doświadczony', | ||||
|     activeColor: 'bg-amber-400', | ||||
|     backgroundColor: 'bg-amber-100', | ||||
|     textColor: 'text-yellow-500', | ||||
|   }, | ||||
|   { | ||||
|     level: 4, | ||||
|     name: 'Ekspert', | ||||
|     activeColor: 'bg-emerald-400', | ||||
|     backgroundColor: 'bg-emerald-100', | ||||
|     textColor: 'text-emerald-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 5, | ||||
|     name: 'Chad', | ||||
|     activeColor: 'bg-blumilk-400', | ||||
|     backgroundColor: 'bg-blumilk-100', | ||||
|     textColor: 'text-blumilk-400', | ||||
|   }, | ||||
| ] | ||||
|  | ||||
| const languageLevels = [ | ||||
|   { | ||||
|     level: 1, | ||||
|     name: 'A1', | ||||
|     activeColor: 'bg-rose-400', | ||||
|     backgroundColor: 'bg-rose-100', | ||||
|     textColor: 'text-rose-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 2, | ||||
|     name: 'A2', | ||||
|     activeColor: 'bg-orange-400', | ||||
|     backgroundColor: 'bg-orange-100', | ||||
|     textColor: 'text-orange-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 3, | ||||
|     name: 'B1', | ||||
|     activeColor: 'bg-amber-400', | ||||
|     backgroundColor: 'bg-amber-100', | ||||
|     textColor: 'text-yellow-500', | ||||
|   }, | ||||
|   { | ||||
|     level: 4, | ||||
|     name: 'B2', | ||||
|     activeColor: 'bg-emerald-400', | ||||
|     backgroundColor: 'bg-emerald-100', | ||||
|     textColor: 'text-emerald-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 5, | ||||
|     name: 'C1', | ||||
|     activeColor: 'bg-blumilk-400', | ||||
|     backgroundColor: 'bg-blumilk-100', | ||||
|     textColor: 'text-blumilk-400', | ||||
|   }, | ||||
|   { | ||||
|     level: 6, | ||||
|     name: 'C2', | ||||
|     activeColor: 'bg-blumilk-600', | ||||
|     backgroundColor: 'bg-blumilk-200', | ||||
|     textColor: 'text-blumilk-600', | ||||
|   }, | ||||
| ] | ||||
| const { technologyLevels, languageLevels } = useLevels() | ||||
|  | ||||
| const languages = [ | ||||
|   'Język polski', | ||||
|   'Język angielski', | ||||
|   'Język niemiecki', | ||||
|   'Polish', | ||||
|   'English', | ||||
|   'German', | ||||
| ] | ||||
|  | ||||
| const form = useForm({ | ||||
|   user: props.users.data.find((user) => user.id === props.resume.user), | ||||
|   name: props.resume.name, | ||||
|   educations: props.resume.educations ?? [], | ||||
|   user: props.users.data.find((user) => user.id === props.resume.user) ?? null, | ||||
|   name: props.resume.name ?? null , | ||||
|   educations: props.resume.education ?? [], | ||||
|   projects: props.resume.projects ?? [], | ||||
|   technologies: props.resume.technologies.map((technology) => ({ | ||||
|     name: props.technologies.find((tech) => tech === technology.name), | ||||
|     level: technologyLevels.find((level) => level.level === technology.level), | ||||
|   })) ?? [], | ||||
|   languages: props.resume.languages.map((language) => ({ | ||||
|     name: languages.find((lang) => lang.name === language.name), | ||||
|     name: languages.find((lang) => lang === language.name), | ||||
|     level: languageLevels.find((level) => level.level === language.level), | ||||
|   })) ?? [], | ||||
| }) | ||||
| @@ -616,6 +579,12 @@ function addLanguage() { | ||||
|   }) | ||||
| } | ||||
|  | ||||
| function hasAnyErrorInSection(section, index) { | ||||
|   return Object | ||||
|     .keys(form.errors) | ||||
|     .some((error) => error.startsWith(`${section}.${index}.`)) | ||||
| } | ||||
|  | ||||
| function submitResume() { | ||||
|   form | ||||
|     .transform((data) => ({ | ||||
|   | ||||
							
								
								
									
										76
									
								
								resources/js/Shared/Forms/MultipleCombobox.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								resources/js/Shared/Forms/MultipleCombobox.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| <template> | ||||
|   <Combobox | ||||
|     as="div" | ||||
|     nullable | ||||
|     multiple | ||||
|   > | ||||
|     <ComboboxLabel class="block text-sm font-medium text-gray-700"> | ||||
|       {{ label }} | ||||
|     </ComboboxLabel> | ||||
|     <div class="relative mt-2"> | ||||
|       <ComboboxInput | ||||
|         as="template" | ||||
|         class="w-full h-12 rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 shadow-sm focus:border-blumilk-500 focus:outline-none focus:ring-1 focus:ring-blumilk-500 sm:text-sm" | ||||
|         :display-value="(item) => item" | ||||
|         @change="query = $event.target.value" | ||||
|       > | ||||
|         <span>aee</span> | ||||
|       </ComboboxInput> | ||||
|       <ComboboxButton class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none"> | ||||
|         <SelectorIcon class="h-5 w-5 text-gray-400" /> | ||||
|       </ComboboxButton> | ||||
|  | ||||
|       <ComboboxOptions | ||||
|         v-if="filteredItems.length" | ||||
|         class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm" | ||||
|       > | ||||
|         <ComboboxOption | ||||
|           v-for="item in filteredItems" | ||||
|           :key="item.id" | ||||
|           v-slot="{ active, selected }" | ||||
|           :value="item" | ||||
|           as="template" | ||||
|         > | ||||
|           <li :class="['relative cursor-default select-none py-2 pl-3 pr-9', active ? 'bg-blumilk-600 text-white' : 'text-gray-900']"> | ||||
|             <span :class="['block truncate', selected && 'font-semibold']"> | ||||
|               {{ item.name }} | ||||
|             </span> | ||||
|  | ||||
|             <span | ||||
|               v-if="selected" | ||||
|               :class="['absolute inset-y-0 right-0 flex items-center pr-4', active ? 'text-white' : 'text-blumilk-600']" | ||||
|             > | ||||
|               <CheckIcon class="h-5 w-5" /> | ||||
|             </span> | ||||
|           </li> | ||||
|         </ComboboxOption> | ||||
|       </ComboboxOptions> | ||||
|     </div> | ||||
|   </Combobox> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { computed, ref } from 'vue' | ||||
| import { CheckIcon, SelectorIcon } from '@heroicons/vue/solid' | ||||
| import { | ||||
|   Combobox, | ||||
|   ComboboxButton, | ||||
|   ComboboxInput, | ||||
|   ComboboxLabel, | ||||
|   ComboboxOption, | ||||
|   ComboboxOptions, | ||||
| } from '@headlessui/vue' | ||||
|  | ||||
| const props = defineProps({ | ||||
|   label: null, | ||||
|   items: Array, | ||||
| }) | ||||
|  | ||||
| const query = ref('') | ||||
|  | ||||
| const filteredItems = computed(() => | ||||
|   query.value === '' | ||||
|     ? props.items | ||||
|     : props.items.filter((item) => item.name.toLowerCase().includes(query.value.toLowerCase())), | ||||
| ) | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user