Code format
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState } from 'react';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
@@ -208,11 +208,11 @@ const BatchTransactionForm: React.FC<BatchTransactionFormProps> = ({ onClose, on
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50"
|
className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
className="bg-gray-900 border-gray-700 text-white w-full max-w-4xl max-h-[90vh] overflow-y-auto"
|
className="bg-gray-900 border-gray-700 text-white w-full max-w-4xl max-h-[90vh] overflow-y-auto"
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
|
@@ -202,7 +202,7 @@ interface PriceDisplayProps {
|
|||||||
const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
||||||
const { copying, copyToClipboard } = useClipboard();
|
const { copying, copyToClipboard } = useClipboard();
|
||||||
const [salesTax, setSalesTax] = useState(() => parseFloat(localStorage.getItem('salesTax') || '0') / 100);
|
const [salesTax, setSalesTax] = useState(() => parseFloat(localStorage.getItem('salesTax') || '0') / 100);
|
||||||
|
|
||||||
// Listen for storage changes to update tax rate
|
// Listen for storage changes to update tax rate
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleStorageChange = () => {
|
const handleStorageChange = () => {
|
||||||
@@ -218,35 +218,35 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
|||||||
const factor = Math.pow(10, digits - 1 - magnitude);
|
const factor = Math.pow(10, digits - 1 - magnitude);
|
||||||
return Math.round(num * factor) / factor;
|
return Math.round(num * factor) / factor;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate total costs and income
|
// Calculate total costs and income
|
||||||
const totalCosts = job.expenditures?.reduce((sum, tx) => sum + tx.totalPrice, 0) || 0;
|
const totalCosts = job.expenditures?.reduce((sum, tx) => sum + tx.totalPrice, 0) || 0;
|
||||||
const totalIncome = job.income?.reduce((sum, tx) => sum + tx.totalPrice, 0) || 0;
|
const totalIncome = job.income?.reduce((sum, tx) => sum + tx.totalPrice, 0) || 0;
|
||||||
const itemsSold = job.income?.reduce((sum, tx) => sum + tx.quantity, 0) || 0;
|
const itemsSold = job.income?.reduce((sum, tx) => sum + tx.quantity, 0) || 0;
|
||||||
const itemsRemaining = (job.produced || 0) - itemsSold;
|
const itemsRemaining = (job.produced || 0) - itemsSold;
|
||||||
|
|
||||||
// Original calculations (based on full revenue and costs)
|
// Original calculations (based on full revenue and costs)
|
||||||
const targetPricePerUnit = job.projectedRevenue / job.produced;
|
const targetPricePerUnit = job.projectedRevenue / job.produced;
|
||||||
const targetPriceWithTax = roundToSignificantDigits(targetPricePerUnit * (1 + salesTax));
|
const targetPriceWithTax = roundToSignificantDigits(targetPricePerUnit * (1 + salesTax));
|
||||||
|
|
||||||
const breakEvenPricePerUnit = totalCosts / job.produced;
|
const breakEvenPricePerUnit = totalCosts / job.produced;
|
||||||
const breakEvenPriceWithTax = roundToSignificantDigits(breakEvenPricePerUnit * (1 + salesTax));
|
const breakEvenPriceWithTax = roundToSignificantDigits(breakEvenPricePerUnit * (1 + salesTax));
|
||||||
|
|
||||||
// Adjusted calculations (based on remaining revenue and uncovered costs)
|
// Adjusted calculations (based on remaining revenue and uncovered costs)
|
||||||
const remainingRevenue = job.projectedRevenue - totalIncome;
|
const remainingRevenue = job.projectedRevenue - totalIncome;
|
||||||
const uncoveredCosts = totalCosts - totalIncome;
|
const uncoveredCosts = totalCosts - totalIncome;
|
||||||
|
|
||||||
const adjustedTargetPricePerUnit = itemsRemaining > 0 ? remainingRevenue / itemsRemaining : 0;
|
const adjustedTargetPricePerUnit = itemsRemaining > 0 ? remainingRevenue / itemsRemaining : 0;
|
||||||
const adjustedTargetPriceWithTax = roundToSignificantDigits(adjustedTargetPricePerUnit * (1 + salesTax));
|
const adjustedTargetPriceWithTax = roundToSignificantDigits(adjustedTargetPricePerUnit * (1 + salesTax));
|
||||||
|
|
||||||
const adjustedBreakEvenPricePerUnit = itemsRemaining > 0 ? Math.max(0, uncoveredCosts / itemsRemaining) : 0;
|
const adjustedBreakEvenPricePerUnit = itemsRemaining > 0 ? Math.max(0, uncoveredCosts / itemsRemaining) : 0;
|
||||||
const adjustedBreakEvenPriceWithTax = roundToSignificantDigits(adjustedBreakEvenPricePerUnit * (1 + salesTax));
|
const adjustedBreakEvenPriceWithTax = roundToSignificantDigits(adjustedBreakEvenPricePerUnit * (1 + salesTax));
|
||||||
|
|
||||||
const handleCopyTargetPrice = async (e: React.MouseEvent) => {
|
const handleCopyTargetPrice = async (e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
await copyToClipboard(
|
await copyToClipboard(
|
||||||
targetPriceWithTax.toString(),
|
targetPriceWithTax.toString(),
|
||||||
'targetPrice',
|
'targetPrice',
|
||||||
'Target price copied to clipboard'
|
'Target price copied to clipboard'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -254,8 +254,8 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
|||||||
const handleCopyBreakEvenPrice = async (e: React.MouseEvent) => {
|
const handleCopyBreakEvenPrice = async (e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
await copyToClipboard(
|
await copyToClipboard(
|
||||||
breakEvenPriceWithTax.toString(),
|
breakEvenPriceWithTax.toString(),
|
||||||
'breakEvenPrice',
|
'breakEvenPrice',
|
||||||
'Break-even price copied to clipboard'
|
'Break-even price copied to clipboard'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -263,8 +263,8 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
|||||||
const handleCopyAdjustedTargetPrice = async (e: React.MouseEvent) => {
|
const handleCopyAdjustedTargetPrice = async (e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
await copyToClipboard(
|
await copyToClipboard(
|
||||||
adjustedTargetPriceWithTax.toString(),
|
adjustedTargetPriceWithTax.toString(),
|
||||||
'adjustedTargetPrice',
|
'adjustedTargetPrice',
|
||||||
'Adjusted target price copied to clipboard'
|
'Adjusted target price copied to clipboard'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -272,8 +272,8 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
|||||||
const handleCopyAdjustedBreakEvenPrice = async (e: React.MouseEvent) => {
|
const handleCopyAdjustedBreakEvenPrice = async (e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
await copyToClipboard(
|
await copyToClipboard(
|
||||||
adjustedBreakEvenPriceWithTax.toString(),
|
adjustedBreakEvenPriceWithTax.toString(),
|
||||||
'adjustedBreakEvenPrice',
|
'adjustedBreakEvenPrice',
|
||||||
'Adjusted break-even price copied to clipboard'
|
'Adjusted break-even price copied to clipboard'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -290,7 +290,7 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
|||||||
<DollarSign className="w-4 h-4" />
|
<DollarSign className="w-4 h-4" />
|
||||||
<span>Break-even{taxSuffix}:</span>
|
<span>Break-even{taxSuffix}:</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-1 text-lg">
|
<div className="flex items-center gap-1 text-lg">
|
||||||
<span
|
<span
|
||||||
className="cursor-pointer hover:text-blue-400 transition-colors inline-flex items-center gap-1 text-white"
|
className="cursor-pointer hover:text-blue-400 transition-colors inline-flex items-center gap-1 text-white"
|
||||||
@@ -322,7 +322,7 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
|
|||||||
<DollarSign className="w-4 h-4" />
|
<DollarSign className="w-4 h-4" />
|
||||||
<span>Adjusted Break-even{taxSuffix}:</span>
|
<span>Adjusted Break-even{taxSuffix}:</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-1 text-lg">
|
<div className="flex items-center gap-1 text-lg">
|
||||||
<span
|
<span
|
||||||
className="cursor-pointer hover:text-blue-400 transition-colors inline-flex items-center gap-1 text-white"
|
className="cursor-pointer hover:text-blue-400 transition-colors inline-flex items-center gap-1 text-white"
|
||||||
|
@@ -31,10 +31,10 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
|||||||
// Calculate performance metrics - Simple price per unit comparison
|
// Calculate performance metrics - Simple price per unit comparison
|
||||||
const itemsSold = sortedIncome.reduce((sum, tx) => sum + tx.quantity, 0);
|
const itemsSold = sortedIncome.reduce((sum, tx) => sum + tx.quantity, 0);
|
||||||
const produced = job.produced || 0;
|
const produced = job.produced || 0;
|
||||||
|
|
||||||
// Only show performance if we have produced items and sold items
|
// Only show performance if we have produced items and sold items
|
||||||
const showPerformanceIndicator = produced > 0 && itemsSold > 0 && job.projectedRevenue > 0;
|
const showPerformanceIndicator = produced > 0 && itemsSold > 0 && job.projectedRevenue > 0;
|
||||||
|
|
||||||
let performancePercentage = 0;
|
let performancePercentage = 0;
|
||||||
if (showPerformanceIndicator) {
|
if (showPerformanceIndicator) {
|
||||||
const expectedPPU = job.projectedRevenue / produced;
|
const expectedPPU = job.projectedRevenue / produced;
|
||||||
@@ -108,12 +108,11 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
|||||||
{formatISK(job.projectedCost)}
|
{formatISK(job.projectedCost)}
|
||||||
</span>
|
</span>
|
||||||
)}</div>
|
)}</div>
|
||||||
<div
|
<div
|
||||||
className={`text-xs font-medium px-2 py-0.5 rounded-full inline-block ${
|
className={`text-xs font-medium px-2 py-0.5 rounded-full inline-block ${totalExpenditure <= job.projectedCost
|
||||||
totalExpenditure <= job.projectedCost
|
? 'bg-green-900/50 text-green-400'
|
||||||
? 'bg-green-900/50 text-green-400'
|
|
||||||
: 'bg-red-900/50 text-red-400'
|
: 'bg-red-900/50 text-red-400'
|
||||||
}`}
|
}`}
|
||||||
title={`Cost efficiency: ${((totalExpenditure / job.projectedCost) * 100).toFixed(1)}% of projected cost`}
|
title={`Cost efficiency: ${((totalExpenditure / job.projectedCost) * 100).toFixed(1)}% of projected cost`}
|
||||||
>
|
>
|
||||||
{totalExpenditure <= job.projectedCost ? '✅' : '⚠️'} {((totalExpenditure / job.projectedCost) * 100).toFixed(0)}%
|
{totalExpenditure <= job.projectedCost ? '✅' : '⚠️'} {((totalExpenditure / job.projectedCost) * 100).toFixed(0)}%
|
||||||
@@ -151,25 +150,23 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
|||||||
</span>
|
</span>
|
||||||
)}</div>
|
)}</div>
|
||||||
<div className="flex justify-center gap-2">
|
<div className="flex justify-center gap-2">
|
||||||
<div
|
<div
|
||||||
className={`text-xs font-medium px-2 py-0.5 rounded-full inline-block ${
|
className={`text-xs font-medium px-2 py-0.5 rounded-full inline-block ${totalIncome >= job.projectedRevenue
|
||||||
totalIncome >= job.projectedRevenue
|
? 'bg-green-900/50 text-green-400'
|
||||||
? 'bg-green-900/50 text-green-400'
|
|
||||||
: 'bg-yellow-900/50 text-yellow-400'
|
: 'bg-yellow-900/50 text-yellow-400'
|
||||||
}`}
|
}`}
|
||||||
title={`Revenue progress: ${((totalIncome / job.projectedRevenue) * 100).toFixed(1)}% of projected revenue`}
|
title={`Revenue progress: ${((totalIncome / job.projectedRevenue) * 100).toFixed(1)}% of projected revenue`}
|
||||||
>
|
>
|
||||||
{totalIncome >= job.projectedRevenue ? '🎯' : '📊'} {((totalIncome / job.projectedRevenue) * 100).toFixed(0)}%
|
{totalIncome >= job.projectedRevenue ? '🎯' : '📊'} {((totalIncome / job.projectedRevenue) * 100).toFixed(0)}%
|
||||||
</div>
|
</div>
|
||||||
{showPerformanceIndicator && (
|
{showPerformanceIndicator && (
|
||||||
<div
|
<div
|
||||||
className={`text-xs font-medium px-2 py-0.5 rounded-full inline-block ${
|
className={`text-xs font-medium px-2 py-0.5 rounded-full inline-block ${performancePercentage >= 100
|
||||||
performancePercentage >= 100
|
? 'bg-green-900/50 text-green-400'
|
||||||
? 'bg-green-900/50 text-green-400'
|
: performancePercentage >= 90
|
||||||
: performancePercentage >= 90
|
? 'bg-yellow-900/50 text-yellow-400'
|
||||||
? 'bg-yellow-900/50 text-yellow-400'
|
|
||||||
: 'bg-red-900/50 text-red-400'
|
: 'bg-red-900/50 text-red-400'
|
||||||
}`}
|
}`}
|
||||||
title={`Price performance: ${formatISK(totalIncome / itemsSold)}/unit vs ${formatISK(job.projectedRevenue / produced)}/unit expected (${performancePercentage.toFixed(1)}%)`}
|
title={`Price performance: ${formatISK(totalIncome / itemsSold)}/unit vs ${formatISK(job.projectedRevenue / produced)}/unit expected (${performancePercentage.toFixed(1)}%)`}
|
||||||
>
|
>
|
||||||
{performancePercentage >= 100 ? '📈' : performancePercentage >= 90 ? '⚠️' : '📉'} {performancePercentage.toFixed(0)}%
|
{performancePercentage >= 100 ? '📈' : performancePercentage >= 90 ? '⚠️' : '📉'} {performancePercentage.toFixed(0)}%
|
||||||
|
Reference in New Issue
Block a user