- add category management
This commit is contained in:
		| @@ -9,6 +9,7 @@ use App\Models\Category; | |||||||
| use App\Repository\Interfaces\CategoryRepository; | use App\Repository\Interfaces\CategoryRepository; | ||||||
| use Illuminate\Http\RedirectResponse; | use Illuminate\Http\RedirectResponse; | ||||||
| use Illuminate\View\View; | use Illuminate\View\View; | ||||||
|  | use Inertia\Response as InertiaResponse; | ||||||
|  |  | ||||||
| class CategoryController | class CategoryController | ||||||
| { | { | ||||||
| @@ -21,42 +22,35 @@ class CategoryController | |||||||
|     { |     { | ||||||
|         $validate = $request->validated(); |         $validate = $request->validated(); | ||||||
|         if ($this->categoryRepository->update($category, $validate)) { |         if ($this->categoryRepository->update($category, $validate)) { | ||||||
|             return back()->with('message', 'Zaktualizowano kategorię!'); |             return back() | ||||||
|  |                 ->with('success', 'Zaktualizowano kategorię!'); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return back()->withError(['message_error', 'Wystąpił błąd podczas aktualizacji!']); |         return back() | ||||||
|  |             ->with(['error', 'Wystąpił błąd podczas aktualizacji!']); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function store(CategoryRequest $request) |     public function store(CategoryRequest $request) | ||||||
|     { |     { | ||||||
|         // $validate = $request->validated(); |  | ||||||
|         // if ($category = $this->categoryRepository->create($validate)) { |  | ||||||
|         //     return redirect() |  | ||||||
|         //         ->route('admin.category.update', compact('category')) |  | ||||||
|         //         ->with('message', 'Utworzono kategorię!'); |  | ||||||
|         // } |  | ||||||
|  |  | ||||||
|         // return back()->withError(['message_error', 'Wystąpił błąd podczas tworzenia!']); |  | ||||||
|  |  | ||||||
|         $category = $this->categoryRepository->create($request->validated()); |         $category = $this->categoryRepository->create($request->validated()); | ||||||
|         return redirect() |         return redirect() | ||||||
|             ->route('admin.category.update', compact('category')) |             ->route('admin.category.update', compact('category')) | ||||||
|             ->with('message', 'Utworzono kategorię!'); |             ->with('message', 'Utworzono kategorię!'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function create(): View |     public function create(): InertiaResponse | ||||||
|     { |     { | ||||||
|         return view('dashboard.categories.create'); |         return inertia('Categories/Create'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function edit(Category $category): View |     public function edit(Category $category): InertiaResponse | ||||||
|     { |     { | ||||||
|         return view('dashboard.categories.edit', compact('category')); |         return inertia('Categories/Edit', compact('category')); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function delete(Category $category): View |     public function delete(Category $category): InertiaResponse | ||||||
|     { |     { | ||||||
|         return view('dashboard.categories.delete', compact('category')); |         return inertia('Categories/ConfirmDelete', compact('category')); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function destroy(Category $category): RedirectResponse |     public function destroy(Category $category): RedirectResponse | ||||||
| @@ -64,7 +58,9 @@ class CategoryController | |||||||
|         $name = $category->name; |         $name = $category->name; | ||||||
|         $category->delete(); |         $category->delete(); | ||||||
|  |  | ||||||
|         return redirect()->route('admin.home')->with('message', 'Usunięto kategorię "'. $name .'"'); |         return redirect() | ||||||
|  |             ->route('admin.home') | ||||||
|  |             ->with('info', 'Usunięto kategorię "'. $name .'"'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
| namespace App\Http\Controllers\Dashboard; | namespace App\Http\Controllers\Dashboard; | ||||||
|  |  | ||||||
| use App\Http\Requests\ProjectRequest; | use App\Http\Requests\ProjectRequest; | ||||||
|   | |||||||
| @@ -48,7 +48,7 @@ class CategoryRepository implements CategoryRepositoryInterface | |||||||
|     public function update(Category $category, array $data = []): bool |     public function update(Category $category, array $data = []): bool | ||||||
|     { |     { | ||||||
|         $data = $this->parseToArray($data); |         $data = $this->parseToArray($data); | ||||||
|         if (!$category->default && isset($data['default']) && $data['default'] === true) |         if (!$category->default && $data['default'] === true) | ||||||
|             $this->unsetDefault(); |             $this->unsetDefault(); | ||||||
|  |  | ||||||
|         return $category |         return $category | ||||||
| @@ -58,7 +58,7 @@ class CategoryRepository implements CategoryRepositoryInterface | |||||||
|     public function create(array $data = []): Category |     public function create(array $data = []): Category | ||||||
|     { |     { | ||||||
|         $data = $this->parseToArray($data); |         $data = $this->parseToArray($data); | ||||||
|         if (isset($data['default']) && $data['default'] === true) |         if ($data['default'] === true) | ||||||
|             $this->unsetDefault(); |             $this->unsetDefault(); | ||||||
|  |  | ||||||
|         return $this->category |         return $this->category | ||||||
| @@ -85,18 +85,12 @@ class CategoryRepository implements CategoryRepositoryInterface | |||||||
|         if (isset($data['priority']) && !is_integer($data['priority'])) |         if (isset($data['priority']) && !is_integer($data['priority'])) | ||||||
|             $toSave['priority'] = (int)$data['priority']; |             $toSave['priority'] = (int)$data['priority']; | ||||||
|  |  | ||||||
|         if ( |         $toSave['default'] = $data['default']; | ||||||
|             isset($data['default']) && |  | ||||||
|             in_array($data['default'], ['yes', 'on', 1, true]) |  | ||||||
|         ) $toSave['default'] = true; |  | ||||||
|         else $toSave['default'] = false; |  | ||||||
|  |  | ||||||
|         if ( |         if ($toSave['default'] === true) | ||||||
|             (isset($toSave['default']) && $toSave['default'] === true) || |             $toSave['visible'] = true; | ||||||
|             (isset($data['visible']) && |         else | ||||||
|             in_array($data['visible'], ['yes', 'on', 1, true])) |             $toSave['visible'] = $data['visible']; | ||||||
|         ) $toSave['visible'] = true; |  | ||||||
|         else $toSave['visible'] = false; |  | ||||||
|  |  | ||||||
|         return $toSave; |         return $toSave; | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								resources/js/Pages/Categories/ConfirmDelete.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								resources/js/Pages/Categories/ConfirmDelete.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | <script setup> | ||||||
|  | import { router } from '@inertiajs/vue3'; | ||||||
|  |  | ||||||
|  | const props = defineProps({ | ||||||
|  |     category: { | ||||||
|  |         type: Object, | ||||||
|  |         required: true, | ||||||
|  |     }, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | function confirmDelete() { | ||||||
|  |     router.delete(`/dashboard/category/${props.category.id}/delete`); | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <InertiaHead title="Usuwanie kategorii" /> | ||||||
|  |     <div class="p-4"> | ||||||
|  |         <header class="pb-4"> | ||||||
|  |             <h1 class="text-3xl font-roboto font-light">Usuwanie kategorii</h1> | ||||||
|  |         </header> | ||||||
|  |         <div class="max-w-[600px]"> | ||||||
|  |             <p class="mb-4">Na pewno usunąć kategorię o nazwie {{ category.name }}?</p> | ||||||
|  |             <div class="grid grid-cols-3 gap-2"> | ||||||
|  |                 <InertiaLink | ||||||
|  |                     as="button" | ||||||
|  |                     href="/dashboard" | ||||||
|  |                     class="col-span-1 flex justify-center items-center gap-3 w-full px-2 py-1 border-t-4 border-b-4 border-transparent hover:border-b-black" | ||||||
|  |                     ><FontAwesomeIcon :icon="['fas', 'backward']" />Anuluj</InertiaLink> | ||||||
|  |                 <button | ||||||
|  |                     @click.prevent="confirmDelete" | ||||||
|  |                     class="col-span-2 flex justify-center items-center gap-3 w-full px-2 py-1 rounded-md bg-red-600 border-4 border-red-600 text-white text-lg hover:bg-transparent hover:text-red-600" | ||||||
|  |                     ><FontAwesomeIcon :icon="['fas', 'trash']" />Usuń kategorię {{ category.name }}</button> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										64
									
								
								resources/js/Pages/Categories/Create.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								resources/js/Pages/Categories/Create.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | <script setup> | ||||||
|  | import { useForm } from '@inertiajs/inertia-vue3'; | ||||||
|  | import Input from '../../Share/Components/Input.vue'; | ||||||
|  |  | ||||||
|  | const form = useForm({ | ||||||
|  |     name: null, | ||||||
|  |     slug: null, | ||||||
|  |     priority: Number(0), | ||||||
|  |     default: Boolean(false), | ||||||
|  |     visible: Boolean(false), | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | function createCategory() { | ||||||
|  |     form.post('/dashboard/category'); | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <InertiaHead title="Nowa kategoria" /> | ||||||
|  |     <div class="p-4"> | ||||||
|  |         <header class="pb-4"> | ||||||
|  |             <h1 class="text-3xl font-roboto font-light">Nowa kategoria</h1> | ||||||
|  |         </header> | ||||||
|  |         <div> | ||||||
|  |             <form class="flex flex-col gap-4" @submit.prevent="createCategory"> | ||||||
|  |                 <Input | ||||||
|  |                     id="name" | ||||||
|  |                     label="Nazwa" | ||||||
|  |                     placeholder="Nazwa kategorii" | ||||||
|  |                     v-model="form.name" | ||||||
|  |                     :error="form.errors.name" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="slug" | ||||||
|  |                     label="Slug" | ||||||
|  |                     placeholder="Slug dla kategorii" | ||||||
|  |                     v-model="form.slug" | ||||||
|  |                     :error="form.errors.slug" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="priority" | ||||||
|  |                     label="Priorytet" | ||||||
|  |                     type="number" | ||||||
|  |                     placeholder="Priorytet dla danej kategorii" | ||||||
|  |                     v-model="form.priority" | ||||||
|  |                     :error="form.errors.priority" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="visible" | ||||||
|  |                     label="Widoczny" | ||||||
|  |                     type="checkbox" | ||||||
|  |                     v-model="form.visible" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="default" | ||||||
|  |                     label="Domyślny" | ||||||
|  |                     type="checkbox" | ||||||
|  |                     v-model="form.default" | ||||||
|  |                 /> | ||||||
|  |                 <button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Dodaj kategorię</button> | ||||||
|  |             </form> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										78
									
								
								resources/js/Pages/Categories/Edit.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								resources/js/Pages/Categories/Edit.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | |||||||
|  | <script setup> | ||||||
|  | import { ref } from 'vue'; | ||||||
|  | import { useForm } from '@inertiajs/inertia-vue3'; | ||||||
|  | import Input from '../../Share/Components/Input.vue'; | ||||||
|  |  | ||||||
|  | const props = defineProps({ | ||||||
|  |     category: { | ||||||
|  |         type: Object, | ||||||
|  |         required: true, | ||||||
|  |     }, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const visibleCheckbox = ref(props.category.visible); | ||||||
|  | const defaultCheckbox = ref(props.category.default); | ||||||
|  |  | ||||||
|  | const form = useForm({ | ||||||
|  |     name: props.category.name, | ||||||
|  |     slug: props.category.slug, | ||||||
|  |     priority: props.category.priority, | ||||||
|  |     visible: visibleCheckbox, | ||||||
|  |     default: defaultCheckbox, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | function updateProject() { | ||||||
|  |     form.clearErrors(); | ||||||
|  |     form.put(`/dashboard/category/${props.category.id}`); | ||||||
|  |     if (defaultCheckbox.value) | ||||||
|  |         visibleCheckbox.value = true; | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <InertiaHead title="Nowy projekt" /> | ||||||
|  |     <div class="p-4"> | ||||||
|  |         <header class="pb-4"> | ||||||
|  |             <h1 class="text-3xl font-roboto font-light">Edytuj {{ category.name }}</h1> | ||||||
|  |         </header> | ||||||
|  |         <div> | ||||||
|  |             <form class="flex flex-col gap-4" @submit.prevent="updateProject"> | ||||||
|  |                 <Input | ||||||
|  |                     id="name" | ||||||
|  |                     label="Nazwa" | ||||||
|  |                     placeholder="Nazwa kategorii" | ||||||
|  |                     v-model="form.name" | ||||||
|  |                     :error="form.errors.name" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="slug" | ||||||
|  |                     label="Slug" | ||||||
|  |                     placeholder="Slug dla kategorii" | ||||||
|  |                     v-model="form.slug" | ||||||
|  |                     :error="form.errors.slug" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="priority" | ||||||
|  |                     label="Priorytet" | ||||||
|  |                     type="number" | ||||||
|  |                     placeholder="Priorytet dla danej kategorii" | ||||||
|  |                     v-model="form.priority" | ||||||
|  |                     :error="form.errors.priority" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="visible" | ||||||
|  |                     label="Widoczny" | ||||||
|  |                     type="checkbox" | ||||||
|  |                     v-model="form.visible" | ||||||
|  |                 /> | ||||||
|  |                 <Input | ||||||
|  |                     id="default" | ||||||
|  |                     label="Domyślny" | ||||||
|  |                     type="checkbox" | ||||||
|  |                     v-model="form.default" | ||||||
|  |                 /> | ||||||
|  |                 <button class="px-0.5 py-1 rounded-lg bg-[#436da7] border-4 border-[#436da7] text-white text-lg hover:bg-transparent hover:text-[#436da7]">Aktualizuj kategorię</button> | ||||||
|  |             </form> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
| @@ -9,16 +9,33 @@ defineProps({ | |||||||
|  |  | ||||||
| <template> | <template> | ||||||
|     <section class="bg-gray-100 rounded-md p-4"> |     <section class="bg-gray-100 rounded-md p-4"> | ||||||
|         <header class="pb-4"> |         <header class="flex justify-between items-center pb-4"> | ||||||
|             <h2 class="text-2xl font-roboto font-light">Categories</h2> |             <h2 class="text-2xl font-roboto font-light">Kategorie</h2> | ||||||
|  |             <InertiaLink | ||||||
|  |                 as="button" | ||||||
|  |                 href="/dashboard/category/create" | ||||||
|  |                 class="bg-blue-400 hover:bg-blue-500 text-white px-2.5 py-1 rounded-full"><FontAwesomeIcon :icon="['fas', 'plus']" /></InertiaLink> | ||||||
|         </header> |         </header> | ||||||
|         <ul class="flex flex-col gap-2"> |         <ul class="flex flex-col gap-2"> | ||||||
|             <li |             <li | ||||||
|                 v-for="(category, key) in categories" |                 v-for="(category, key) in categories" | ||||||
|                 :key="key" |                 :key="key" | ||||||
|                 class="px-3 py-2 bg-white hover:bg-zinc-300" |                 class="flex items-center justify-between px-3 py-2 bg-white hover:bg-neutral-200" | ||||||
|             > |             > | ||||||
|                 {{ category.name }} |                 <InertiaLink :href="`/dashboard/category/${category.id}`">{{ category.name }}</InertiaLink> | ||||||
|  |                 <div class="flex items-center gap-1"> | ||||||
|  |                     <InertiaLink | ||||||
|  |                         as="button" | ||||||
|  |                         class="px-1 py-0.5 text-lime-600 hover:text-lime-800 border-t-2 border-b-2 border-transparent hover:border-b-lime-600" | ||||||
|  |                         :href="`/dashboard/category/${category.id}`" | ||||||
|  |                         title="Edytuj kategorię"><FontAwesomeIcon :icon="['fas', 'pen-to-square']" /></InertiaLink> | ||||||
|  |                     <InertiaLink | ||||||
|  |                         v-if="!category.default" | ||||||
|  |                         as="button" | ||||||
|  |                         class="px-1 py-0.5 text-red-600 hover:text-red-800" | ||||||
|  |                         :href="`/dashboard/category/${category.id}/delete`" | ||||||
|  |                         title="Usuń kategorię z listy"><FontAwesomeIcon :icon="['fas', 'trash']" /></InertiaLink> | ||||||
|  |                 </div> | ||||||
|             </li> |             </li> | ||||||
|         </ul> |         </ul> | ||||||
|     </section> |     </section> | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ defineProps({ | |||||||
|         default: null, |         default: null, | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
| defineEmits(['update:modelValue']); | defineEmits(['update:model-value']); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <template> | <template> | ||||||
| @@ -32,19 +32,21 @@ defineEmits(['update:modelValue']); | |||||||
|             :id="id" |             :id="id" | ||||||
|             :class="['w-full min-w-full max-w-full h-[200px] min-h-[200px] px-2.5 py-2 border-b-2 rounded-md', error ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']" |             :class="['w-full min-w-full max-w-full h-[200px] min-h-[200px] px-2.5 py-2 border-b-2 rounded-md', error ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']" | ||||||
|             :value="modelValue" |             :value="modelValue" | ||||||
|             @input="$emit('update:modelValue', $event.target.value)" |             @input="$emit('update:model-value', $event.target.value)" | ||||||
|             :placeholder="placeholder"></textarea> |             :placeholder="placeholder"></textarea> | ||||||
|         <input v-else-if="type === 'checkbox'" |         <input v-else-if="type === 'checkbox'" | ||||||
|             :id="id" |             :id="id" | ||||||
|             :value="modelValue" |             :checked="modelValue" | ||||||
|             @input="$emit('update:modelValue', $event.target.value)" |             @input="$emit('update:model-value', $event.target.checked)" | ||||||
|  |             :true-value="true" | ||||||
|  |             :false-value="false" | ||||||
|             type="checkbox" /> |             type="checkbox" /> | ||||||
|         <input v-else |         <input v-else | ||||||
|             :id="id" |             :id="id" | ||||||
|             :class="['w-full px-2.5 py-2 border-b-2 rounded-md', error ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']" |             :class="['w-full px-2.5 py-2 border-b-2 rounded-md', error ? 'border-red-300 focus:border-red-400 hover:border-red-500 outline-none text-red-900 placeholder-red-400' : 'border-neutral-300 focus:border-neutral-400 hover:border-neutral-500 outline-none text-gray-900 placeholder-gray-400']" | ||||||
|             :type="type" |             :type="type" | ||||||
|             :value="modelValue" |             :value="modelValue" | ||||||
|             @input="$emit('update:modelValue', $event.target.value)" |             @input="$emit('update:model-value', $event.target.value)" | ||||||
|             :placeholder="placeholder" /> |             :placeholder="placeholder" /> | ||||||
|         <span class="text-red-400" v-if="error">{{ error }}</span> |         <span class="text-red-400" v-if="error">{{ error }}</span> | ||||||
|     </div> |     </div> | ||||||
|   | |||||||
| @@ -11,7 +11,11 @@ defineProps({ | |||||||
|     <section class="bg-gray-100 rounded-md p-4"> |     <section class="bg-gray-100 rounded-md p-4"> | ||||||
|         <header class="flex justify-between items-center pb-4"> |         <header class="flex justify-between items-center pb-4"> | ||||||
|             <h2 class="text-2xl font-roboto font-light">Projekty</h2> |             <h2 class="text-2xl font-roboto font-light">Projekty</h2> | ||||||
|             <InertiaLink as="button" href="/dashboard/project/create" class="bg-blue-400 hover:bg-blue-500 text-white px-2 py-1">Dodaj nowy</InertiaLink> |             <InertiaLink | ||||||
|  |                 as="button" | ||||||
|  |                 href="/dashboard/project/create" | ||||||
|  |                 class="bg-blue-400 hover:bg-blue-500 text-white px-2.5 py-1 rounded-full" | ||||||
|  |                 ><FontAwesomeIcon :icon="['fas', 'plus']" /></InertiaLink> | ||||||
|         </header> |         </header> | ||||||
|         <ul v-if="projects.length" class="flex flex-col gap-2"> |         <ul v-if="projects.length" class="flex flex-col gap-2"> | ||||||
|             <li |             <li | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user