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 <noreply@anthropic.com>
This commit is contained in:
parent
cab561a20e
commit
946c2ebdf0
1 changed files with 100 additions and 2 deletions
|
|
@ -1753,7 +1753,7 @@
|
||||||
`<span>No photo yet</span>`}
|
`<span>No photo yet</span>`}
|
||||||
</div>
|
</div>
|
||||||
<div class="photo-actions">
|
<div class="photo-actions">
|
||||||
<button class="btn btn-secondary" onclick="MenuBuilder.uploadPhoto('${item.id}')">
|
<button class="btn btn-secondary" onclick="MenuBuilder.showUploadModal('${item.id}', '${item.dbId || ''}')">
|
||||||
Upload
|
Upload
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary" onclick="MenuBuilder.createPhotoTask('${item.id}')">
|
<button class="btn btn-secondary" onclick="MenuBuilder.createPhotoTask('${item.id}')">
|
||||||
|
|
@ -2804,10 +2804,108 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Show upload modal - works better on mobile
|
||||||
|
showUploadModal(itemId, dbId) {
|
||||||
|
if (!dbId) {
|
||||||
|
alert('Please save the menu first before uploading photos.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('modalTitle').textContent = 'Upload Item Photo';
|
||||||
|
document.getElementById('modalBody').innerHTML = `
|
||||||
|
<form id="photoUploadForm" enctype="multipart/form-data" style="text-align: center;">
|
||||||
|
<input type="hidden" name="ItemID" value="${dbId}">
|
||||||
|
<input type="hidden" id="uploadItemId" value="${itemId}">
|
||||||
|
<p style="color: var(--gray-600); margin-bottom: 16px;">
|
||||||
|
Select or take a photo for this item
|
||||||
|
</p>
|
||||||
|
<div style="margin-bottom: 16px;">
|
||||||
|
<input type="file" name="photo" id="modalPhotoInput" accept="image/*"
|
||||||
|
style="font-size: 16px; padding: 12px; border: 2px dashed var(--gray-300);
|
||||||
|
border-radius: 8px; width: 100%; cursor: pointer;">
|
||||||
|
</div>
|
||||||
|
<div id="uploadPreview" style="margin-bottom: 16px; display: none;">
|
||||||
|
<img id="previewImg" style="max-width: 100%; max-height: 200px; border-radius: 8px;">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary" id="uploadSubmitBtn" disabled
|
||||||
|
style="width: 100%; padding: 12px;">
|
||||||
|
Upload Photo
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
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)
|
// Pending photo upload info (for mobile camera flow)
|
||||||
_pendingPhotoUpload: null,
|
_pendingPhotoUpload: null,
|
||||||
|
|
||||||
// Upload photo - mobile-friendly version
|
// Upload photo - legacy version (kept for compatibility)
|
||||||
uploadPhoto(itemId) {
|
uploadPhoto(itemId) {
|
||||||
// Find the item and check it has a database ID
|
// Find the item and check it has a database ID
|
||||||
let targetItem = null;
|
let targetItem = null;
|
||||||
|
|
|
||||||
Reference in a new issue