video preview version
This commit is contained in:
@@ -4,12 +4,13 @@ import {
|
||||
ArrowLeft, Plus, Check, Trash2, Edit3, LayoutGrid, List,
|
||||
GanttChart, Settings, Calendar, Clock
|
||||
} from 'lucide-react'
|
||||
import { format, differenceInDays, startOfDay, addDays, isAfter, isBefore, parseISO } from 'date-fns'
|
||||
import { format, differenceInDays, startOfDay, addDays, isAfter, isBefore } from 'date-fns'
|
||||
import { AppContext } from '../App'
|
||||
import { api, PRIORITY_CONFIG } from '../utils/api'
|
||||
import StatusBadge from '../components/StatusBadge'
|
||||
import BrandBadge from '../components/BrandBadge'
|
||||
import Modal from '../components/Modal'
|
||||
import CommentsSection from '../components/CommentsSection'
|
||||
|
||||
const TASK_COLUMNS = [
|
||||
{ id: 'todo', label: 'To Do', color: 'bg-gray-400' },
|
||||
@@ -24,6 +25,7 @@ export default function ProjectDetail() {
|
||||
const [project, setProject] = useState(null)
|
||||
const [tasks, setTasks] = useState([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [assignableUsers, setAssignableUsers] = useState([])
|
||||
const [view, setView] = useState('kanban')
|
||||
const [showTaskModal, setShowTaskModal] = useState(false)
|
||||
const [showProjectModal, setShowProjectModal] = useState(false)
|
||||
@@ -42,6 +44,9 @@ export default function ProjectDetail() {
|
||||
const [dragOverCol, setDragOverCol] = useState(null)
|
||||
|
||||
useEffect(() => { loadProject() }, [id])
|
||||
useEffect(() => {
|
||||
api.get('/users/assignable').then(res => setAssignableUsers(res.data || res || [])).catch(() => {})
|
||||
}, [])
|
||||
|
||||
const loadProject = async () => {
|
||||
try {
|
||||
@@ -208,31 +213,6 @@ export default function ProjectDetail() {
|
||||
const ownerName = project.ownerName || project.owner_name
|
||||
const brandName = project.brandName || project.brand_name
|
||||
|
||||
// Gantt chart helpers
|
||||
const getGanttRange = () => {
|
||||
const today = startOfDay(new Date())
|
||||
let earliest = today
|
||||
let latest = addDays(today, 14)
|
||||
|
||||
tasks.forEach(t => {
|
||||
if (t.createdAt) {
|
||||
const d = startOfDay(new Date(t.createdAt))
|
||||
if (isBefore(d, earliest)) earliest = d
|
||||
}
|
||||
if (t.dueDate) {
|
||||
const d = startOfDay(new Date(t.dueDate))
|
||||
if (isAfter(d, latest)) latest = addDays(d, 1)
|
||||
}
|
||||
})
|
||||
if (project.dueDate) {
|
||||
const d = startOfDay(new Date(project.dueDate))
|
||||
if (isAfter(d, latest)) latest = addDays(d, 1)
|
||||
}
|
||||
// Ensure minimum 14 days
|
||||
if (differenceInDays(latest, earliest) < 14) latest = addDays(earliest, 14)
|
||||
return { earliest, latest, totalDays: differenceInDays(latest, earliest) + 1 }
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6 animate-fade-in">
|
||||
{/* Back button */}
|
||||
@@ -296,6 +276,11 @@ export default function ProjectDetail() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Discussion */}
|
||||
<div className="bg-white rounded-xl border border-border p-6">
|
||||
<CommentsSection entityType="project" entityId={Number(id)} />
|
||||
</div>
|
||||
|
||||
{/* View switcher + Add Task */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-1 bg-surface-tertiary rounded-lg p-0.5">
|
||||
@@ -491,7 +476,7 @@ export default function ProjectDetail() {
|
||||
<select value={taskForm.assigned_to} onChange={e => setTaskForm(f => ({ ...f, assigned_to: e.target.value }))}
|
||||
className="w-full px-3 py-2 text-sm border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary">
|
||||
<option value="">Unassigned</option>
|
||||
{teamMembers.map(m => <option key={m._id} value={m._id}>{m.name}</option>)}
|
||||
{assignableUsers.map(m => <option key={m._id || m.team_member_id} value={m._id || m.team_member_id}>{m.name}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
@@ -586,6 +571,19 @@ export default function ProjectDetail() {
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{/* ─── DELETE TASK CONFIRMATION ─── */}
|
||||
<Modal
|
||||
isOpen={showDeleteConfirm}
|
||||
onClose={() => { setShowDeleteConfirm(false); setTaskToDelete(null) }}
|
||||
title="Delete Task?"
|
||||
isConfirm
|
||||
danger
|
||||
confirmText="Delete Task"
|
||||
onConfirm={confirmDeleteTask}
|
||||
>
|
||||
Are you sure you want to delete this task? This action cannot be undone.
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -760,18 +758,6 @@ function GanttView({ tasks, project, onEditTask }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Delete Task Confirmation */}
|
||||
<Modal
|
||||
isOpen={showDeleteConfirm}
|
||||
onClose={() => { setShowDeleteConfirm(false); setTaskToDelete(null) }}
|
||||
title="Delete Task?"
|
||||
isConfirm
|
||||
danger
|
||||
confirmText="Delete Task"
|
||||
onConfirm={confirmDeleteTask}
|
||||
>
|
||||
Are you sure you want to delete this task? This action cannot be undone.
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user