From 946c2ebdf04a173694906a8462a64926ec6c37cf Mon Sep 17 00:00:00 2001 From: John Mizerek Date: Sun, 8 Feb 2026 13:08:24 -0800 Subject: [PATCH] Add modal-based photo upload for better mobile support - Show a modal with file input and preview - Uses alert() instead of toast for error messages (more visible on mobile) - Preview shows selected image before upload - Submit button with loading state - Keeps old uploadPhoto function for compatibility Co-Authored-By: Claude Opus 4.5 --- portal/menu-builder.html | 102 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/portal/menu-builder.html b/portal/menu-builder.html index 20111c5..8386f91 100644 --- a/portal/menu-builder.html +++ b/portal/menu-builder.html @@ -1753,7 +1753,7 @@ `No photo yet`}
- + + `; + this.showModal(); + + const fileInput = document.getElementById('modalPhotoInput'); + const submitBtn = document.getElementById('uploadSubmitBtn'); + const preview = document.getElementById('uploadPreview'); + const previewImg = document.getElementById('previewImg'); + const form = document.getElementById('photoUploadForm'); + + fileInput.addEventListener('change', (e) => { + const file = e.target.files[0]; + if (file) { + submitBtn.disabled = false; + // Show preview + const reader = new FileReader(); + reader.onload = (ev) => { + previewImg.src = ev.target.result; + preview.style.display = 'block'; + }; + reader.readAsDataURL(file); + } + }); + + form.addEventListener('submit', async (e) => { + e.preventDefault(); + const file = fileInput.files[0]; + if (!file) return; + + submitBtn.disabled = true; + submitBtn.textContent = 'Uploading...'; + + try { + const formData = new FormData(); + formData.append('photo', file); + formData.append('ItemID', dbId); + + const response = await fetch(`${this.config.apiBaseUrl}/menu/uploadItemPhoto.cfm`, { + method: 'POST', + body: formData, + credentials: 'include' + }); + + const data = await response.json(); + if (data.OK) { + // Update the item + const itemIdVal = document.getElementById('uploadItemId').value; + for (const cat of this.menu.categories) { + const item = cat.items.find(i => i.id === itemIdVal); + if (item) { + item.imageUrl = data.IMAGEURL + '?t=' + Date.now(); + break; + } + } + this.closeModal(); + this.render(); + this.toast('Photo uploaded!', 'success'); + } else { + alert('Upload failed: ' + (data.MESSAGE || data.ERROR || 'Unknown error')); + submitBtn.disabled = false; + submitBtn.textContent = 'Upload Photo'; + } + } catch (err) { + console.error('Upload error:', err); + alert('Upload failed: ' + err.message); + submitBtn.disabled = false; + submitBtn.textContent = 'Upload Photo'; + } + }); + }, + // Pending photo upload info (for mobile camera flow) _pendingPhotoUpload: null, - // Upload photo - mobile-friendly version + // Upload photo - legacy version (kept for compatibility) uploadPhoto(itemId) { // Find the item and check it has a database ID let targetItem = null;