"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { Card, CardHeader, CardContent } from "@/components/ui/Card"; import Button from "@/components/ui/Button"; import Badge from "@/components/ui/Badge"; import PageContainer from "@/components/ui/PageContainer"; import PageHeader from "@/components/ui/PageHeader"; import { LoadingState } from "@/components/ui/States"; import { formatDate } from "@/lib/utils"; import { useTranslation } from "@/lib/i18n"; import { format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, addDays, isSameMonth, isSameDay, addMonths, subMonths, parseISO, isAfter, isBefore, startOfDay, addWeeks } from "date-fns"; import { pl } from "date-fns/locale"; const statusColors = { registered: "bg-blue-100 text-blue-800", approved: "bg-green-100 text-green-800", pending: "bg-yellow-100 text-yellow-800", in_progress: "bg-orange-100 text-orange-800", in_progress_design: "bg-purple-100 text-purple-800", in_progress_construction: "bg-indigo-100 text-indigo-800", fulfilled: "bg-gray-100 text-gray-800", cancelled: "bg-red-100 text-red-800", }; const getStatusTranslation = (status) => { const translations = { registered: "Zarejestrowany", approved: "Zatwierdzony", pending: "Oczekujący", in_progress: "W trakcie", in_progress_design: "W realizacji (projektowanie)", in_progress_construction: "W realizacji (realizacja)", fulfilled: "Zakończony", cancelled: "Wycofany", }; return translations[status] || status; }; export default function ProjectCalendarPage() { const { t } = useTranslation(); const [projects, setProjects] = useState([]); const [loading, setLoading] = useState(true); const [currentDate, setCurrentDate] = useState(new Date()); const [viewMode, setViewMode] = useState('month'); // 'month' or 'upcoming' const [downloading, setDownloading] = useState(false); useEffect(() => { fetch("/api/projects") .then((res) => res.json()) .then((data) => { // Filter projects that have finish dates and are not fulfilled const projectsWithDates = data.filter(p => p.finish_date && p.project_status !== 'fulfilled' ); setProjects(projectsWithDates); setLoading(false); }) .catch((error) => { console.error("Error fetching projects:", error); setLoading(false); }); }, []); const getProjectsForDate = (date) => { return projects.filter(project => { if (!project.finish_date) return false; try { const projectDate = parseISO(project.finish_date); return isSameDay(projectDate, date); } catch (error) { return false; } }); }; const getUpcomingProjects = () => { const today = startOfDay(new Date()); const nextMonth = addWeeks(today, 5); // Next 5 weeks return projects .filter(project => { if (!project.finish_date) return false; try { const projectDate = parseISO(project.finish_date); return isAfter(projectDate, today) && isBefore(projectDate, nextMonth); } catch (error) { return false; } }) .sort((a, b) => { const dateA = parseISO(a.finish_date); const dateB = parseISO(b.finish_date); return dateA - dateB; }); }; const getOverdueProjects = () => { const today = startOfDay(new Date()); return projects .filter(project => { if (!project.finish_date) return false; try { const projectDate = parseISO(project.finish_date); return isBefore(projectDate, today); } catch (error) { return false; } }) .sort((a, b) => { const dateA = parseISO(a.finish_date); const dateB = parseISO(b.finish_date); return dateB - dateA; // Most recently overdue first }); }; const handleDownloadReport = async () => { setDownloading(true); try { const response = await fetch('/api/reports/upcoming-projects'); if (!response.ok) { throw new Error('Failed to download report'); } // Get the blob from the response const blob = await response.blob(); // Create a download link const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `nadchodzace_projekty_${new Date().toISOString().split('T')[0]}.xlsx`; document.body.appendChild(link); link.click(); // Clean up document.body.removeChild(link); window.URL.revokeObjectURL(url); } catch (error) { console.error('Error downloading report:', error); alert('Błąd podczas pobierania raportu'); } finally { setDownloading(false); } }; const renderCalendarGrid = () => { const monthStart = startOfMonth(currentDate); const monthEnd = endOfMonth(currentDate); const calendarStart = startOfWeek(monthStart, { weekStartsOn: 1 }); const calendarEnd = endOfWeek(monthEnd, { weekStartsOn: 1 }); const days = []; let day = calendarStart; while (day <= calendarEnd) { days.push(day); day = addDays(day, 1); } const weekdays = ['Pon', 'Wt', 'Śr', 'Czw', 'Pt', 'Sob', 'Nie']; return (
{/* Calendar Header */}

{format(currentDate, 'LLLL yyyy', { locale: pl })}

{/* Weekday Headers */}
{weekdays.map(weekday => (
{weekday}
))}
{/* Calendar Grid */}
{days.map((day, index) => { const dayProjects = getProjectsForDate(day); const isCurrentMonth = isSameMonth(day, currentDate); const isToday = isSameDay(day, new Date()); return (
{format(day, 'd')}
{dayProjects.length > 0 && (
{dayProjects.slice(0, 3).map(project => (
{project.project_name}
))} {dayProjects.length > 3 && (
+{dayProjects.length - 3} więcej
{dayProjects.slice(3).map(project => (
{project.project_name}
))}
)}
)}
); })}
); }; const renderUpcomingView = () => { const upcomingProjects = getUpcomingProjects().filter(project => project.project_status !== 'cancelled'); const overdueProjects = getOverdueProjects().filter(project => project.project_status !== 'cancelled'); return (
{/* Upcoming Projects */}

Nadchodzące terminy ({upcomingProjects.length})

{upcomingProjects.length > 0 ? (
{upcomingProjects.map(project => { const daysUntilDeadline = Math.ceil((parseISO(project.finish_date) - new Date()) / (1000 * 60 * 60 * 24)); return (
{project.project_name}
{project.customer && `${project.customer} • `} {project.address}
{formatDate(project.finish_date)}
za {daysUntilDeadline} dni
{getStatusTranslation(project.project_status) || project.project_status}
); })}
) : (

Brak nadchodzących projektów w następnych 4 tygodniach

)}
{/* Overdue Projects */} {overdueProjects.length > 0 && (

Projekty przeterminowane ({overdueProjects.length})

{overdueProjects.map(project => (
{project.project_name}
{project.customer && `${project.customer} • `} {project.address}
{formatDate(project.finish_date)}
{getStatusTranslation(project.project_status) || project.project_status}
))}
)}
); }; if (loading) { return ; } return (
{viewMode === 'month' ? renderCalendarGrid() : renderUpcomingView()}
); }