44 Commits

Author SHA1 Message Date
Matt
deb4351e21 Enhance UX: Remove calculator comparisons and redesign receipt page
All checks were successful
Build and Push Docker Images / docker (push) Successful in 51s
## Changes Made:

### 1. Remove Carbon Impact Comparisons from Calculator Pages
- Removed from OffsetOrder.tsx (lines 532-542)
- Removed from MobileOffsetOrder.tsx (lines 429-432)
- Keep comparisons ONLY on CheckoutSuccess receipt page per user request

### 2. Comprehensive CheckoutSuccess Page Redesign
- Add Puffin logo prominently at top of receipt
- Implement status mapping: paid/fulfilled → "Confirmed", pending → "Processing"
- Add comprehensive print CSS (@media print rules)
- Hide interactive elements (buttons) when printing
- Optimize layout and spacing for printed receipt
- Professional receipt aesthetics with enhanced design:
  * Beautiful gradient header with logo
  * Highlighted carbon offset display with icon
  * Enhanced pricing breakdown section
  * Better typography and spacing throughout
  * Professional metadata section with date
  * Improved button styling with gradients and hover effects
  * Email confirmation notice with icon
  * Footer with contact information

### Benefits:
- Cleaner calculator UX (comparisons only on success)
- Professional printable receipt
- Clear "Confirmed" status (not "PENDING")
- Beautiful modern design that matches brand

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 14:09:00 +01:00
Matt
043cdf07b3 Fix state persistence: save state before navigation
All checks were successful
Build and Push Docker Images / docker (push) Successful in 47s
Issue: Calculator inputs were not being saved before navigating to checkout
because navigation happened synchronously before useEffect could run.

Solution: Call saveState() directly in handleCalculate before navigation
in both TripCalculator and MobileCalculator components.

This ensures calculator inputs (fuel amount, distance, etc.) are properly
preserved when users click "Calculate Impact" and then cancel checkout.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 14:02:28 +01:00
Matt
5e642794d8 Implement calculator state persistence and fix checkout navigation
All checks were successful
Build and Push Docker Images / docker (push) Successful in 49s
Features:
- Add useCalculatorState hook with localStorage persistence and 1-hour expiry
- State persists through page reloads and Stripe checkout redirects
- Automatically clears state on successful payment (paid/fulfilled status)

Navigation fixes:
- Fix white page issues on checkout success/cancel pages
- Replace <a> links with button handlers for proper state-based routing
- Pass navigation handlers from App.tsx to checkout pages

State persistence integration:
- TripCalculator: Save/restore calculator inputs (fuel, distance, custom)
- MobileCalculator: Full state persistence for mobile app route
- OffsetOrder: Persist offset percentage and portfolio selection
- MobileOffsetOrder: Persist offset percentage for mobile flow

Carbon impact comparisons:
- Add varied carbon impact comparisons with random selection
- Display 3 comparisons in preview mode, 5 in success mode
- Categories: cars, flights, trees, streaming, homes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 13:55:51 +01:00
Matt
9c7e65b894 Round prices UP and change portfolio name to "Puffin Portfolio"
All checks were successful
Build and Push Docker Images / docker (push) Successful in 49s
Changes:
- Changed portfolio description from "Portfolio {ID}" to "Puffin Portfolio"
- Round pricePerTon UP using Math.ceil() instead of exact decimals
- Round total cost UP using Math.ceil()

Example: $237.19 per ton → $238 per ton

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 13:05:52 +01:00
Matt
09e3c13eaf Fix pricing calculation by passing pricePerTon from frontend to backend
All checks were successful
Build and Push Docker Images / docker (push) Successful in 51s
The backend was using a hardcoded PORTFOLIO_PRICING map that only had prices
for portfolios 1, 2, 3 (defaulting to $18/ton for others). When Wren API
returns Portfolio ID 37 at $237/ton, the backend was calculating with $18/ton
instead, causing massive pricing discrepancies.

Changes:
- Frontend now passes pricePerTon (from Wren API) in checkout request
- Backend uses the received pricePerTon instead of lookup table
- Removed dependency on hardcoded PORTFOLIO_PRICING map
- Added validation for pricePerTon parameter

