From a5484283f40f5a57f739329551b28622218f7469 Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Mon, 20 Apr 2026 15:16:19 +0000 Subject: [PATCH] Add app opens & services activity charts to admin dashboard - New `app_opens` table (id, user_id, app_id, created_at) and Drizzle schema; exported from lib/db schema index. - New `POST /api/apps/{id}/open` endpoint logs an open for the current user (auth required, 204 on success, 404 for unknown app id). - Extended `GET /api/stats/admin` with appOpensByDay/appOpensLast7Days/ appOpensPrev7Days and servicesCreatedByDay/servicesCreatedLast7Days, refactored around a shared buildSeries helper. - Regenerated api-client/zod and added two new bar charts (App opens, Services added) to the admin Dashboard alongside the existing Sign-ups chart, with EN/AR translations. - Home page fires bare `logAppOpen(id, { keepalive: true })` before navigating so the request survives client-side route changes; the bottom dock buttons also use this helper. - Restructured SortableAppIcon so the click target and dnd-kit listeners live on the same + ); } @@ -110,9 +108,17 @@ function SortableAppIcon({ app, onClick }: { app: App; onClick: () => void }) { touchAction: "none", }; return ( -
- -
+ ); } @@ -199,6 +205,15 @@ export default function HomePage() { const logout = useLogout(); const updateLanguage = useUpdateLanguage(); + const openApp = (app: App) => { + // Fire-and-forget: keepalive ensures the request survives any + // imminent navigation triggered by setLocation below. + logAppOpen(app.id, { keepalive: true }).catch(() => { + // Best-effort tracking; ignore failures so navigation isn't blocked. + }); + setLocation(app.route); + }; + useEffect(() => { const timer = setInterval(() => setTime(new Date()), 1000); return () => clearInterval(timer); @@ -373,7 +388,7 @@ export default function HomePage() { setLocation(app.route)} + onClick={() => openApp(app)} /> ))} @@ -392,7 +407,7 @@ export default function HomePage() { return (