Skip to content

Commit a4810fa

Browse files
authored
Merge pull request #23 from badgerloop-software/fix/web-strategy-github-pages-sidebar
fix(web): Strategy crash, Meteoblue key coercion, GitHub Pages tab CSS
2 parents e7827d2 + 118647f commit a4810fa

3 files changed

Lines changed: 42 additions & 14 deletions

File tree

app/(tabs)/_layout.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ import { useAuthGuard } from '../../src/hooks/useAuthGuard';
99
import useDeviceType from '../../src/hooks/useDeviceType';
1010
import { useNavigation } from '../../src/context/NavigationContext';
1111
import { useUser } from '@clerk/expo';
12+
import { getExpoWebBasePath } from '../../src/lib/expoWebBasePath';
13+
14+
/** Href segment for Expo Router tab links (with optional GitHub Pages `experiments.baseUrl`). */
15+
function tabHref(pathFromRoot) {
16+
const base = getExpoWebBasePath();
17+
const p = pathFromRoot.startsWith('/') ? pathFromRoot : `/${pathFromRoot}`;
18+
if (!base) return p;
19+
return `${base}${p}`.replace(/\/{2,}/g, '/');
20+
}
1221

1322
export default function TabLayout() {
1423
const { isDark } = useTheme();
@@ -37,6 +46,18 @@ export default function TabLayout() {
3746
if (document.getElementById(styleId)) return;
3847
const style = document.createElement('style');
3948
style.id = styleId;
49+
const base = getExpoWebBasePath();
50+
const homeSelectors = base
51+
? `[role="tablist"] a[href="${base}"]::after, [role="tablist"] a[href="${base}/"]::after`
52+
: `[role="tablist"] a[href="/"]::after`;
53+
const tabRules = [
54+
`${homeSelectors} { content: "Home"; }`,
55+
`[role="tablist"] a[href="${tabHref('/systems')}"]::after { content: "Systems"; }`,
56+
`[role="tablist"] a[href="${tabHref('/classic-dashboard')}"]::after { content: "Classic"; }`,
57+
`[role="tablist"] a[href="${tabHref('/signal-search')}"]::after { content: "Signals"; }`,
58+
`[role="tablist"] a[href="${tabHref('/account')}"]::after { content: "Account"; }`,
59+
`[role="tablist"] a[href="${tabHref('/profile')}"]::after { content: "Settings"; }`,
60+
].join('\n ');
4061
style.textContent = `
4162
[role="tablist"] {
4263
flex-direction: column !important;
@@ -65,12 +86,7 @@ export default function TabLayout() {
6586
position: relative !important;
6687
}
6788
68-
[role="tablist"] a[href="/"]::after { content: "Home"; }
69-
[role="tablist"] a[href="/systems"]::after { content: "Systems"; }
70-
[role="tablist"] a[href="/classic-dashboard"]::after { content: "Classic"; }
71-
[role="tablist"] a[href="/signal-search"]::after { content: "Signals"; }
72-
[role="tablist"] a[href="/account"]::after { content: "Account"; }
73-
[role="tablist"] a[href="/profile"]::after { content: "Settings"; }
89+
${tabRules}
7490
7591
[role="tablist"] a::after {
7692
display: block !important;

src/components/WeatherMapView.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ const WeatherMapView = ({
159159
const lat = latitude;
160160
const lng = longitude;
161161
const layersJson = JSON.stringify(WEATHER_LAYERS.map(({ id, mapId }) => ({ id, mapId })));
162-
const safeMeteoblueKey = (meteoblueKey || '').replace(/\\/g, '\\\\').replace(/'/g, "\\'");
162+
// extra.METEOBLUE_API_KEY must be treated as opaque text; numbers/objects truthy values break .replace.
163+
const safeMeteoblueKey = String(meteoblueKey ?? '')
164+
.replace(/\\/g, '\\\\')
165+
.replace(/'/g, "\\'");
163166

164167
return `<!DOCTYPE html>
165168
<html>

src/screens/StrategyScreen.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,22 @@ export default function StrategyScreen({ hideHeader = false }) {
8585
setGeocodeError(null);
8686
}, []);
8787

88-
if (!telemetryData) return null;
89-
90-
const currentSpeed = telemetryData.speed ? parseFloat(telemetryData.speed) : null;
91-
const currentPower = telemetryData.motor_power ? parseFloat(telemetryData.motor_power) : (telemetryData.pack_power ? parseFloat(telemetryData.pack_power) : null);
92-
const optSpeed = telemetryData.strategy_opt_speed !== null ? parseFloat(telemetryData.strategy_opt_speed) : null;
93-
const optPower = telemetryData.strategy_opt_power !== null ? parseFloat(telemetryData.strategy_opt_power) : null;
94-
const lastStrategyUpdate = telemetryData.strategy_last_update || 0;
88+
const d = telemetryData;
89+
const currentSpeed = d?.speed ? parseFloat(d.speed) : null;
90+
const currentPower = d?.motor_power
91+
? parseFloat(d.motor_power)
92+
: d?.pack_power
93+
? parseFloat(d.pack_power)
94+
: null;
95+
const optSpeed =
96+
d?.strategy_opt_speed !== undefined && d?.strategy_opt_speed !== null
97+
? parseFloat(d.strategy_opt_speed)
98+
: null;
99+
const optPower =
100+
d?.strategy_opt_power !== undefined && d?.strategy_opt_power !== null
101+
? parseFloat(d.strategy_opt_power)
102+
: null;
103+
const lastStrategyUpdate = d?.strategy_last_update || 0;
95104

96105
const secondsSinceStrategy = Math.max(0, Math.floor((Date.now() - lastStrategyUpdate) / 1000));
97106
const fmtAge = secondsSinceStrategy < 60 ? `${secondsSinceStrategy}s ago` : `${Math.floor(secondsSinceStrategy/60)}m ago`;

0 commit comments

Comments
 (0)