174 lines
6.7 KiB
JavaScript
174 lines
6.7 KiB
JavaScript
import { useState, useEffect } from 'react';
|
|
import './MediaGallery.css';
|
|
|
|
function MediaGallery({ kaNumber, token, onInsertMedia, isOpen, onToggle }) {
|
|
const [media, setMedia] = useState([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [uploading, setUploading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
useEffect(() => {
|
|
fetchMedia();
|
|
}, [kaNumber, isOpen]);
|
|
|
|
const fetchMedia = async () => {
|
|
try {
|
|
const response = await fetch(`http://localhost:9000/api/articles/${kaNumber}/media`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setMedia(data);
|
|
} else {
|
|
setError('Failed to fetch media');
|
|
}
|
|
} catch(err) {
|
|
console.error('Error fetching media:', err);
|
|
setError('Failed to load media');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleFileUpload = async (e) => {
|
|
const file = e.target.files[0];
|
|
if (!file) return;
|
|
|
|
setUploading(true);
|
|
setError('');
|
|
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
try {
|
|
const response = await fetch(`/api/articles/${kaNumber}/media`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
},
|
|
body: formData
|
|
});
|
|
|
|
if (response.ok) {
|
|
const newMedia = await response.json();
|
|
setMedia([...media, newMedia]);
|
|
} else {
|
|
const data = await response.json();
|
|
setError(data.error || 'Upload failed');
|
|
}
|
|
} catch(err) {
|
|
console.error('Failed to upload file:', err);
|
|
setError('Failed to upload file');
|
|
} finally {
|
|
setUploading(false);
|
|
e.target.value = '';
|
|
}
|
|
}
|
|
|
|
const handleDelete = async (filename) => {
|
|
if (!confirm('Are you sure you want to delete this file?')) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/articles/${kaNumber}/media/${filename}`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
setMedia(media.filter(m => m.filename !== filename));
|
|
} else {
|
|
alert('Failed to delete file');
|
|
}
|
|
} catch(err) {
|
|
console.error('Error deleting file:', err);
|
|
alert('Failed to delete file');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<button className={`drawer-toggle ${isOpen ? 'open' : ''}`} onClick={onToggle}>
|
|
<span className='toggle-icon'>{isOpen ? '▼' : '▲'}</span>
|
|
<span className='toggle-text'>Media Gallery</span>
|
|
{media.length > 0 && <span className='media-count'>{media.length}</span>}
|
|
</button>
|
|
|
|
<div className={`media-drawer ${isOpen ? 'open' : ''}`}>
|
|
<div className='drawer-handle' onClick={onToggle}>
|
|
<div className='handle-bar'></div>
|
|
</div>
|
|
|
|
<div className='drawer-content'>
|
|
<div className='gallery-header'>
|
|
<h3>Media Gallery - {kaNumber}</h3>
|
|
<label className='btn btn-success'>
|
|
<input
|
|
type='file'
|
|
onChange={handleFileUpload}
|
|
accept='image/*, video/*'
|
|
disabled={uploading}
|
|
style={{display: 'none'}}
|
|
/>
|
|
{uploading ? 'Uploading...' : '+ Upload Media'}
|
|
</label>
|
|
</div>
|
|
|
|
{error && <div className='error-message'>{error}</div>}
|
|
|
|
{loading ? (
|
|
<div className='loading-container'>
|
|
<div className='loading-spinner'></div>
|
|
<div className='loading-text'>Loading media...</div>
|
|
</div>
|
|
) : media.length === 0 ? (
|
|
<div className='empty-state'>
|
|
<div className='empty-state-icon'>📷</div>
|
|
<h3 className='empty-state-title'>No Media Yet</h3>
|
|
<p className='empty-state-description'>
|
|
Click "Upload Media" to add images or videos to this article.
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className='media-grid'>
|
|
{media.map(item => (
|
|
<div key={item.filename} className='media-item'>
|
|
{item.type === 'image' ? (
|
|
<img
|
|
src={`${item.url}`}
|
|
alt={item.filename}
|
|
onClick={() => onInsertMedia(item)}
|
|
/>
|
|
) : (
|
|
<div className='video-thumbnail' onClick={() => onInsertMedia(item)}>
|
|
<span className='video-icon'>🎥</span>
|
|
<span className='video-label'>Video</span>
|
|
</div>
|
|
)}
|
|
|
|
<div className='btn-group gap-sm'>
|
|
<button
|
|
className='btn btn-primary btn-sm'
|
|
onClick={() => onInsertMedia(item)}
|
|
>Insert</button>
|
|
<button
|
|
className='btn btn-danger btn-sm'
|
|
onClick={() => handleDelete(item.filename)}
|
|
>Delete</button>
|
|
</div>
|
|
<div className='media-filename'>{item.filename}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default MediaGallery; |