diff --git a/src/pages/TaskDetail.jsx b/src/pages/TaskDetail.jsx index 18c651a..6e91dca 100644 --- a/src/pages/TaskDetail.jsx +++ b/src/pages/TaskDetail.jsx @@ -219,6 +219,10 @@ export default function TaskDetail() { const [amendDragging, setAmendDragging] = useState(false); const amendDragCounter = useRef(0); const amendFileRef = useRef(null); + const [reviewModal, setReviewModal] = useState(false); + const [reviewFiles, setReviewFiles] = useState([]); + const [reviewSaving, setReviewSaving] = useState(false); + const reviewFileRef = useRef(null); const [comments, setComments] = useState([]); const [commentBody, setCommentBody] = useState(''); const [commentSaving, setCommentSaving] = useState(false); @@ -291,7 +295,35 @@ export default function TaskDetail() { const handleStart = () => updateStatus('in_progress', { assigned_to: currentUser.id, assigned_name: currentUser.name }, 'task_started'); const handleOnHold = () => updateStatus('on_hold', {}, 'task_on_hold'); const handleResume = () => updateStatus('in_progress', {}, 'task_resumed'); - const handleSendToReview = () => updateStatus('client_review', {}, 'task_submitted'); + const handleSendToReview = () => { setReviewFiles([]); setReviewModal(true); }; + const handleRemoveFromReview = () => updateStatus('in_progress', {}, 'task_resumed'); + const handleConfirmReview = async () => { + setReviewSaving(true); + try { + if (reviewFiles.length > 0) { + let sub = submission; + if (!sub) { + const { data: newSub } = await supabase.from('submissions').insert({ task_id: id, type: 'initial', version_number: task.current_version || 0, service_type: task.title, submitted_by: currentUser.id, submitted_by_name: currentUser.name }).select().single(); + sub = newSub; + } + if (sub) { + const uploaded = []; + for (const file of reviewFiles) { + const path = `${id}/${Date.now()}_${file.name}`; + const { data: up } = await supabase.storage.from('submissions').upload(path, file); + if (up) uploaded.push({ name: file.name, storage_path: path, size: file.size, submission_id: sub.id }); + } + if (uploaded.length > 0) await supabase.from('submission_files').insert(uploaded); + if (project?.name && task?.title) uploadFilesToRequestInfo(reviewFiles, company?.name, project.name, task.title, task.current_version || 0).catch(() => {}); + } + } + await updateStatus('client_review', {}, 'task_submitted'); + setReviewModal(false); + setReviewFiles([]); + } finally { + setReviewSaving(false); + } + }; const handleClientApprove = () => updateStatus('client_approved', { completed_at: new Date().toISOString() }, 'task_approved'); const handleClientReject = () => updateStatus('not_started', { current_version: (task.current_version || 0) + 1, assigned_to: null, assigned_name: null }, 'revision_requested'); const handleRelease = () => updateStatus('not_started', { assigned_to: null, assigned_name: null }, 'task_released'); @@ -418,6 +450,9 @@ export default function TaskDetail() { > )} + {isTeamOrSub && status === 'client_review' && task.assigned_to === currentUser?.id && ( + + )} {isTeamOrSub && status === 'on_hold' && task.assigned_to === currentUser?.id && ( <> @@ -703,6 +738,38 @@ export default function TaskDetail() { + {reviewModal && ( +