Skip to content

Commit f973073

Browse files
committed
WIP - Simple storage added
1 parent a6ac07b commit f973073

File tree

3 files changed

+181
-12
lines changed

3 files changed

+181
-12
lines changed

src/frontend/src/App.tsx

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,57 @@ export default function App() {
2828
}
2929
}, [userId, isLoading, error, isAuthenticated]);
3030

31+
// Load theme preference from backend when user authenticates
32+
useEffect(() => {
33+
if (isAuthenticated && userId) {
34+
console.log('🎨 [Theme] Loading theme preference for user:', userId);
35+
36+
fetch(`/api/theme-preference?userId=${encodeURIComponent(userId)}`)
37+
.then(res => res.json())
38+
.then(data => {
39+
if (data.theme) {
40+
console.log('🎨 [Theme] Loaded theme preference:', data.theme);
41+
setIsDark(data.theme === 'dark');
42+
}
43+
})
44+
.catch(error => {
45+
console.error('🎨 [Theme] Failed to load theme preference:', error);
46+
// Keep default theme on error
47+
});
48+
}
49+
}, [isAuthenticated, userId]);
50+
51+
// Handle theme change and save to backend
52+
const handleThemeChange = async (newIsDark: boolean) => {
53+
// Update UI immediately for responsive feel
54+
setIsDark(newIsDark);
55+
56+
// Save to backend if user is authenticated
57+
if (userId) {
58+
const theme = newIsDark ? 'dark' : 'light';
59+
console.log(`🎨 [Theme] Saving theme preference for user ${userId}:`, theme);
60+
61+
try {
62+
const response = await fetch('/api/theme-preference', {
63+
method: 'POST',
64+
headers: { 'Content-Type': 'application/json' },
65+
body: JSON.stringify({ userId, theme })
66+
});
67+
68+
const data = await response.json();
69+
70+
if (data.success) {
71+
console.log('🎨 [Theme] Theme preference saved successfully:', theme);
72+
} else {
73+
console.error('🎨 [Theme] Failed to save theme preference:', data);
74+
}
75+
} catch (error) {
76+
console.error('🎨 [Theme] Error saving theme preference:', error);
77+
// Continue using the theme locally even if save fails
78+
}
79+
}
80+
};
81+
3182
// Handle loading state
3283
if (isLoading) {
3384
return (
@@ -56,16 +107,16 @@ export default function App() {
56107
}
57108

58109
// Handle unauthenticated state
59-
if (!isAuthenticated || !userId) {
60-
return (
61-
<div className="min-h-screen flex items-center justify-center bg-slate-900">
62-
<div className="text-center p-8">
63-
<h2 className="text-red-500 text-2xl font-semibold mb-4">Not Authenticated</h2>
64-
<p className="text-gray-400">Please open this page from the MentraOS manager app.</p>
65-
</div>
66-
</div>
67-
);
68-
}
110+
// if (!isAuthenticated || !userId) {
111+
// return (
112+
// <div className="min-h-screen flex items-center justify-center bg-slate-900">
113+
// <div className="text-center p-8">
114+
// <h2 className="text-red-500 text-2xl font-semibold mb-4">Not Authenticated</h2>
115+
// <p className="text-gray-400">Please open this page from the MentraOS manager app.</p>
116+
// </div>
117+
// </div>
118+
// );
119+
// }
69120

70121
return (
71122
<div className={`min-h-screen ${isDark ? 'dark' : 'light'}`} style={{
@@ -138,7 +189,11 @@ export default function App() {
138189
<div className="relative">
139190
<button
140191
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
141-
className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-[#00e2a2] bg-slate-800/50 rounded-md"
192+
className={`flex items-center gap-2 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
193+
isDark
194+
? 'text-[#00e2a2] bg-slate-800/50'
195+
: 'text-emerald-700 bg-emerald-100/80'
196+
}`}
142197
>
143198
{activeTab === 'home' ? 'Home' : 'Template'}
144199
<svg
@@ -188,7 +243,7 @@ export default function App() {
188243

189244
{/* Content */}
190245
<main>
191-
{activeTab === 'home' ? <Home /> : <Template isDark={isDark} setIsDark={setIsDark} userId={userId} />}
246+
{activeTab === 'home' ? <Home /> : <Template isDark={isDark} setIsDark={handleThemeChange} userId={userId || ''} />}
192247
</main>
193248
</div>
194249
);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { AppSession } from '@mentra/sdk';
2+
3+
/**
4+
* Get the user's theme preference from Simple Storage
5+
* @param session - The active MentraOS session
6+
* @param userId - The user ID
7+
* @returns The theme preference ('dark' or 'light'), defaults to 'dark'
8+
*/
9+
export async function getThemePreference(
10+
session: AppSession,
11+
userId: string
12+
): Promise<'dark' | 'light'> {
13+
try {
14+
const theme = await session.simpleStorage.get('theme');
15+
16+
if (theme === 'dark' || theme === 'light') {
17+
console.log(`[Simple Storage] Retrieved theme preference for user ${userId}: ${theme}`);
18+
return theme;
19+
}
20+
21+
// Default to dark if not set or invalid value
22+
console.log(`[Simple Storage] No theme preference found for user ${userId}, defaulting to dark`);
23+
return 'dark';
24+
} catch (error) {
25+
console.error(`[Simple Storage] Error getting theme preference for user ${userId}:`, error);
26+
return 'dark'; // Fallback to dark on error
27+
}
28+
}
29+
30+
/**
31+
* Set the user's theme preference in Simple Storage
32+
* @param session - The active MentraOS session
33+
* @param userId - The user ID
34+
* @param theme - The theme preference to save ('dark' or 'light')
35+
*/
36+
export async function setThemePreference(
37+
session: AppSession,
38+
userId: string,
39+
theme: 'dark' | 'light'
40+
): Promise<void> {
41+
try {
42+
await session.simpleStorage.set('theme', theme);
43+
console.log(`[Simple Storage] Saved theme preference for user ${userId}: ${theme}`);
44+
} catch (error) {
45+
console.error(`[Simple Storage] Error setting theme preference for user ${userId}:`, error);
46+
throw error; // Re-throw to let caller handle error response
47+
}
48+
}

src/mentra-app/routes/routes.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { Express, Response } from 'express';
1919
import { AuthenticatedRequest } from '@mentra/sdk';
2020
import * as ejs from 'ejs';
2121
import * as path from 'path';
22+
import { getThemePreference, setThemePreference } from '../modules/simple-storage';
2223

2324
// Store SSE clients with userId mapping
2425
interface SSEClient {
@@ -307,6 +308,71 @@ export function setupWebviewRoutes(
307308
}
308309
});
309310

311+
// Route: Get theme preference from Simple Storage
312+
app.get('/api/theme-preference', async (req: any, res: any) => {
313+
try {
314+
const userId = req.query.userId as string;
315+
316+
if (!userId) {
317+
res.status(400).json({ error: 'userId is required' });
318+
return;
319+
}
320+
321+
// Get the session for this specific user
322+
const session = activeSessions.get(userId);
323+
324+
if (!session) {
325+
res.status(404).json({ error: `No active session for user ${userId}` });
326+
return;
327+
}
328+
329+
console.log(`[Theme] Getting theme preference for user: ${userId}`);
330+
331+
// Get theme preference from Simple Storage
332+
const theme = await getThemePreference(session, userId);
333+
334+
res.json({ theme, userId });
335+
} catch (error: any) {
336+
console.error('Error getting theme preference:', error);
337+
res.status(500).json({ error: error.message });
338+
}
339+
});
340+
341+
// Route: Set theme preference in Simple Storage
342+
app.post('/api/theme-preference', async (req: any, res: any) => {
343+
try {
344+
const { userId, theme } = req.body;
345+
346+
if (!userId) {
347+
res.status(400).json({ error: 'userId is required' });
348+
return;
349+
}
350+
351+
if (!theme || (theme !== 'dark' && theme !== 'light')) {
352+
res.status(400).json({ error: 'theme must be "dark" or "light"' });
353+
return;
354+
}
355+
356+
// Get the session for this specific user
357+
const session = activeSessions.get(userId);
358+
359+
if (!session) {
360+
res.status(404).json({ error: `No active session for user ${userId}` });
361+
return;
362+
}
363+
364+
console.log(`[Theme] Setting theme preference for user ${userId}: ${theme}`);
365+
366+
// Set theme preference in Simple Storage
367+
await setThemePreference(session, userId, theme);
368+
369+
res.json({ success: true, theme, userId });
370+
} catch (error: any) {
371+
console.error('Error setting theme preference:', error);
372+
res.status(500).json({ error: error.message });
373+
}
374+
});
375+
310376
// Route 1: Get the latest photo metadata for a specific user
311377
app.get('/api/latest-photo', (req: any, res: any) => {
312378
const userId = req.query.userId as string;

0 commit comments

Comments
 (0)