Example fix:
- Before: 0.03 tons × $18/ton = $0.54 (wrong!)
- After: 0.03 tons × $237/ton = $7.11 (correct!)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 13:00:13 +01:00
Matt
5ec24af338 Fix service worker cache preventing code updates and change fallback URL
All checks were successful
Build and Push Docker Images / docker (push) Successful in 44s
- Bumped service worker cache version to v2 to force cache invalidation
- Added activate event to explicitly clear old caches
- Enhanced service worker logging with update checking
- Changed API fallback URL from localhost:3001 to https://puffinoffset.com/api

This fixes the issue where new code deployments were not being used due to
service worker caching the old JavaScript with the timing bug.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 12:50:15 +01:00
Matt
8d9f65868a CRITICAL FIX: Lazy evaluate API URLs at request time, not module load time
All checks were successful
Build and Push Docker Images / docker (push) Successful in 43s
ROOT CAUSE (Zen Debug Investigation):
The API_BASE_URL constant was being evaluated when the module loaded,
BEFORE window.env was populated by env-config.js. This caused the app
to permanently use the fallback localhost:3001 instead of reading the
production URL from the .env file.

TIMING ISSUE:
1. Browser loads index.html
2. env-config.js loads (creates window.env)
3. main.tsx loads as ES module (DEFERRED)
4. Module imports checkoutClient → const API_BASE_URL executes
5. window.env NOT READY YET → falls back to localhost:3001
6. API_BASE_URL locked to wrong value forever

THE FIX:
Changed from module-level constants to request-time lazy evaluation.
Now getApiBaseUrl() is called WHEN THE API REQUEST HAPPENS, not when
the module loads. At that point window.env is guaranteed to exist.

FILES CHANGED:
- src/api/checkoutClient.ts:
  * Removed constant API_BASE_URL
  * All 3 functions now call getApiBaseUrl() at request time
  * Added logging to show which URL is being used

- src/api/aisClient.ts:
  * Removed constant API_KEY
  * Added getApiKey() function with lazy evaluation
  * Same pattern for consistency and future-proofing

This fixes: "FetchEvent for http://localhost:3001 resulted in network error"
Now uses: https://puffinoffset.com/api (from .env file)

🔒 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 12:43:16 +01:00
Matt
3aac87de50 Fix API_BASE_URL to use runtime configuration
All checks were successful
Build and Push Docker Images / docker (push) Successful in 45s
CRITICAL FIX: Checkout was failing because API calls went to localhost

The checkoutClient was hardcoded to use import.meta.env.VITE_API_BASE_URL
which is build-time only. In production, this defaulted to localhost:3001
instead of the actual backend URL.

Changed to read from window.env.API_BASE_URL (runtime config) first,
then fall back to build-time config. This matches the pattern used
in src/utils/config.ts.

Frontend will now correctly connect to:
- Development: http://localhost:3001
- Production: https://puffinoffset.com/api (from .env file)

Fixes network error: "Failed to fetch" when creating checkout session

🔒 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 12:36:57 +01:00
Matt
0d7ac4b1de Add missing logger.info() and logger.debug() methods
All checks were successful
Build and Push Docker Images / docker (push) Successful in 43s
FIX: TypeError: z.info is not a function in production

The logger object was missing .info() and .debug() methods that were
being called in OffsetOrder.tsx and other components. This caused
checkout to fail in production with "z.info is not a function" error.

Added:
- logger.info() - Info level logging (dev only)
- logger.debug() - Debug level logging (dev only)

All logger methods now follow the same pattern:
- log, info, warn, debug: Only log in development
- error: Always log (production + development)

🔒 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 12:34:07 +01:00
Matt
06733cb2cb Integrate Stripe Checkout and add comprehensive UI enhancements
All checks were successful
Build and Push Docker Image / docker (push) Successful in 42s
## 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
Matt
3a33221130 Hide debug logs in production
All checks were successful
Build and Push Docker Image / docker (push) Successful in 48s
- Create logger utility that only logs in development mode
- Update wrenClient.ts to use logger instead of console.log/warn
- Update OffsetOrder.tsx to use logger for debug messages
- Update config.ts to only log environment loading in dev mode
- Keeps console.error for actual errors (always shown)

