# 2026-02-10 - Tradeify iOS Safari Fix & Map Implementation

## Major Work: Tradeify NEXT iOS Safari Debugging

### The Problem
iOS Safari required double-tap on all interactive elements (buttons, links, cards). First tap triggered hover state, second tap actually navigated.

### Root Cause
1. iOS Safari treats first tap as hover, requiring second tap for click
2. CSS hover rules were interfering with touch events
3. React Router's `<NavLink>` and `<Link>` components weren't firing properly on iOS

### The Fix (Critical Learning)
**Replace all `onClick` with `onPointerUp`** and use `<div role="button">` instead of `<button>` or `<Link>`:

```tsx
// DON'T do this on iOS:
<button onClick={() => navigate('/path')}>Click</button>
<Link to="/path">Link</Link>
<NavLink to="/path">Nav</NavLink>

// DO this instead:
<div role="button" onPointerUp={() => navigate('/path')}>Click</div>
```

**Also removed problematic CSS:**
- `all: unset` on hover states was breaking navigation
- `:active` opacity changes were causing visual glitches
- Keep CSS minimal for touch devices

### Files Changed
- `Layout.tsx` - Bottom nav buttons → divs with onPointerUp
- `Search.tsx` - All buttons (List/Map/Filter/sort pills) → divs with onPointerUp
- `TradespersonCard.tsx` - Link → div with onPointerUp + useNavigate
- `HeartBtn.tsx` - button → div with onPointerUp
- `index.css` - Removed aggressive hover/active overrides

## Map Implementation

### Features Added
1. **Map view toggle** - List/Map buttons on Search page
2. **Company logos as markers** - Profile images displayed as circular map pins
3. **Dark theme tiles** - Stadia Alidade Smooth Dark (shows parks/grass in green)
4. **Address/Eircode search** - Top bar geocodes location using OpenStreetMap Nominatim
5. **Auto-zoom** - Centers on user location at ~10km radius (zoom level 12)
6. **Smart tap detection** - Cancels navigation if user is zooming (pinch/pan detected)

### Map Tap Detection (for zooming)
Had to implement custom tap detection because Leaflet's click events didn't work well on iOS:
- Track pointer down position
- Cancel if moved >10px (user is panning)
- Cancel on multi-touch (user is pinching to zoom)
- Only navigate on clean, stationary tap
- Uses data-trade-id attributes on marker divs for event delegation

### Stack
- `react-leaflet` + `leaflet` for maps
- Lazy loaded (`React.lazy`) to reduce initial bundle
- Stadia Maps tiles (free, shows natural features)
- OpenStreetMap Nominatim for geocoding (free)

## Deployment
All changes deployed to: tradeify-next.pages.dev
Deploy command: `npx wrangler pages deploy dist --project-name=tradeify-next --commit-dirty=true`

## Key Learnings

### iOS Safari Touch Handling
1. **onPointerUp > onClick** for touch devices
2. **div role="button" > button/Link** when click handling is problematic
3. **Avoid CSS hover overrides** - they can break touch states
4. **pointer-events-none on children** - prevents child elements intercepting taps
5. **touch-manipulation** - reduces 300ms tap delay

### Map UX
1. **Marker tap vs zoom conflict** - need gesture detection to distinguish
2. **Profile images as markers** - more engaging than generic pins
3. **Dark tiles with features** - Stadia > CartoDB for natural feature visibility

## Status
- iOS Safari double-tap bug: FIXED
- Map view: WORKING
- Address search: WORKING
- Ready for Rob's continued testing

---

## Afternoon: Business Verification System

### Spec (Approved by Rob)
Built a complete claim flow for tradespeople to verify they own their business listing.

### Verification Methods (in priority order)
1. **Email** - Instant verify if email matches listing (masked: m••••x@tilt.ie)
2. **Phone** - Instant verify via SMS code (masked: +353 •••••• 789)
3. **Website** - Add meta tag/file to domain, pending staff review
4. **Document** - Upload business registration, reviewed manually

### New Files Created
- `/src/lib/verification.ts` - Types, masking functions, rate limits (3 attempts, 15min lockout), code generation
- `/src/pages/ClaimStart.tsx` - Entry point, explains process
- `/src/pages/VerifyMethod.tsx` - Select email/phone/website/document
- `/src/pages/VerifyCode.tsx` - 6-digit code entry with auto-advance between inputs
- `/src/pages/ClaimStatus.tsx` - Shows pending/approved/rejected status
- `/src/pages/ClaimComplete.tsx` - Success page with next steps

### Design Decisions
- **Full-page flow** - Routes outside Layout (no bottom nav during claim)
- **No postal verification** - Competitors could add fake addresses
- **"Verified since [date]"** - Shows on profile after verification
- **Rate limiting** - 3 code attempts, then 15min lockout

### Routes Added to App.tsx
```tsx
<Route path="/claim/:id" element={<ClaimStart />} />
<Route path="/claim/:id/verify" element={<VerifyMethod />} />
<Route path="/claim/:id/code" element={<VerifyCode />} />
<Route path="/claim/:id/status" element={<ClaimStatus />} />
<Route path="/claim/:id/complete" element={<ClaimComplete />} />
```

### Quote Request Cleanup
- Removed hourly rate field (tradespeople set their own)
- Removed estimated cost calculations
- Removed fee breakdown display
- Kept: job description, photos, preferred dates, location

---

## Love Irish Food Scanner Migration

Migrated from Netlify to Cloudflare Pages:
- **Old URL**: stellular-froyo-a16382.netlify.app
- **New URL**: love-irish-food-scanner.pages.dev
- Same single HTML file, no build needed
- Deployed via Cloudflare Pages dashboard

---

## Pending
- Tradeify claim flow deployment (upload in progress at session end)
- Wire Mission Control to OpenClaw sessions API
- Switch tradeify.ie production to NEXT (waiting for Rob to add ALIAS record)
