208 lines
6.6 KiB
TypeScript
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
|