Fixes: Console clutter in production deployment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 14:58:22 +01:00
Matt
01b232f909 Enhance UX with number formatting and improve offset workflow
- Add comma-separated number formatting for better readability in all calculator inputs
- Move offset percentage selection from calculator to offset order page for clearer workflow
- Improve project card layout with consistent height alignment in OffsetOrder
- Change number inputs to text inputs to support formatted display
- Update form messages to reflect chosen offset percentage
- Add CLAUDE.md documentation for repository guidance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 12:51:43 +01:00
Matt
ab0dbbdb35 Refactor MobileOffsetOrder component for enhanced clarity and maintainability 2025-06-05 01:56:50 +02:00
Matt
e67e64947c Refactor MobileOffsetOrder component for improved structure and clarity 2025-06-05 01:52:03 +02:00
Matt
1a9a1b9464 Refactor MobileOffsetOrder component for improved readability and maintainability 2025-06-05 01:43:39 +02:00
Matt
fc828becdc Add MobileOffsetOrder component for CO₂ offset ordering process 2025-06-05 01:35:18 +02:00
Matt
8cc4284140 Add PWA support and implement mobile calculator component 2025-06-05 01:08:00 +02:00
Matt
4df64da3d4 removed divider 2025-06-03 19:16:32 +02:00
Matt
7690d59447 updates 2025-06-03 19:12:15 +02:00
Matt
1663329d7b updates 2025-06-03 19:07:33 +02:00
Matt
7484824246 Update favicon and logo from SVG to WebP format
Replace puffin-logo.svg with puffinOffset.webp in both the favicon link and JSON-LD structured data to use WebP image format instead of SVG.
2025-06-03 18:45:33 +02:00
Matt
fe801c1542 Improve responsive layout and clean up interaction handling
- Increase max widths and improve responsive spacing across components
- Add responsive grid columns (xl:grid-cols-4) for better large screen layout
- Remove redundant click area overlay and hover effects for cleaner code
- Consolidate padding management to main container level
2025-06-03 18:29:34 +02:00
Matt
8ff0ba44f8 updates 2025-06-03 18:18:42 +02:00
Matt
1f2e0e8222 updates 2025-06-03 17:07:59 +02:00
Matt
df2e11f600 updates 2025-06-03 15:25:13 +02:00
Matt
bf38357c74 updates 2025-06-03 15:21:29 +02:00
Matt
e816ea48d2 updates 2025-06-03 15:09:20 +02:00
Matt
5308cb61d1 updates 2025-06-03 15:02:29 +02:00
Matt
f9e4bc0149 Add framer-motion animations to enhance UI interactions
- Install framer-motion dependency (v12.15.0)
- Add smooth transitions to forms and buttons in TripCalculator
- Implement hover and tap animations for interactive elements
- Add entrance/exit animations for component state changes
- Enhance user experience with motion effects in Home and OffsetOrder components
2025-06-03 14:26:22 +02:00
Matt
bf0f362ab7 Merge branch 'main' of https://code.puffinoffset.com/matt/puffin-app 2025-06-03 14:08:35 +02:00
Matt
2376205371 Added lightboxes 2025-06-03 14:07:33 +02:00
Matt
96496350ee Updated with Lightboxes 2025-06-02 20:36:04 +02:00
Matt
5d0cfdef47 more fixes 2025-05-13 21:05:12 +02:00
Matt
43fca42b7f more fixes 2025-05-13 20:58:17 +02:00
Matt
444ab364a4 better connections 2025-05-13 20:48:28 +02:00
Matt
c29b15cd0b more fixes 2025-05-13 20:42:16 +02:00
Matt
7be9fc3722 more fixes 2025-05-13 20:21:05 +02:00
Matt
279098e9fa more fixes 2025-05-13 20:12:41 +02:00
Matt
2f7f26e4fd updates 2025-05-13 20:09:23 +02:00
Matt
fc47823714 more fixes 2025-05-13 19:54:39 +02:00
Matt
6ebd2527cd fixes 2025-05-13 19:37:22 +02:00
Matt
04160a2fd2 fixes 2025-05-13 19:26:51 +02:00
Matt
0ce149bf89 fixes 2025-05-13 19:13:31 +02:00
Matt
121b1264b7 initial push 2025-05-13 18:50:30 +02:00