Files
edbridge-scholars/src/components/lessons/MultiStepPercentWidget.tsx
2026-03-12 02:39:34 +06:00

151 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from "react";
const MultiStepPercentWidget: React.FC = () => {
const start = 100;
const [change1, setChange1] = useState(40); // +40%
const [change2, setChange2] = useState(-25); // -25%
const step1Val = start * (1 + change1 / 100);
const finalVal = step1Val * (1 + change2 / 100);
const overallChange = ((finalVal - start) / start) * 100;
const naiveChange = change1 + change2;
// Scale for visualization
const maxVal = Math.max(start, step1Val, finalVal, 150);
const getWidth = (val: number) => (val / maxVal) * 100;
return (
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
<div className="flex flex-col md:flex-row gap-8 mb-8">
<div className="w-full md:w-1/3 space-y-6">
<div>
<label className="text-xs font-bold text-slate-400 uppercase">
Change 1 (Markup)
</label>
<div className="flex items-center gap-3">
<input
type="range"
min="-50"
max="100"
step="5"
value={change1}
onChange={(e) => setChange1(parseInt(e.target.value))}
className="flex-1 accent-indigo-600"
/>
<span className="font-bold text-indigo-600 w-12 text-right">
{change1 > 0 ? "+" : ""}
{change1}%
</span>
</div>
</div>
<div>
<label className="text-xs font-bold text-slate-400 uppercase">
Change 2 (Discount)
</label>
<div className="flex items-center gap-3">
<input
type="range"
min="-50"
max="50"
step="5"
value={change2}
onChange={(e) => setChange2(parseInt(e.target.value))}
className="flex-1 accent-rose-600"
/>
<span className="font-bold text-rose-600 w-12 text-right">
{change2 > 0 ? "+" : ""}
{change2}%
</span>
</div>
</div>
</div>
<div className="flex-1 space-y-4">
{/* Step 0 */}
<div className="relative">
<div className="flex justify-between text-xs font-bold text-slate-400 mb-1">
<span>Start</span>
<span>${start}</span>
</div>
<div
className="h-8 bg-slate-200 rounded-md"
style={{ width: `${getWidth(start)}%` }}
></div>
</div>
{/* Step 1 */}
<div className="relative">
<div className="flex justify-between text-xs font-bold text-indigo-500 mb-1">
<span>
After {change1 > 0 ? "+" : ""}
{change1}%
</span>
<span>${step1Val.toFixed(2)}</span>
</div>
<div
className="h-8 bg-indigo-100 rounded-md transition-all duration-500"
style={{ width: `${getWidth(step1Val)}%` }}
>
<div
className="h-full bg-indigo-500 rounded-l-md"
style={{ width: `${(start / step1Val) * 100}%` }}
></div>
</div>
</div>
{/* Step 2 */}
<div className="relative">
<div className="flex justify-between text-xs font-bold text-rose-500 mb-1">
<span>
After {change2 > 0 ? "+" : ""}
{change2}%
</span>
<span>${finalVal.toFixed(2)}</span>
</div>
<div
className="h-8 bg-rose-100 rounded-md transition-all duration-500"
style={{ width: `${getWidth(finalVal)}%` }}
>
<div
className="h-full bg-rose-500 rounded-l-md"
style={{ width: `${(step1Val / finalVal) * 100}%` }}
></div>
</div>
</div>
</div>
</div>
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 grid grid-cols-2 gap-4 text-center">
<div>
<div className="text-xs font-bold text-slate-400 uppercase mb-1">
The Trap (Additive)
</div>
<div className="text-lg font-bold text-slate-400 line-through decoration-red-500 decoration-2">
{naiveChange > 0 ? "+" : ""}
{naiveChange}%
</div>
<div className="text-[10px] text-slate-400">
({change1} + {change2})
</div>
</div>
<div>
<div className="text-xs font-bold text-emerald-600 uppercase mb-1">
Actual Change
</div>
<div className="text-2xl font-bold text-emerald-600">
{overallChange > 0 ? "+" : ""}
{overallChange.toFixed(2)}%
</div>
<div className="text-[10px] text-emerald-600 font-mono">
1.{change1} × {1 + change2 / 100} ={" "}
{(1 + change1 / 100) * (1 + change2 / 100)}
</div>
</div>
</div>
</div>
);
};
export default MultiStepPercentWidget;