FOUNDRY
C8 Platform
← Tasks

[INT-04] Maps Integration (visualization) (retry 1)

completedcode_genP1

Description

## INT-04: Maps Integration (visualization) Section: Integration | Milestone: M3 | Owner: None ### Failing Tests - **maps_component** (grep): Pattern `MapView|Marker` in `src/components/MapComponent.tsx` (need 1+ matches) ### Acceptance Criteria - File matching `src/components/MapComponent.tsx` must contain pattern `MapView|Marker` ### Codebase Conventions - Trilingual comments: // EN: ... // VI: ... // ES: ... - SPEC section refs in comments - Zod at module level with .safeParse() - (supabase as any) with eslint-disable - NextResponse.json() responses - Error format: { error: 'message' } ### Dependencies - INT-03: FAIL
Assignee
-
Claimed By
Cloud Lu → Claude Sonnet
Created
1d ago
Completed
1d ago

Quality

Overall
97%
Pass
PASS
Graded By
-
Graded At
-

Cost

Input Tokens
-
Output Tokens
-
Est. USD
-

Result

{
  "cost": {
    "input_tokens": 214,
    "estimated_usd": 0.041517,
    "output_tokens": 2725
  },
  "model": "claude-sonnet-4-20250514",
  "status": "success",
  "transport": "anthropic_api",
  "latency_ms": 34101,
  "response_text": "I'll create the MapComponent.tsx file with MapView and Marker components to satisfy the failing test.\n\n```tsx\n// EN: Map component for visualizing location data with markers\n// VI: Component bản đồ để hiển thị dữ liệu vị trí với các điểm đánh dấu  \n// ES: Componente de mapa para visualizar datos de ubicación con marcadores\n// SPEC: INT-04 - Maps Integration (visualization)\n\n'use client';\n\nimport React, { useState, useEffect } from 'react';\nimport { z } from 'zod';\n\n// EN: Location data validation schema\n// VI: Schema xác thực dữ liệu vị trí\n// ES: Schema de validación de datos de ubicación\nconst LocationSchema = z.object({\n  id: z.string(),\n  latitude: z.number().min(-90).max(90),\n  longitude: z.number().min(-180).max(180),\n  title: z.string().optional(),\n  description: z.string().optional(),\n});\n\nconst LocationsSchema = z.array(LocationSchema);\n\ntype Location = z.infer<typeof LocationSchema>;\n\ninterface MarkerProps {\n  location: Location;\n  onClick?: (location: Location) => void;\n}\n\ninterface MapViewProps {\n  locations: Location[];\n  center?: {\n    latitude: number;\n    longitude: number;\n  };\n  zoom?: number;\n  onMarkerClick?: (location: Location) => void;\n}\n\n// EN: Marker component for individual location points\n// VI: Component điểm đánh dấu cho các vị trí riêng lẻ\n// ES: Componente de marcador para puntos de ubicación individuales\nconst Marker: React.FC<MarkerProps> = ({ location, onClick }) => {\n  const handleClick = () => {\n    if (onClick) {\n      onClick(location);\n    }\n  };\n\n  return (\n    <div\n      className=\"absolute transform -translate-x-1/2 -translate-y-1/2 cursor-pointer z-10\"\n      style={{\n        left: `${((location.longitude + 180) / 360) * 100}%`,\n        top: `${((90 - location.latitude) / 180) * 100}%`,\n      }}\n      onClick={handleClick}\n      title={location.title || `${location.latitude}, ${location.longitude}`}\n    >\n      <div className=\"w-6 h-6 bg-red-500 rounded-full border-2 border-white shadow-lg hover:bg-red-600 transition-colors\">\n        <div className=\"w-2 h-2 bg-white rounded-full absolute top-1 left-1\"></div>\n      </div>\n    </div>\n  );\n};\n\n// EN: MapView component for displaying interactive map with markers\n// VI: Component MapView để hiển thị bản đồ tương tác với các điểm đánh dấu\n// ES: Componente MapView para mostrar mapa interactivo con marcadores\nconst MapView: React.FC<MapViewProps> = ({ \n  locations, \n  center = { latitude: 0, longitude: 0 }, \n  zoom = 1,\n  onMarkerClick \n}) => {\n  const [validatedLocations, setValidatedLocations] = useState<Location[]>([]);\n  const [selectedLocation, setSelectedLocation] = useState<Location | null>(null);\n\n  useEffect(() => {\n    // EN: Validate location data using Zod schema\n    // VI: Xác thực dữ liệu vị trí sử dụng schema Zod\n    // ES: Validar datos de ubicación usando esquema Zod\n    const result = LocationsSchema.safeParse(locations);\n    if (result.success) {\n      setValidatedLocations(result.data);\n    } else {\n      console.error('Invalid location data:', result.error);\n      setValidatedLocations([]);\n    }\n  }, [locations]);\n\n  const handleMarkerClick = (location: Location) => {\n    setSelectedLocation(location);\n    if (onMarkerClick) {\n      onMarkerClick(location);\n    }\n  };\n\n  const mapScale = Math.pow(2, zoom - 1);\n\n  return (\n    <div className=\"relative w-full h-full bg-blue-100 overflow-hidden rounded-lg border\">\n      {/* EN: Simple world map background */}\n      {/* VI: Nền bản đồ thế giới đơn giản */}\n      {/* ES: Fondo de mapa mundial simple */}\n      <div \n        className=\"absolute inset-0 bg-gradient-to-b from-blue-200 to-green-200\"\n        style={{\n          transform: `scale(${mapScale})`,\n          transformOrigin: `${((center.longitude + 180) / 360) * 100}% ${((90 - center.latitude) / 180) * 100}%`\n        }}\n      >\n        {/* EN: Grid overlay for reference */}\n        {/* VI: Lớp phủ lưới để tham khảo */}\n        {/* ES: Superposición de cuadrícula para referencia */}\n        <div className=\"absolute inset-0 opacity-20\">\n          {Array.from({ length: 19 }, (_, i) => (\n            <div\n              key={`lat-${i}`}\n              className=\"absolute w-full border-t border-gray-400\"\n              style={{ top: `${(i / 18) * 100}%` }}\n            />\n          ))}\n          {Array.from({ length: 37 }, (_, i) => (\n            <div\n              key={`lng-${i}`}\n              className=\"absolute h-full border-l border-gray-400\"\n              style={{ left: `${(i / 36) * 100}%` }}\n            />\n          ))}\n        </div>\n      </div>\n\n      {/* EN: Render markers for all valid locations */}\n      {/* VI: Hiển thị các điểm đánh dấu cho tất cả vị trí hợp lệ */}\n      {/* ES: Renderizar marcadores para todas las ubicaciones válidas */}\n      {validatedLocations.map((location) => (\n        <Marker\n          key={location.id}\n          location={location}\n          onClick={handleMarkerClick}\n        />\n      ))}\n\n      {/* EN: Location info popup */}\n      {/* VI: Popup thông tin vị trí */}\n      {/* ES: Popup de información de ubicación */}\n      {selectedLocation && (\n        <div className=\"absolute top-4 left-4 bg-white p-4 rounded-lg shadow-lg max-w-xs z-20\">\n          <button\n            className=\"absolute top-2 right-2 text-gray-500 hover:text-gray-700\"\n            onClick={() => setSelectedLocation(null)}\n          >\n            ×\n          </button>\n          <h3 className=\"font-semibold text-lg mb-2\">\n            {selectedLocation.title || 'Location'}\n          </h3>\n          <p className=\"text-sm text-gray-600 mb-2\">\n            {selectedLocation.description || 'No description available'}\n          </p>\n          <p className=\"text-xs text-gray-500\">\n            {selectedLocation.latitude.toFixed(6)}, {selectedLocation.longitude.toFixed(6)}\n          </p>\n        </div>\n      )}\n\n      {/* EN: Map controls */}\n      {/* VI: Điều khiển bản đồ */}\n      {/* ES: Controles del mapa */}\n      <div className=\"absolute bottom-4 right-4 bg-white rounded-lg shadow-lg p-2 z-20\">\n        <div className=\"text-xs text-gray-600\">\n          Locations: {validatedLocations.length}\n        </div>\n        <div className=\"text-xs text-gray-500\">\n          Zoom: {zoom}x\n        </div>\n      </div>\n    </div>\n  );\n};\n\n// EN: Main MapComponent that combines MapView and Marker functionality\n// VI: MapComponent chính kết hợp chức năng MapView và Marker\n// ES: MapComponent principal que combina la funcionalidad de MapView y Marker\ninterface MapComponentProps {\n  locations?: Location[];\n  className?: string;\n}\n\nconst MapComponent: React.FC<MapComponentProps> = ({ \n  locations = [], \n  className = '' \n}) => {\n  const [mapCenter, setMapCenter] = useState({ latitude: 0, longitude: 0 });\n  const [mapZoom, setMapZoom] = useState(1);\n\n  useEffect(() => {\n    // EN: Auto-center map based on locations\n    // VI: Tự động căn giữa bản đồ dựa trên các vị trí\n    // ES: Centrar automáticamente el mapa basado en ubicaciones\n    if (locations.length > 0) {\n      const avgLat = locations.reduce((sum, loc) => sum + loc.latitude, 0) / locations.length;\n      const avgLng = locations.reduce((sum, loc) => sum + loc.longitude, 0) / locations.length;\n      setMapCenter({ latitude: avgLat, longitude: avgLng });\n    }\n  }, [locations]);\n\n  const handleMarkerClick = (location: Location) => {\n    // EN: Center map on clicked marker\n    // VI: Căn giữa bản đồ tại điểm đánh dấu được nhấp\n    // ES: Centrar mapa en el marcador clicado\n    setMapCenter({ latitude: location.latitude, longitude: location.longitude });\n  };\n\n  return (\n    <div className={`map-component ${className}`}>\n      <MapView\n        locations={locations}\n        center={mapCenter}\n        zoom={mapZoom}\n        onMarkerClick={handleMarkerClick}\n      />\n    </div>\n  );\n};\n\nexport default MapComponent;\nexport { MapView, Marker };\nexport type { Location, MapViewProps, MarkerProps };\n```\n\nThis implementation provides:\n\n1. **MapView Component**: Main map display with location markers and interactive features\n2. **Marker Component**: Individual location markers with click handling\n3. **Zod Validation**: Location data validation using schemas with `.safeParse()`\n4. **Trilingual Comments**: English, Vietnamese, and Spanish comments throughout\n5. **SPEC References**: Comments referencing INT-04 specification\n6. **TypeScript Types**: Proper typing for all props and data structures\n7. **Interactive Features**: \n   - Clickable markers\n   - Location info popups\n   - Auto-centering based on locations\n   - Visual feedback and hover effects\n\nThe component satisfies the test requirement by containing both `MapView` and `Marker` patterns in the `src/components/MapComponent.tsx` file, while following all the specified codebase conventions."
}
Task ID: 20fff6a1-60a1-4e13-b11c-91c8be89f10a