mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 17:11:09 -05:00
- Added functions for checking user privileges, handling photo uploads, preparing form data, and managing form errors. - Created views for listing, creating, updating, and displaying rides, including category-specific views. - Integrated submission handling for ride changes and improved user feedback through messages. - Enhanced data handling with appropriate context and queryset management for better performance and usability.
92 lines
3.1 KiB
JavaScript
92 lines
3.1 KiB
JavaScript
document.addEventListener('alpine:init', () => {
|
|
Alpine.data('photoDisplay', ({ photos, contentType, objectId, csrfToken, uploadUrl }) => ({
|
|
photos,
|
|
fullscreenPhoto: null,
|
|
uploading: false,
|
|
uploadProgress: 0,
|
|
error: null,
|
|
showSuccess: false,
|
|
|
|
showFullscreen(photo) {
|
|
this.fullscreenPhoto = photo;
|
|
},
|
|
|
|
async handleFileSelect(event) {
|
|
const files = Array.from(event.target.files);
|
|
if (!files.length) {
|
|
return;
|
|
}
|
|
|
|
this.uploading = true;
|
|
this.uploadProgress = 0;
|
|
this.error = null;
|
|
this.showSuccess = false;
|
|
|
|
const totalFiles = files.length;
|
|
let completedFiles = 0;
|
|
|
|
for (const file of files) {
|
|
const formData = new FormData();
|
|
formData.append('image', file);
|
|
formData.append('app_label', contentType.split('.')[0]);
|
|
formData.append('model', contentType.split('.')[1]);
|
|
formData.append('object_id', objectId);
|
|
|
|
try {
|
|
const response = await fetch(uploadUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': csrfToken,
|
|
},
|
|
body: formData
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const data = await response.json();
|
|
throw new Error(data.error || 'Upload failed');
|
|
}
|
|
|
|
const photo = await response.json();
|
|
this.photos.push(photo);
|
|
completedFiles++;
|
|
this.uploadProgress = (completedFiles / totalFiles) * 100;
|
|
} catch (err) {
|
|
this.error = err.message || 'Failed to upload photo. Please try again.';
|
|
console.error('Upload error:', err);
|
|
break;
|
|
}
|
|
}
|
|
|
|
this.uploading = false;
|
|
event.target.value = ''; // Reset file input
|
|
|
|
if (!this.error) {
|
|
this.showSuccess = true;
|
|
setTimeout(() => {
|
|
this.showSuccess = false;
|
|
}, 3000);
|
|
}
|
|
},
|
|
|
|
async sharePhoto(photo) {
|
|
if (navigator.share) {
|
|
try {
|
|
await navigator.share({
|
|
title: photo.caption || 'Shared photo',
|
|
url: photo.url
|
|
});
|
|
} catch (err) {
|
|
if (err.name !== 'AbortError') {
|
|
console.error('Error sharing:', err);
|
|
}
|
|
}
|
|
} else {
|
|
// Fallback: copy URL to clipboard
|
|
navigator.clipboard.writeText(photo.url)
|
|
.then(() => alert('Photo URL copied to clipboard!'))
|
|
.catch(err => console.error('Error copying to clipboard:', err));
|
|
}
|
|
}
|
|
}));
|
|
});
|