"use client"; import { completeProjectRecord, createProjectPlanningSectionRecord, deleteProjectPlanningSectionRecord, updateProjectPlanningSectionRecord, } from "@/app/(dashboard)/projects/actions"; import { createTaskRecord, updateTaskStatusRecord, } from "@/app/(dashboard)/tasks/actions"; import { PendingLink } from "@/components/ui/pending-link"; import { PendingSubmitButton } from "@/components/ui/pending-submit-button"; import { Badge, Button, Card, CardContent, Input, Label, Textarea } from "poyraz-ui/atoms"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "poyraz-ui/molecules"; import { ArrowLeft, CalendarDays, CheckCircle2, ClipboardList, FileText, FolderKanban, KanbanSquare, LayoutList, Loader2, Palette, Pencil, Plus, Settings2, Target, Trash2, Wallet, } from "lucide-react"; import Image from "next/image"; import { useState, useTransition, type DragEvent } from "react"; export type ProjectDetail = { id: string; client_id: string | null; clientName: string | null; name: string; type: "client_project" | "side_project"; description: string | null; status: "planning" | "active" | "paused" | "completed" | "cancelled"; start_date: string | null; due_date: string | null; budget_amount: number | null; currency: string; progress: number; progress_type: "manual" | "auto"; revision_quota: number; cover_image_alt: string | null; coverImageUrl: string | null; }; export type ProjectPlanningSectionItem = { id: string; project_id: string; category: | "overview" | "problem" | "goal" | "audience" | "scope" | "design_system" | "color_palette" | "typography" | "assets" | "notes"; title: string; content: string | null; sort_order: number; }; export type ProjectDetailTaskItem = { id: string; title: string; status: "todo" | "in_progress" | "done"; priority: "low" | "medium" | "high" | "urgent"; due_at: string | null; is_public_to_client: boolean; }; export type ProjectFinanceItem = { id: string; type: "income" | "expense"; amount: number; currency: string; payment_status: "planned" | "pending" | "paid" | "cancelled"; transaction_date: string; category: string | null; }; export type ProjectRevisionItem = { id: string; description: string; status: "pending" | "in_progress" | "completed" | "rejected"; created_at: string; requested_by: string; }; type ProjectDetailClientProps = { project: ProjectDetail; sections: ProjectPlanningSectionItem[]; tasks: ProjectDetailTaskItem[]; financeTransactions: ProjectFinanceItem[]; revisions: ProjectRevisionItem[]; }; const typeLabels = { client_project: "Müşteri projesi", side_project: "Side project", }; const statusLabels = { planning: "Planlama", active: "Aktif", paused: "Duraklatıldı", completed: "Tamamlandı", cancelled: "İptal edildi", }; const statusClasses = { planning: "border-blue-200 bg-blue-50 text-blue-700", active: "border-emerald-200 bg-emerald-50 text-emerald-700", paused: "border-amber-200 bg-amber-50 text-amber-700", completed: "border-zinc-200 bg-zinc-50 text-zinc-700", cancelled: "border-rose-200 bg-rose-50 text-rose-700", }; const priorityClasses = { low: "border-zinc-200 bg-zinc-50 text-zinc-700", medium: "border-blue-200 bg-blue-50 text-blue-700", high: "border-amber-200 bg-amber-50 text-amber-700", urgent: "border-rose-200 bg-rose-50 text-rose-700", }; const sectionLabels: Record = { overview: "Genel bakış", problem: "Çözdüğü problem", goal: "Amaç", audience: "Hedef kitle", scope: "Kapsam", design_system: "Design system", color_palette: "Renk paleti", typography: "Tipografi", assets: "Görsel varlıklar", notes: "Notlar", }; const planningCategories: ProjectPlanningSectionItem["category"][] = [ "overview", "problem", "goal", "audience", "scope", "notes", ]; const designCategories: ProjectPlanningSectionItem["category"][] = [ "design_system", "color_palette", "typography", "assets", ]; export function ProjectDetailClient({ project, sections, tasks, financeTransactions, revisions, }: ProjectDetailClientProps) { const [activeTab, setActiveTab] = useState<"planning" | "design" | "tasks" | "finance" | "revisions">( "planning", ); const planningSections = sections.filter((section) => planningCategories.includes(section.category), ); const designSections = sections.filter((section) => designCategories.includes(section.category), ); const doneTaskCount = tasks.filter((task) => task.status === "done").length; const incomeTotal = financeTransactions .filter((transaction) => transaction.type === "income") .reduce((sum, transaction) => sum + transaction.amount, 0); const expenseTotal = financeTransactions .filter((transaction) => transaction.type === "expense") .reduce((sum, transaction) => sum + transaction.amount, 0); return (

{project.name}

{statusLabels[project.status]}
{project.status !== "completed" ? (
} pendingChildren="Tamamlanıyor" > Tamamla
) : null}
{project.coverImageUrl ? (
{project.cover_image_alt
) : (
Kapak görseli yok
)}
setActiveTab("planning")}> Planlama setActiveTab("design")}> Design system setActiveTab("tasks")}> Görevler setActiveTab("finance")}> Finans setActiveTab("revisions")}> Revizyonlar {revisions.filter(r => r.status === 'pending').length > 0 && ( {revisions.filter(r => r.status === 'pending').length} )}
{activeTab === "planning" ? ( ) : null} {activeTab === "design" ? ( ) : null} {activeTab === "tasks" ? ( ) : null} {activeTab === "finance" ? : null} {activeTab === "revisions" ? : null}
); } function RevisionsPanel({ projectId, revisions, }: { projectId: string; revisions: ProjectRevisionItem[]; }) { const [isUpdating, setIsUpdating] = useState(false); async function handleStatusChange( id: string, status: ProjectRevisionItem["status"], ) { setIsUpdating(true); try { const { updateRevisionStatus } = await import("@/app/(dashboard)/projects/actions"); await updateRevisionStatus(id, projectId, status); } catch (error) { toast.error( error instanceof Error ? error.message : "Revizyon durumu güncellenemedi.", ); } finally { setIsUpdating(false); } } return (

Müşteri Revizyon Talepleri

{revisions.length === 0 ? (

Bu proje için henüz bir revizyon talebi oluşturulmamış.

) : (
{revisions.map(rev => (
{new Date(rev.created_at).toLocaleString('tr-TR')}

{rev.description}

))}
)}
); } function SectionGrid({ projectId, title, description, sections, defaultCategory, }: { projectId: string; title: string; description: string; sections: ProjectPlanningSectionItem[]; defaultCategory: ProjectPlanningSectionItem["category"]; }) { return (

{title}

{description}

{sections.length > 0 ? (
{sections.map((section) => ( ))}
) : (

Henüz kayıt yok

Bu proje için ilk planlama veya design system alanını ekleyerek proje bilgisini görevlerden bağımsız hale getir.

)}
); } function PlanningSectionCard({ section }: { section: ProjectPlanningSectionItem }) { return (
{sectionLabels[section.category]}

{section.title}

} aria-label="Sil" />

{section.content || "İçerik eklenmedi."}

); } function SectionDialog({ projectId, mode, defaultCategory, section, }: { projectId: string; mode: "create" | "edit"; defaultCategory?: ProjectPlanningSectionItem["category"]; section?: ProjectPlanningSectionItem; }) { const [open, setOpen] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const action = mode === "create" ? createProjectPlanningSectionRecord : updateProjectPlanningSectionRecord; async function handleSubmit(formData: FormData) { setIsSubmitting(true); try { await action(formData); setOpen(false); } finally { setIsSubmitting(false); } } return (
{section ? : null} {mode === "create" ? "Planlama alanı ekle" : "Planlama alanını düzenle"} Projenin görev dışı bilgisini yapılandırılmış alanlarda sakla.