From 6ef3e36141a0eb8fa5693f93878f754a18722714 Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Wed, 13 Aug 2025 13:43:31 +0530 Subject: [PATCH] audit --- .../DocumentCompletionScreen.tsx | 2 +- src/components/transactions/AuditModal.tsx | 528 ++++++++++-------- 2 files changed, 298 insertions(+), 232 deletions(-) diff --git a/src/components/process/CompletionScreen/DocumentCompletionScreen.tsx b/src/components/process/CompletionScreen/DocumentCompletionScreen.tsx index ce2a410..3ba00f5 100644 --- a/src/components/process/CompletionScreen/DocumentCompletionScreen.tsx +++ b/src/components/process/CompletionScreen/DocumentCompletionScreen.tsx @@ -448,7 +448,7 @@ const DocumentSubmissionOptions = () => { -
+
{/* Left Panel - Configuration */}
diff --git a/src/components/transactions/AuditModal.tsx b/src/components/transactions/AuditModal.tsx index bba20e3..f7dbcb2 100644 --- a/src/components/transactions/AuditModal.tsx +++ b/src/components/transactions/AuditModal.tsx @@ -1,254 +1,320 @@ -import React, { useState } from "react"; -import { - FiX, - FiCheckCircle, - FiXCircle, - FiClock, - FiUser, - FiCalendar, - FiFileText, - FiAlertTriangle, - FiTruck, - FiUserCheck, - FiUserX, - FiPackage, - FiMapPin, - FiEye, - FiRotateCcw +import React, { useEffect, useState } from "react"; +import { + FiX, + FiCheckCircle, + FiXCircle, + FiClock, + FiUser, + FiCalendar, + FiFileText, + FiAlertTriangle, + FiTruck, + FiUserCheck, + FiUserX, + FiPackage, + FiMapPin, + FiEye, + FiRotateCcw, + FiSend, + FiMail, + FiActivity, + FiRefreshCw, + FiLock, + FiUnlock, + FiUserPlus, + FiEdit } from "react-icons/fi"; +import api from "../../config/api"; +import { useParams } from "react-router-dom"; +import logoRecord from '../../assets/record.svg' +import LoaderUi from "../../helper/LoaderUi"; +import { FaRegEyeSlash } from "react-icons/fa"; +import { MdAccessTime, MdCancel } from "react-icons/md"; interface AuditModalProps { - closeModal: () => void; + closeModal: () => void; } const AuditModal: React.FC = ({ closeModal }) => { - const [activeTab, setActiveTab] = useState<'status' | 'audit'>('status'); + const { accountId, transactionId } = useParams<{ accountId: string, transactionId: string }>(); - const statusHistory = [ - { - id: 1, - title: "The Accrual status has been successfully changed to Approved.", - author: "Alexander Turner", - role: "Analyst Perspective on Transaction", - time: "34m ago", - fromStatus: "Ready to Review", - toStatus: "Approved", - icon: , - statusColor: "text-green-600" - }, - { - id: 2, - title: "The Accrual has been updated to reflect a status of Reject.", - author: "Alexander Turner", - time: "3h ago", - fromStatus: "Ready to Review", - toStatus: "Rejected", - icon: , - statusColor: "text-red-600" - }, - { - id: 3, - title: "The Accrual has been revised for accuracy.", - author: "Alex Turner", - role: "Manager View Transaction State", - time: "7d ago", - fromStatus: "Rejected", - toStatus: "Reviewed", - icon: , - statusColor: "text-yellow-600" - }, - { - id: 4, - title: "The Accrual state has been updated from 'ready' to 'under review'.", - author: "Alexander Turner", - role: "Analyst Perspective on Transaction", - time: "34m ago", - fromStatus: "Ready to Review", - toStatus: "Reviewed", - icon: , - statusColor: "text-blue-600" - }, - { - id: 5, - title: "The Accrual has been updated from rejected to reviewed.", - author: "Alex Turner", - role: "Analyst View Transaction", - time: "34m ago", - fromStatus: "Rejected", - toStatus: "Reviewed", - icon: , - statusColor: "text-blue-600" + if (!accountId || !transactionId) { + window.location.href = "/"; + return null; } - ]; - const auditTrail = [ - { - id: 1, - title: "Batch 11317 Pickup Request Created", - author: "Sandra Darlington", - location: "Lagos General Hospital Gbagada", - time: "11 Aug, 2023 09:23 AM", - icon: , - type: "created" - }, - { - id: 2, - title: "Batch 11317 Pickup Request", - author: "Oladejo Israel", - location: "Institute of Human Virology H3Africa BioRepository", - time: "12 Aug, 2023 11:19 AM", - status: "Approved", - icon: , - type: "approved" - }, - { - id: 3, - title: "Batch 11317 was Initiated", - author: "Sandra Darlington", - location: "Lagos General Hospital Gbagada", - time: "12 Aug, 2023 11:19 AM", - icon: , - type: "initiated" - }, - { - id: 4, - title: "Sandra Darlington Assigned batch 11317", - assignee: "Yusuf Ahmed", - time: "12 Aug, 2023 11:20 AM", - icon: , - type: "assigned" - }, - { - id: 5, - title: "Batch 11317 was rejected by Yusuf Ahmed", - reason: "due to faulty vehicle", - time: "12 Aug, 2023 11:20 AM", - icon: , - type: "rejected" - }, - { - id: 6, - title: "Sandra Darlington Assigned batch 11317", - assignee: "Kolado Jolade", - time: "12 Aug, 2023 11:20 AM", - icon: , - type: "assigned" - }, - { - id: 7, - title: "Logger Synced", - deviceId: "ID: LGR-0421", - status: "95% remaining", - time: "12 Aug, 2023 11:25 AM", - icon: , - type: "synced" - }, - { - id: 8, - title: "Logger Disconnected", - deviceId: "ID: LGR-0421", - time: "12 Aug, 2023 11:25 AM", - icon: , - type: "disconnected" + let [auditStatus, setAuditStatus] = useState([]) + let [loading, setLoading] = useState(false) + const getAuditDetails = async () => { + setLoading(true) + try { + let res = await api.get(`/api/accounts/${accountId}/transactions/${transactionId}/audit`) + if (res?.status === 200) { + // console.log(res?.data?.events) + let auditResponse = res?.data?.events + setAuditStatus(auditResponse) + } + } catch (error) { + console.log(error) + } finally { + setLoading(false) + } } - ]; - const getStatusBadge = (status: string) => { - const statusClasses = { - 'Approved': 'bg-green-100 text-green-800', - 'Rejected': 'bg-red-100 text-red-800', - 'Reviewed': 'bg-yellow-100 text-yellow-800', - 'Ready to Review': 'bg-blue-100 text-blue-800' + useEffect(() => { + if (accountId && transactionId) { + getAuditDetails() + } + }, [accountId, transactionId]) + + + const statusHistory = [ + { + "action": "SENT", + "message": "Transaction Sent by John Doe ", + "status": "SENT", + "eventData": { + "ip": "192.168.1.1", + "longitude": "3.3792", + "latitude": "6.5244", + "timezone": "WAT" + }, + "timestamp": "2025-01-15T10:30:00Z", + "language": "en" + }, + { + "action": "INVITED", + "message": "Invitation Sent to Jane Smith to sign documents", + "status": "SENT", + "eventData": { + "ip": "0.0.0.0", + "longitude": "11", + "latitude": "12", + "timezone": "" + }, + "timestamp": "2025-01-15T11:45:00Z", + "language": "es" + }, + { + "action": "VIEWED", + "message": "Document viewed by recipient Alice Johnson ", + "status": "VIEWED", + "eventData": { + "ip": "203.0.113.5", + "longitude": "-74.0059", + "latitude": "40.7128", + "timezone": "EST" + }, + "timestamp": "2025-01-15T14:20:00Z", + "language": "en" + }, + { + "action": "SIGNED", + "message": "Document signed by Bob Wilson ", + "status": "COMPLETED", + "eventData": { + "ip": "198.51.100.10", + "longitude": "-122.4194", + "latitude": "37.7749", + "timezone": "PST" + }, + "timestamp": "2025-01-15T16:10:00Z", + "language": "en" + } + ]; + + const getActionIcon = (action: string) => { + const icons = { + 'CREATED': , + 'SENT': , + 'INVITED': , + 'COMPLETED': , + 'RE_SENT_INVITATION': , + 'RE_SENT_EXPIRED_INVITATION': , + 'VIEWED': , + 'VIEWED_IN_PERSON': , // Slightly different eye icon + 'AUTH_FAILED': , + 'ACCESS_CODE_FAILED': , + 'ACCESS_CODE_VALIDATED': , + 'AUTH_VALIDATED': , + 'SIGNED': , + 'EXPIRED': , + 'CANCELLED': , + 'DECLINED': , + 'PENDING': , + 'ASSIGNED': , + 'REASSIGNED': , + 'EDITED': , + }; + + return icons[action as keyof typeof icons] || ; }; - return statusClasses[status as keyof typeof statusClasses] || 'bg-gray-100 text-gray-800'; - }; - const getAuditTypeColor = (type: string) => { - const colors = { - 'created': 'text-blue-600', - 'approved': 'text-green-600', - 'initiated': 'text-purple-600', - 'assigned': 'text-indigo-600', - 'rejected': 'text-red-600', - 'synced': 'text-green-600', - 'disconnected': 'text-orange-600' + const getActionColor = (action: string, status: string) => { + if (status === 'COMPLETED') return 'text-green-600'; + if (status === 'FAILED' || status === 'REJECTED') return 'text-red-600'; + if (status === 'PENDING') return 'text-yellow-600'; + + const colors = { + 'SENT': 'text-blue-600', + 'INVITED': 'text-indigo-600', + 'VIEWED': 'text-purple-600', + 'SIGNED': 'text-green-600', + 'REJECTED': 'text-red-600' + }; + return colors[action as keyof typeof colors] || 'text-gray-600'; }; - return colors[type as keyof typeof colors] || 'text-gray-600'; - }; - return ( -
-
- {/* Header */} -
-
-

- Audit Status -

-
- -
+ const getStatusBadge = (status: string) => { + const statusClasses = { + 'SENT': 'bg-blue-100 text-blue-800', + 'COMPLETED': 'bg-green-100 text-green-800', + 'FAILED': 'bg-red-100 text-red-800', + 'PENDING': 'bg-yellow-100 text-yellow-800', + 'VIEWED': 'bg-purple-100 text-purple-800', + 'REJECTED': 'bg-red-100 text-red-800' + }; + return statusClasses[status as keyof typeof statusClasses] || 'bg-gray-100 text-gray-800'; + }; - {/* Content */} -
- -
-
TODAY
- - {statusHistory.slice(0, 2).map((item) => ( -
-
- {item.icon} -
-
-

{item.title}

-
- By {item.author} - {item.role && ( - <> - • - ({item.role}) - - )} + const formatTimestamp = (timestamp: string) => { + try { + const date = new Date(timestamp); + if (isNaN(date.getTime())) { + return timestamp; + } + + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / (1000 * 60)); + const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); + const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); + + if (diffMins < 60) { + return `${diffMins}m ago`; + } else if (diffHours < 24) { + return `${diffHours}h ago`; + } else if (diffDays < 7) { + return `${diffDays}d ago`; + } else { + return date.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + } + } catch (error) { + return timestamp; + } + }; + + const extractEmailFromMessage = (message: string) => { + const emailMatch = message.match(/<([^>]+)>/); + return emailMatch ? emailMatch[1] : ''; + }; + + return ( +
+
+ {/* Header */} +
+
+

+ Audit Status +

-
- {item.time} -
- - {item.fromStatus} - - → - - {item.toStatus} - -
-
-
+
- ))} - + {/* Content */} +
+ {/* {loading ? : ""} */} + {auditStatus.length ? +
+ {/*
TODAY
*/} + {auditStatus.map((item, index) => ( +
+
+ {getActionIcon(item.action)} +
+
+

{item.message}

+ +
+ Action: {item.action} + {extractEmailFromMessage(item.message) && ( + <> + • + {extractEmailFromMessage(item.message)} + + )} +
+ +
+ Status: + {item.status} + + {formatTimestamp(item.timestamp)} + {item.language && ( + {item.language} + )} +
+ + {/* Event Data Details */} + {/*
+ {item.eventData.ip && ( +
+ IP: {item.eventData.ip} +
+ )} + {item.eventData.timezone && ( +
+ Timezone: {item.eventData.timezone} +
+ )} + {item.eventData.latitude && item.eventData.longitude && ( +
+ Location: + Lat: {item.eventData.latitude}, Lng: {item.eventData.longitude} +
+ )} +
*/} +
+
+ ))} +
: +
+ Record Not Found +
+ } +
+ + {/* Footer */} +
+
+ Showing {auditStatus.length} event{auditStatus.length !== 1 ? 's' : ''} +
+ +
-
- - {/* Footer */} -
- -
-
-
- ); + ); }; -export default AuditModal; +export default AuditModal; \ No newline at end of file