Compare commits
2 Commits
092e3b2a61
...
b9e8b495b7
| Author | SHA1 | Date | |
|---|---|---|---|
| b9e8b495b7 | |||
| bec9b466fc |
@ -115,6 +115,9 @@ class ReceiptScanController extends Controller
|
||||
if (isset($previousMeta['validated_at'])) {
|
||||
$rawMeta['validated_at'] = $previousMeta['validated_at'];
|
||||
}
|
||||
if (isset($previousMeta['item_selection_state']) && is_array($previousMeta['item_selection_state'])) {
|
||||
$rawMeta['item_selection_state'] = $previousMeta['item_selection_state'];
|
||||
}
|
||||
|
||||
$nextStoreName = $receiptScan->store_name;
|
||||
if (trim((string) $nextStoreName) === '' && is_string($ocr['store_name'] ?? null) && trim($ocr['store_name']) !== '') {
|
||||
@ -182,6 +185,17 @@ class ReceiptScanController extends Controller
|
||||
$prices = $validated['row_prices'] ?? [];
|
||||
$qtys = $validated['row_qty'] ?? [];
|
||||
$take = $validated['row_take'] ?? [];
|
||||
$selectionState = [];
|
||||
foreach ($labels as $i => $labelRaw) {
|
||||
$label = trim((string) $labelRaw);
|
||||
if ($label === '') {
|
||||
continue;
|
||||
}
|
||||
$priceRaw = trim((string) ($prices[$i] ?? ''));
|
||||
$qtyRaw = trim((string) ($qtys[$i] ?? ''));
|
||||
$selectionKey = $this->suggestionRowKey($label, $priceRaw, $qtyRaw);
|
||||
$selectionState[$selectionKey] = isset($take[$i]);
|
||||
}
|
||||
|
||||
$rows = collect($labels)
|
||||
->map(function ($label, $i) use ($prices, $qtys, $take) {
|
||||
@ -285,6 +299,7 @@ class ReceiptScanController extends Controller
|
||||
$meta = is_array($receiptScan->raw_meta) ? $receiptScan->raw_meta : [];
|
||||
$meta['validated_items'] = $rows->all();
|
||||
$meta['validated_at'] = Carbon::now()->toISOString();
|
||||
$meta['item_selection_state'] = $selectionState;
|
||||
$receiptScan->update(['raw_meta' => $meta]);
|
||||
|
||||
return back()->with(
|
||||
@ -398,6 +413,11 @@ class ReceiptScanController extends Controller
|
||||
return trim(preg_replace('/\s+[A-E]\s*$/u', '', $raw) ?? $raw);
|
||||
}
|
||||
|
||||
private function suggestionRowKey(string $label, string $priceRaw, string $quantityRaw): string
|
||||
{
|
||||
return mb_strtolower(trim($label)).'|'.trim($priceRaw).'|'.trim($quantityRaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{label: string, price_raw: string, quantity_raw: string, is_uncertain: bool}>
|
||||
*/
|
||||
|
||||
@ -104,7 +104,9 @@ class ShoppingListController extends Controller
|
||||
'quantity' => $request->filled('quantity') ? $request->string('quantity')->toString() : $doneItem->quantity,
|
||||
]);
|
||||
|
||||
return back()->with('status', 'Eintrag wurde aus erledigt nach offen uebernommen.');
|
||||
return back()
|
||||
->with('status', 'Eintrag wurde aus erledigt nach offen uebernommen.')
|
||||
->with('focus_new_item', true);
|
||||
}
|
||||
|
||||
ShoppingItem::query()->create([
|
||||
@ -116,7 +118,9 @@ class ShoppingListController extends Controller
|
||||
'is_done' => false,
|
||||
]);
|
||||
|
||||
return back()->with('status', 'Eintrag wurde hinzugefuegt.');
|
||||
return back()
|
||||
->with('status', 'Eintrag wurde hinzugefuegt.')
|
||||
->with('focus_new_item', true);
|
||||
}
|
||||
|
||||
public function update(UpdateShoppingItemRequest $request, ShoppingItem $shoppingItem): RedirectResponse
|
||||
|
||||
@ -149,6 +149,9 @@
|
||||
->filter()
|
||||
->all();
|
||||
$appliedSet = array_flip($appliedLowerKeys);
|
||||
$selectionState = is_array($scan->raw_meta['item_selection_state'] ?? null)
|
||||
? $scan->raw_meta['item_selection_state']
|
||||
: [];
|
||||
@endphp
|
||||
<div class="mt-3 rounded-md border border-blue-200 bg-blue-50 p-3">
|
||||
<p class="text-xs font-semibold text-blue-900">
|
||||
@ -177,13 +180,21 @@
|
||||
$listKey = mb_strtolower(trim($label));
|
||||
$listStatus = $listProductLookup[$listKey] ?? null;
|
||||
$wasAppliedFromReceipt = $listKey !== '' && isset($appliedSet[$listKey]);
|
||||
$selectionKey = $listKey.'|'.trim((string) $priceRaw).'|'.trim((string) $qtyRaw);
|
||||
$storedSelection = $selectionState[$selectionKey] ?? null;
|
||||
$defaultChecked = $storedSelection !== null
|
||||
? (bool) $storedSelection
|
||||
: (! $isUncertain);
|
||||
if ($wasAppliedFromReceipt) {
|
||||
$defaultChecked = false;
|
||||
}
|
||||
@endphp
|
||||
<div class="receipt-suggestion-row flex flex-nowrap items-center gap-2 w-full min-w-0 {{ $isUncertain ? 'opacity-85' : '' }}">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="row_take[{{ $rowIndex }}]"
|
||||
value="1"
|
||||
@checked(! $isUncertain)
|
||||
@checked($defaultChecked)
|
||||
class="shrink-0 rounded border-gray-300 text-blue-600 shadow-sm h-5 w-5 mt-0.5"
|
||||
aria-label="Position als erledigt uebernehmen"
|
||||
title="Uebernehmen"
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<div id="shopping-list-page" data-focus-new-item="{{ session('focus_new_item') ? '1' : '0' }}" class="py-3 sm:py-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-4 sm:space-y-6">
|
||||
<datalist id="store-options">
|
||||
@foreach($stores as $store)
|
||||
<option value="{{ $store->name }}"></option>
|
||||
@ -34,8 +34,8 @@
|
||||
@endif
|
||||
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-xl p-4 sm:p-6">
|
||||
<h3 class="text-lg font-semibold mb-3">Neuer Eintrag</h3>
|
||||
<p class="text-sm text-gray-600 mb-3">Nur Namen eingeben, mit <kbd class="px-1 bg-gray-100 rounded text-xs">Enter</kbd> speichern.</p>
|
||||
<h3 class="text-lg font-semibold mb-2">Neuer Eintrag</h3>
|
||||
<p class="hidden sm:block text-sm text-gray-600 mb-3">Nur Namen eingeben, mit <kbd class="px-1 bg-gray-100 rounded text-xs">Enter</kbd> speichern.</p>
|
||||
<form method="POST" action="{{ route('shopping-items.store') }}" class="flex flex-col sm:flex-row gap-2">
|
||||
@csrf
|
||||
<input
|
||||
@ -364,6 +364,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const pageRoot = document.getElementById('shopping-list-page');
|
||||
const shouldFocusNewItem = pageRoot?.dataset.focusNewItem === '1';
|
||||
if (!shouldFocusNewItem) {
|
||||
return;
|
||||
}
|
||||
const input = document.getElementById('new-item-name');
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
input.focus({ preventScroll: true });
|
||||
input.select();
|
||||
});
|
||||
|
||||
document.addEventListener('click', async (event) => {
|
||||
const pasteBtn = event.target.closest('.js-paste-price');
|
||||
if (!pasteBtn) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user