Overview
The Location Manager handles geocoding, location persistence, and CRUD operations for favorite locations. It integrates with the backend API and Nominatim for geocoding services.
API Configuration
The application dynamically configures API endpoints based on the environment:
export var pythonURI ;
if ( location . hostname === "localhost" ) {
pythonURI = "http://localhost:8888" ;
} else if ( location . hostname === "127.0.0.1" ) {
pythonURI = "http://127.0.0.1:8888" ;
} else {
pythonURI = "https://autonomous.stu.nighthawkcodingsociety.com" ;
}
export const fetchOptions = {
method: 'GET' ,
mode: 'cors' ,
cache: 'default' ,
credentials: 'include' ,
headers: {
'Content-Type' : 'application/json' ,
'X-Origin' : 'client'
},
};
The credentials: 'include' setting ensures cookies are sent with cross-origin requests for authentication.
Geocoding with Nominatim
Nominatim converts location names to geographic coordinates:
navigation/dailyroutine.html
async function geocodePlace ( place ) {
const response = await fetch (
`https://nominatim.openstreetmap.org/search?format=json&q= ${ encodeURIComponent ( place ) } `
);
const data = await response . json ();
return data [ 0 ];
}
Response Structure
{
"lat" : "32.7157" ,
"lon" : "-117.1611" ,
"display_name" : "San Diego, California, USA" ,
"type" : "city"
}
Usage Example
const location = await geocodePlace ( "San Diego" );
const latLng = L . latLng ( parseFloat ( location . lat ), parseFloat ( location . lon ));
Favorite Locations CRUD
Create Location
Add a new favorite location to the database:
navigation/favoriteLocations/favoriteLocations.js
async function createScores ( inputName , inputAddress ) {
const locationData = {
address: inputAddress ,
name: inputName
};
try {
const response = await fetch ( ` ${ pythonURI } /api/saved_locations` , {
... fetchOptions ,
method: 'POST' ,
body: JSON . stringify ( locationData ),
});
if ( ! response . ok ) {
throw new Error ( `Failed to submit location: ${ response . statusText } ` );
}
const result = await response . json ();
return ( result );
} catch ( error ) {
console . error ( 'Error submitting location:' , error );
alert ( 'Error submitting location: ' + error . message );
return null ;
}
}
Read Locations
Fetch all saved locations from the API:
navigation/favoriteLocations/favoriteLocations.js
async function readScores () {
try {
const scoresResponse = await fetch ( ` ${ pythonURI } /api/saved_locations` , fetchOptions );
if ( ! scoresResponse . ok ) throw new Error ( 'Failed to fetch locations' );
const scores = await scoresResponse . json ();
return ( scores );
} catch ( error ) {
console . error ( 'Error fetching locations:' , error );
alert ( 'Error fetching locations: ' + error . message );
return null ;
}
}
Update Location
Modify an existing favorite location:
navigation/favoriteLocations/favoriteLocations.js
async function updateScores ( inputId , inputAddress , inputName ) {
const scoreData = {
id: inputId ,
address: inputAddress ,
name: inputName
}
try {
const response = await fetch ( ` ${ pythonURI } /api/saved_locations` , {
... fetchOptions ,
method: 'PUT' ,
body: JSON . stringify ( scoreData ),
});
if ( ! response . ok ) {
throw new Error ( `Failed to update location: ${ response . statusText } ` );
}
const result = await response . json ();
return ( result );
}
catch ( error ) {
console . error ( 'Error updating location:' , error );
alert ( 'Error updating location: ' + error . message );
}
}
Delete Location
Remove a favorite location:
navigation/favoriteLocations/favoriteLocations.js
async function deleteScores ( inputId ) {
const scoreData = {
id: inputId
}
try {
const response = await fetch ( ` ${ pythonURI } /api/saved_locations` , {
... fetchOptions ,
method: 'DELETE' ,
body: JSON . stringify ( scoreData ),
});
if ( ! response . ok ) {
throw new Error ( `Failed to delete location: ${ response . statusText } ` );
}
const result = await response . json ();
return ( result );
}
catch ( error ) {
console . error ( 'Error deleting location:' , error );
alert ( 'Error deleting location: ' + error . message );
return null ;
}
}
User Filtering
Filter locations for the current authenticated user:
navigation/favoriteLocations/favoriteLocations.js
async function filterForUsername ( scores ) {
const currentUserResponse = await fetch ( ` ${ pythonURI } /api/user` , fetchOptions );
if ( ! currentUserResponse . ok ) throw new Error ( 'Failed to fetch current user' );
const currentUser = await currentUserResponse . json ();
let userName = currentUser . name ;
return ( scores . filter (( entry ) => String ( entry . username ) === String ( userName )));
}
UI Population
Display locations in a grid layout:
navigation/favoriteLocations/favoriteLocations.js
async function populateScores () {
const grid = document . getElementById ( 'locations-grid' );
grid . innerHTML = '' ; // Clear existing content
let scores = await filterForUsername ( await readScores ());
scores . forEach ( location => {
const square = document . createElement ( 'button' );
square . className = 'location-square' ;
square . textContent = location . user_name ;
square . addEventListener ( 'click' , () => showPopup ( location ));
grid . appendChild ( square );
});
}
Create dynamic popups for location details:
navigation/favoriteLocations/favoriteLocations.js
function showPopup ( location ) {
const popup = document . createElement ( 'div' );
popup . className = 'popup' ;
popup . innerHTML = `
<div class="popup-content">
<button class="popup-close">×</button>
<p><strong>Name:</strong> <span id="location-name"> ${ location . user_name } </span></p>
<p><strong>Address:</strong> <span id="location-address"> ${ location . user_address } </span></p>
<div>
<button class="popup-delete">Delete</button>
<button class="popup-edit">Edit</button>
</div>
</div>
` ;
popup . querySelector ( '.popup-close' ). addEventListener ( 'click' , () => {
document . body . removeChild ( popup );
});
popup . querySelector ( '.popup-delete' ). addEventListener ( 'click' , async () => {
await deleteScores ( location . id );
document . body . removeChild ( popup );
populateScores ();
});
document . body . appendChild ( popup );
}
Inline Editing
Toggle between view and edit modes:
navigation/favoriteLocations/favoriteLocations.js
const editButton = popup . querySelector ( '.popup-edit' );
editButton . addEventListener ( 'click' , () => {
const nameSpan = document . getElementById ( 'location-name' );
const addressSpan = document . getElementById ( 'location-address' );
if ( editButton . textContent === 'Edit' ) {
nameSpan . innerHTML = `<input type="text" id="edit-location-name" value=" ${ location . user_name } " />` ;
addressSpan . innerHTML = `<input type="text" id="edit-location-address" value=" ${ location . user_address } " />` ;
editButton . textContent = 'Submit' ;
} else {
const updatedName = document . getElementById ( 'edit-location-name' ). value . trim ();
const updatedAddress = document . getElementById ( 'edit-location-address' ). value . trim ();
if ( updatedName && updatedAddress ) {
updateScores ( location . id , updatedAddress , updatedName ). then (() => {
document . body . removeChild ( popup );
populateScores ();
}). catch ( error => {
alert ( 'Error updating location: ' + error . message );
});
} else {
alert ( 'Please fill in both fields.' );
}
}
});
Local Storage Integration
Daily Routine Schedule
Store schedule data locally:
navigation/dailyroutine.html
let scheduleData = JSON . parse ( localStorage . getItem ( 'dailySchedule' )) || {};
function saveSchedule () {
localStorage . setItem ( 'dailySchedule' , JSON . stringify ( scheduleData ));
}
Best Practices
Environment-based configuration
Always use the dynamic API URI configuration: import { pythonURI , fetchOptions } from '../../assets/js/api/config.js' ;
Provide user-friendly error messages: if ( ! response . ok ) {
throw new Error ( `Failed to update location: ${ response . statusText } ` );
}
Encode location strings for geocoding: const url = `https://nominatim.openstreetmap.org/search?format=json&q= ${ encodeURIComponent ( place ) } ` ;
API Endpoints
CRUD operations for favorite locations
Fetch current authenticated user information
Calculate routes with traffic data
Map Integration Learn about Leaflet map setup and configuration
Routing Engine Explore route calculation and rendering