Add delete job functionality with confirmation step
Adds DELETE /api/jobs/{id} endpoint (removes DB record and image file),
and a two-step Delete / Confirm button on the review page that returns
to the job list on success.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { useSuggestions } from '../hooks/useSuggestions'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import {
|
||||
Search, ChevronLeft, ChevronRight, CheckCircle2, Clock,
|
||||
FileText, Loader2, Save, RefreshCw,
|
||||
FileText, Loader2, Save, RefreshCw, Trash2,
|
||||
} from 'lucide-react'
|
||||
import axios from 'axios'
|
||||
|
||||
@@ -31,7 +31,7 @@ function StatusBadge({ status }) {
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Full-screen Job Detail
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
function JobDetail({ jobId, onClose, onReviewed, suggestions = {} }) {
|
||||
function JobDetail({ jobId, onClose, onReviewed, onDeleted, suggestions = {} }) {
|
||||
const [job, setJob] = useState(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState(null)
|
||||
@@ -45,6 +45,8 @@ function JobDetail({ jobId, onClose, onReviewed, suggestions = {} }) {
|
||||
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [saveResult, setSaveResult] = useState(null)
|
||||
const [confirmDelete, setConfirmDelete] = useState(false)
|
||||
const [deleting, setDeleting] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
@@ -99,6 +101,19 @@ function JobDetail({ jobId, onClose, onReviewed, suggestions = {} }) {
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = async () => {
|
||||
setDeleting(true)
|
||||
try {
|
||||
await axios.delete(`${API_BASE}/jobs/${jobId}`)
|
||||
onDeleted(jobId)
|
||||
} catch (err) {
|
||||
setSaveResult({ success: false, error: err.response?.data?.detail || err.message })
|
||||
setConfirmDelete(false)
|
||||
} finally {
|
||||
setDeleting(false)
|
||||
}
|
||||
}
|
||||
|
||||
const isReviewed = job?.status === 'reviewed'
|
||||
|
||||
return (
|
||||
@@ -125,6 +140,38 @@ function JobDetail({ jobId, onClose, onReviewed, suggestions = {} }) {
|
||||
<span className="text-xs text-gray-500 font-mono hidden sm:block">{job.id}</span>
|
||||
</>
|
||||
)}
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
{confirmDelete ? (
|
||||
<>
|
||||
<span className="text-xs text-red-400">Delete this job permanently?</span>
|
||||
<motion.button
|
||||
onClick={handleDelete}
|
||||
disabled={deleting}
|
||||
className="flex items-center gap-1 px-3 py-2 rounded-xl text-sm font-medium bg-red-600 hover:bg-red-500 disabled:opacity-50"
|
||||
whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
{deleting ? <Loader2 className="w-4 h-4 animate-spin" /> : <Trash2 className="w-4 h-4" />}
|
||||
Confirm
|
||||
</motion.button>
|
||||
<motion.button
|
||||
onClick={() => setConfirmDelete(false)}
|
||||
className="px-3 py-2 rounded-xl text-sm glass glass-hover text-gray-300"
|
||||
whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
Cancel
|
||||
</motion.button>
|
||||
</>
|
||||
) : (
|
||||
<motion.button
|
||||
onClick={() => setConfirmDelete(true)}
|
||||
className="flex items-center gap-2 px-3 py-2 rounded-xl text-sm glass glass-hover text-red-400 hover:bg-red-500/10"
|
||||
whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
Delete
|
||||
</motion.button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{loading && (
|
||||
@@ -322,6 +369,11 @@ export default function JobsPanel() {
|
||||
jobId={selectedJobId}
|
||||
onClose={() => setSelectedJobId(null)}
|
||||
onReviewed={handleReviewed}
|
||||
onDeleted={(id) => {
|
||||
setJobs(prev => prev.filter(j => j.id !== id))
|
||||
setTotal(prev => prev - 1)
|
||||
setSelectedJobId(null)
|
||||
}}
|
||||
suggestions={suggestions}
|
||||
/>
|
||||
</AnimatePresence>
|
||||
|
||||
Reference in New Issue
Block a user