355 lines
15 KiB
TypeScript
355 lines
15 KiB
TypeScript
import React from "react";
|
||
import { DashboardLayout } from "../layout";
|
||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||
import { Button } from "~/components/ui/button";
|
||
import { Badge } from "~/components/ui/badge";
|
||
import {
|
||
ArrowRight,
|
||
Calendar,
|
||
User,
|
||
Users,
|
||
DollarSign,
|
||
Clock,
|
||
FileText,
|
||
Edit,
|
||
Trash2,
|
||
} from "lucide-react";
|
||
|
||
interface ProjectDetailProps {
|
||
projectId: string;
|
||
}
|
||
|
||
// Mock project data
|
||
const mockProject = {
|
||
id: 1,
|
||
name: "پروژه توسعه اپلیکیشن موبایل",
|
||
manager: "علی احمدی",
|
||
team: "تیم توسعه موبایل",
|
||
status: "در حال انجام",
|
||
priority: "بالا",
|
||
startDate: "1403/01/15",
|
||
endDate: "1403/06/30",
|
||
budget: "500,000,000",
|
||
progress: 65,
|
||
description: "این پروژه شامل توسعه یک اپلیکیشن موبایل کراس پلتفرم برای مدیریت پروژهها و وظایف میباشد. اپلیکیشن باید قابلیتهای مختلفی از جمله مدیریت کاربران، گزارشگیری و نوتیفیکیشن را داشته باشد.",
|
||
teamMembers: [
|
||
{ id: 1, name: "علی احمدی", role: "مدیر پروژه", avatar: "AA" },
|
||
{ id: 2, name: "سارا کریمی", role: "توسعهدهنده فرانتاند", avatar: "SK" },
|
||
{ id: 3, name: "محمد رضایی", role: "توسعهدهنده بکاند", avatar: "MR" },
|
||
{ id: 4, name: "فاطمه موسوی", role: "طراح UI/UX", avatar: "FM" },
|
||
],
|
||
milestones: [
|
||
{ id: 1, title: "تحلیل نیازمندیها", status: "تکمیل شده", date: "1403/01/30" },
|
||
{ id: 2, title: "طراحی رابط کاربری", status: "تکمیل شده", date: "1403/02/15" },
|
||
{ id: 3, title: "توسعه بکاند", status: "در حال انجام", date: "1403/04/01" },
|
||
{ id: 4, title: "توسعه فرانتاند", status: "در حال انجام", date: "1403/05/01" },
|
||
{ id: 5, title: "تست و رفع باگ", status: "در انتظار", date: "1403/06/01" },
|
||
{ id: 6, title: "انتشار نهایی", status: "در انتظار", date: "1403/06/30" },
|
||
],
|
||
tasks: [
|
||
{ id: 1, title: "پیادهسازی سیستم احراز هویت", assignee: "محمد رضایی", status: "در حال انجام", priority: "بالا" },
|
||
{ id: 2, title: "طراحی صفحه داشبورد", assignee: "سارا کریمی", status: "تکمیل شده", priority: "متوسط" },
|
||
{ id: 3, title: "توسعه API گزارشگیری", assignee: "محمد رضایی", status: "در انتظار", priority: "بالا" },
|
||
{ id: 4, title: "طراحی آیکونهای اپلیکیشن", assignee: "فاطمه موسوی", status: "در حال انجام", priority: "پایین" },
|
||
],
|
||
};
|
||
|
||
const statusColors = {
|
||
"در حال انجام": "info",
|
||
"تکمیل شده": "success",
|
||
"در انتظار": "warning",
|
||
"لغو شده": "destructive",
|
||
} as const;
|
||
|
||
const priorityColors = {
|
||
"بالا": "destructive",
|
||
"متوسط": "warning",
|
||
"پایین": "secondary",
|
||
} as const;
|
||
|
||
export function ProjectDetail({ projectId }: ProjectDetailProps) {
|
||
const project = mockProject; // In real app, fetch by projectId
|
||
|
||
return (
|
||
<DashboardLayout>
|
||
<div className="p-6 space-y-6">
|
||
{/* Breadcrumb */}
|
||
<div className="flex items-center space-x-2 text-sm text-gray-500 dark:text-gray-400">
|
||
<Button variant="ghost" size="sm" className="font-persian p-0 h-auto">
|
||
پروژهها
|
||
</Button>
|
||
<ArrowRight className="w-4 h-4" />
|
||
<span className="font-persian text-gray-900 dark:text-white">
|
||
جزئیات پروژه
|
||
</span>
|
||
</div>
|
||
|
||
{/* Project Header */}
|
||
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4">
|
||
<div>
|
||
<h1 className="text-3xl font-bold text-gray-900 dark:text-white font-persian">
|
||
{project.name}
|
||
</h1>
|
||
<p className="text-gray-600 dark:text-gray-400 font-persian mt-2">
|
||
{project.description}
|
||
</p>
|
||
</div>
|
||
|
||
<div className="flex gap-2">
|
||
<Button variant="outline" className="font-persian">
|
||
<Edit className="w-4 h-4 ml-2" />
|
||
ویرایش پروژه
|
||
</Button>
|
||
<Button variant="destructive" className="font-persian">
|
||
<Trash2 className="w-4 h-4 ml-2" />
|
||
حذف پروژه
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Project Stats */}
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||
<Card>
|
||
<CardContent className="p-4">
|
||
<div className="flex items-center space-x-2">
|
||
<div className="p-2 bg-blue-100 rounded-lg dark:bg-blue-900">
|
||
<Calendar className="w-5 h-5 text-blue-600 dark:text-blue-400" />
|
||
</div>
|
||
<div className="flex-1 text-right">
|
||
<p className="text-sm text-gray-600 dark:text-gray-400 font-persian">تاریخ شروع</p>
|
||
<p className="text-lg font-bold text-gray-900 dark:text-white font-persian">
|
||
{project.startDate}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardContent className="p-4">
|
||
<div className="flex items-center space-x-2">
|
||
<div className="p-2 bg-green-100 rounded-lg dark:bg-green-900">
|
||
<Clock className="w-5 h-5 text-green-600 dark:text-green-400" />
|
||
</div>
|
||
<div className="flex-1 text-right">
|
||
<p className="text-sm text-gray-600 dark:text-gray-400 font-persian">تاریخ پایان</p>
|
||
<p className="text-lg font-bold text-gray-900 dark:text-white font-persian">
|
||
{project.endDate}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardContent className="p-4">
|
||
<div className="flex items-center space-x-2">
|
||
<div className="p-2 bg-yellow-100 rounded-lg dark:bg-yellow-900">
|
||
<DollarSign className="w-5 h-5 text-yellow-600 dark:text-yellow-400" />
|
||
</div>
|
||
<div className="flex-1 text-right">
|
||
<p className="text-sm text-gray-600 dark:text-gray-400 font-persian">بودجه</p>
|
||
<p className="text-lg font-bold text-gray-900 dark:text-white font-persian">
|
||
{project.budget} ریال
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardContent className="p-4">
|
||
<div className="flex items-center space-x-2">
|
||
<div className="p-2 bg-purple-100 rounded-lg dark:bg-purple-900">
|
||
<FileText className="w-5 h-5 text-purple-600 dark:text-purple-400" />
|
||
</div>
|
||
<div className="flex-1 text-right">
|
||
<p className="text-sm text-gray-600 dark:text-gray-400 font-persian">پیشرفت</p>
|
||
<p className="text-lg font-bold text-gray-900 dark:text-white font-persian">
|
||
{project.progress}%
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
{/* Project Details */}
|
||
<div className="lg:col-span-2 space-y-6">
|
||
{/* Progress Bar */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="font-persian">پیشرفت پروژه</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-4">
|
||
<div className="flex justify-between items-center">
|
||
<span className="text-sm font-medium text-gray-500 dark:text-gray-400 font-persian">
|
||
{project.progress}% تکمیل شده
|
||
</span>
|
||
<div className="flex items-center gap-2">
|
||
<Badge variant={statusColors[project.status as keyof typeof statusColors]} className="font-persian">
|
||
{project.status}
|
||
</Badge>
|
||
<Badge variant={priorityColors[project.priority as keyof typeof priorityColors]} className="font-persian">
|
||
اولویت {project.priority}
|
||
</Badge>
|
||
</div>
|
||
</div>
|
||
<div className="w-full bg-gray-200 rounded-full h-3 dark:bg-gray-700">
|
||
<div
|
||
className="bg-gradient-to-r from-blue-500 to-blue-600 h-3 rounded-full transition-all duration-500"
|
||
style={{ width: `${project.progress}%` }}
|
||
></div>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Milestones */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="font-persian">مراحل پروژه</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-4">
|
||
{project.milestones.map((milestone) => (
|
||
<div key={milestone.id} className="flex items-center justify-between p-3 border rounded-lg dark:border-gray-700">
|
||
<div className="flex items-center space-x-3">
|
||
<div
|
||
className={`w-3 h-3 rounded-full ${
|
||
milestone.status === "تکمیل شده"
|
||
? "bg-green-500"
|
||
: milestone.status === "در حال انجام"
|
||
? "bg-blue-500"
|
||
: "bg-gray-300"
|
||
}`}
|
||
></div>
|
||
<div className="text-right">
|
||
<p className="font-medium text-gray-900 dark:text-white font-persian">
|
||
{milestone.title}
|
||
</p>
|
||
<p className="text-sm text-gray-500 dark:text-gray-400 font-persian">
|
||
{milestone.date}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<Badge
|
||
variant={statusColors[milestone.status as keyof typeof statusColors]}
|
||
className="font-persian"
|
||
>
|
||
{milestone.status}
|
||
</Badge>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Recent Tasks */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="font-persian">وظایف اخیر</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-3">
|
||
{project.tasks.map((task) => (
|
||
<div key={task.id} className="flex items-center justify-between p-3 border rounded-lg dark:border-gray-700">
|
||
<div className="text-right">
|
||
<p className="font-medium text-gray-900 dark:text-white font-persian">
|
||
{task.title}
|
||
</p>
|
||
<p className="text-sm text-gray-500 dark:text-gray-400 font-persian">
|
||
مسئول: {task.assignee}
|
||
</p>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Badge variant={statusColors[task.status as keyof typeof statusColors]} className="font-persian">
|
||
{task.status}
|
||
</Badge>
|
||
<Badge variant={priorityColors[task.priority as keyof typeof priorityColors]} className="font-persian">
|
||
{task.priority}
|
||
</Badge>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
|
||
{/* Sidebar */}
|
||
<div className="space-y-6">
|
||
{/* Project Info */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="font-persian">اطلاعات پروژه</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="space-y-4">
|
||
<div className="flex items-center space-x-2">
|
||
<User className="w-4 h-4 text-gray-500" />
|
||
<div className="text-right">
|
||
<p className="text-sm text-gray-500 dark:text-gray-400 font-persian">مدیر پروژه</p>
|
||
<p className="font-medium text-gray-900 dark:text-white font-persian">
|
||
{project.manager}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex items-center space-x-2">
|
||
<Users className="w-4 h-4 text-gray-500" />
|
||
<div className="text-right">
|
||
<p className="text-sm text-gray-500 dark:text-gray-400 font-persian">تیم</p>
|
||
<p className="font-medium text-gray-900 dark:text-white font-persian">
|
||
{project.team}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex items-center space-x-2">
|
||
<Calendar className="w-4 h-4 text-gray-500" />
|
||
<div className="text-right">
|
||
<p className="text-sm text-gray-500 dark:text-gray-400 font-persian">مدت زمان</p>
|
||
<p className="font-medium text-gray-900 dark:text-white font-persian">
|
||
{project.startDate} تا {project.endDate}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Team Members */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="font-persian">اعضای تیم</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-3">
|
||
{project.teamMembers.map((member) => (
|
||
<div key={member.id} className="flex items-center space-x-3">
|
||
<div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-500 rounded-full flex items-center justify-center text-white font-medium text-sm">
|
||
{member.avatar}
|
||
</div>
|
||
<div className="text-right">
|
||
<p className="font-medium text-gray-900 dark:text-white font-persian">
|
||
{member.name}
|
||
</p>
|
||
<p className="text-sm text-gray-500 dark:text-gray-400 font-persian">
|
||
{member.role}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</DashboardLayout>
|
||
);
|
||
}
|
||
|
||
export default ProjectDetail;
|