Refactor MobileOffsetOrder component for improved readability and maintainability
This commit is contained in:
parent
fc828becdc
commit
1a9a1b9464
@ -11,8 +11,19 @@ interface Props {
|
|||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Project {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
description: string;
|
||||||
|
location: string;
|
||||||
|
pricePerTon: number;
|
||||||
|
imageUrl: string;
|
||||||
|
percentage: number;
|
||||||
|
}
|
||||||
|
|
||||||
export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Props) {
|
export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Props) {
|
||||||
const [currentStep, setCurrentStep] = useState<'summary' | 'payment' | 'confirmation'>('summary');
|
const [currentStep, setCurrentStep] = useState<'summary' | 'projects' | 'payment' | 'confirmation'>('summary');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [orderData, setOrderData] = useState({
|
const [orderData, setOrderData] = useState({
|
||||||
name: '',
|
name: '',
|
||||||
@ -20,6 +31,40 @@ export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Pr
|
|||||||
phone: ''
|
phone: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Dummy projects data
|
||||||
|
const projects: Project[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'Coastal Blue Carbon',
|
||||||
|
type: 'Blue Carbon',
|
||||||
|
description: 'Protecting and restoring coastal wetlands that capture carbon 10x faster than forests.',
|
||||||
|
location: 'Indonesia',
|
||||||
|
pricePerTon: 25,
|
||||||
|
imageUrl: 'https://images.unsplash.com/photo-1559827260-dc66d52bef19?auto=format&fit=crop&q=80&w=800',
|
||||||
|
percentage: 0.35
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: 'Wind Power Initiative',
|
||||||
|
type: 'Renewable Energy',
|
||||||
|
description: 'Supporting offshore wind farms to replace fossil fuel energy generation.',
|
||||||
|
location: 'North Sea',
|
||||||
|
pricePerTon: 15,
|
||||||
|
imageUrl: 'https://images.unsplash.com/photo-1548337138-e87d889cc369?auto=format&fit=crop&q=80&w=800',
|
||||||
|
percentage: 0.30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
name: 'Rainforest Conservation',
|
||||||
|
type: 'Forestry',
|
||||||
|
description: 'Protecting critical rainforest habitats from deforestation.',
|
||||||
|
location: 'Amazon Basin',
|
||||||
|
pricePerTon: 12,
|
||||||
|
imageUrl: 'https://images.unsplash.com/photo-1511884642898-4c92249e20b6?auto=format&fit=crop&q=80&w=800',
|
||||||
|
percentage: 0.35
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
// Calculate cost (using dummy pricing)
|
// Calculate cost (using dummy pricing)
|
||||||
const pricePerTon = 18; // $18 per ton
|
const pricePerTon = 18; // $18 per ton
|
||||||
const totalCost = monetaryAmount || (tons * pricePerTon);
|
const totalCost = monetaryAmount || (tons * pricePerTon);
|
||||||
@ -30,6 +75,10 @@ export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Pr
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleProceedToPayment = () => {
|
const handleProceedToPayment = () => {
|
||||||
|
setCurrentStep('projects');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProceedFromProjects = () => {
|
||||||
setCurrentStep('payment');
|
setCurrentStep('payment');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -149,6 +198,87 @@ export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Pr
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderProjectsStep = () => (
|
||||||
|
<motion.div
|
||||||
|
className="space-y-6"
|
||||||
|
initial={{ opacity: 0, x: 20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
exit={{ opacity: 0, x: -20 }}
|
||||||
|
>
|
||||||
|
<div className="bg-white rounded-2xl p-6 shadow-sm">
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Project Portfolio</h3>
|
||||||
|
<p className="text-sm text-gray-600 mb-4">
|
||||||
|
Your offset will be distributed across these verified carbon reduction projects
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{projects.map((project, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={project.id}
|
||||||
|
className="border border-gray-200 rounded-xl overflow-hidden"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: index * 0.1 }}
|
||||||
|
>
|
||||||
|
<div className="relative h-32">
|
||||||
|
<img
|
||||||
|
src={project.imageUrl}
|
||||||
|
alt={project.name}
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
|
||||||
|
<div className="absolute bottom-2 left-3 right-3">
|
||||||
|
<h4 className="text-white font-semibold text-sm">{project.name}</h4>
|
||||||
|
<p className="text-white/80 text-xs">{project.location}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-xs font-medium text-blue-600 bg-blue-50 px-2 py-1 rounded">
|
||||||
|
{project.type}
|
||||||
|
</span>
|
||||||
|
<span className="text-sm font-semibold text-gray-900">
|
||||||
|
{(project.percentage * 100).toFixed(0)}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-sm text-gray-600 mb-3">
|
||||||
|
{project.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between text-xs">
|
||||||
|
<span className="text-gray-500">Price per ton</span>
|
||||||
|
<span className="font-medium text-gray-900">${project.pricePerTon}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-blue-50 rounded-xl p-4">
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="font-medium text-blue-900">Total CO₂ Offset</span>
|
||||||
|
<span className="font-bold text-blue-900">{tons.toFixed(2)} tons</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="font-medium text-blue-900">Portfolio Price</span>
|
||||||
|
<span className="font-bold text-lg text-blue-900">
|
||||||
|
{formatCurrency(totalCost, targetCurrency)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleProceedFromProjects}
|
||||||
|
className="w-full bg-gradient-to-r from-blue-500 to-blue-600 text-white py-4 px-6 rounded-xl font-semibold text-lg shadow-md hover:shadow-lg transition-all"
|
||||||
|
>
|
||||||
|
Continue to Payment
|
||||||
|
</button>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
|
||||||
const renderPaymentStep = () => (
|
const renderPaymentStep = () => (
|
||||||
<motion.div
|
<motion.div
|
||||||
className="space-y-6"
|
className="space-y-6"
|
||||||
@ -340,6 +470,7 @@ export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Pr
|
|||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<h1 className="text-lg font-bold text-gray-900">
|
<h1 className="text-lg font-bold text-gray-900">
|
||||||
{currentStep === 'summary' ? 'Order Summary' :
|
{currentStep === 'summary' ? 'Order Summary' :
|
||||||
|
currentStep === 'projects' ? 'Project Portfolio' :
|
||||||
currentStep === 'payment' ? 'Payment' :
|
currentStep === 'payment' ? 'Payment' :
|
||||||
'Order Confirmed'}
|
'Order Confirmed'}
|
||||||
</h1>
|
</h1>
|
||||||
@ -353,7 +484,10 @@ export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Pr
|
|||||||
<div className="px-4 pb-3">
|
<div className="px-4 pb-3">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div className={`flex-1 h-2 rounded-full ${
|
<div className={`flex-1 h-2 rounded-full ${
|
||||||
currentStep === 'summary' ? 'bg-blue-200' : 'bg-blue-500'
|
['summary', 'projects', 'payment'].includes(currentStep) ? 'bg-blue-500' : 'bg-gray-200'
|
||||||
|
}`} />
|
||||||
|
<div className={`flex-1 h-2 rounded-full ${
|
||||||
|
['projects', 'payment'].includes(currentStep) ? 'bg-blue-500' : 'bg-gray-200'
|
||||||
}`} />
|
}`} />
|
||||||
<div className={`flex-1 h-2 rounded-full ${
|
<div className={`flex-1 h-2 rounded-full ${
|
||||||
currentStep === 'payment' ? 'bg-blue-500' : 'bg-gray-200'
|
currentStep === 'payment' ? 'bg-blue-500' : 'bg-gray-200'
|
||||||
@ -366,6 +500,7 @@ export function MobileOffsetOrder({ tons, monetaryAmount, currency, onBack }: Pr
|
|||||||
<div className="p-4 pb-20">
|
<div className="p-4 pb-20">
|
||||||
<AnimatePresence mode="wait">
|
<AnimatePresence mode="wait">
|
||||||
{currentStep === 'summary' && renderSummaryStep()}
|
{currentStep === 'summary' && renderSummaryStep()}
|
||||||
|
{currentStep === 'projects' && renderProjectsStep()}
|
||||||
{currentStep === 'payment' && renderPaymentStep()}
|
{currentStep === 'payment' && renderPaymentStep()}
|
||||||
{currentStep === 'confirmation' && renderConfirmationStep()}
|
{currentStep === 'confirmation' && renderConfirmationStep()}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user