Refactored key components to use react-i18next translations: - ErrorBoundary: error messages and labels - ProgressStepper: step labels - DimensionCard: health status labels, descriptions, benchmark text, action buttons - DashboardTabs: back button, footer, default title Added translation keys to es.json and en.json: - dashboard.defaultTitle - All health status and benchmark keys already existed Build verified successfully. Remaining 31 components to be refactored in subsequent commits. https://claude.ai/code/session_4f888c33-8937-4db8-8a9d-ddc9ac51a725
107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import React from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import { Check, Package, Upload, BarChart3 } from 'lucide-react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import clsx from 'clsx';
|
|
|
|
interface Step {
|
|
id: number;
|
|
label: string;
|
|
icon: React.ElementType;
|
|
}
|
|
|
|
interface ProgressStepperProps {
|
|
currentStep: number;
|
|
}
|
|
|
|
const ProgressStepper: React.FC<ProgressStepperProps> = ({ currentStep }) => {
|
|
const { t } = useTranslation();
|
|
|
|
const steps: Step[] = [
|
|
{ id: 1, label: t('stepper.selectTier'), icon: Package },
|
|
{ id: 2, label: t('stepper.uploadData'), icon: Upload },
|
|
{ id: 3, label: t('stepper.viewResults'), icon: BarChart3 },
|
|
];
|
|
|
|
return (
|
|
<div className="w-full max-w-3xl mx-auto mb-8">
|
|
<div className="relative flex items-center justify-between">
|
|
{steps.map((step, index) => {
|
|
const Icon = step.icon;
|
|
const isCompleted = currentStep > step.id;
|
|
const isCurrent = currentStep === step.id;
|
|
const isUpcoming = currentStep < step.id;
|
|
|
|
return (
|
|
<React.Fragment key={step.id}>
|
|
{/* Step Circle */}
|
|
<div className="relative flex flex-col items-center z-10">
|
|
<motion.div
|
|
initial={{ scale: 0.8, opacity: 0 }}
|
|
animate={{ scale: 1, opacity: 1 }}
|
|
transition={{ delay: index * 0.1 }}
|
|
className={clsx(
|
|
'w-12 h-12 rounded-full flex items-center justify-center border-2 transition-all duration-300',
|
|
isCompleted && 'bg-green-500 border-green-500',
|
|
isCurrent && 'bg-blue-600 border-blue-600 shadow-lg shadow-blue-500/50',
|
|
isUpcoming && 'bg-white border-slate-300'
|
|
)}
|
|
>
|
|
{isCompleted ? (
|
|
<motion.div
|
|
initial={{ scale: 0 }}
|
|
animate={{ scale: 1 }}
|
|
transition={{ type: 'spring', stiffness: 200 }}
|
|
>
|
|
<Check className="text-white" size={24} />
|
|
</motion.div>
|
|
) : (
|
|
<Icon
|
|
className={clsx(
|
|
'transition-colors',
|
|
isCurrent && 'text-white',
|
|
isUpcoming && 'text-slate-400'
|
|
)}
|
|
size={20}
|
|
/>
|
|
)}
|
|
</motion.div>
|
|
|
|
{/* Step Label */}
|
|
<motion.span
|
|
initial={{ opacity: 0, y: 10 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: index * 0.1 + 0.1 }}
|
|
className={clsx(
|
|
'mt-2 text-sm font-medium text-center whitespace-nowrap',
|
|
(isCompleted || isCurrent) && 'text-slate-900',
|
|
isUpcoming && 'text-slate-500'
|
|
)}
|
|
>
|
|
{step.label}
|
|
</motion.span>
|
|
</div>
|
|
|
|
{/* Connector Line */}
|
|
{index < steps.length - 1 && (
|
|
<div className="flex-1 h-0.5 bg-slate-200 mx-4 relative -mt-6">
|
|
<motion.div
|
|
className="absolute inset-0 bg-gradient-to-r from-green-500 to-blue-600 h-full"
|
|
initial={{ width: '0%' }}
|
|
animate={{
|
|
width: currentStep > step.id ? '100%' : '0%',
|
|
}}
|
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
|
/>
|
|
</div>
|
|
)}
|
|
</React.Fragment>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ProgressStepper;
|