2 - Show projected distribution on progress bars with yellow indicators
This commit is contained in:
parent
c2d2262488
commit
a07d916663
3 changed files with 21 additions and 5 deletions
|
|
@ -5,7 +5,7 @@ const centsToDollars = (cents: number): number => cents / 100;
|
||||||
const basisPointsToPercent = (bp: number): number => bp / 100;
|
const basisPointsToPercent = (bp: number): number => bp / 100;
|
||||||
const formatDollars = (cents: number): string => `$${centsToDollars(cents).toFixed(0)}`;
|
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;
|
const hasFiniteCapacity = bucket.allocation_type === 'fixed_limit' && bucket.effective_capacity !== null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -24,6 +24,7 @@ export default function BucketCard({ bucket }: { bucket: Bucket }) {
|
||||||
<DigitalProgressBar
|
<DigitalProgressBar
|
||||||
current={bucket.current_balance}
|
current={bucket.current_balance}
|
||||||
capacity={bucket.effective_capacity!}
|
capacity={bucket.effective_capacity!}
|
||||||
|
projected={projectedAmount}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -40,6 +41,11 @@ export default function BucketCard({ bucket }: { bucket: Bucket }) {
|
||||||
<span className="font-digital text-red-500 text-sm">
|
<span className="font-digital text-red-500 text-sm">
|
||||||
{formatDollars(bucket.current_balance)}
|
{formatDollars(bucket.current_balance)}
|
||||||
</span>
|
</span>
|
||||||
|
{projectedAmount && projectedAmount > 0 && (
|
||||||
|
<span className="font-digital text-yellow-500 text-sm">
|
||||||
|
{' '}+{formatDollars(projectedAmount)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
{hasFiniteCapacity && (
|
{hasFiniteCapacity && (
|
||||||
<span className="font-digital text-red-500/50 text-sm">
|
<span className="font-digital text-red-500/50 text-sm">
|
||||||
{' '}/ {formatDollars(bucket.effective_capacity!)}
|
{' '}/ {formatDollars(bucket.effective_capacity!)}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
interface DigitalProgressBarProps {
|
interface DigitalProgressBarProps {
|
||||||
current: number;
|
current: number;
|
||||||
capacity: number;
|
capacity: number;
|
||||||
|
projected?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BAR_COUNT = 20;
|
const BAR_COUNT = 20;
|
||||||
|
|
@ -17,10 +18,15 @@ function getBarColor(index: number): string {
|
||||||
return 'bg-green-500';
|
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
|
const filledBars = capacity > 0
|
||||||
? Math.min(Math.round((current / capacity) * BAR_COUNT), BAR_COUNT)
|
? Math.min(Math.round((current / capacity) * BAR_COUNT), BAR_COUNT)
|
||||||
: 0;
|
: 0;
|
||||||
|
const projectedBars = capacity > 0 && projected
|
||||||
|
? Math.min(Math.round(((current + projected) / capacity) * BAR_COUNT), BAR_COUNT)
|
||||||
|
: filledBars;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
@ -33,15 +39,16 @@ export default function DigitalProgressBar({ current, capacity }: DigitalProgres
|
||||||
>
|
>
|
||||||
{Array.from({ length: BAR_COUNT }, (_, i) => {
|
{Array.from({ length: BAR_COUNT }, (_, i) => {
|
||||||
const filled = i < filledBars;
|
const filled = i < filledBars;
|
||||||
|
const isProjected = !filled && i < projectedBars;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: '3px',
|
borderRadius: '3px',
|
||||||
transition: 'background-color 300ms, box-shadow 300ms',
|
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'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,10 @@ export default function Show({ scenario, buckets }: Props) {
|
||||||
onClick={() => setEditingBucket(bucket)}
|
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"
|
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>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue