Refactor image processing and add image file serving functionality

- Updated image directory handling to prioritize mounted volume for persistence.
- Enhanced logging for directory write tests and fallback mechanisms.
- Introduced a new endpoint to serve image files directly from local paths.
- Added error handling for file serving, including checks for file existence and readability.
- Updated the frontend to include a new ContentView component and corresponding route.
This commit is contained in:
IGNY8 VPS (Salman)
2025-11-12 01:24:44 +00:00
parent 18505de848
commit 645c6f3f9e
8 changed files with 594 additions and 20 deletions

View File

@@ -0,0 +1,71 @@
/**
* ContentView Page - Displays individual content using ContentViewTemplate
* Route: /writer/content/:id
*/
import { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router';
import ContentViewTemplate from '../../templates/ContentViewTemplate';
import { fetchContentById, Content } from '../../services/api';
import { useToast } from '../../components/ui/toast/ToastContainer';
import PageMeta from '../../components/common/PageMeta';
export default function ContentView() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const toast = useToast();
const [content, setContent] = useState<Content | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadContent = async () => {
// Validate ID parameter - must be a number
if (!id) {
toast.error('Content ID is required');
navigate('/writer/content');
return;
}
const contentId = parseInt(id, 10);
if (isNaN(contentId) || contentId <= 0) {
toast.error('Invalid content ID');
navigate('/writer/content');
return;
}
setLoading(true);
try {
const data = await fetchContentById(contentId);
setContent(data);
} catch (error: any) {
console.error('Error loading content:', error);
toast.error(`Failed to load content: ${error.message || 'Unknown error'}`);
setContent(null);
} finally {
setLoading(false);
}
};
loadContent();
}, [id, navigate, toast]);
const handleBack = () => {
navigate('/writer/content');
};
return (
<>
<PageMeta
title={content ? `${content.meta_title || content.title || `Content #${content.id}`} - IGNY8` : 'Content View - IGNY8'}
description={content?.meta_description || 'View content details and metadata'}
/>
<ContentViewTemplate
content={content}
loading={loading}
onBack={handleBack}
/>
</>
);
}