Activity History
+ +All quiet. No notifications yet.
+diff --git a/Backend/README.md b/Backend/README.md index ce857e5..2a78aee 100644 --- a/Backend/README.md +++ b/Backend/README.md @@ -169,7 +169,17 @@ OpenAPI docs are generated from Zod/OpenAPI definitions: | `GET /docs` | Swagger UI | ### Web Mobile Simulator -Use `GET /sim/mobile-sim.html` to run a browser simulator that behaves like the mobile app: +Use `GET /sim/mobile-sim.html` to run the full single-page browser simulator that behaves like the mobile app. + +Split-page entrypoints are also available: +- `GET /sim/mobile-sim-auth.html` +- `GET /sim/mobile-sim-onboarding.html` +- `GET /sim/mobile-sim-camera.html` +- `GET /sim/mobile-sim-client.html` +- `GET /sim/mobile-sim-activity.html` +- `GET /sim/mobile-sim-settings.html` + +All simulator pages support the same flow: - Register as `camera` or `client` - Connect Socket.IO with bearer device token - Camera: process incoming `start_stream` commands, fetch publish credentials, start/end motion events diff --git a/Backend/public/mobile-sim-activity.html b/Backend/public/mobile-sim-activity.html new file mode 100644 index 0000000..9f82dc3 --- /dev/null +++ b/Backend/public/mobile-sim-activity.html @@ -0,0 +1,268 @@ + + + +
+ + +All quiet. No notifications yet.
+Sign in to manage visual security from your browser.
+Camera Offline
+ +No cameras linked yet
+Set up this browser simulator's role
+user@example.com
+No cameras linked yet
No cameras linked yet
No recordings found
No recordings found
${msg}
`; - list.prepend(item); + list.prepend(item); + } // Also update camera logs if applicable if ($('cameraLogs')) { @@ -1756,27 +1879,34 @@ const addActivity = (type, msg) => { const updateNotificationDot = (show) => { const dot = $('notificationDot'); + if (!dot) return; if (show) dot.classList.remove('hidden'); else dot.classList.add('hidden'); }; // --- 6. Event Listeners --- -$('toggleAuthModeBtn').addEventListener('click', Actions.toggleAuthMode); -$('signInBtn').addEventListener('click', Actions.submitAuth); -$('registerBtn').addEventListener('click', Actions.registerDevice); -$('loadSavedBtn').addEventListener('click', () => { /* Handle legacy loading if needed */ }); +const bind = (id, eventName, handler) => { + const element = $(id); + if (!element) return; + element.addEventListener(eventName, handler); +}; + +bind('toggleAuthModeBtn', 'click', Actions.toggleAuthMode); +bind('signInBtn', 'click', Actions.submitAuth); +bind('registerBtn', 'click', Actions.registerDevice); +bind('loadSavedBtn', 'click', () => { /* Handle legacy loading if needed */ }); $$('#screen-onboarding [data-role]').forEach((btn) => { btn.addEventListener('click', () => Actions.selectRole(btn.dataset.role)); }); -$('recordingsList').addEventListener('click', (event) => { +bind('recordingsList', 'click', (event) => { const target = event.target.closest('.download-recording-btn'); if (!target || target.disabled) return; const recordingId = target.dataset.recordingId; if (!recordingId) return; Actions.openRecording(recordingId); }); -$('activityFeedList').addEventListener('click', (event) => { +bind('activityFeedList', 'click', (event) => { const target = event.target.closest('.motion-notification-btn'); if (!target) return; const notificationId = target.dataset.notificationId; @@ -1857,31 +1987,31 @@ $$('.nav-btn').forEach(btn => { if (btn.dataset.target === 'activity') { markAllNotificationsRead(); } - store.update({ screen: btn.dataset.target }); + if (navigateToScreen(btn.dataset.target)) return; }); }); // Camera Controls -$('cameraGoOnlineBtn').addEventListener('click', async () => { +bind('cameraGoOnlineBtn', 'click', async () => { if (store.get().device?.role === 'camera') { await startCameraPreview(); } connectSocket(); }); -$('startMotionBtn').addEventListener('click', Actions.startMotion); -$('endMotionBtn').addEventListener('click', Actions.endMotion); +bind('startMotionBtn', 'click', Actions.startMotion); +bind('endMotionBtn', 'click', Actions.endMotion); // Client Controls -$('linkCameraBtn').addEventListener('click', Actions.linkCamera); -$('refreshClientBtn').addEventListener('click', startPolling); +bind('linkCameraBtn', 'click', Actions.linkCamera); +bind('refreshClientBtn', 'click', startPolling); // Settings -$('signOutBtn').addEventListener('click', Actions.signOut); -$('clearActivityBtn').addEventListener('click', () => { +bind('signOutBtn', 'click', Actions.signOut); +bind('clearActivityBtn', 'click', () => { store.update({ motionNotifications: [] }); }); -$('recordingModalCloseBtn').addEventListener('click', Actions.closeRecordingModal); -$('recordingModal').addEventListener('click', (event) => { +bind('recordingModalCloseBtn', 'click', Actions.closeRecordingModal); +bind('recordingModal', 'click', (event) => { if (event.target === $('recordingModal')) { Actions.closeRecordingModal(); }