"use client"; import { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { TrendingUp, TrendingDown, Calculator, DollarSign, Loader2, Info } from "lucide-react"; import { toast } from "sonner"; import { apiRequest } from "@/lib/api"; import { motion, AnimatePresence } from "framer-motion"; interface ProfitAnalysisModalProps { open: boolean; onClose: () => void; productId: string; productName: string; } interface ProfitData { productId: string; name: string; costPerUnit: number; pricing: Array<{ minQuantity: number; pricePerUnit: number; }>; profitMargins: Array<{ minQuantity: number; pricePerUnit: number; profit: number | null; profitMargin: number | null; markup: number | null; }>; summary: { hasCostData: boolean; averageProfit: number | null; averageProfitMargin: number | null; averageMarkup: number | null; }; } export const ProfitAnalysisModal: React.FC = ({ open, onClose, productId, productName, }) => { const [profitData, setProfitData] = useState(null); const [loading, setLoading] = useState(false); useEffect(() => { if (open && productId) { fetchProfitAnalysis(); } }, [open, productId]); const fetchProfitAnalysis = async () => { try { setLoading(true); const response = await apiRequest(`/products/${productId}/profit-analysis`); setProfitData(response); } catch (error) { console.error("Error fetching profit analysis:", error); toast.error("Failed to load profit analysis"); } finally { setLoading(false); } }; const formatCurrency = (amount: number | null) => { if (amount === null) return "N/A"; return new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP', minimumFractionDigits: 2 }).format(amount); }; const formatPercentage = (percentage: number | null) => { if (percentage === null) return "N/A"; return `${percentage.toFixed(1)}%`; }; const getProfitColor = (profit: number | null) => { if (profit === null) return "text-muted-foreground"; return profit >= 0 ? "text-emerald-500" : "text-rose-500"; }; const getProfitIcon = (profit: number | null) => { if (profit === null) return Calculator; return profit >= 0 ? TrendingUp : TrendingDown; }; // Variants for staggered animations const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.1 } } }; const itemVariants = { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0 } }; if (loading) { return ( Profit Analysis - {productName}

Calculating metrics...

); } if (!profitData) { return ( Profit Analysis - {productName}

No profit data available

); } return (
Profit Analysis: {productName}
{/* Summary Cards */} {profitData.summary.hasCostData ? (
Average Profit
{formatCurrency(profitData.summary.averageProfit)}

Per unit sold

Avg. Margin
{formatPercentage(profitData.summary.averageProfitMargin)}

Of selling price

Avg. Markup
{formatPercentage(profitData.summary.averageMarkup)}

On cost price

) : (

Missing Cost Data

Add a generic "Cost Per Unit" to this product to see detailed profit calculations.

Current Cost: {formatCurrency(profitData.costPerUnit)}
)} {/* Cost Information */}
Base Cost Per Unit
{formatCurrency(profitData.costPerUnit)}
{/* Pricing Tier Analysis */}

Tier Breakdown

{profitData.profitMargins .sort((a, b) => a.minQuantity - b.minQuantity) .map((tier, index) => { const ProfitIcon = getProfitIcon(tier.profit); const totalProfitForMinQty = tier.profit !== null ? tier.profit * tier.minQuantity : null; const totalRevenueForMinQty = tier.pricePerUnit * tier.minQuantity; const totalCostForMinQty = profitData.costPerUnit * tier.minQuantity; return (
= 0 ? 'bg-emerald-500' : 'bg-rose-500'}`} />
{tier.minQuantity}+ UNITS at {formatCurrency(tier.pricePerUnit)}
Rev: {formatCurrency(totalRevenueForMinQty)} Cost: {formatCurrency(totalCostForMinQty)}
Margin
= 50 ? 'text-emerald-400' : 'text-blue-400'}`}> {formatPercentage(tier.profitMargin)}
Net Profit
{tier.profit && tier.profit > 0 ? '+' : ''}{formatCurrency(tier.profit)}
Total: {formatCurrency(totalProfitForMinQty)}
); })}
{/* Help Text */}

Quick Guide

Profit Selling Price - Cost Price
Margin (Profit / Selling Price) × 100
Markup (Profit / Cost Price) × 100
); };