"use client"; import { useState, useEffect } from "react"; import { useParams } from "next/navigation"; import { useSession } from "next-auth/react"; import NoteForm from "@/components/NoteForm"; import ProjectTasksSection from "@/components/ProjectTasksSection"; import FieldWithHistory from "@/components/FieldWithHistory"; import { Card, CardHeader, CardContent } from "@/components/ui/Card"; import Button from "@/components/ui/Button"; import Badge from "@/components/ui/Badge"; import Link from "next/link"; import { differenceInCalendarDays, parseISO } from "date-fns"; import { formatDate, formatCoordinates } from "@/lib/utils"; import PageContainer from "@/components/ui/PageContainer"; import PageHeader from "@/components/ui/PageHeader"; import ProjectStatusDropdown from "@/components/ProjectStatusDropdown"; import ProjectAssigneeDropdown from "@/components/ProjectAssigneeDropdown"; import ClientProjectMap from "@/components/ui/ClientProjectMap"; import FileUploadBox from "@/components/FileUploadBox"; import FileItem from "@/components/FileItem"; import proj4 from "proj4"; export default function ProjectViewPage() { const params = useParams(); const { data: session } = useSession(); const [project, setProject] = useState(null); const [notes, setNotes] = useState([]); const [loading, setLoading] = useState(true); const [uploadedFiles, setUploadedFiles] = useState([]); const [editingNoteId, setEditingNoteId] = useState(null); const [editText, setEditText] = useState(''); // Helper function to parse note text with links const parseNoteText = (text) => { const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g; const parts = []; let lastIndex = 0; let match; while ((match = linkRegex.exec(text)) !== null) { // Add text before the link if (match.index > lastIndex) { parts.push(text.slice(lastIndex, match.index)); } // Add the link parts.push( {match[1]} ); lastIndex = match.index + match[0].length; } // Add remaining text if (lastIndex < text.length) { parts.push(text.slice(lastIndex)); } return parts.length > 0 ? parts : text; }; // Helper function to add a new note to the list const addNote = (newNote) => { setNotes(prevNotes => [newNote, ...prevNotes]); }; // Helper function to check if user can modify a note (edit or delete) const canModifyNote = (note) => { if (!session?.user) return false; // Admins can modify any note if (session.user.role === 'admin') return true; // Users can modify their own notes 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 ) ); }; // Helper function to save edited note const handleSaveNote = async (noteId) => { try { const res = await fetch(`/api/notes/${noteId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ note: editText }), }); if (res.ok) { // Update the note in local state setNotes(prevNotes => prevNotes.map(note => note.note_id === noteId ? { ...note, note: editText, edited_at: new Date().toISOString() } : note ) ); setEditingNoteId(null); setEditText(''); } else { alert('Błąd podczas aktualizacji notatki'); } } catch (error) { console.error('Error updating note:', error); alert('Błąd podczas aktualizacji notatki'); } }; useEffect(() => { const fetchData = async () => { if (!params.id) return; try { // Fetch project data const projectRes = await fetch(`/api/projects/${params.id}`); if (!projectRes.ok) { throw new Error('Project not found'); } const projectData = await projectRes.json(); // Fetch notes data 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); setNotes([]); } finally { setLoading(false); } }; fetchData(); }, [params.id]); useEffect(() => { if (project?.project_name) { document.title = `${project.project_name} - Panel`; } else { document.title = 'Panel'; } }, [project]); if (loading) { return (
Loading...
); } if (!project) { return (

Projekt nie został znaleziony.

); } const daysRemaining = project.finish_date ? differenceInCalendarDays(parseISO(project.finish_date), new Date()) : null; const getDeadlineVariant = (days) => { if (days < 0) return "danger"; if (days <= 7) return "warning"; return "success"; }; return ( {/* Mobile: Full-width title, Desktop: Standard PageHeader */}
{/* Mobile Layout */}
{/* Full-width title */}

{project.project_name}

{project.city} • {project.address} • {project.project_number}

{/* Mobile action bar */}
{/* Status and deadline badges */}
{daysRemaining !== null && ( {daysRemaining === 0 ? "Termin dzisiaj" : daysRemaining > 0 ? `${daysRemaining} dni pozostało` : `${Math.abs(daysRemaining)} dni po terminie`} )}
{/* Action buttons - full width */}
{/* Desktop: Standard PageHeader */}
{daysRemaining !== null && ( {daysRemaining === 0 ? "Termin dzisiaj" : daysRemaining > 0 ? `${daysRemaining} dni pozostało` : `${Math.abs(daysRemaining)} dni po terminie`} )}
} />
{/* Main Project Information */}
{" "}

Informacje o projekcie

{project.project_type === "design" ? "Projektowanie (P)" : project.project_type === "construction" ? "Budowa (B)" : project.project_type === "design+construction" ? "Projektowanie + Budowa (P+B)" : "Nieznany"}
Lokalizacja

{project.city || "N/A"}

Adres

{project.address || "N/A"}

Działka

{project.plot || "N/A"}

Jednostka ewidencyjna

{project.district || "N/A"}

Obręb

{project.unit || "N/A"}

{" "} {project.completion_date && (
Data zakończenia projektu

{formatDate(project.completion_date)}

)}
WP

{project.wp || "N/A"}

Numer inwestycji

{project.investment_number || "N/A"}

{session?.user?.role === 'team_lead' && project.wartosc_zlecenia && ( )}
{project.contact && (
Kontakt

{project.contact}

)} {project.coordinates && (
Współrzędne
)} {project.notes && (
Notes

{project.notes}

)}
{/* Contract Details */}

Szczegóły umowy

Numer umowy

{project.contract_number || "N/A"}

Numer umowy klienta

{project.customer_contract_number ? ( {project.customer_contract_number} ) : ( "N/A" )}

Klient

{project.customer || "N/A"}

Inwestor

{project.investor || "N/A"}

{/* Status Sidebar */}

Status projektu

{" "}
Aktualny status
Przypisany do
{daysRemaining !== null && (
Harmonogram
{daysRemaining === 0 ? "Termin dzisiaj" : daysRemaining > 0 ? `${daysRemaining} dni pozostało` : `${Math.abs(daysRemaining)} dni po terminie`}
)}
{/* Quick Actions */}

Szybkie akcje

{" "}
{/* File Upload */}

Załączniki

{uploadedFiles.length > 0 && (

Przesłane pliki:

{uploadedFiles.map((file) => ( ))}
)}
{/* Project Location Map */} {project.coordinates && (
{" "} {" "}

Lokalizacja projektu

{project.coordinates && ( )}
)} {/* Project Tasks Section */}
{/* Notes Section */}

Notatki

{notes.length === 0 ? (

Brak notatek

Dodaj swoją pierwszą notatkę używając formularza powyżej.

) : (
{notes.map((n) => (
{formatDate(n.note_date, { includeTime: true })} {n.created_by_name && ( {n.created_by_name} )} {n.edited_at && ( • edytowane )}
{canModifyNote(n) && (
)}
{editingNoteId === n.note_id ? (