2 - Show projected distribution on progress bars with yellow indicators

This commit is contained in:
myrmidex 2026-03-22 16:59:53 +01:00
parent c2d2262488
commit a07d916663
3 changed files with 21 additions and 5 deletions

View file

@ -5,7 +5,7 @@ const centsToDollars = (cents: number): number => cents / 100;
const basisPointsToPercent = (bp: number): number => bp / 100;
const formatDollars = (cents: number): string => `$${centsToDollars(cents).toFixed(0)}`;
export default function BucketCard({ bucket }: { bucket: Bucket }) {
export default function BucketCard({ bucket, projectedAmount }: { bucket: Bucket; projectedAmount?: number }) {
const hasFiniteCapacity = bucket.allocation_type === 'fixed_limit' && bucket.effective_capacity !== null;
return (
@ -24,6 +24,7 @@ export default function BucketCard({ bucket }: { bucket: Bucket }) {
<DigitalProgressBar
current={bucket.current_balance}
capacity={bucket.effective_capacity!}
projected={projectedAmount}
/>
</div>
) : (
@ -40,6 +41,11 @@ export default function BucketCard({ bucket }: { bucket: Bucket }) {
<span className="font-digital text-red-500 text-sm">
{formatDollars(bucket.current_balance)}
</span>
{projectedAmount && projectedAmount > 0 && (
<span className="font-digital text-yellow-500 text-sm">
{' '}+{formatDollars(projectedAmount)}
</span>
)}
{hasFiniteCapacity && (
<span className="font-digital text-red-500/50 text-sm">
{' '}/ {formatDollars(bucket.effective_capacity!)}

View file

@ -1,6 +1,7 @@
interface DigitalProgressBarProps {
current: number;
capacity: number;
projected?: number;
}
const BAR_COUNT = 20;
@ -17,10 +18,15 @@ function getBarColor(index: number): string {
return 'bg-green-500';
}
export default function DigitalProgressBar({ current, capacity }: DigitalProgressBarProps) {
const PROJECTED_GLOW = '0 0 8px rgba(234, 179, 8, 0.6)';
export default function DigitalProgressBar({ current, capacity, projected }: DigitalProgressBarProps) {
const filledBars = capacity > 0
? Math.min(Math.round((current / capacity) * BAR_COUNT), BAR_COUNT)
: 0;
const projectedBars = capacity > 0 && projected
? Math.min(Math.round(((current + projected) / capacity) * BAR_COUNT), BAR_COUNT)
: filledBars;
return (
<div
@ -33,15 +39,16 @@ export default function DigitalProgressBar({ current, capacity }: DigitalProgres
>
{Array.from({ length: BAR_COUNT }, (_, i) => {
const filled = i < filledBars;
const isProjected = !filled && i < projectedBars;
return (
<div
key={i}
style={{
borderRadius: '3px',
transition: 'background-color 300ms, box-shadow 300ms',
boxShadow: filled ? getGlow(i) : 'none',
boxShadow: filled ? getGlow(i) : isProjected ? PROJECTED_GLOW : 'none',
}}
className={filled ? getBarColor(i) : 'bg-red-500/10'}
className={filled ? getBarColor(i) : isProjected ? 'bg-yellow-500' : 'bg-red-500/10'}
/>
);
})}

View file

@ -281,7 +281,10 @@ export default function Show({ scenario, buckets }: Props) {
onClick={() => setEditingBucket(bucket)}
className="w-full border-4 border-red-500 bg-black glow-red transition-all text-left hover:border-red-400 cursor-pointer"
>
<BucketCard bucket={bucket} />
<BucketCard
bucket={bucket}
projectedAmount={distribution?.allocations.find(a => a.bucket_id === bucket.id)?.allocated_amount}
/>
</button>
))}
</div>