Enhance mobile UX and hero sections across dive entity pages#10
Closed
Enhance mobile UX and hero sections across dive entity pages#10
Conversation
Move diving centers map above search filters for better UX consistency with dive sites page. Simplify sorting controls in map view to show only view mode switching. Fix onViewportChange prop requirement by making it optional in map components to prevent runtime errors. - Move map section above sticky filter bar - Add simplified view mode controls for map view - Make onViewportChange prop optional in DivingCentersMap and DiveSitesMap - Match layout pattern used in dive sites page - Fix compilation and formatting issues
This comprehensive update improves the mobile user experience and visual consistency across dive-sites, diving-centers, and dive-trips pages. ## Mobile Sorting Controls Visibility - Add visible text labels to mobile sorting control buttons - Replace icon-only buttons with clear text labels: 'Filters', 'Sort' - Update CSS to accommodate text labels in mobile floating action buttons - Resolve issue where mobile users couldn't understand button functions ## Mobile View Mode Buttons - Add List/Grid/Map view mode buttons to dive-sites and diving-centers pages - Implement consistent mobile detection using window resize listeners - Ensure buttons only appear on mobile devices (≤768px screen width) - Match existing functionality from dive-trips page ## Hero Section Button Updates - Rename '+ Create Dive Site' to '+ Add Dive Site' on dive-sites page - Copy hero button styling from dive-sites to diving-centers page - Add three consistent buttons to diving-centers hero: * 'Explore Map' with Compass icon and map view functionality * 'Browse Centers' with Globe icon and list view functionality * '+ Add Center' with Plus icon and create functionality - Maintain responsive design and hover effects across all buttons ## Technical Improvements - Add Compass icon import for map exploration functionality - Implement proper mobile detection with useEffect and event listeners - Ensure consistent button styling, spacing, and animations - Maintain accessibility with proper touch targets (44px minimum) ## Files Modified - EnhancedMobileSortingControls.js: Add text labels to mobile buttons - index.css: Update mobile-fab styling for text labels - DiveSites.js: Rename button text, add mobile detection, add view mode buttons - DivingCenters.js: Add mobile detection, add view mode buttons, update hero section All changes maintain existing functionality while significantly improving mobile UX and visual consistency across the platform.
kargig
added a commit
that referenced
this pull request
Dec 7, 2025
Implement comprehensive cache optimizations to reduce Open-Meteo API calls and improve wind overlay performance: Backend optimizations: - Increase cache size from 100 to 500 entries to accommodate 24-hour caching for multiple grid points - Always use hourly forecast API to cache all 24 hours from single API response (Optimization #10) - Implement smart cache lookup checking representative hours (00:00, 12:00, requested hour) to quickly find cached data - Group grid points by cache key (0.1° rounding) before API calls, ensuring only one call per cache cell (Optimization #3) - Add skip_validation parameter to avoid redundant datetime validation when called from grid function - Add detailed cache logging with [CACHE HIT], [CACHE MISS], [API CALL] prefixes for better debugging - Detect and warn about cache inconsistencies when date data exists but specific hour is missing Frontend optimizations: - Add prefetchWindHours function that prefetches next 2 days (one request per day at noon) when play button is pressed - Integrate prefetch with WindDateTimePicker via onPrefetch prop to cache upcoming hours before slider advances - Enhance useViewportData with zoom-based detail levels (minimal < 4, basic 8-9, full >= 10) for progressive loading - Expand bounds for zoom >= 11 to ensure nearby dive sites remain visible when panning - Increase debounce time from 1s to 1.5s for smoother UX These optimizations significantly reduce API calls by leveraging 24-hour bulk caching and intelligent cache lookup strategies.
kargig
added a commit
that referenced
this pull request
Dec 7, 2025
* Add wind overlay backend and shore direction detection
Implement backend infrastructure for wind overlay feature on dive
sites map. Adds automatic shore direction detection from OpenStreetMap
coastline data and wind-based dive site suitability recommendations.
Backend Services:
- Open-Meteo service for fetching wind data (current and forecast)
- OSM coastline service for automatic shore direction detection
- Wind recommendation service with 6.2 m/s safe threshold
- In-memory caching with TTL for wind data
Database Changes:
- Migration 0042: Add shore_direction fields to dive_sites table
- Fields: shore_direction, shore_direction_confidence,
shore_direction_method, shore_direction_distance_m
API Endpoints:
- GET /api/v1/weather/wind - Fetch wind data for coordinates/bounds
- GET /api/v1/dive-sites/wind-recommendations - Get suitability
recommendations with datetime_str support (max +2 days ahead)
- POST /api/v1/dive-sites/{id}/detect-shore-direction - Trigger
automatic detection
Features:
- Auto-detect shore direction on dive site create/update
- Wind speed threshold: 6.2 m/s (safe for diving)
- Gust handling: Upgrades severity if gusts > 25 knots
- Validation: shore_direction cannot be set to None
- Forecast support: Recommendations for current time or future dates
Fixes:
- Fixed response serialization for shore_direction fields
- Fixed Open-Meteo unit issue (explicitly request m/s)
- Updated DiveSiteUpdate schema with all shore_direction fields
Phase: Backend foundation complete (Phases 1-2)
* Add wind overlay to dive sites map with toggle control
Implement wind overlay feature displaying real-time wind speed and
direction on dive sites map. Wind arrows show where wind is going
(opposite of meteorological wind direction) with color-coded speed
indicators.
Key features:
- WindOverlay component renders SVG arrows on Leaflet map
- WindOverlayToggle button enables/disables overlay (zoom 13+)
- Integration into IndependentMapView and DiveSitesMap
- Arrow direction calculation fixed to point correctly
- Toggle functionality fixed (arrows disappear when disabled)
- Improved marker cleanup on component unmount
- Tooltip updated to show zoom requirement
Technical improvements:
- Arrow size increased (40px base, max 80px) for visibility
- White outline/shadow added for better contrast
- React Query caching (5min stale, 15min cache)
- Debounced map movements (1s delay)
- Coordinate validation before marker creation
- Auto-disable overlay when zoom < 13
Files modified:
- frontend/src/components/WindOverlay.js (new)
- frontend/src/components/WindOverlayToggle.js (new)
- frontend/src/components/LeafletMapView.js
- frontend/src/components/DiveSitesMap.js
- frontend/src/pages/IndependentMapView.js
- frontend/src/pages/DiveSiteMap.js
- docs/development/work/.../task.md (updated)
* Update button colors to colorblind-safe palette
Replace all Tailwind button color classes with Okabe-Ito
colorblind-safe colors from the approved palette. This ensures
accessibility for users with color vision deficiencies while
maintaining visual consistency across the application.
Button color mapping:
- Primary actions (Save/Submit): Tailwind blue-600 -> Okabe-Ito Blue (#0072B2)
- Add/Auxiliary actions: Tailwind green-600 -> Okabe-Ito Bluish Green (#009E73)
- Cancel actions: Tailwind gray-600 -> Dark Gray (#374151)
All buttons now use inline styles with UI_COLORS constants from
colorPalette.js, ensuring consistency and accessibility compliance.
Files updated:
- EditDiveSite.js: All form buttons (Save, Add, Cancel, Re-detect)
- EditDive.js: Media and form action buttons
- EditDivingCenter.js: Organization and gear rental buttons
- DivingCenterForm.js: Suggest and form submission buttons
- CreateDiveSite.js: Suggest and create buttons
- DiveSitesMap.js: Wind suitability indicators and popups
- LeafletMapView.js: Wind suitability indicators and popups
Documentation:
- Added button-color-coding-standards.md with comprehensive
guidelines for button color usage, implementation examples,
and colorblind accessibility notes
- Updated wind overlay task.md with recent changes
This change improves accessibility for approximately 8% of men
and 0.5% of women who experience color vision deficiencies,
particularly red-green color blindness.
* Improve wind overlay with jitter and fix viewport issues
Add jitter factor to multiply wind arrows (5x default) for better
visual density. Implement retry logic to ensure jittered points
stay within bounds. Fix wind arrows appearing at viewport edges
by adding margin to bounds and filtering points strictly within
viewport.
Rename enabled props to isWindOverlayEnabled/isOverlayEnabled for
better clarity. Fix React Query enabled prop to always be boolean
using !! operator to prevent runtime errors.
Update backend grid generation to create points INSIDE bounds with
margin. Add jitter_factor parameter to weather API endpoint (default
5, max 10). Implement adaptive grid spacing for zoom levels 13-18.
Update task.md documentation with all recent fixes and improvements.
* Add comprehensive backend tests for wind overlay
Add 71 new tests across 4 test files covering Open-Meteo service,
Weather API router, OSM Coastline service, and Meteo API response
parsing.
Test coverage includes:
- Grid point generation and jitter factor functionality
- Wind data fetching (current/forecast) with caching
- API error handling and edge cases
- Overpass API querying with retry/fallback logic
- Shore direction detection with confidence levels
- Response structure parsing and validation
- Endpoint parameter validation and HTTP behavior
Fixed cache interference issues in Docker test environment using
monkeypatch to ensure test isolation.
All 969 tests passing in Docker CI-like environment.
* Fix datetime validation and display format
Fixed backend datetime validation to round max_future to next hour,
allowing users to select any hour within the 2-day window without
hitting edge cases at the 2-day limit.
Updated frontend datetime display to show full time format (22:00)
instead of just hours (22) for better clarity in wind data info box.
Updated task.md documentation with recent datetime-related fixes.
Files modified:
- backend/app/routers/weather.py: Rounded max_future validation
- backend/app/routers/dive_sites.py: Rounded max_future validation
- frontend/src/components/LeafletMapView.js: Added minute display
- frontend/src/components/DiveSitesMap.js: Added minute display
- docs/development/work/.../task.md: Updated with recent fixes
* Refactor tests and add wind suitability filter
Refactor test suite for better maintainability and add wind
suitability filtering to dive sites endpoint.
Test Refactoring:
- Split large test_dive_sites.py (1625 lines) into focused test
files for better organization and maintainability
- Created test_dive_sites_crud.py: 21 CRUD operation tests
- Created test_dive_sites_diving_centers.py: 13 diving center
association tests (MySQL-only, skipped on SQLite)
- Created test_dive_sites_wind_suitability.py: 14 wind suitability
filter tests (MySQL-only, skipped on SQLite)
- Removed 414 lines of duplicate tests from test_dive_sites.py
Test Improvements:
- Added freezegun==1.5.5 to requirements.txt for simplified
datetime mocking
- Refactored datetime mocking in test_open_meteo_service.py and
test_open_meteo_api_responses.py to use @freeze_time() decorator
- Reduced test code complexity by ~13 lines per test (from 15
lines of manual datetime patching to 1 decorator)
- Fixed test cache isolation: Added monkeypatch cache clearing
to test_fetch_wind_data_single_point_caching
Wind Suitability Filter:
- Added wind_suitability query parameter to GET /api/v1/dive-sites/
endpoint (values: good, caution, difficult, avoid, unknown)
- Added optional datetime_str parameter for forecast filtering
(defaults to current time, max +2 days ahead)
- Implemented filtering logic: Fetches wind data for center point
of matching dive sites, calculates suitability for each site,
filters results based on wind_suitability parameter
- Added validation for wind_suitability parameter
- Handles edge cases: Sites without shore_direction match
'unknown' filter, graceful error handling for wind data fetch
failures
Documentation:
- Updated task.md with freezegun refactoring details
- Documented test file splitting and wind suitability filter
implementation
All tests passing. Test suite is now more maintainable with
focused test files and simplified datetime mocking.
Files changed:
- backend/requirements.txt: Added freezegun==1.5.5
- backend/tests/test_dive_sites.py: Removed 414 lines (moved to
separate files)
- backend/tests/test_dive_sites_crud.py: New file (292 lines)
- backend/tests/test_dive_sites_diving_centers.py: New file
(155 lines)
- backend/tests/test_dive_sites_wind_suitability.py: New file
(432 lines)
- backend/tests/test_open_meteo_service.py: Refactored datetime
mocking
- backend/tests/test_open_meteo_api_responses.py: Refactored
datetime mocking
- backend/app/routers/dive_sites.py: Added wind suitability
filtering (108 lines added)
- docs/development/work/.../task.md: Updated with recent changes
* Fix wind arrow direction and improve UX
Fixed critical bug in wind arrow direction calculation and improved user experience with better loading indicators and accessibility.
Wind Arrow Direction Fix:
- Corrected SVG rotation formula from (targetDirection - 90) to (targetDirection - 180) to account for default arrow pointing down (south, 180° compass)
- Arrows now correctly point in direction wind is going
- Validated formula for all cardinal directions (0°, 90°, 180°, 270°, 360°)
Zoom Level Improvements:
- Reduced minimum zoom from 13 to 12 for better accessibility
- Added zoom level 12 support in backend (0.10° spacing)
- Updated all zoom level checks and tooltips throughout frontend components
Loading Indicator Enhancements:
- Added centered loading overlay on map showing "Loading wind data..." with spinner
- Uses isFetching in addition to isLoading to show indicator on refetches (map movement, zoom changes, datetime changes)
- Loading indicator now visible during all data fetches, not just initial load
UX Improvements:
- Reduced frontend margin from 5% to 2.5% for better arrow coverage while maintaining viewport visibility
- Added close button to map info box (points count and coordinates) allowing users to dismiss it
- Added comprehensive logging for debugging: frontend console logs for bounds calculation and grid point distribution, backend logs for grid point generation
Files Modified:
- backend/app/services/open_meteo_service.py: Added zoom 12 support, grid point distribution logging
- frontend/src/components/WindOverlay.js: Fixed arrow direction calculation formula
- frontend/src/components/WindOverlayToggle.js: Updated zoom level checks and tooltips
- frontend/src/components/LeafletMapView.js: Added loading indicator, reduced margin, added info box close button, updated zoom checks, added logging
- frontend/src/components/DiveSitesMap.js: Added loading indicator, reduced margin, updated zoom checks, added logging
- frontend/src/pages/IndependentMapView.js: Updated zoom level references
- docs/development/work/.../task.md: Updated documentation with all recent changes
This commit fixes the critical arrow direction bug reported by users and significantly improves the wind overlay user experience.
* Enhance wind date/time picker with slider UI
Replace dropdown/calendar date picker with modern slider-based
interface using react-slider library. The new slider provides
better UX with floating design, play/pause animation, and manual
control.
Major improvements:
- Slider-based date/time selection with visual timeline
- Play/pause animation advances by 3 hours, waits for data
loading with minimum 3-second pause between advances
- Date labels centered in day ranges for better readability
- Day boundary markers show transitions at midnight
- Compact design: reduced height (24px), increased width
(600px min, 95vw max)
- Close button allows users to hide slider when not needed
- "Show Time Slider" button appears when slider is hidden
Additional enhancements:
- Wind feature promotion banner with one-click enable and
auto-zoom to demo location
- Fixed zoom level tracking using map instance for accurate
wind button state (fixes disabled button at zoom 15)
- Fixed z-index layering: popups can now overlay slider
(changed from z-50 to z-40, added CSS rules)
- Removed redundant wind data info box (timestamp now on
slider)
- Removed all debugging console.log statements from
frontend files for cleaner production code
Files modified:
- WindDateTimePicker.js: Complete rewrite with react-slider
- IndependentMapView.js: Added promotion banner, slider
visibility controls, accurate zoom tracking
- LeafletMapView.js: Fixed z-index, removed debug logs,
added fetching callback
- DiveSitesMap.js: Removed debug logs, removed info box
- index.css: Added React Slider styles and popup z-index
rules
- Various files: Removed console.log debugging statements
This improves user experience by making date/time selection
more intuitive and providing better visual feedback for wind
data navigation.
* Add tooltips and legends for wind overlay (Phase 6)
Implement comprehensive tooltips and legends to help users
understand wind overlay features, arrow meanings, and dive site
suitability indicators.
Major features:
- Enhanced tooltips in WindOverlayToggle with detailed
explanations of wind overlay, arrow direction, and zoom
requirements
- WindOverlayLegend component with tabbed interface (Wind
Arrows / Suitability tabs)
- Wind arrow legend: Color scale, speed thresholds, arrow
direction explanation, and size information
- Dive site suitability legend: All suitability levels with
descriptions and wind speed thresholds
- "Show Legend" button on map (top right) similar to "Show
Time Slider" button
- Map info button: Changed from always visible to toggle
button (left side, below zoom buttons) for cleaner UI
Implementation details:
- WindOverlayToggle: Enhanced tooltip shows title,
description, and current zoom level on hover
- WindOverlayLegend: Collapsible legend with tabs, color
swatches, and detailed explanations
- Map buttons: Legend and map info buttons positioned on map
for better UX (not in controls area)
- Accessibility: ARIA labels, keyboard navigation, screen
reader support
Files modified:
- WindOverlayToggle.js: Enhanced tooltip with detailed
explanations
- WindOverlayLegend.js: New combined legend component
- WindArrowLegend.js: New wind arrow legend (standalone)
- DiveSiteSuitabilityLegend.js: New suitability legend
(standalone)
- IndependentMapView.js: Added "Show Legend" button and
legend integration
- DiveSitesMap.js: Added "Show Legend" button and legend
integration
- LeafletMapView.js: Changed map info to toggle button
- task.md: Updated Phase 6 progress and documentation
This improves user understanding of wind overlay features
and makes the interface more intuitive with clear visual
guides.
* Add bulk update script for shore direction
Create scripts/bulk_update_shore_direction.py to enable bulk
updating of shore_direction field for multiple dive sites.
The script provides comprehensive CLI options including:
- Dry-run mode to preview changes
- Force mode to skip confirmation prompts
- Selective processing via --ids option
- Rate limiting controls (max-retries, base-wait-time,
max-requests-per-minute)
- Debug logging support
Implements sophisticated rate limiting similar to
update_dive_site_locations.py:
- Sliding window rate limiting with proactive checking
- Retry logic with exponential backoff for 429 responses
- Respects Retry-After headers from API
- Auto-refreshes expired authentication tokens
Features comprehensive progress display:
- Progress percentage and estimated time remaining
- Running statistics after each site
- Total time and average time per site in summary
- Timestamped logging with emoji indicators
Updated task.md documentation to reflect the new script
and its capabilities.
This enables administrators to efficiently update shore
direction for existing dive sites that lack this data.
* Add error handling with retry for wind data fetching
Implement comprehensive error handling for wind data fetching
failures with user-friendly error messages and retry functionality.
Created WindDataError component (frontend/src/components/WindDataError.js):
- Displays contextual error messages for different error types
(network errors, rate limits, server errors, 404, etc.)
- Shows "Using cached data" indicator when cached data exists
but fresh fetch fails
- Provides "Retry" button to manually retry fetching wind data
- Optional dismiss button to close error message
- Positioned at top center of map (z-50) for visibility
Updated LeafletMapView.js:
- Extracts error, isError, and refetch from React Query useQuery
- Displays WindDataError component when wind data fetch fails
- Checks for cached data to show appropriate indicator
- Only displays error when wind overlay enabled and zoom >= 12
Updated DiveSitesMap.js:
- Same error handling implementation as LeafletMapView
- Consistent error display across both map components
Simplified legend text:
- Removed specific arrow size details from WindArrowLegend and
WindOverlayLegend components for cleaner, more concise UI
- Changed from "40px base + 10px per 5 m/s, max 80px" to
"Larger arrows indicate stronger winds"
Updated task.md documentation:
- Marked error messages task as complete
- Updated Phase 6 progress from 60% to 70%
- Added comprehensive details about error handling implementation
This enables users to understand and recover from wind data
fetching failures, improving overall user experience and
reliability of the wind overlay feature.
* Optimize wind data caching and API calls
Implement comprehensive cache optimizations to reduce Open-Meteo
API calls and improve wind overlay performance:
Backend optimizations:
- Increase cache size from 100 to 500 entries to accommodate
24-hour caching for multiple grid points
- Always use hourly forecast API to cache all 24 hours from
single API response (Optimization #10)
- Implement smart cache lookup checking representative hours
(00:00, 12:00, requested hour) to quickly find cached data
- Group grid points by cache key (0.1° rounding) before API
calls, ensuring only one call per cache cell (Optimization #3)
- Add skip_validation parameter to avoid redundant datetime
validation when called from grid function
- Add detailed cache logging with [CACHE HIT], [CACHE MISS],
[API CALL] prefixes for better debugging
- Detect and warn about cache inconsistencies when date data
exists but specific hour is missing
Frontend optimizations:
- Add prefetchWindHours function that prefetches next 2 days
(one request per day at noon) when play button is pressed
- Integrate prefetch with WindDateTimePicker via onPrefetch prop
to cache upcoming hours before slider advances
- Enhance useViewportData with zoom-based detail levels
(minimal < 4, basic 8-9, full >= 10) for progressive loading
- Expand bounds for zoom >= 11 to ensure nearby dive sites
remain visible when panning
- Increase debounce time from 1s to 1.5s for smoother UX
These optimizations significantly reduce API calls by leveraging
24-hour bulk caching and intelligent cache lookup strategies.
* Disable dive site clustering at zoom level 13+
Update clustering threshold to show individual markers at high
zoom levels for better user interaction and visibility.
- Change clustering threshold from zoom <= 11 to zoom <= 12 in
DiveSitesMap.js
- Add conditional clustering logic in LeafletMapView.js:
- Dive sites at zoom <= 12: Use clustering
- Dive sites at zoom >= 13: Show individual markers
- Other entity types: Always use clustering
- Add zoom tracking and individual marker management
- Add comprehensive backend tests for cache optimizations
- Update task documentation with clustering improvements
This ensures users can see and interact with individual dive
sites without needing to click clusters when zoomed in at
levels 13 and above.
* Add database caching and wind suitability range filter
Implement 3-tier caching system for Open-Meteo API calls:
- Add WindDataCache database model with persistent storage
- Create migrations 0043 (table) and 0044 (last_accessed_at)
- Implement database cache as Tier 2 (in-memory → database → API)
- Add automatic TTL cleanup via MySQL event scheduler
- Serialize/deserialize timestamps for JSON storage
Change wind suitability filter to range-based:
- Backend: Filter by cumulative range (good, caution, difficult, avoid)
- Backend: Add include_unknown_wind parameter for unknown conditions
- Backend: Optimize by grouping sites by cache key for batch fetching
- Frontend: Update dropdown to show range behavior
- Frontend: Add checkbox to include unknown conditions
- Frontend: Fix duplicate 'All Conditions' labels
Fix React component deprecation warning:
- Replace defaultProps with JavaScript default parameters in WindDateTimePicker
Files modified:
- backend/app/models.py: Add WindDataCache model
- backend/migrations/versions/0043_add_wind_data_cache_table.py: Create cache table
- backend/migrations/versions/0044_add_last_accessed_at_to_wind_cache.py: Add access tracking
- backend/app/services/open_meteo_service.py: Implement 3-tier caching
- backend/app/routers/dive_sites.py: Range-based wind suitability filtering
- frontend/src/components/UnifiedMapFilters.js: Range filter UI with unknown checkbox
- frontend/src/components/WindDateTimePicker.js: Fix defaultProps warning
- frontend/src/hooks/useViewportData.js: Add include_unknown_wind support
- frontend/src/pages/IndependentMapView.js: Minor updates
- scripts/bulk_update_shore_direction.py: Script file (existing)
- docs/development/work/2025-11-30-11-59-24-add-wind-overlay-dive-sites-map/task.md: Update documentation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This comprehensive update improves the mobile user experience and visual consistency
across dive-sites, diving-centers, and dive-trips pages.
Mobile Sorting Controls Visibility
Mobile View Mode Buttons
Hero Section Button Updates
Technical Improvements
Files Modified
All changes maintain existing functionality while significantly improving mobile UX
and visual consistency across the platform.