Fix gallery login errors and photo upload issues
- Fix photo upload cross-device link error - Changed fs.rename to fs.copyFile + fs.unlink to handle Docker volume mounts - This fixes EXDEV errors when uploading photos from /tmp to storage - Improve gallery login error handling - Add console logging for debugging - Prevent form refresh with stopPropagation - Show specific error messages based on status codes - Keep password field populated on error for retry - Map 404 to gallery not found message - Enhanced upload error messages - Show specific error message for each failed file - Display backend error messages in toast notifications These fixes resolve: 1. Photo uploads failing silently with cross-device link errors 2. Login errors not displaying and form refreshing 3. Upload errors not showing user-friendly messages 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -63,7 +63,9 @@ async function processUploadedPhotos(files, eventId, uploadedBy = 'admin', categ
|
||||
await fs.mkdir(destPath, { recursive: true });
|
||||
|
||||
const newPath = path.join(destPath, newFilename);
|
||||
await fs.rename(file.path, newPath);
|
||||
// Use copyFile and unlink instead of rename to avoid cross-device issues
|
||||
await fs.copyFile(file.path, newPath);
|
||||
await fs.unlink(file.path);
|
||||
|
||||
// Generate thumbnail
|
||||
const thumbnailPath = await generateThumbnail(newPath);
|
||||
|
||||
@@ -78,9 +78,13 @@ export const UserPhotoUpload: React.FC<UserPhotoUploadProps> = ({
|
||||
},
|
||||
});
|
||||
successCount++;
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error(`Failed to upload ${file.name}:`, error);
|
||||
failedCount++;
|
||||
|
||||
// Show specific error message
|
||||
const errorMessage = error.response?.data?.error || error.message || 'Upload failed';
|
||||
toast.error(`${file.name}: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ export const GalleryPage: React.FC = () => {
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation(); // Prevent any bubbling
|
||||
|
||||
if (!password.trim()) {
|
||||
setLoginError(t('auth.pleaseEnterPassword'));
|
||||
return;
|
||||
@@ -66,13 +68,17 @@ export const GalleryPage: React.FC = () => {
|
||||
success: true
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('Login error:', error);
|
||||
const errorMessage = error.response?.data?.error || 'Invalid password';
|
||||
const statusCode = error.response?.status;
|
||||
|
||||
// Map backend error messages to user-friendly translations
|
||||
if (errorMessage.toLowerCase().includes('invalid password')) {
|
||||
if (statusCode === 401 || errorMessage.toLowerCase().includes('invalid password')) {
|
||||
setLoginError(t('auth.wrongPassword'));
|
||||
} else if (error.response?.status === 429 || errorMessage.toLowerCase().includes('too many')) {
|
||||
} else if (statusCode === 429 || errorMessage.toLowerCase().includes('too many')) {
|
||||
setLoginError(t('auth.tooManyAttempts'));
|
||||
} else if (statusCode === 404) {
|
||||
setLoginError(t('errors.galleryNotFound'));
|
||||
} else {
|
||||
setLoginError(t('auth.invalidPassword'));
|
||||
}
|
||||
@@ -80,8 +86,12 @@ export const GalleryPage: React.FC = () => {
|
||||
// Track failed password entry
|
||||
analyticsService.trackGalleryEvent('password_entry', {
|
||||
gallery: slug,
|
||||
success: false
|
||||
success: false,
|
||||
statusCode
|
||||
});
|
||||
|
||||
// Keep the password field to allow retry
|
||||
// Do not clear the password
|
||||
} finally {
|
||||
setIsLoggingIn(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user