Enhance PriceDisplay component with adjusted pricing calculations

- Added calculations for adjusted target and break-even prices based on remaining revenue and uncovered costs.
- Implemented clipboard copy functionality for adjusted prices.
- Updated layout to display adjusted prices alongside original calculations for better clarity.
This commit is contained in:
2025-07-08 13:17:16 +02:00
parent 78f4f1e527
commit 1dc07159c1

View File

@@ -219,17 +219,29 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
return Math.round(num * factor) / factor;
};
// Calculate total costs
// Calculate total costs and income
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 itemsSold = job.income?.reduce((sum, tx) => sum + tx.quantity, 0) || 0;
const itemsRemaining = (job.produced || 0) - itemsSold;
// Target price (based on projected revenue)
// Original calculations (based on full revenue and costs)
const targetPricePerUnit = job.projectedRevenue / job.produced;
const targetPriceWithTax = roundToSignificantDigits(targetPricePerUnit * (1 + salesTax));
// Break-even price (based on actual costs)
const breakEvenPricePerUnit = totalCosts / job.produced;
const breakEvenPriceWithTax = roundToSignificantDigits(breakEvenPricePerUnit * (1 + salesTax));
// Adjusted calculations (based on remaining revenue and uncovered costs)
const remainingRevenue = job.projectedRevenue - totalIncome;
const uncoveredCosts = totalCosts - totalIncome;
const adjustedTargetPricePerUnit = itemsRemaining > 0 ? remainingRevenue / itemsRemaining : 0;
const adjustedTargetPriceWithTax = roundToSignificantDigits(adjustedTargetPricePerUnit * (1 + salesTax));
const adjustedBreakEvenPricePerUnit = itemsRemaining > 0 ? Math.max(0, uncoveredCosts / itemsRemaining) : 0;
const adjustedBreakEvenPriceWithTax = roundToSignificantDigits(adjustedBreakEvenPricePerUnit * (1 + salesTax));
const handleCopyTargetPrice = async (e: React.MouseEvent) => {
e.stopPropagation();
await copyToClipboard(
@@ -248,6 +260,24 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
);
};
const handleCopyAdjustedTargetPrice = async (e: React.MouseEvent) => {
e.stopPropagation();
await copyToClipboard(
adjustedTargetPriceWithTax.toString(),
'adjustedTargetPrice',
'Adjusted target price copied to clipboard'
);
};
const handleCopyAdjustedBreakEvenPrice = async (e: React.MouseEvent) => {
e.stopPropagation();
await copyToClipboard(
adjustedBreakEvenPriceWithTax.toString(),
'adjustedBreakEvenPrice',
'Adjusted break-even price copied to clipboard'
);
};
const taxSuffix = salesTax > 0 ? ` (+${(salesTax * 100).toFixed(1)}% tax)` : '';
return (
@@ -283,6 +313,38 @@ const PriceDisplay: React.FC<PriceDisplayProps> = ({ job }) => {
{copying === 'breakEvenPrice' && <Copy className="w-3 h-3 text-green-400" />}
</span>
</div>
<div className="flex items-center gap-2 text-gray-400">
<Factory className="w-4 h-4" />
<span>Adjusted Target{taxSuffix}:</span>
</div>
<div className="flex items-center gap-2 text-gray-400">
<DollarSign className="w-4 h-4" />
<span>Adjusted Break-even{taxSuffix}:</span>
</div>
<div className="flex items-center gap-1 text-lg">
<span
className="cursor-pointer hover:text-blue-400 transition-colors inline-flex items-center gap-1 text-white"
onClick={handleCopyAdjustedTargetPrice}
title="Click to copy adjusted target price per unit (based on remaining revenue)"
data-no-navigate
>
{formatISK(adjustedTargetPriceWithTax)}
{copying === 'adjustedTargetPrice' && <Copy className="w-3 h-3 text-green-400" />}
</span>
</div>
<div className="flex items-center gap-1 text-lg">
<span
className="cursor-pointer hover:text-yellow-400 transition-colors inline-flex items-center gap-1 text-white"
onClick={handleCopyAdjustedBreakEvenPrice}
title="Click to copy adjusted break-even price per unit (based on uncovered costs)"
data-no-navigate
>
{formatISK(adjustedBreakEvenPriceWithTax)}
{copying === 'adjustedBreakEvenPrice' && <Copy className="w-3 h-3 text-green-400" />}
</span>
</div>
</div>
);
};