feat: Complete hybrid image upload system with URL compatibility
- Add hybrid image system supporting both file uploads and URL images - Implement Active Storage for file uploads while preserving existing URL functionality - Update Event model with both has_one_attached :image and image_url virtual attribute - Create tabbed interface in event forms for upload/URL selection - Add JavaScript preview functionality for both upload and URL inputs - Fix promotion code validation issue in tests using distinct() to prevent duplicates - Update all views to use hybrid display methods prioritizing uploads over URLs - Update seeds file to use image_url attribute for compatibility - Ensure backward compatibility with existing events using URL images 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -687,8 +687,8 @@ export default class extends Controller {
|
||||
// Show preview
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
const previewContainer = document.getElementById('image-preview')
|
||||
const previewImg = document.getElementById('preview-img')
|
||||
const previewContainer = document.getElementById('upload-preview')
|
||||
const previewImg = document.getElementById('upload-preview-img')
|
||||
|
||||
if (previewContainer && previewImg) {
|
||||
previewImg.src = e.target.result
|
||||
@@ -697,4 +697,54 @@ export default class extends Controller {
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
// Preview image from URL
|
||||
previewImageUrl(event) {
|
||||
const url = event.target.value.trim()
|
||||
const previewContainer = document.getElementById('url-preview')
|
||||
const previewImg = document.getElementById('url-preview-img')
|
||||
|
||||
if (!url) {
|
||||
if (previewContainer) {
|
||||
previewContainer.classList.add('hidden')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Basic URL validation
|
||||
if (!this.isValidImageUrl(url)) {
|
||||
if (previewContainer) {
|
||||
previewContainer.classList.add('hidden')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Show preview with error handling
|
||||
if (previewImg) {
|
||||
previewImg.onload = () => {
|
||||
if (previewContainer) {
|
||||
previewContainer.classList.remove('hidden')
|
||||
}
|
||||
}
|
||||
|
||||
previewImg.onerror = () => {
|
||||
if (previewContainer) {
|
||||
previewContainer.classList.add('hidden')
|
||||
}
|
||||
}
|
||||
|
||||
previewImg.src = url
|
||||
}
|
||||
}
|
||||
|
||||
// Validate image URL format
|
||||
isValidImageUrl(url) {
|
||||
try {
|
||||
new URL(url)
|
||||
// Check if it looks like an image URL
|
||||
return /\.(jpg|jpeg|png|gif|webp)(\?.*)?$/i.test(url)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user