Overview
The interactive parking map provides a visual representation of 10 parking spots with real-time availability status. Users can select available spots directly from the map interface.
Map Layout
The parking lot features a dual-column layout with 5 spots on each side:
Left Column Spots 1-5 on the left side of the central lane
Right Column Spots 6-10 on the right side of the central lane
Spot Configuration
const SPOTS_LAYOUT : Spot [] = [
// Left Column
{ id: '1' , x: 20 , y: 20 , label: '1' },
{ id: '2' , x: 20 , y: 100 , label: '2' },
{ id: '3' , x: 20 , y: 180 , label: '3' },
{ id: '4' , x: 20 , y: 260 , label: '4' },
{ id: '5' , x: 20 , y: 340 , label: '5' },
// Right Column
{ id: '6' , x: 190 , y: 20 , label: '6' },
{ id: '7' , x: 190 , y: 100 , label: '7' },
{ id: '8' , x: 190 , y: 180 , label: '8' },
{ id: '9' , x: 190 , y: 260 , label: '9' },
{ id: '10' , x: 190 , y: 340 , label: '10' },
];
Visual Indicators
Color Coding
The map uses three colors to indicate spot status:
Green (#4CAF50)
Available spots that can be selected for reservation
Red (#FF4444)
Occupied spots with active or pending reservations
Yellow (#FFE100)
Currently selected spot by the user
const getSpotColor = ( spotId : string , isOccupied : boolean ) => {
if ( selectedSpot === spotId ) return '#FFE100' ; // Yellow
if ( isOccupied ) return '#FF4444' ; // Red
return '#4CAF50' ; // Green
};
Status Badges
Occupied spots display a prohibition icon (⛔) to clearly indicate unavailability:
{ isOccupied && (
< SvgText
x = {spot.x + 60 }
y = {spot.y + 20 }
fill = "#FFF"
fontSize = "12"
textAnchor = "middle"
>
⛔
</ SvgText >
)}
Real-Time Updates
The map receives real-time updates via Firebase listeners:
interface ParkingMapProps {
selectedSpot : string | null ;
onSelectSpot : ( spotId : string ) => void ;
occupiedSpots : string []; // Live data from Firebase
}
When another user books a spot, it immediately turns red for all other users viewing the map.
User Interactions
Selecting a Spot
Users can tap any available (green) spot to select it:
< G
key = {spot. id }
onPress = {() => {
if ( ! isOccupied ) {
onSelectSpot ( spot . id );
}
}}
>
< Rect
x = {spot. x }
y = {spot. y }
width = "70"
height = "70"
rx = "8"
fill = { getSpotColor (spot.id, isOccupied )}
stroke = "#FFF"
strokeWidth = "2"
/>
< SvgText
x = {spot.x + 35 }
y = {spot.y + 42 }
fill = { selectedSpot === spot . id ? '#000' : '#FFF' }
fontSize = "24"
fontWeight = "bold"
>
{ spot . label }
</ SvgText >
</ G >
Occupied spots are non-interactive. Taps on red spots are ignored to prevent selection errors.
Android Touch Handling
A transparent overlay ensures reliable touch detection across all devices:
{ /* Transparent touch area for Android compatibility */ }
< Rect
x = {spot. x }
y = {spot. y }
width = "70"
height = "70"
fill = "transparent"
/>
Map Design Elements
A dashed white line runs down the center, simulating the parking lot drive lane: < Rect
x = "138"
y = "10"
width = "4"
height = "420"
fill = "#555"
stroke = "#FFF"
strokeWidth = "2"
strokeDasharray = "15,10"
/>
An arrow at the bottom indicates the parking entrance: < SvgText
x = "140"
y = "430"
fill = "#FFE100"
fontSize = "14"
fontWeight = "bold"
>
⬆ ENTRADA ⬆
</ SvgText >
A dark gray rounded rectangle simulates the parking lot surface: < Rect
x = "0"
y = "0"
width = "280"
height = "440"
rx = "15"
fill = "#333"
/>
Legend
A visual legend helps users understand the color coding:
< View style = {styles. legend } >
< View style = {styles. legendItem } >
< View style = { [styles.dot, {backgroundColor: '#4CAF50' }]}/>
<Text style={styles.legendText}>Libre</Text>
</View>
<View style={styles.legendItem}>
<View style={[styles.dot, {backgroundColor: '#FF4444' }]}/>
<Text style={styles.legendText}>Ocupado</Text>
</View>
<View style={styles.legendItem}>
<View style={[styles.dot, {backgroundColor: '#FFE100' }]}/>
<Text style={styles.legendText}>Seleccionado</Text>
</View>
</View>
Implementation
The map is built using react-native-svg for crisp vector rendering:
import Svg , { Rect , Text as SvgText , G } from 'react-native-svg' ;
export default function ParkingMap ({
selectedSpot ,
onSelectSpot ,
occupiedSpots
} : ParkingMapProps ) {
return (
< View style = {styles. container } >
< Text style = {styles. title } > Selecciona tu lugar ( 1 - 10 ) 👇 </ Text >
< View style = {styles. mapWrapper } >
< Svg height = "440" width = "280" viewBox = "0 0 280 440" >
{ /* Background */ }
< Rect x = "0" y = "0" width = "280" height = "440" rx = "15" fill = "#333" />
{ /* Central lane */ }
< Rect x = "138" y = "10" width = "4" height = "420"
fill = "#555" stroke = "#FFF" strokeWidth = "2"
strokeDasharray = "15,10" />
{ /* Render spots */ }
{ SPOTS_LAYOUT . map (( spot ) => {
const isOccupied = occupiedSpots . includes ( spot . id );
// ... spot rendering logic
})}
{ /* Entrance marker */ }
< SvgText x = "140" y = "430" fill = "#FFE100" > ⬆ ENTRADA ⬆ </ SvgText >
</ Svg >
</ View >
</ View >
);
}
The SVG approach ensures the map scales perfectly across different screen sizes while maintaining crisp edges.
Accessibility
Large tap targets (70x70 pixels) ensure easy selection
High contrast colors improve visibility
Clear labeling with spot numbers
Visual and textual status indicators