SME-Web/src/components/process/processStepOne/DocumentCard.tsx

208 lines
6.6 KiB
TypeScript

import React, { useEffect, useState } from 'react'
import { FaFileAlt, FaCheckCircle, FaUpload } from 'react-icons/fa'
import { MdFileUpload } from 'react-icons/md'
import { RiDraggable } from 'react-icons/ri'
import { deleteDocument, setDocProgComplete } from '../../../store/slices/documentSlice'
import { useDispatch } from 'react-redux'
import { AppDispatch } from '../../../store/store'
import { IoMdClose } from 'react-icons/io'
import api from '../../../config/api'
import { useParams } from 'react-router-dom'
import axios from 'axios'
interface DocumentCardProps {
id: string;
name: string;
isCompleted: boolean;
transactionTemplateToggle:boolean;
}
const DocumentCard: React.FC<DocumentCardProps> = ({ id, name, isCompleted , transactionTemplateToggle }) => {
const params = useParams<{ accountId?: string; transactionId?: string; templateId?: string }>();
const accountId = params.accountId;
const transactionId = params.transactionId || params.templateId;
// if (!accountId || !transactionId) {
// window.location.href = "/";
// return null;
// }
const [progress, setProgress] = useState<number>(0)
const [message, setMessage] = useState<string>('')
const [documentDel, setDocumentDel] = useState<{ docId: string | null, isDel: boolean }>({ docId: null, isDel: false })
const dispatch = useDispatch<AppDispatch>()
useEffect(() => {
let isCompleted = false;
let updateTimeout: ReturnType<typeof setTimeout> | null = null;
let lastUpdate = 0;
const delay = 1000;
const docProgSSE = new EventSource(`http://192.168.2.112:8083/api/progress/${id}`);
docProgSSE.addEventListener('progress', (event) => {
const jsonData = JSON.parse(event.data);
console.log(jsonData, "Kaboom");
if (jsonData.isComplete) {
isCompleted = true;
if (updateTimeout) clearTimeout(updateTimeout);
dispatch(setDocProgComplete(id));
setProgress(jsonData.progress);
setMessage(jsonData.message);
docProgSSE.close(); // Close connection ourselves
return;
}
const now = Date.now();
const sinceLast = now - lastUpdate;
if (sinceLast >= delay) {
setProgress(jsonData.progress);
setMessage(jsonData.message);
lastUpdate = now;
} else {
if (updateTimeout) clearTimeout(updateTimeout);
updateTimeout = setTimeout(() => {
setProgress(jsonData.progress);
setMessage(jsonData.message);
lastUpdate = Date.now();
}, delay - sinceLast);
}
});
docProgSSE.onerror = (error) => {
if (!isCompleted) {
console.error("SSE Error", error);
}
docProgSSE.close();
};
return () => {
docProgSSE.close();
if (updateTimeout) clearTimeout(updateTimeout);
};
}, [id]);
console.log(isCompleted, "line 118")
const radius = 28
const circumference = 2 * Math.PI * radius
const offset = circumference - (progress / 100) * circumference
const handleDeleteDocument = async () => {
const docId = documentDel.docId;
if (!docId || !accountId || !transactionId) {
console.error("Missing document ID, account ID, or transaction ID");
return;
}
const res = await api.delete(`/api/accounts/${accountId}/${transactionTemplateToggle}/${transactionId}/documents/${docId}`)
if (res.status === 202) {
dispatch(deleteDocument(docId));
setDocumentDel({ docId: null, isDel: false });
console.log("Document deleted successfully");
}
}
return (
<>
<div
key={id}
className="relative w-[160px] h-[170px] bg-white rounded-xl shadow-sm hover:shadow-md transition p-4 flex flex-col items-center justify-between"
draggable
>
<IoMdClose
onClick={() => setDocumentDel({ docId: id, isDel: false })}
className='absolute right-2.5 top-2.5 text-slate-400 text-xl hover:text-red-500 cursor-pointer transition-all' />
{/* Draggable handle */}
<RiDraggable
draggable
onDragStart={(e) => e.dataTransfer.setData('text/plain', id)}
className="absolute top-2 left-2 text-gray-400 text-lg cursor-grab drag-handle"
/>
{/* Main icon or circular loader */}
<div className="flex flex-col items-center mt-2 mb-1">
{!isCompleted ? (
<div className="relative w-16 h-16">
<svg width="64" height="64" className="rotate-[-90deg]">
<circle
cx="32"
cy="32"
r={radius}
fill="none"
stroke="#e5e7eb"
strokeWidth="6"
/>
<circle
cx="32"
cy="32"
r={radius}
fill="none"
stroke="#3b82f6"
strokeWidth="6"
strokeDasharray={circumference}
strokeDashoffset={offset}
strokeLinecap="round"
className="transition-all duration-300 ease-in-out"
/>
</svg>
<div className="absolute inset-0 flex items-center justify-center text-xs font-semibold text-gray-700 select-none">
{progress}%
</div>
</div>
) : (
<FaFileAlt className="text-red-600 text-5xl mb-1" />
)}
</div>
{/* Document name */}
<span className="text-center text-sm text-gray-800 font-medium truncate max-w-[14ch] leading-snug">
{name}
</span>
{/* Status message */}
<span className="text-xs text-gray-500 mt-1">{message}</span>
</div>
{
documentDel.docId !== null && <div className="fixed inset-0 backdrop-blur-sm flex items-center justify-center z-50">
<div className="bg-white rounded-lg shadow-xl p-6 w-80">
<h3 className="text-lg font-medium text-gray-800 mb-4">Confirm Delete</h3>
<p className="text-gray-600 mb-6">Are you sure you want to delete?</p>
<div className="flex justify-end gap-3">
<button
onClick={() => setDocumentDel({ docId: null, isDel: false })}
className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-md transition-colors"
>
Cancel
</button>
<button
onClick={handleDeleteDocument}
className="px-4 py-2 bg-red-600 text-white hover:bg-red-700 rounded-md transition-colors"
>
Delete
</button>
</div>
</div>
</div>
}
</>
)
}
export default DocumentCard