Plants Location Record
#exportBtn {
background-color: #007bff;
}
#clearBtn {
background-color: #dc3545;
}
#addSpeciesBtn {
background-color: #28a745;
padding: 6px 12px;
font-size: 0.85em;
margin-top: 5px;
}
#addSpeciesBtn:hover {
background-color: #218838;
}
.status {
margin-top: 10px;
padding: 10px;
border-radius: 4px;
}
.success {
background-color: #d4edda;
color: #155724;
}
.error {
background-color: #f8d7da;
color: #721c24;
}
.warning {
background-color: #fff3cd;
color: #856404;
}
/* Mobile responsive table styles */
@media screen and (max-width: 768px) {
table, thead, tbody, th, td, tr {
display: block;
}
thead tr {
position: absolute;
top: -9999px;
left: -9999px;
}
tr {
border: 1px solid #ccc;
margin-bottom: 10px;
padding: 10px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
td {
border: none;
border-bottom: 1px solid #eee;
position: relative;
padding-left: 35%;
padding-top: 10px;
padding-bottom: 10px;
word-wrap: break-word;
}
td:before {
content: attr(data-label) ": ";
position: absolute;
left: 6px;
width: 30%;
padding-right: 10px;
white-space: nowrap;
font-weight: bold;
color: #333;
}
td:last-child {
border-bottom: none;
}
}
/* Very small screens */
@media screen and (max-width: 480px) {
#exportBtn, #clearBtn {
width: calc(50% - 5px);
display: inline-block;
margin-right: 10px;
}
#clearBtn {
margin-right: 0;
}
}
.hidden {
display: none;
}
.location-info {
font-size: 0.9em;
color: #666;
margin-top: 5px;
}
/* Modal styles */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background-color: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
text-align: center;
max-width: 400px;
width: 90%;
position: relative;
animation: modalFadeIn 0.3s ease-out;
}
@keyframes modalFadeIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
.modal-icon {
font-size: 48px;
color: #4CAF50;
margin-bottom: 15px;
}
.modal-title {
font-size: 1.4em;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.modal-message {
color: #666;
margin-bottom: 20px;
line-height: 1.4;
}
.modal-details {
background-color: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
text-align: left;
}
.modal-details strong {
color: #333;
}
.modal-close {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 30px;
border-radius: 6px;
cursor: pointer;
font-size: 1em;
}
.modal-close:hover {
background-color: #45a049;
}
/* Add species modal specific styles */
.add-species-modal {
text-align: left;
}
.modal-form-group {
margin-bottom: 15px;
}
.modal-form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.modal-form-group input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
.modal-buttons {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.modal-cancel {
background-color: #6c757d;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 1em;
}
.modal-cancel:hover {
background-color: #5a6268;
}
.modal-add {
background-color: #28a745;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 1em;
}
.modal-add:hover {
background-color: #218838;
}
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const locationBtn = document.getElementById('getLocation');
const latitudeInput = document.getElementById('latitude');
const longitudeInput = document.getElementById('longitude');
const statusDiv = document.getElementById('status');
const form = document.getElementById('locationForm');
const dataSection = document.getElementById('dataSection');
const tableBody = document.getElementById('tableBody');
const exportBtn = document.getElementById('exportBtn');
const clearBtn = document.getElementById('clearBtn');
const areaByCoordsBtn = document.getElementById('areaByCoords');
const areaInput = document.getElementById('area');
const addSpeciesBtn = document.getElementById('addSpeciesBtn');
const plantSpeciesSelect = document.getElementById('plantSpecies');
// Storage keys
const STORAGE_KEY = 'simplePlantLocations';
const SPECIES_STORAGE_KEY = 'plantSpeciesList';
// Arrays to store data
let plantEntries = [];
let customSpecies = [];
// Default species (always available)
const defaultSpecies = [
];
// Load existing data on page load
loadData();
loadCustomSpecies();
updateSpeciesDropdown();
updateTable();
// Load custom species from localStorage
function loadCustomSpecies() {
try {
const data = JSON.parse(localStorage.getItem(SPECIES_STORAGE_KEY) || '[]');
customSpecies = data;
} catch (error) {
console.error('Error loading custom species:', error);
customSpecies = [];
}
}
// Save custom species to localStorage
function saveCustomSpecies() {
try {
localStorage.setItem(SPECIES_STORAGE_KEY, JSON.stringify(customSpecies));
return true;
} catch (error) {
console.error('Error saving custom species:', error);
return false;
}
}
// Update the species dropdown with default + custom species
function updateSpeciesDropdown() {
const currentValue = plantSpeciesSelect.value;
// Clear existing options except the first placeholder
while (plantSpeciesSelect.children.length > 1) {
plantSpeciesSelect.removeChild(plantSpeciesSelect.lastChild);
}
// Combine default and custom species, remove duplicates
const allSpecies = [...defaultSpecies, ...customSpecies];
const uniqueSpecies = [...new Set(allSpecies)].sort();
// Add options to dropdown
uniqueSpecies.forEach(species => {
const option = document.createElement('option');
option.value = species;
option.textContent = species;
plantSpeciesSelect.appendChild(option);
});
// Restore selected value if it still exists
if (currentValue && uniqueSpecies.includes(currentValue)) {
plantSpeciesSelect.value = currentValue;
}
}
// Show add species modal
function showAddSpeciesModal() {
const modalHTML = `
`;
document.body.insertAdjacentHTML('beforeend', modalHTML);
// Focus on input
setTimeout(() => {
document.getElementById('newSpeciesName').focus();
}, 100);
// Handle Enter key
document.getElementById('newSpeciesName').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
addNewSpecies();
}
});
// Handle Escape key
document.addEventListener('keydown', handleEscapeKey);
}
// Handle escape key to close modal
function handleEscapeKey(e) {
if (e.key === 'Escape') {
closeAddSpeciesModal();
}
}
// Close add species modal
function closeAddSpeciesModal() {
const modal = document.getElementById('addSpeciesModal');
if (modal) {
document.removeEventListener('keydown', handleEscapeKey);
modal.style.opacity = '0';
modal.style.transform = 'scale(0.8)';
setTimeout(() => modal.remove(), 300);
}
}
// Add new species to the list
function addNewSpecies() {
const input = document.getElementById('newSpeciesName');
const speciesName = input.value.trim();
if (!speciesName) {
showStatus('Please enter a species name', 'error');
input.focus();
return;
}
// Check if species already exists (case insensitive)
const allSpecies = [...defaultSpecies, ...customSpecies];
const exists = allSpecies.some(species =>
species.toLowerCase() === speciesName.toLowerCase()
);
if (exists) {
showStatus('This species already exists in the list', 'error');
input.focus();
input.select();
return;
}
// Add to custom species array
customSpecies.push(speciesName);
// Save to localStorage
if (saveCustomSpecies()) {
updateSpeciesDropdown();
plantSpeciesSelect.value = speciesName; // Select the newly added species
showStatus(`Species "${speciesName}" added successfully!`, 'success');
closeAddSpeciesModal();
} else {
showStatus('Error saving species. Please try again.', 'error');
}
}
// Make functions globally accessible for onclick handlers
window.closeAddSpeciesModal = closeAddSpeciesModal;
window.addNewSpecies = addNewSpecies;
// Check if geolocation is available
function checkGeolocationSupport() {
if (!navigator.geolocation) {
showStatus('Geolocation is not supported by your browser. Please enter coordinates manually.', 'warning');
makeCoordinatesEditable();
return false;
}
// Check if we're on HTTPS or localhost
if (location.protocol !== 'https:' && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1') {
showStatus('Location services require HTTPS. You can manually enter coordinates.', 'warning');
makeCoordinatesEditable();
return false;
}
return true;
}
// Make coordinate inputs editable for manual entry
function makeCoordinatesEditable() {
latitudeInput.removeAttribute('readonly');
longitudeInput.removeAttribute('readonly');
latitudeInput.placeholder = 'Enter latitude (e.g., 26.9124)';
longitudeInput.placeholder = 'Enter longitude (e.g., 75.7873)';
// Add input validation
latitudeInput.addEventListener('input', validateCoordinates);
longitudeInput.addEventListener('input', validateCoordinates);
}
// Validate coordinate inputs
function validateCoordinates() {
const lat = parseFloat(latitudeInput.value);
const lon = parseFloat(longitudeInput.value);
if (latitudeInput.value && (isNaN(lat) || lat < -90 || lat > 90)) {
latitudeInput.style.borderColor = '#dc3545';
} else {
latitudeInput.style.borderColor = '#ddd';
}
if (longitudeInput.value && (isNaN(lon) || lon < -180 || lon > 180)) {
longitudeInput.style.borderColor = '#dc3545';
} else {
longitudeInput.style.borderColor = '#ddd';
}
}
// Save data to localStorage
function saveData() {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(plantEntries));
return true;
} catch (error) {
console.error('Storage error:', error);
return false;
}
}
// Load data from localStorage
function loadData() {
try {
const data = localStorage.getItem(STORAGE_KEY);
if (data) {
plantEntries = JSON.parse(data);
} else {
plantEntries = [];
}
} catch (error) {
console.error('Error loading data:', error);
plantEntries = [];
}
}
// Format date for display
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleString();
}
// Format date for CSV - escape commas and quotes
function formatDateForCSV(dateString) {
const date = new Date(dateString);
// Format as YYYY-MM-DD HH:MM:SS
return date.toISOString().replace('T', ' ').substring(0, 19);
}
// CSV escape function to handle fields with commas or quotes
function escapeCSV(field) {
if (field === null || field === undefined) {
return '';
}
field = String(field);
// If field contains commas, quotes, or newlines, wrap in quotes
if (field.includes(',') || field.includes('"') || field.includes('\n')) {
// Double up any quotes
field = field.replace(/"/g, '""');
// Wrap in quotes
return `"${field}"`;
}
return field;
}
// Get current location with improved error handling
function getCurrentLocation() {
if (!checkGeolocationSupport()) {
return;
}
locationBtn.disabled = true;
locationBtn.textContent = 'Getting Location...';
showStatus('Fetching your location... This may take a few seconds.', 'status');
const options = {
enableHighAccuracy: true,
timeout: 10000, // 10 seconds timeout
maximumAge: 60000 // Accept cached position up to 1 minute old
};
navigator.geolocation.getCurrentPosition(
function(position) {
const lat = position.coords.latitude.toFixed(6);
const lon = position.coords.longitude.toFixed(6);
latitudeInput.value = lat;
longitudeInput.value = lon;
const accuracy = position.coords.accuracy;
showStatus(`Location fetched successfully! (Accuracy: ±${Math.round(accuracy)}m)`, 'success');
locationBtn.disabled = false;
locationBtn.textContent = 'Get Current Location';
},
function(error) {
let errorMessage = 'Error getting location: ';
switch(error.code) {
case error.PERMISSION_DENIED:
errorMessage += 'Location permission denied. Please allow location access or enter coordinates manually.';
makeCoordinatesEditable();
break;
case error.POSITION_UNAVAILABLE:
errorMessage += 'Location information unavailable. Please enter coordinates manually.';
makeCoordinatesEditable();
break;
case error.TIMEOUT:
errorMessage += 'Location request timed out. Please try again or enter coordinates manually.';
makeCoordinatesEditable();
break;
default:
errorMessage += 'Unknown error occurred. Please enter coordinates manually.';
makeCoordinatesEditable();
}
showStatus(errorMessage, 'error');
locationBtn.disabled = false;
locationBtn.textContent = 'Get Current Location';
},
options
);
}
// Show status message
function showStatus(message, type) {
statusDiv.textContent = message;
statusDiv.className = 'status ' + type;
if (type === 'success') {
setTimeout(() => {
statusDiv.textContent = '';
statusDiv.className = 'status';
}, 5000);
}
}
// Update table with entries
function updateTable() {
tableBody.innerHTML = '';
if (plantEntries.length === 0) {
dataSection.classList.add('hidden');
return;
}
const fragment = document.createDocumentFragment();
// Sort entries by timestamp (most recent first)
const sortedEntries = [...plantEntries].sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
sortedEntries.forEach(entry => {
const row = document.createElement('tr');
// Create cells with data labels for mobile
const areaCell = document.createElement('td');
areaCell.textContent = entry.area;
areaCell.setAttribute('data-label', 'Area');
const speciesCell = document.createElement('td');
speciesCell.textContent = entry.plantSpecies;
speciesCell.setAttribute('data-label', 'Plant Species');
const latCell = document.createElement('td');
latCell.textContent = entry.latitude;
latCell.setAttribute('data-label', 'Latitude');
const longCell = document.createElement('td');
longCell.textContent = entry.longitude;
longCell.setAttribute('data-label', 'Longitude');
const remarksCell = document.createElement('td');
remarksCell.textContent = entry.remarks || '-';
remarksCell.setAttribute('data-label', 'Remarks');
const dateCell = document.createElement('td');
dateCell.textContent = formatDate(entry.timestamp);
dateCell.setAttribute('data-label', 'Date');
// Append cells to row
row.appendChild(areaCell);
row.appendChild(speciesCell);
row.appendChild(latCell);
row.appendChild(longCell);
row.appendChild(remarksCell);
row.appendChild(dateCell);
fragment.appendChild(row);
});
tableBody.appendChild(fragment);
dataSection.classList.remove('hidden');
}
// Export data to CSV
function exportToCSV() {
if (plantEntries.length === 0) {
showStatus('No data to export', 'error');
return;
}
// Create CSV content
let csvContent = "data:text/csv;charset=utf-8,";
csvContent += "Area,Plant Species,Latitude,Longitude,Remarks,Date\n";
plantEntries.forEach(entry => {
const formattedDate = formatDateForCSV(entry.timestamp);
csvContent += [
escapeCSV(entry.area),
escapeCSV(entry.plantSpecies),
escapeCSV(entry.latitude),
escapeCSV(entry.longitude),
escapeCSV(entry.remarks || ''),
escapeCSV(formattedDate)
].join(',') + '\n';
});
// Create download link
const encodedUri = encodeURI(csvContent);
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "plant-locations.csv");
document.body.appendChild(link);
// Trigger download
link.click();
document.body.removeChild(link);
showStatus('CSV exported!', 'success');
}
// Clear all data
function clearData() {
if (confirm('Are you sure you want to delete all data? This cannot be undone.')) {
localStorage.removeItem(STORAGE_KEY);
plantEntries = [];
updateTable();
showStatus('All data cleared', 'success');
}
}
// Show success popup
function showSuccessPopup(entry) {
// Create popup HTML
const popupHTML = `
`;
// Add popup to body
document.body.insertAdjacentHTML('beforeend', popupHTML);
// Auto-close after 5 seconds
setTimeout(closeSuccessPopup, 5000);
}
// Close success popup
function closeSuccessPopup() {
const popup = document.getElementById('successPopup');
if (popup) {
popup.style.opacity = '0';
popup.style.transform = 'scale(0.8)';
setTimeout(() => popup.remove(), 300);
}
}
// Make closeSuccessPopup globally accessible
window.closeSuccessPopup = closeSuccessPopup;
// Fill area name with address from coordinates
async function fillAreaByCoordinates() {
const lat = latitudeInput.value.trim();
const lon = longitudeInput.value.trim();
if (!lat || !lon) {
showStatus('Please get location or enter coordinates first', 'error');
return;
}
// Validate coordinates
const latNum = parseFloat(lat);
const lonNum = parseFloat(lon);
if (isNaN(latNum) || latNum < -90 || latNum > 90 || isNaN(lonNum) || lonNum < -180 || lonNum > 180) {
showStatus('Invalid coordinates. Please check latitude and longitude values.', 'error');
return;
}
// Disable button and show loading
areaByCoordsBtn.disabled = true;
areaByCoordsBtn.textContent = 'Getting Address...';
showStatus('Fetching address from coordinates...', 'status');
try {
// Use OpenStreetMap Nominatim API for reverse geocoding (free, no API key required)
const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${latNum}&lon=${lonNum}&zoom=18&addressdetails=1`, {
headers: {
'User-Agent': 'PlantLocationForm/1.0'
}
});
if (!response.ok) {
throw new Error('Geocoding service unavailable');
}
const data = await response.json();
if (data && data.display_name) {
// Try to extract a meaningful location name
let areaName = '';
if (data.address) {
// Priority order for location naming
const locationParts = [
// Tourist and historic sites (highest priority)
data.address.tourism, // Tourist attractions like "Jaigarh Fort"
data.address.historic, // Historic sites
// Amenities and landmarks
data.address.amenity, // Parks: "Ram Niwas Garden", monuments, hospitals: "SMS Hospital"
data.address.leisure, // Parks, gardens: "Central Park", "Sisodia Rani Garden"
data.address.natural, // Natural features: hills, lakes
data.address.place_of_worship, // Religious places
// Buildings and structures
data.address.building, // Specific buildings: "Birla Auditorium"
data.address.house_name, // Named houses or buildings
data.address.building_name, // Building names
// Government and institutions
data.address.government, // Government buildings: "Raj Bhawan", "Secretariat"
data.address.office, // Office buildings, complexes
data.address.university, // Universities and colleges: "University of Rajasthan"
data.address.college, // Colleges
data.address.school, // Educational institutions
data.address.hospital, // Hospitals and clinics
// Commercial areas
data.address.shop, // Major shopping areas: "Johari Bazaar"
data.address.marketplace, // Markets and bazaars
data.address.mall, // Shopping malls: "World Trade Park"
data.address.commercial, // Commercial buildings
data.address.hotel, // Hotels: "Rambagh Palace Hotel"
data.address.guest_house, // Guest houses
data.address.restaurant, // Notable restaurants
data.address.cafe, // Cafes and eateries
data.address.bank, // Banks and financial institutions
data.address.pharmacy, // Pharmacies
// Infrastructure
data.address.transport, // Transport hubs
data.address.fuel, // Petrol stations
data.address.parking, // Parking areas
// Land use and areas
data.address.landuse, // Specific land use areas
data.address.industrial, // Industrial areas
data.address.residential, // Residential complexes
data.address.farm, // Farms and agricultural areas
data.address.allotments, // Garden allotments
// Geographic divisions (lowest priority)
data.address.neighbourhood, // Local neighborhoods: "Civil Lines", "Malviya Nagar"
data.address.quarter, // City quarters
data.address.suburb, // Suburbs: "Vaishali Nagar", "Mansarovar"
data.address.hamlet, // Small settlements
data.address.isolated_dwelling, // Isolated houses
data.address.village, // Villages: "Kukas", "Goner"
data.address.town, // Towns
data.address.city_district, // City districts: "Jaipur North", "Jaipur South"
data.address.municipality, // Municipalities
data.address.borough, // Boroughs
data.address.county, // Counties
data.address.district, // Districts: "Jaipur District"
data.address.province, // Provinces
data.address.region, // Regions
data.address.city // City
].filter(Boolean);
if (locationParts.length > 0) {
areaName = locationParts[0];
// Add additional context if it's a generic name
if (locationParts.length > 1 && locationParts[0].length < 10) {
areaName += `, ${locationParts[1]}`;
}
}
}
// Fallback to display name if no specific address parts found
if (!areaName) {
// Use the first part of display name (usually the most specific location)
const parts = data.display_name.split(',');
areaName = parts[0].trim();
// If first part is just a number (like house number), use first two parts
if (parts.length > 1 && /^\d+$/.test(areaName)) {
areaName = `${areaName}, ${parts[1].trim()}`;
}
}
areaInput.value = areaName;
showStatus('Address fetched successfully!', 'success');
} else {
// Fallback to coordinate format if no address found
const formattedLat = Math.abs(latNum).toFixed(4) + (latNum >= 0 ? 'N' : 'S');
const formattedLon = Math.abs(lonNum).toFixed(4) + (lonNum >= 0 ? 'E' : 'W');
areaInput.value = `${formattedLat}, ${formattedLon}`;
showStatus('No address found. Used coordinate format instead.', 'warning');
}
} catch (error) {
console.error('Geocoding error:', error);
// Fallback to coordinate format
const formattedLat = Math.abs(latNum).toFixed(4) + (latNum >= 0 ? 'N' : 'S');
const formattedLon = Math.abs(lonNum).toFixed(4) + (lonNum >= 0 ? 'E' : 'W');
areaInput.value = `${formattedLat}, ${formattedLon}`;
showStatus('Could not fetch address. Used coordinate format instead.', 'warning');
}
// Re-enable button
areaByCoordsBtn.disabled = false;
areaByCoordsBtn.textContent = 'Area by Coordinates';
}
// Event listeners
locationBtn.addEventListener('click', getCurrentLocation);
addSpeciesBtn.addEventListener('click', showAddSpeciesModal);
form.addEventListener('submit', function(e) {
e.preventDefault();
const areaValue = document.getElementById('area').value.trim();
const plantSpeciesValue = document.getElementById('plantSpecies').value;
const remarksValue = document.getElementById('remarks').value.trim();
const latValue = latitudeInput.value.trim();
const lonValue = longitudeInput.value.trim();
if (!plantSpeciesValue) {
showStatus('Please select a plant species', 'error');
return;
}
if (!latValue || !lonValue) {
showStatus('Please get your location first or enter coordinates manually', 'error');
return;
}
// Validate coordinates
const lat = parseFloat(latValue);
const lon = parseFloat(lonValue);
if (isNaN(lat) || lat < -90 || lat > 90) {
showStatus('Invalid latitude. Must be between -90 and 90', 'error');
return;
}
if (isNaN(lon) || lon < -180 || lon > 180) {
showStatus('Invalid longitude. Must be between -180 and 180', 'error');
return;
}
// Create new entry
const newEntry = {
area: areaValue,
plantSpecies: plantSpeciesValue,
latitude: lat.toFixed(6),
longitude: lon.toFixed(6),
remarks: remarksValue,
timestamp: new Date().toISOString()
};
// Add to array and save
plantEntries.push(newEntry);
if (saveData()) {
updateTable();
showSuccessPopup(newEntry);
// Reset form
document.getElementById('area').value = '';
document.getElementById('plantSpecies').value = '';
document.getElementById('remarks').value = '';
latitudeInput.value = '';
longitudeInput.value = '';
}
});
exportBtn.addEventListener('click', exportToCSV);
clearBtn.addEventListener('click', clearData);
areaByCoordsBtn.addEventListener('click', fillAreaByCoordinates);
});
Area Name:
Area by Coordinates
Plant Species:
Select a plant species
+ Add Species
Latitude:
Longitude:
Remarks:
Get Current Location
Submit
Note: Location access requires HTTPS or localhost. If location doesn't work, manually enter coordinates.
Recorded Plant Locations
| Area | Plant Species | Latitude | Longitude | Remarks | Date |
|---|
Export CSV
Clear Data
Add New Plant Species
Enter the name of the new plant species you want to add to the dropdown.
Species Name:
Cancel
Add Species
✅
Entry Recorded Successfully!
Your plant location has been saved
Area: ${entry.area || 'Not specified'}
Plant Species: ${entry.plantSpecies}
Location: ${entry.latitude}, ${entry.longitude}
Remarks: ${entry.remarks || 'None'}
Time: ${formatDate(entry.timestamp)}
Continue
Plant Species: ${entry.plantSpecies}
Location: ${entry.latitude}, ${entry.longitude}
Remarks: ${entry.remarks || 'None'}
Time: ${formatDate(entry.timestamp)}