mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 01:31:39 -05:00
Show battery status on family member popup
This commit is contained in:
parent
1bf02bc063
commit
1e63b03b49
6 changed files with 69 additions and 12 deletions
File diff suppressed because one or more lines are too long
|
|
@ -109,7 +109,7 @@ export default class extends Controller {
|
||||||
const lastSeen = new Date(location.updated_at).toLocaleString();
|
const lastSeen = new Date(location.updated_at).toLocaleString();
|
||||||
|
|
||||||
// Create small tooltip that shows automatically
|
// Create small tooltip that shows automatically
|
||||||
const tooltipContent = this.createTooltipContent(lastSeen);
|
const tooltipContent = this.createTooltipContent(lastSeen, location.battery);
|
||||||
const tooltip = familyMarker.bindTooltip(tooltipContent, {
|
const tooltip = familyMarker.bindTooltip(tooltipContent, {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
direction: 'top',
|
direction: 'top',
|
||||||
|
|
@ -177,7 +177,7 @@ export default class extends Controller {
|
||||||
|
|
||||||
// Update tooltip content
|
// Update tooltip content
|
||||||
const lastSeen = new Date(locationData.updated_at).toLocaleString();
|
const lastSeen = new Date(locationData.updated_at).toLocaleString();
|
||||||
const tooltipContent = this.createTooltipContent(lastSeen);
|
const tooltipContent = this.createTooltipContent(lastSeen, locationData.battery);
|
||||||
existingMarker.setTooltipContent(tooltipContent);
|
existingMarker.setTooltipContent(tooltipContent);
|
||||||
|
|
||||||
// Update popup content
|
// Update popup content
|
||||||
|
|
@ -216,7 +216,7 @@ export default class extends Controller {
|
||||||
|
|
||||||
const lastSeen = new Date(location.updated_at).toLocaleString();
|
const lastSeen = new Date(location.updated_at).toLocaleString();
|
||||||
|
|
||||||
const tooltipContent = this.createTooltipContent(lastSeen);
|
const tooltipContent = this.createTooltipContent(lastSeen, location.battery);
|
||||||
familyMarker.bindTooltip(tooltipContent, {
|
familyMarker.bindTooltip(tooltipContent, {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
direction: 'top',
|
direction: 'top',
|
||||||
|
|
@ -238,8 +238,9 @@ export default class extends Controller {
|
||||||
this.familyMarkers[location.user_id] = familyMarker;
|
this.familyMarkers[location.user_id] = familyMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
createTooltipContent(lastSeen) {
|
createTooltipContent(lastSeen, battery) {
|
||||||
return `Last seen: ${lastSeen}`;
|
const batteryInfo = battery !== null && battery !== undefined ? ` | Battery: ${battery}%` : '';
|
||||||
|
return `Last seen: ${lastSeen}${batteryInfo}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
createPopupContent(location, lastSeen) {
|
createPopupContent(location, lastSeen) {
|
||||||
|
|
@ -250,6 +251,59 @@ export default class extends Controller {
|
||||||
|
|
||||||
const emailInitial = location.email_initial || location.email?.charAt(0)?.toUpperCase() || '?';
|
const emailInitial = location.email_initial || location.email?.charAt(0)?.toUpperCase() || '?';
|
||||||
|
|
||||||
|
// Battery display with icon
|
||||||
|
const battery = location.battery;
|
||||||
|
const batteryStatus = location.battery_status;
|
||||||
|
let batteryDisplay = '';
|
||||||
|
|
||||||
|
if (battery !== null && battery !== undefined) {
|
||||||
|
// Determine battery color based on level and status
|
||||||
|
let batteryColor = '#10B981'; // green
|
||||||
|
if (batteryStatus === 'charging') {
|
||||||
|
batteryColor = battery <= 50 ? '#F59E0B' : '#10B981'; // orange if low, green if high
|
||||||
|
} else if (battery <= 20) {
|
||||||
|
batteryColor = '#EF4444'; // red
|
||||||
|
} else if (battery <= 50) {
|
||||||
|
batteryColor = '#F59E0B'; // orange
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get appropriate Lucide battery icon
|
||||||
|
const getBatteryIcon = (battery, batteryStatus, batteryColor) => {
|
||||||
|
const baseAttrs = `width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="${batteryColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle; margin-right: 4px;"`;
|
||||||
|
|
||||||
|
// Charging icon
|
||||||
|
if (batteryStatus === 'charging') {
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" ${baseAttrs}><path d="m11 7-3 5h4l-3 5"/><path d="M14.856 6H16a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.935"/><path d="M22 14v-4"/><path d="M5.14 18H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2.936"/></svg>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full battery
|
||||||
|
if (battery === 100 || batteryStatus === 'full') {
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" ${baseAttrs}><path d="M10 10v4"/><path d="M14 10v4"/><path d="M22 14v-4"/><path d="M6 10v4"/><rect x="2" y="6" width="16" height="12" rx="2"/></svg>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Low battery (≤20%)
|
||||||
|
if (battery <= 20) {
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" ${baseAttrs}><path d="M22 14v-4"/><path d="M6 14v-4"/><rect x="2" y="6" width="16" height="12" rx="2"/></svg>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Medium battery (21-50%)
|
||||||
|
if (battery <= 50) {
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" ${baseAttrs}><path d="M10 14v-4"/><path d="M22 14v-4"/><path d="M6 14v-4"/><rect x="2" y="6" width="16" height="12" rx="2"/></svg>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// High battery (>50%, default to full)
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" ${baseAttrs}><path d="M10 10v4"/><path d="M14 10v4"/><path d="M22 14v-4"/><path d="M6 10v4"/><rect x="2" y="6" width="16" height="12" rx="2"/></svg>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const batteryIcon = getBatteryIcon(battery, batteryStatus, batteryColor);
|
||||||
|
|
||||||
|
batteryDisplay = `
|
||||||
|
<p style="margin: 0 0 8px 0; font-size: 13px;">
|
||||||
|
${batteryIcon}<strong>Battery:</strong> ${battery}%${batteryStatus ? ` (${batteryStatus})` : ''}
|
||||||
|
</p>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="family-member-popup" style="background-color: ${bgColor}; color: ${textColor}; padding: 12px; border-radius: 8px; min-width: 220px;">
|
<div class="family-member-popup" style="background-color: ${bgColor}; color: ${textColor}; padding: 12px; border-radius: 8px; min-width: 220px;">
|
||||||
<h3 style="margin: 0 0 12px 0; color: #10B981; font-size: 15px; font-weight: bold; display: flex; align-items: center; gap: 8px;">
|
<h3 style="margin: 0 0 12px 0; color: #10B981; font-size: 15px; font-weight: bold; display: flex; align-items: center; gap: 8px;">
|
||||||
|
|
@ -263,6 +317,7 @@ export default class extends Controller {
|
||||||
<strong>Coordinates:</strong><br/>
|
<strong>Coordinates:</strong><br/>
|
||||||
${location.latitude.toFixed(6)}, ${location.longitude.toFixed(6)}
|
${location.latitude.toFixed(6)}, ${location.longitude.toFixed(6)}
|
||||||
</p>
|
</p>
|
||||||
|
${batteryDisplay}
|
||||||
<p style="margin: 0; font-size: 12px; color: ${mutedColor}; padding-top: 8px; border-top: 1px solid ${isDark ? '#374151' : '#e5e7eb'};">
|
<p style="margin: 0; font-size: 12px; color: ${mutedColor}; padding-top: 8px; border-top: 1px solid ${isDark ? '#374151' : '#e5e7eb'};">
|
||||||
<strong>Last seen:</strong> ${lastSeen}
|
<strong>Last seen:</strong> ${lastSeen}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@ export default class extends BaseController {
|
||||||
const SettingsControl = L.Control.extend({
|
const SettingsControl = L.Control.extend({
|
||||||
onAdd: (map) => {
|
onAdd: (map) => {
|
||||||
const button = L.DomUtil.create('button', 'map-settings-button tooltip tooltip-right');
|
const button = L.DomUtil.create('button', 'map-settings-button tooltip tooltip-right');
|
||||||
button.innerHTML = '⚙️'; // Gear icon
|
button.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cog-icon lucide-cog"><path d="M11 10.27 7 3.34"/><path d="m11 13.73-4 6.93"/><path d="M12 22v-2"/><path d="M12 2v2"/><path d="M14 12h8"/><path d="m17 20.66-1-1.73"/><path d="m17 3.34-1 1.73"/><path d="M2 12h2"/><path d="m20.66 17-1.73-1"/><path d="m20.66 7-1.73 1"/><path d="m3.34 17 1.73-1"/><path d="m3.34 7 1.73 1"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="12" r="8"/></svg>'; // Gear icon
|
||||||
button.setAttribute('data-tip', 'Settings');
|
button.setAttribute('data-tip', 'Settings');
|
||||||
|
|
||||||
// Style the button with theme-aware styling
|
// Style the button with theme-aware styling
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ class Families::Locations
|
||||||
latitude: point.lat,
|
latitude: point.lat,
|
||||||
longitude: point.lon,
|
longitude: point.lon,
|
||||||
timestamp: point.timestamp.to_i,
|
timestamp: point.timestamp.to_i,
|
||||||
updated_at: Time.zone.at(point.timestamp.to_i)
|
updated_at: Time.zone.at(point.timestamp.to_i),
|
||||||
|
battery: point.battery,
|
||||||
|
battery_status: point.battery_status
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,14 @@
|
||||||
|
|
||||||
<body class='h-screen overflow-hidden relative'>
|
<body class='h-screen overflow-hidden relative'>
|
||||||
<!-- Fixed Navbar -->
|
<!-- Fixed Navbar -->
|
||||||
<div class='fixed w-full z-50 bg-base-100 shadow-md h-16'>
|
<div class='fixed w-full z-40 bg-base-100 shadow-md h-16'>
|
||||||
<div class='container mx-auto h-full w-full flex items-center'>
|
<div class='container mx-auto h-full w-full flex items-center'>
|
||||||
<%= render 'shared/navbar' %>
|
<%= render 'shared/navbar' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Flash Messages - Fixed below navbar -->
|
<!-- Flash Messages - Fixed below navbar -->
|
||||||
<div class='fixed top-16 w-full z-40'>
|
<div class='fixed top-16 w-full z-50'>
|
||||||
<div class='container mx-auto px-5'>
|
<div class='container mx-auto px-5'>
|
||||||
<%= render 'shared/flash' %>
|
<%= render 'shared/flash' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -525,7 +525,7 @@ test.describe('Map Functionality', () => {
|
||||||
|
|
||||||
// Verify it's actually a clickable button with gear icon
|
// Verify it's actually a clickable button with gear icon
|
||||||
const buttonText = await settingsButton.textContent();
|
const buttonText = await settingsButton.textContent();
|
||||||
expect(buttonText).toBe('⚙️');
|
expect(buttonText).toBe('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cog-icon lucide-cog"><path d="M11 10.27 7 3.34"/><path d="m11 13.73-4 6.93"/><path d="M12 22v-2"/><path d="M12 2v2"/><path d="M14 12h8"/><path d="m17 20.66-1-1.73"/><path d="m17 3.34-1 1.73"/><path d="M2 12h2"/><path d="m20.66 17-1.73-1"/><path d="m20.66 7-1.73 1"/><path d="m3.34 17 1.73-1"/><path d="m3.34 7 1.73 1"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="12" r="8"/></svg>');
|
||||||
|
|
||||||
// Test opening settings panel
|
// Test opening settings panel
|
||||||
await settingsButton.click();
|
await settingsButton.click();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue