puffin-app/src/components/forms/FormFieldWrapper.tsx

100 lines
2.5 KiB
TypeScript
Raw Normal View History

Integrate Stripe Checkout and add comprehensive UI enhancements ## Stripe Payment Integration - Add Express.js backend server with Stripe Checkout Sessions - Create SQLite database for order tracking - Implement Stripe webhook handlers for payment events - Integrate with Wren Climate API for carbon offset fulfillment - Add CheckoutSuccess and CheckoutCancel pages - Create checkout API client for frontend - Update OffsetOrder component to redirect to Stripe Checkout - Add processing fee calculation (3% of base amount) - Implement order status tracking (pending → paid → fulfilled) Backend (server/): - Express server with CORS and middleware - SQLite database with Order schema - Stripe configuration and client - Order CRUD operations model - Checkout session creation endpoint - Webhook handler for payment confirmation - Wren API client for offset fulfillment Frontend: - CheckoutSuccess page with order details display - CheckoutCancel page with retry encouragement - Updated OffsetOrder to use Stripe checkout flow - Added checkout routes to App.tsx - TypeScript interfaces for checkout flow ## Visual & UX Enhancements - Add CertificationBadge component for project verification status - Create PortfolioDonutChart for visual portfolio allocation - Implement RadialProgress for percentage displays - Add reusable form components (FormInput, FormTextarea, FormSelect, FormFieldWrapper) - Refactor OffsetOrder with improved layout and animations - Add offset percentage slider with visual feedback - Enhance MobileOffsetOrder with better responsive design - Improve TripCalculator with cleaner UI structure - Update CurrencySelect with better styling - Add portfolio distribution visualization - Enhance project cards with hover effects and animations - Improve color palette and gradient usage throughout ## Configuration - Add VITE_API_BASE_URL environment variable - Create backend .env.example template - Update frontend .env.example with API URL - Add Stripe documentation references 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 21:45:14 +01:00
import React, { ReactNode } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { AlertCircle } from 'lucide-react';
interface FormFieldWrapperProps {
id: string;
label: string;
icon?: ReactNode;
error?: string;
isFilled: boolean;
isFocused: boolean;
disabled?: boolean;
children: ReactNode;
}
export function FormFieldWrapper({
id,
label,
icon,
error,
isFilled,
isFocused,
disabled,
children,
}: FormFieldWrapperProps) {
const isFloated = isFocused || isFilled;
const hasError = !!error;
return (
<div className="w-full">
<div className="relative">
{/* Icon (if provided) */}
{icon && (
<div className="absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none text-puffin-gray-label z-10">
{icon}
</div>
)}
{/* Floating Label */}
<motion.label
htmlFor={id}
className={`
absolute left-3 pointer-events-none origin-left z-10
transition-colors duration-200
${icon ? 'pl-7' : ''}
${hasError ? 'text-puffin-error' : isFloated ? 'text-puffin-blue-focus' : 'text-puffin-gray-label'}
${disabled ? 'opacity-50' : ''}
`}
initial={false}
animate={{
y: isFloated ? -24 : 12,
scale: isFloated ? 0.85 : 1,
}}
transition={{
type: 'tween',
ease: 'easeOut',
duration: 0.2,
}}
>
{label}
</motion.label>
{/* Input Container with Border & Focus Effect */}
<div
className={`
relative rounded-lg transition-all duration-200
${hasError
? isFocused
? 'shadow-focus-red'
: ''
: isFocused
? 'shadow-focus-blue'
: ''
}
`}
>
{children}
</div>
</div>
{/* Error Message */}
<AnimatePresence>
{hasError && (
<motion.div
id={`${id}-error`}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
className="flex items-center gap-1.5 mt-1.5 text-sm text-puffin-error"
>
<AlertCircle className="w-4 h-4 flex-shrink-0" />
<span>{error}</span>
</motion.div>
)}
</AnimatePresence>
</div>
);
}