import React, { useState } from 'react' import { useData } from '../DataContext.jsx' export default function PriceGradient() { const { pgi } = useData() const [ch, setCh] = useState('TT') if (!pgi) return
Loading…
const d = pgi[ch] if (!d) return
No data for {ch}
const { rows, gi_c, gi_n, gi_chg } = d const giColor = gi_chg < 0 ? 'var(--gn)' : gi_chg > 0 ? 'var(--rd)' : 'var(--mt)' const dirColor = gi_n < 1 ? 'var(--gn)' : gi_n > 1 ? 'var(--rd)' : 'var(--mt)' const giSubLabel = gi_chg === 0 ? 'Unchanged' : (gi_chg < 0 ? 'Compressed ' : 'Stretched ') + (gi_chg < 0 ? '' : '+') + gi_chg.toFixed(2) + '%' return (
Price Gradient Index — Current vs Recommended
Reward gradient = % change in price/ml (PML) moving to the next pack size. Negative = discount for buying bigger (good). Positive premium = consumer penalised for upsizing (bad). GI = 400+ml PML ÷ 20-30ml PML.
{/* Channel filter */}
Channel
{/* KPI cards */}
GI Current
{gi_c.toFixed(4)}
400+ml PML ÷ 20-30ml PML
GI Recommended
{gi_n.toFixed(4)}
{giSubLabel}
Gradient Direction
{gi_n < 1 ? 'Inverted ✓' : 'Positive'}
{gi_n < 1 ? 'Large packs cheaper/ml' : 'Large packs costlier/ml'}
{/* Pack table */}
Pack-level Detail Shaded rows = packs with recommended price change
{rows.map((r, i) => { const changed = r.delta !== 0 const flipWarn = r.rg_c !== null && r.rg_n !== null && ((r.rg_c <= 0 && r.rg_n > 0) || (r.rg_c > 0 && r.rg_n < 0)) const rgStr = r.rg_c !== null && r.rg_n !== null ? `${r.rg_c >= 0 ? '+' : ''}${r.rg_c.toFixed(1)}% → ${r.rg_n >= 0 ? '+' : ''}${r.rg_n.toFixed(1)}%${flipWarn ? ' ⚠' : ''}` : '—' const rgClass = r.rg_n === null ? 'gi-rg-neu' : r.rg_n > 5 ? 'gi-rg-bad' : r.rg_n <= 0 ? 'gi-rg-good' : 'gi-rg-neu' return ( ) })}
PackSKU (ml)MRP currentMRP recommended Change PML currentPML recReward gradient (current → rec)
{r.pack}ml {r.sku} ₹{r.mrp_c.toFixed(2)} 0 ? 'gi-mrp-up' : r.delta < 0 ? 'gi-mrp-dn' : ''}> ₹{r.mrp_n.toFixed(2)} {r.delta === 0 ? : 0 ? 'gi-delta-up' : 'gi-delta-dn'}`}> {r.delta > 0 ? '+' : ''}{r.delta.toFixed(0)}% } ₹{r.pml_c.toFixed(4)} r.pml_c ? 'gi-mrp-up' : 'gi-mrp-dn') : ''}> ₹{r.pml_n.toFixed(4)} {rgStr}
{/* Flags */}
) } function GIFlags({ rows, gi_n, gi_chg }) { const flags = [] rows.forEach((r, i) => { if (r.rg_c !== null && r.rg_n !== null) { const flip = (r.rg_c <= 0 && r.rg_n > 0) || (r.rg_c > 0 && r.rg_n < 0) const fix = r.rg_c > 5 && r.rg_n <= 0 const prevPack = rows[i - 1] if (flip && r.rg_n > 0) { flags.push(
!
{prevPack ? prevPack.pack + 'ml' : '—'}→{r.pack}ml step flips to premium (+{r.rg_n.toFixed(1)}%) {' '}— after the {r.delta > 0 ? '+' : '−'}{Math.abs(r.delta)}% change on {r.pack}ml, it becomes MORE expensive per ml than the previous pack.
) } if (fix) { flags.push(
{prevPack ? prevPack.pack + 'ml' : '—'}→{r.pack}ml penalty removed {' '}— current premium of +{r.rg_c.toFixed(1)}% becomes a reward of {r.rg_n.toFixed(1)}% after the price cut.
) } } }) if (gi_chg <= -10) { flags.push(
!
GI compressed by {Math.abs(gi_chg).toFixed(1)}% {' '}— large packs are now significantly cheaper per ml than small packs (GI={gi_n.toFixed(4)}).
) } if (!flags.length) return null return (
{flags}
) }