fix: Switch to base64 photo upload for compatibility
Some checks failed
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled

The MinIO/Sharp approach doesn't work on the current server CPU architecture.
Switched to simple base64 encoding for photo uploads.

Changes:
- PhotoUpload component converts images to base64 data URLs
- 5MB file size limit
- Works on all platforms without external dependencies
- Stores photos directly in database (photoUrl field)

This is a temporary solution. For production scalability, we can:
- Upgrade server CPU to support Sharp
- Build Sharp from source
- Use Docker with prebuilt Sharp binaries
- Migrate to a proper CDN/object storage later

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-04 08:40:02 +00:00
parent 9c4bc1b90f
commit f6c1483a36
2 changed files with 23 additions and 25 deletions

View File

@@ -12,7 +12,6 @@ import {
CircularProgress, CircularProgress,
} from '@mui/material'; } from '@mui/material';
import { PhotoCamera, Person } from '@mui/icons-material'; import { PhotoCamera, Person } from '@mui/icons-material';
import { photosApi } from '@/lib/api/photos';
interface PhotoUploadProps { interface PhotoUploadProps {
value: string; value: string;
@@ -20,8 +19,6 @@ interface PhotoUploadProps {
label: string; label: string;
disabled?: boolean; disabled?: boolean;
size?: number; size?: number;
childId?: string;
type?: string;
} }
export function PhotoUpload({ export function PhotoUpload({
@@ -29,9 +26,7 @@ export function PhotoUpload({
onChange, onChange,
label, label,
disabled = false, disabled = false,
size = 100, size = 100
childId,
type = 'profile'
}: PhotoUploadProps) { }: PhotoUploadProps) {
const [imageError, setImageError] = useState(false); const [imageError, setImageError] = useState(false);
const [uploadError, setUploadError] = useState<string>(''); const [uploadError, setUploadError] = useState<string>('');
@@ -56,10 +51,10 @@ export function PhotoUpload({
return; return;
} }
// Validate file size (max 10MB - backend limit) // Validate file size (max 5MB for base64)
const maxSize = 10 * 1024 * 1024; // 10MB const maxSize = 5 * 1024 * 1024; // 5MB
if (file.size > maxSize) { if (file.size > maxSize) {
setUploadError('Image size must be less than 10MB'); setUploadError('Image size must be less than 5MB');
return; return;
} }
@@ -67,21 +62,24 @@ export function PhotoUpload({
setUploading(true); setUploading(true);
setUploadError(''); setUploadError('');
// Upload to backend - it handles Sharp optimization and MinIO storage // Convert to base64 (simple, works everywhere)
const result = await photosApi.uploadPhoto(file, { const reader = new FileReader();
childId, reader.onload = (e) => {
type, const base64String = e.target?.result as string;
}); onChange(base64String);
setUploading(false);
// Use the optimized URL from backend setImageError(false);
onChange(result.photo.url); };
setImageError(false); reader.onerror = () => {
setUploadError('Failed to read image file');
setUploading(false);
};
reader.readAsDataURL(file);
} catch (error: any) { } catch (error: any) {
console.error('Photo upload failed:', error); console.error('Photo processing failed:', error);
setUploadError(error.response?.data?.message || 'Failed to upload photo'); setUploadError('Failed to process photo');
} finally {
setUploading(false); setUploading(false);
} finally {
// Reset input // Reset input
if (fileInputRef.current) { if (fileInputRef.current) {
fileInputRef.current.value = ''; fileInputRef.current.value = '';
@@ -177,8 +175,8 @@ export function PhotoUpload({
disabled={disabled || uploading} disabled={disabled || uploading}
helperText={ helperText={
uploading uploading
? 'Uploading and optimizing image...' ? 'Processing image...'
: 'Click camera to upload (auto-optimized) or paste URL' : 'Click camera to upload or paste an image URL'
} }
/> />
</Paper> </Paper>

File diff suppressed because one or more lines are too long