diff --git a/app/Http/Controllers/NailPolishImportController.php b/app/Http/Controllers/NailPolishImportController.php index c1f3581..9d88839 100644 --- a/app/Http/Controllers/NailPolishImportController.php +++ b/app/Http/Controllers/NailPolishImportController.php @@ -40,7 +40,13 @@ class NailPolishImportController extends Controller ProcessNailPolishImage::dispatch($import->id); - return redirect()->route('nail-polish-imports.show', $import) + $redirectUrl = route('nail-polish-imports.show', $import); + + if (request()->ajax()) { + return response()->json(['redirect' => $redirectUrl]); + } + + return redirect($redirectUrl) ->with('success', 'Bild hochgeladen! Die KI analysiert es jetzt im Hintergrund.'); } diff --git a/app/Jobs/ProcessNailPolishImage.php b/app/Jobs/ProcessNailPolishImage.php index 744f42f..a47a90c 100644 --- a/app/Jobs/ProcessNailPolishImage.php +++ b/app/Jobs/ProcessNailPolishImage.php @@ -34,14 +34,18 @@ class ProcessNailPolishImage implements ShouldQueue $imageB64 = base64_encode(Storage::disk('public')->get($import->image_path)); $prompt = <<post("{$ai->ollama_url}/api/generate", [ diff --git a/resources/views/nail-polish-imports/create.blade.php b/resources/views/nail-polish-imports/create.blade.php index 18987b1..a5cc59d 100644 --- a/resources/views/nail-polish-imports/create.blade.php +++ b/resources/views/nail-polish-imports/create.blade.php @@ -13,35 +13,41 @@
-
- @csrf +
-
- +
+ -
-
- -

Foto hierher ziehen oder klicken

-

JPG, PNG, WebP – max. 10 MB

-
- +
+
+ +

Foto hierher ziehen oder klicken

+

JPG, PNG, WebP – max. 10 MB

- - - - @error('image') -
{{ $message }}
- @enderror +
- - + +
+ + {{-- Upload-Progress --}} +
+
+ Wird hochgeladen… + 0% +
+
+
+
+
+ +
@@ -61,8 +67,9 @@ const dropzone = document.getElementById('dropzone'); const input = document.getElementById('image'); const preview = document.getElementById('preview'); const content = document.getElementById('dropzoneContent'); +const submitBtn = document.getElementById('submitBtn'); -input.addEventListener('change', e => showPreview(e.target.files[0])); +input.addEventListener('change', e => { if (e.target.files[0]) selectFile(e.target.files[0]); }); dropzone.addEventListener('dragover', e => { e.preventDefault(); dropzone.style.borderColor = '#7c3aed'; }); dropzone.addEventListener('dragleave', () => { dropzone.style.borderColor = '#d1d5db'; }); @@ -70,11 +77,10 @@ dropzone.addEventListener('drop', e => { e.preventDefault(); dropzone.style.borderColor = '#d1d5db'; const file = e.dataTransfer.files[0]; - if (file) { input.files = e.dataTransfer.files; showPreview(file); } + if (file) { input.files = e.dataTransfer.files; selectFile(file); } }); -function showPreview(file) { - if (!file) return; +function selectFile(file) { const reader = new FileReader(); reader.onload = e => { preview.src = e.target.result; @@ -82,12 +88,63 @@ function showPreview(file) { content.style.display = 'none'; }; reader.readAsDataURL(file); + submitBtn.disabled = false; } -document.getElementById('importForm').addEventListener('submit', () => { - const btn = document.getElementById('submitBtn'); - btn.disabled = true; - btn.innerHTML = 'Wird hochgeladen…'; -}); +function startUpload() { + const file = input.files[0]; + if (!file) return; + + submitBtn.disabled = true; + submitBtn.innerHTML = 'Wird hochgeladen…'; + document.getElementById('progressWrap').classList.remove('d-none'); + document.getElementById('errorBox').classList.add('d-none'); + + const formData = new FormData(); + formData.append('image', file); + formData.append('_token', '{{ csrf_token() }}'); + + const xhr = new XMLHttpRequest(); + + xhr.upload.addEventListener('progress', e => { + if (e.lengthComputable) { + const pct = Math.round(e.loaded / e.total * 100); + document.getElementById('progressBar').style.width = pct + '%'; + document.getElementById('progressPct').textContent = pct + '%'; + } + }); + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const data = JSON.parse(xhr.responseText); + if (data.redirect) { window.location.href = data.redirect; return; } + } catch(e) {} + } + showError('Upload fehlgeschlagen (Status ' + xhr.status + '). Bitte erneut versuchen.'); + resetBtn(); + }); + + xhr.addEventListener('error', () => { + showError('Netzwerkfehler beim Upload. Bitte erneut versuchen.'); + resetBtn(); + }); + + xhr.open('POST', '{{ route('nail-polish-imports.store') }}'); + xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + xhr.send(formData); +} + +function showError(msg) { + const box = document.getElementById('errorBox'); + box.textContent = msg; + box.classList.remove('d-none'); + document.getElementById('progressWrap').classList.add('d-none'); +} + +function resetBtn() { + submitBtn.disabled = false; + submitBtn.innerHTML = 'KI-Analyse starten'; +} @endsection