524 lines
22 KiB
TypeScript
524 lines
22 KiB
TypeScript
import React from 'react';
|
|
import { exportReportToExcel } from '~/utils/excelExport';
|
|
|
|
interface ReportSheet {
|
|
id: string;
|
|
date: string;
|
|
area: string;
|
|
dredgerLocation: string;
|
|
reclamationLocation: string;
|
|
dayReport?: any;
|
|
nightReport?: any;
|
|
}
|
|
|
|
interface ReportSheetViewModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
sheet: ReportSheet | null;
|
|
}
|
|
|
|
export default function ReportSheetViewModal({ isOpen, onClose, sheet }: ReportSheetViewModalProps) {
|
|
if (!isOpen || !sheet) return null;
|
|
|
|
const handleExportExcel = async () => {
|
|
if (sheet.dayReport) {
|
|
await exportReportToExcel(sheet.dayReport);
|
|
}
|
|
if (sheet.nightReport) {
|
|
await exportReportToExcel(sheet.nightReport);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-50 overflow-y-auto">
|
|
<div className="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
|
<div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" onClick={onClose}></div>
|
|
|
|
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-7xl sm:w-full">
|
|
<div className="bg-white px-6 pt-6 pb-4">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h3 className="text-xl font-bold text-gray-900">Report Sheet - {new Date(sheet.date).toLocaleDateString('en-GB')}</h3>
|
|
<div className="flex space-x-2">
|
|
<button
|
|
type="button"
|
|
onClick={handleExportExcel}
|
|
className="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"
|
|
>
|
|
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
</svg>
|
|
Export Excel
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const printContent = document.getElementById('reportframe');
|
|
if (printContent) {
|
|
const printWindow = window.open('', '_blank');
|
|
if (printWindow) {
|
|
printWindow.document.write(`
|
|
<html>
|
|
<head>
|
|
<title>Report Sheet Print</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
-webkit-print-color-adjust: exact;
|
|
color-adjust: exact;
|
|
}
|
|
table { border-collapse: collapse; }
|
|
.border-2 { border: 2px solid black; }
|
|
.border { border: 1px solid black; }
|
|
.border-t { border-top: 1px solid black; }
|
|
.border-r { border-right: 1px solid black; }
|
|
.border-black { border-color: black; }
|
|
.bg-green-500 {
|
|
background-color: #10b981 !important;
|
|
-webkit-print-color-adjust: exact;
|
|
color-adjust: exact;
|
|
}
|
|
.text-white { color: white !important; }
|
|
.text-center { text-align: center; }
|
|
.font-bold { font-weight: bold; }
|
|
.font-semibold { font-weight: 600; }
|
|
.p-2 { padding: 8px; }
|
|
.p-4 { padding: 16px; }
|
|
.mb-2 { margin-bottom: 8px; }
|
|
.mb-4 { margin-bottom: 16px; }
|
|
.mt-1 { margin-top: 4px; }
|
|
.mt-4 { margin-top: 16px; }
|
|
.mt-6 { margin-top: 24px; }
|
|
.pt-1 { padding-top: 4px; }
|
|
.pt-2 { padding-top: 8px; }
|
|
.w-full { width: 100%; }
|
|
.h-16 { height: 64px; }
|
|
.mx-auto { margin-left: auto; margin-right: auto; }
|
|
.underline { text-decoration: underline; }
|
|
.text-sm { font-size: 14px; }
|
|
.text-lg { font-size: 18px; }
|
|
.min-h-[100px] { min-height: 100px; }
|
|
@media print {
|
|
body {
|
|
margin: 0;
|
|
-webkit-print-color-adjust: exact;
|
|
color-adjust: exact;
|
|
}
|
|
.no-print { display: none; }
|
|
.bg-green-500 {
|
|
background-color: #10b981 !important;
|
|
-webkit-print-color-adjust: exact;
|
|
color-adjust: exact;
|
|
}
|
|
.text-white { color: white !important; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
${printContent.innerHTML}
|
|
</body>
|
|
</html>
|
|
`);
|
|
printWindow.document.close();
|
|
printWindow.print();
|
|
printWindow.close();
|
|
}
|
|
}
|
|
}}
|
|
className="inline-flex items-center px-3 py-2 border border-gray-300 shadow-sm text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
>
|
|
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z" />
|
|
</svg>
|
|
Print
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={onClose}
|
|
className="bg-white rounded-md text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
|
>
|
|
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Combined Report Sheet Layout */}
|
|
<div id="reportframe" className="max-h-[80vh] overflow-y-auto bg-white p-6 border border-gray-300" style={{ fontFamily: 'Arial, sans-serif' }}>
|
|
<ReportSheetHeader sheet={sheet} />
|
|
<ReportSheetInfo sheet={sheet} />
|
|
<ReportSheetDredgerSection sheet={sheet} />
|
|
<ReportSheetLocationData sheet={sheet} />
|
|
<ReportSheetPipelineLength sheet={sheet} />
|
|
|
|
{/* Day Shift Section */}
|
|
{sheet.dayReport && (
|
|
<>
|
|
<ReportSheetShiftHeader shift="day" />
|
|
<ReportSheetEquipmentStats report={sheet.dayReport} />
|
|
<ReportSheetTimeSheet report={sheet.dayReport} />
|
|
<ReportSheetStoppages report={sheet.dayReport} />
|
|
<ReportSheetNotes report={sheet.dayReport} />
|
|
</>
|
|
)}
|
|
|
|
{/* Night Shift Section */}
|
|
{sheet.nightReport && (
|
|
<>
|
|
<ReportSheetShiftHeader shift="night" />
|
|
<ReportSheetEquipmentStats report={sheet.nightReport} />
|
|
<ReportSheetTimeSheet report={sheet.nightReport} />
|
|
<ReportSheetStoppages report={sheet.nightReport} />
|
|
<ReportSheetNotes report={sheet.nightReport} />
|
|
</>
|
|
)}
|
|
|
|
<ReportSheetFooter />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Header Section Component
|
|
function ReportSheetHeader({ sheet }: { sheet: ReportSheet }) {
|
|
return (
|
|
<div className="border-2 border-black mb-4">
|
|
<table className="w-full border-collapse">
|
|
<tbody>
|
|
<tr>
|
|
<td className="border-r-2 border-black p-2 text-center font-bold text-lg" style={{ width: '70%' }}>
|
|
<div>Reclamation Work Diary - Daily Sheet</div>
|
|
<div className="border-t border-black mt-1 pt-1">QF-3.6.1-08</div>
|
|
<div className="border-t border-black mt-1 pt-1">Rev. 1.0</div>
|
|
</td>
|
|
<td className="p-2 text-center" style={{ width: '30%' }}>
|
|
<img
|
|
src="/logo-light.png"
|
|
alt="Arab Potash Logo"
|
|
className="h-16 mx-auto"
|
|
onError={(e) => {
|
|
e.currentTarget.style.display = 'none';
|
|
}}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Report Info Component
|
|
function ReportSheetInfo({ sheet }: { sheet: ReportSheet }) {
|
|
return (
|
|
<div className="border-2 border-black mb-4">
|
|
<table className="w-full border-collapse">
|
|
<tbody>
|
|
<tr>
|
|
<td className="border-r border-black p-2 font-semibold" style={{ width: '15%' }}>Date:</td>
|
|
<td className="border-r border-black p-2" style={{ width: '35%' }}>
|
|
{new Date(sheet.date).toLocaleDateString('en-GB')}
|
|
</td>
|
|
<td className="border-r border-black p-2 font-semibold" style={{ width: '20%' }}> Report No. </td>
|
|
<td className="p-2" style={{ width: '30%' }}>{sheet.id}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Dredger Section Component
|
|
function ReportSheetDredgerSection({ sheet }: { sheet: ReportSheet }) {
|
|
return (
|
|
<div className="text-center font-bold text-lg mb-2 underline">
|
|
{sheet.area} Dredger
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Location Data Component (using data from either available report)
|
|
function ReportSheetLocationData({ sheet }: { sheet: ReportSheet }) {
|
|
const report = sheet.dayReport || sheet.nightReport;
|
|
if (!report) return null;
|
|
|
|
return (
|
|
<div className="border-2 border-black mb-4">
|
|
<table className="w-full border-collapse text-sm">
|
|
<tbody>
|
|
<tr>
|
|
<td className="bg-green-500 text-white p-2 font-semibold border-r border-black" style={{ width: '25%' }}>
|
|
Dredger Location
|
|
</td>
|
|
<td className="p-2 border-r border-black text-center" style={{ width: '25%' }}>
|
|
{report.dredgerLocation.name}
|
|
</td>
|
|
<td className="bg-green-500 text-white p-2 font-semibold border-r border-black" style={{ width: '25%' }}>
|
|
Dredger Line Length
|
|
</td>
|
|
<td className="p-2 text-center" style={{ width: '25%' }}>
|
|
{report.dredgerLineLength}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="bg-green-500 text-white p-2 font-semibold border-r border-black border-t border-black">
|
|
Reclamation Location
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.reclamationLocation.name}
|
|
</td>
|
|
<td className="bg-green-500 text-white p-2 font-semibold border-r border-black border-t border-black">
|
|
Shore Connection
|
|
</td>
|
|
<td className="p-2 border-t border-black text-center">
|
|
{report.shoreConnection}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="bg-green-500 text-white p-2 font-semibold border-r border-black border-t border-black">
|
|
Reclamation Height
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.reclamationHeight?.base || 0}m - {(report.reclamationHeight?.extra + report.reclamationHeight?.base || 0 || 0)}m
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black" colSpan={2}></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Pipeline Length Component (using data from either available report)
|
|
function ReportSheetPipelineLength({ sheet }: { sheet: ReportSheet }) {
|
|
const report = sheet.dayReport || sheet.nightReport;
|
|
if (!report) return null;
|
|
|
|
return (
|
|
<div className="border-2 border-black mb-4">
|
|
<table className="w-full border-collapse text-sm">
|
|
<tbody>
|
|
<tr>
|
|
<td className="bg-green-500 text-white p-2 font-semibold border-r border-black" rowSpan={2}>
|
|
Pipeline Length "from Shore Connection"
|
|
</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Main</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">extension</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">total</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Reserve</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">extension</td>
|
|
<td className="p-2 text-center font-semibold">total</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.pipelineLength?.main || 0}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.pipelineLength?.ext1 || 0}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{(report.pipelineLength?.main || 0) + (report.pipelineLength?.ext1 || 0)}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.pipelineLength?.reserve || 0}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.pipelineLength?.ext2 || 0}
|
|
</td>
|
|
<td className="p-2 border-t border-black text-center">
|
|
{(report.pipelineLength?.reserve || 0) + (report.pipelineLength?.ext2 || 0)}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Shift Header Component
|
|
function ReportSheetShiftHeader({ shift }: { shift: string }) {
|
|
return (
|
|
<div className="bg-green-500 text-white p-2 text-center font-bold mb-2 mt-6">
|
|
{shift.charAt(0).toUpperCase() + shift.slice(1)} Shift
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Equipment Statistics Component
|
|
function ReportSheetEquipmentStats({ report }: { report: any }) {
|
|
return (
|
|
<div className="border-2 border-black mb-4">
|
|
<table className="w-full border-collapse text-sm">
|
|
<tbody>
|
|
<tr>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Dozers</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Exc.</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Loader</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Foreman</td>
|
|
<td className="p-2 text-center font-semibold">Laborer</td>
|
|
</tr>
|
|
<tr>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.stats?.Dozers || 0}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.stats?.Exc || 0}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.stats?.Loaders || 0}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{report.stats?.Foreman || ''}
|
|
</td>
|
|
<td className="p-2 border-t border-black text-center">
|
|
{report.stats?.Laborer || 0}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Time Sheet Component
|
|
function ReportSheetTimeSheet({ report }: { report: any }) {
|
|
return (
|
|
<div className="border-2 border-black mb-4">
|
|
<table className="w-full border-collapse text-sm">
|
|
<thead>
|
|
<tr>
|
|
<td className="p-2 border-r border-black text-center font-semibold" rowSpan={2}>Time Sheet</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">From</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">To</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">From</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">To</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Total</td>
|
|
<td className="p-2 text-center font-semibold">Reason</td>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{Array.isArray(report.timeSheet) && report.timeSheet.length > 0 ? (
|
|
report.timeSheet.map((entry: any, index: number) => (
|
|
<tr key={index}>
|
|
<td className="p-2 border-r border-black border-t border-black font-semibold">
|
|
{entry.machine}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.from1}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.to1}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.from2}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.to2}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.total}
|
|
</td>
|
|
<td className="p-2 border-t border-black">
|
|
{entry.reason}
|
|
</td>
|
|
</tr>
|
|
))
|
|
) : (
|
|
<tr>
|
|
<td className="p-2 border-r border-black border-t border-black text-center" colSpan={7}>
|
|
No time sheet entries
|
|
</td>
|
|
</tr>
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Stoppages Component
|
|
function ReportSheetStoppages({ report }: { report: any }) {
|
|
return (
|
|
<>
|
|
<div className="bg-green-500 text-white p-2 text-center font-bold mb-2">
|
|
Dredger Stoppages
|
|
</div>
|
|
<div className="border-2 border-black mb-4">
|
|
<table className="w-full border-collapse text-sm">
|
|
<thead>
|
|
<tr>
|
|
<td className="p-2 border-r border-black text-center font-semibold">From</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">To</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Total</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Reason</td>
|
|
<td className="p-2 border-r border-black text-center font-semibold">Responsible</td>
|
|
<td className="p-2 text-center font-semibold">Notes</td>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{Array.isArray(report.stoppages) && report.stoppages.length > 0 ? (
|
|
report.stoppages.map((entry: any, index: number) => (
|
|
<tr key={index}>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.from}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.to}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black text-center">
|
|
{entry.total}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black">
|
|
{entry.reason}
|
|
</td>
|
|
<td className="p-2 border-r border-black border-t border-black">
|
|
{entry.responsible}
|
|
</td>
|
|
<td className="p-2 border-t border-black">
|
|
{entry.note}
|
|
</td>
|
|
</tr>
|
|
))
|
|
) : (
|
|
<tr>
|
|
<td className="p-2 border-r border-black border-t border-black text-center" colSpan={6}>
|
|
No stoppages recorded
|
|
</td>
|
|
</tr>
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
// Notes Component
|
|
function ReportSheetNotes({ report }: { report: any }) {
|
|
return (
|
|
<>
|
|
<div className="bg-green-500 text-white p-2 text-center font-bold mb-2">
|
|
Notes & Comments
|
|
</div>
|
|
<div className="border-2 border-black mb-4 min-h-[100px]">
|
|
<div className="p-4 text-center">
|
|
{report.notes || 'No additional notes'}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
// Footer Component
|
|
function ReportSheetFooter() {
|
|
return (
|
|
<div className="text-center text-sm mt-4 border-t border-black pt-2">
|
|
{/* موقعة لأعمال الصيانة */}
|
|
</div>
|
|
);
|
|
} |