All files / features/live/components/gauges GaugeClassic.tsx

100% Statements 7/7
75% Branches 3/4
100% Functions 2/2
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104              1x           3x 3x 3x 3x   3x                                                                                                                         3x                                                
import { motion } from 'framer-motion'
import CountUp from 'react-countup'
import { useTranslation } from 'react-i18next'
import { useCurrencyFormatter } from '@core/hooks/useCurrencyFormatter'
 
import { type GaugeProps } from '../../types'
 
export const GaugeClassic = ({
    totalRaisedCents,
    prevTotal,
    goalAmount,
    totalLabel,
}: GaugeProps) => {
    const { t } = useTranslation('common')
    const { formatCurrency } = useCurrencyFormatter()
    const percentage = goalAmount > 0 ? (totalRaisedCents / (goalAmount * 100)) * 100 : 100
    const progressPercentage = Math.min(percentage, 100)
 
    return (
        <div className="relative w-[500px] h-[500px]">
            <svg
                className="w-full h-full transform -rotate-90 filter"
                style={{ filter: 'drop-shadow(0 0 15px var(--live-gauge-shadow))' }}
            >
                {/* Track */}
                <circle
                    cx="50%"
                    cy="50%"
                    r="45%"
                    stroke="var(--live-gauge-track)"
                    strokeWidth="12"
                    fill="none"
                />
                {/* Progress */}
                <motion.circle
                    cx="50%"
                    cy="50%"
                    r="45%"
                    stroke="url(#gradient)"
                    strokeWidth="12"
                    fill="none"
                    strokeLinecap="round"
                    strokeDasharray="283"
                    strokeDashoffset={283 - (283 * progressPercentage) / 100}
                    initial={{ strokeDashoffset: 283 }}
                    animate={{ strokeDashoffset: 283 - (283 * progressPercentage) / 100 }}
                    transition={{ duration: 1.5, ease: 'easeOut' }}
                    pathLength={1}
                    style={{
                        pathLength: 1,
                        strokeDasharray: 1,
                        strokeDashoffset: 1 - progressPercentage / 100,
                    }}
                />
                <defs>
                    <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
                        <stop offset="0%" stopColor="var(--live-gauge-from, var(--primary))" />
                        <stop offset="100%" stopColor="var(--live-gauge-to, var(--secondary))" />
                    </linearGradient>
                </defs>
            </svg>
 
            {/* Center Counter */}
            <div className="absolute inset-0 flex flex-col items-center justify-center">
                <motion.div
                    className="text-6xl font-black tabular-nums tracking-tighter bg-clip-text text-transparent"
                    style={{
                        backgroundImage:
                            'linear-gradient(to bottom, var(--live-classic-counter-gradient-from), var(--live-classic-counter-gradient-to))',
                    }}
                    initial={{ scale: 0.5, opacity: 0 }}
                    animate={{ scale: 1, opacity: 1 }}
                >
                    <CountUp
                        start={prevTotal / 100}
                        end={totalRaisedCents / 100}
                        duration={2.5}
                        separator=","
                        decimals={0}
                        formattingFn={(value) => formatCurrency(value)}
                    />
                </motion.div>
                <div
                    className="mt-4 px-6 py-2 rounded-full border text-sm font-medium tracking-widest uppercase"
                    style={{
                        backgroundColor: 'var(--live-badge-bg, var(--glass-bg))',
                        backdropFilter: 'blur(var(--glass-blur))',
                        borderColor: 'var(--live-badge-border, var(--glass-border))',
                        color: 'var(--live-badge-text, var(--live-text-secondary))',
                    }}
                >
                    {totalLabel || t('live.total_raised')}
                </div>
                <div
                    className="mt-2 text-xs uppercase tracking-widest"
                    style={{ color: 'var(--live-text-muted)' }}
                >
                    {t('live.goal')}: {formatCurrency(goalAmount)}
                </div>
            </div>
        </div>
    )
}