feat: Implement file upload and management features in ProjectViewPage

This commit is contained in:
2025-09-24 21:55:44 +02:00
parent 0f451555d3
commit 96333ecced
7 changed files with 490 additions and 15 deletions

View File

@@ -16,6 +16,8 @@ import PageContainer from "@/components/ui/PageContainer";
import PageHeader from "@/components/ui/PageHeader";
import ProjectStatusDropdown from "@/components/ProjectStatusDropdown";
import ClientProjectMap from "@/components/ui/ClientProjectMap";
import FileUploadBox from "@/components/FileUploadBox";
import FileItem from "@/components/FileItem";
export default function ProjectViewPage() {
const params = useParams();
@@ -23,6 +25,7 @@ export default function ProjectViewPage() {
const [project, setProject] = useState(null);
const [notes, setNotes] = useState([]);
const [loading, setLoading] = useState(true);
const [uploadedFiles, setUploadedFiles] = useState([]);
// Helper function to add a new note to the list
const addNote = (newNote) => {
@@ -40,6 +43,39 @@ export default function ProjectViewPage() {
return note.created_by === session.user.id;
};
// Helper function to handle file upload
const handleFileUploaded = (newFile) => {
setUploadedFiles(prevFiles => [newFile, ...prevFiles]);
};
// Helper function to handle file deletion
const handleFileDelete = async (fileId) => {
if (confirm('Czy na pewno chcesz usunąć ten plik?')) {
try {
const res = await fetch(`/api/files/${fileId}`, {
method: 'DELETE',
});
if (res.ok) {
setUploadedFiles(prevFiles => prevFiles.filter(file => file.file_id !== fileId));
} else {
alert('Błąd podczas usuwania pliku');
}
} catch (error) {
console.error('Error deleting file:', error);
alert('Błąd podczas usuwania pliku');
}
}
};
// Helper function to handle file update (edit)
const handleFileUpdate = async (updatedFile) => {
setUploadedFiles(prevFiles =>
prevFiles.map(file =>
file.file_id === updatedFile.file_id ? updatedFile : file
)
);
};
useEffect(() => {
const fetchData = async () => {
if (!params.id) return;
@@ -56,8 +92,13 @@ export default function ProjectViewPage() {
const notesRes = await fetch(`/api/notes?project_id=${params.id}`);
const notesData = notesRes.ok ? await notesRes.json() : [];
// Fetch files data
const filesRes = await fetch(`/api/files?entityType=project&entityId=${params.id}`);
const filesData = filesRes.ok ? await filesRes.json() : [];
setProject(projectData);
setNotes(notesData);
setUploadedFiles(filesData);
} catch (error) {
console.error('Error fetching data:', error);
setProject(null);
@@ -168,7 +209,7 @@ export default function ProjectViewPage() {
<Link href={`/projects/${params.id}/edit`} className="flex-1">
<Button variant="primary" size="sm" className="w-full text-xs">
<svg
className="w-4 h-4 mr-1"
className="w-4 h-4 mr-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
@@ -229,7 +270,7 @@ export default function ProjectViewPage() {
className="w-4 h-4 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
@@ -493,7 +534,7 @@ export default function ProjectViewPage() {
<Link href="/projects" className="block">
<Button
variant="outline"
size="sm"
size="sm"
className="w-full justify-start"
>
<svg
@@ -536,6 +577,31 @@ export default function ProjectViewPage() {
</Link>
</CardContent>
</Card>
{/* File Upload */}
<Card>
<CardHeader>
<h2 className="text-lg font-semibold text-gray-900">
Załączniki
</h2>
</CardHeader>
<CardContent className="space-y-4">
<FileUploadBox projectId={params.id} onFileUploaded={handleFileUploaded} />
{uploadedFiles.length > 0 && (
<div className="space-y-2">
<h3 className="text-sm font-medium text-gray-700">Przesłane pliki:</h3>
{uploadedFiles.map((file) => (
<FileItem
key={file.file_id}
file={file}
onDelete={handleFileDelete}
onUpdate={handleFileUpdate}
/>
))}
</div>
)}
</CardContent>
</Card>
</div>
</div>
{/* Project Location Map */}