diff --git a/src/components/JobCardDetails.tsx b/src/components/JobCardDetails.tsx index 20f8bcc..eb79922 100644 --- a/src/components/JobCardDetails.tsx +++ b/src/components/JobCardDetails.tsx @@ -1,3 +1,4 @@ + import { useState, useEffect } from 'react'; import { Calendar, Factory, Clock, Copy, DollarSign } from 'lucide-react'; import { Input } from '@/components/ui/input'; @@ -6,6 +7,7 @@ import { useJobs } from '@/hooks/useDataService'; import { useToast } from '@/hooks/use-toast'; import { useClipboard } from '@/hooks/useClipboard'; import { formatISK } from '@/utils/priceUtils'; +import { formatDuration, calculateRemainingTime } from '@/utils/timeUtils'; interface JobCardDetailsProps { job: IndJob; @@ -14,11 +16,26 @@ interface JobCardDetailsProps { const JobCardDetails: React.FC = ({ job }) => { const [editingField, setEditingField] = useState(null); const [tempValues, setTempValues] = useState<{ [key: string]: string }>({}); + const [remainingTime, setRemainingTime] = useState(0); const { updateJob } = useJobs(); const { toast } = useToast(); const { copying, copyToClipboard } = useClipboard(); + // Update remaining time for running jobs + useEffect(() => { + if (job.status === 'Running' && job.jobStart && job.runtime) { + const updateRemainingTime = () => { + const remaining = calculateRemainingTime(job.jobStart, job.runtime); + setRemainingTime(remaining); + }; + + updateRemainingTime(); + const interval = setInterval(updateRemainingTime, 1000); + return () => clearInterval(interval); + } + }, [job.status, job.jobStart, job.runtime]); + const formatDateTime = (dateString: string | null | undefined) => { if (!dateString) return 'Not set'; return new Date(dateString).toLocaleString('en-CA', { @@ -183,6 +200,26 @@ const JobCardDetails: React.FC = ({ job }) => { fieldName="saleEnd" icon={} /> + + {job.status === 'Running' && job.runtime && ( + <> +
+ + Runtime: +
+
+ {formatDuration(job.runtime)} +
+ +
+ + Remaining: +
+
+ {formatDuration(remainingTime)} +
+ + )} {job.projectedRevenue > 0 && job.produced > 0 && ( diff --git a/src/components/JobStatusNavigation.tsx b/src/components/JobStatusNavigation.tsx index 3e6e505..9eedc6a 100644 --- a/src/components/JobStatusNavigation.tsx +++ b/src/components/JobStatusNavigation.tsx @@ -74,7 +74,7 @@ const JobStatusNavigation: React.FC = ({ job }) => { e.stopPropagation(); handleStatusChange(previousStatus); }} - className={`${getStatusColor(previousStatus)}/60 text-white px-4 py-2 rounded flex items-center justify-center gap-1 hover:opacity-80 transition-opacity w-32`} + className={`${getStatusColor(previousStatus)} text-white px-4 py-2 rounded flex items-center justify-center gap-1 hover:opacity-80 transition-opacity w-32`} data-no-navigate title={`Move to ${previousStatus}`} > @@ -88,7 +88,7 @@ const JobStatusNavigation: React.FC = ({ job }) => { e.stopPropagation(); handleStatusChange(nextStatus); }} - className={`${getStatusColor(nextStatus)}/60 text-white px-4 py-2 rounded flex items-center justify-center gap-1 hover:opacity-80 transition-opacity w-32`} + className={`${getStatusColor(nextStatus)} text-white px-4 py-2 rounded flex items-center justify-center gap-1 hover:opacity-80 transition-opacity w-32`} data-no-navigate title={`Move to ${nextStatus}`} > diff --git a/src/utils/timeUtils.ts b/src/utils/timeUtils.ts new file mode 100644 index 0000000..16aa472 --- /dev/null +++ b/src/utils/timeUtils.ts @@ -0,0 +1,35 @@ + +export const formatDuration = (seconds: number): string => { + if (seconds <= 0) return 'Ready!'; + + const units = [ + { name: 'w', value: 604800 }, // weeks + { name: 'd', value: 86400 }, // days + { name: 'h', value: 3600 }, // hours + { name: 'm', value: 60 }, // minutes + { name: 's', value: 1 } // seconds + ]; + + const parts: string[] = []; + let remaining = Math.floor(seconds); + + for (const unit of units) { + if (remaining >= unit.value) { + const count = Math.floor(remaining / unit.value); + parts.push(`${count}${unit.name}`); + remaining %= unit.value; + } + } + + return parts.length > 0 ? parts.join(' ') : '0s'; +}; + +export const calculateRemainingTime = (jobStart: string | null, runtime: number): number => { + if (!jobStart || !runtime) return 0; + + const startTime = new Date(jobStart).getTime(); + const currentTime = Date.now(); + const elapsedSeconds = (currentTime - startTime) / 1000; + + return Math.max(0, runtime - elapsedSeconds); +};