Listen: anlegen, Titel, Foto-Log

Made-with: Cursor
This commit is contained in:
Stefan Zwischenbrugger 2026-03-30 10:36:09 +02:00
parent 52ef8feba3
commit a707aadd4f
6 changed files with 93 additions and 7 deletions

View File

@ -109,10 +109,6 @@ class ShoppingListController extends Controller
'done_at' => $isDone ? Carbon::now() : null,
]);
if (! $isDone) {
return;
}
$photoPath = $request->file('photo')?->store('price-photos', 'public');
if (! $request->filled('price_decimal') && $photoPath === null) {

View File

@ -0,0 +1,32 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreShoppingListRequest;
use App\Models\ShoppingList;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
class ShoppingListCreateController extends Controller
{
public function __invoke(StoreShoppingListRequest $request): RedirectResponse
{
/** @var \App\Models\User $user */
$user = $request->user();
$list = DB::transaction(function () use ($request, $user): ShoppingList {
$list = ShoppingList::query()->create([
'owner_id' => $user->id,
'name' => $request->string('name')->toString(),
]);
$list->members()->attach($user->id);
return $list;
});
$request->session()->put('current_shopping_list_id', $list->id);
return redirect()->route('dashboard')->with('status', 'Liste wurde erstellt.');
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreShoppingListRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user() !== null;
}
/**
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
];
}
public function messages(): array
{
return [
'name.required' => 'Bitte gib einen Listennamen ein.',
'name.max' => 'Der Listenname darf maximal 255 Zeichen lang sein.',
];
}
public function attributes(): array
{
return [
'name' => 'Listenname',
];
}
}

View File

@ -1,7 +1,7 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Einkaufsliste
{{ $currentList->name }}
</h2>
</x-slot>
@ -195,6 +195,22 @@
<span class="text-gray-500">(geteilt von {{ $currentList->owner->name }})</span>
@endif
</p>
<form method="POST" action="{{ route('shopping-lists.store') }}" class="flex flex-col sm:flex-row gap-2 items-stretch sm:items-center sm:flex-wrap mb-4">
@csrf
<label for="new-list-name" class="text-sm text-gray-600 shrink-0">Neue Liste:</label>
<input
id="new-list-name"
type="text"
name="name"
value="{{ old('name') }}"
placeholder="z. B. Drogerie"
class="rounded-md border-gray-300 text-sm min-h-[44px] max-w-md flex-1"
autocomplete="off"
>
<button type="submit" class="shrink-0 rounded-md bg-indigo-600 text-white px-5 min-h-[44px] text-sm font-medium hover:bg-indigo-700">
Erstellen
</button>
</form>
@if($accessibleLists->count() > 1)
<form method="POST" action="{{ route('shopping-lists.switch', $currentList) }}" id="shopping-list-switch-form" class="flex flex-col sm:flex-row gap-2 items-stretch sm:items-center sm:flex-wrap">
@csrf
@ -202,7 +218,7 @@
<select
id="list-switch"
class="rounded-md border-gray-300 text-sm min-h-[44px] max-w-md flex-1"
onchange="this.form.action = '{{ url('/shopping-lists') }}/' + this.value + '/switch'; this.form.requestSubmit();"
onchange="this.form.action = @js(url('/shopping-lists')) + '/' + this.value + '/switch'; this.form.requestSubmit();"
>
@foreach($accessibleLists as $list)
<option value="{{ $list->id }}" @selected($list->id === $currentList->id)>

View File

@ -69,6 +69,7 @@
list="store-options"
class="rounded-md border-gray-300 text-sm min-h-[44px]"
>
<input type="hidden" name="is_done" value="0">
<label class="flex items-start gap-2 mt-1 cursor-pointer">
<input
type="checkbox"
@ -79,7 +80,7 @@
>
<span class="text-xs text-gray-700">Als erledigt markieren</span>
</label>
<p class="text-xs text-gray-500 -mt-1">Preis und Foto werden nur gespeichert, wenn der Eintrag als erledigt markiert ist.</p>
<p class="text-xs text-gray-500 -mt-1">Preis und Foto koennen auch ohne „erledigt“ gespeichert werden.</p>
<input
type="number"
step="0.01"

View File

@ -2,6 +2,7 @@
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\ShoppingListController;
use App\Http\Controllers\ShoppingListCreateController;
use App\Http\Controllers\ShoppingListMemberController;
use App\Http\Controllers\ShoppingListSwitchController;
use Illuminate\Support\Facades\Route;
@ -16,6 +17,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
Route::patch('/shopping-items/{shoppingItem}', [ShoppingListController::class, 'update'])->name('shopping-items.update');
Route::patch('/shopping-items/{shoppingItem}/toggle', [ShoppingListController::class, 'toggle'])->name('shopping-items.toggle');
Route::post('/shopping-lists', ShoppingListCreateController::class)->name('shopping-lists.store');
Route::post('/shopping-lists/{shoppingList}/switch', ShoppingListSwitchController::class)->name('shopping-lists.switch');
Route::post('/shopping-lists/{shoppingList}/members', [ShoppingListMemberController::class, 'store'])->name('shopping-lists.members.store');
Route::delete('/shopping-lists/{shoppingList}/members/{user}', [ShoppingListMemberController::class, 'destroy'])->name('shopping-lists.members.destroy');