- add category management

This commit is contained in:
Kamil Niemczycki 2023-07-28 15:43:53 +02:00
parent d47c719d13
commit 8974721c9c
Signed by: kamilniemczycki
GPG Key ID: 04D4E2012F969213
9 changed files with 235 additions and 41 deletions

View File

@ -9,6 +9,7 @@ use App\Models\Category;
use App\Repository\Interfaces\CategoryRepository;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Inertia\Response as InertiaResponse;
class CategoryController
{
@ -21,42 +22,35 @@ class CategoryController
{
$validate = $request->validated();
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)
{
// $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());
return redirect()
->route('admin.category.update', compact('category'))
->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
@ -64,7 +58,9 @@ class CategoryController
$name = $category->name;
$category->delete();
return redirect()->route('admin.home')->with('message', 'Usunięto kategorię "'. $name .'"');
return redirect()
->route('admin.home')
->with('info', 'Usunięto kategorię "'. $name .'"');
}
}

View File

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Dashboard;
use App\Http\Requests\ProjectRequest;

View File

@ -48,7 +48,7 @@ class CategoryRepository implements CategoryRepositoryInterface
public function update(Category $category, array $data = []): bool
{
$data = $this->parseToArray($data);
if (!$category->default && isset($data['default']) && $data['default'] === true)
if (!$category->default && $data['default'] === true)
$this->unsetDefault();
return $category
@ -58,7 +58,7 @@ class CategoryRepository implements CategoryRepositoryInterface
public function create(array $data = []): Category
{
$data = $this->parseToArray($data);
if (isset($data['default']) && $data['default'] === true)
if ($data['default'] === true)
$this->unsetDefault();
return $this->category
@ -85,18 +85,12 @@ class CategoryRepository implements CategoryRepositoryInterface
if (isset($data['priority']) && !is_integer($data['priority']))
$toSave['priority'] = (int)$data['priority'];
if (
isset($data['default']) &&
in_array($data['default'], ['yes', 'on', 1, true])
) $toSave['default'] = true;
else $toSave['default'] = false;
$toSave['default'] = $data['default'];
if (
(isset($toSave['default']) && $toSave['default'] === true) ||
(isset($data['visible']) &&
in_array($data['visible'], ['yes', 'on', 1, true]))
) $toSave['visible'] = true;
else $toSave['visible'] = false;
if ($toSave['default'] === true)
$toSave['visible'] = true;
else
$toSave['visible'] = $data['visible'];
return $toSave;
}

View 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>

View 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>

View 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>

View File

@ -9,16 +9,33 @@ defineProps({
<template>
<section class="bg-gray-100 rounded-md p-4">
<header class="pb-4">
<h2 class="text-2xl font-roboto font-light">Categories</h2>
<header class="flex justify-between items-center pb-4">
<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>
<ul class="flex flex-col gap-2">
<li
v-for="(category, key) in categories"
: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>
</ul>
</section>

View File

@ -20,7 +20,7 @@ defineProps({
default: null,
}
});
defineEmits(['update:modelValue']);
defineEmits(['update:model-value']);
</script>
<template>
@ -32,19 +32,21 @@ defineEmits(['update:modelValue']);
: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']"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
@input="$emit('update:model-value', $event.target.value)"
:placeholder="placeholder"></textarea>
<input v-else-if="type === 'checkbox'"
:id="id"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
:checked="modelValue"
@input="$emit('update:model-value', $event.target.checked)"
:true-value="true"
:false-value="false"
type="checkbox" />
<input v-else
: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']"
:type="type"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
@input="$emit('update:model-value', $event.target.value)"
:placeholder="placeholder" />
<span class="text-red-400" v-if="error">{{ error }}</span>
</div>

View File

@ -11,7 +11,11 @@ defineProps({
<section class="bg-gray-100 rounded-md p-4">
<header class="flex justify-between items-center pb-4">
<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>
<ul v-if="projects.length" class="flex flex-col gap-2">
<li