From 373018cebb0f6e6bf1d4c3e5ac05891088cec8a6 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 30 Jul 2025 09:04:21 -0600 Subject: [PATCH] anaylitics dashboard --- map/README.md | 8 ++ map/app/controllers/dashboardController.js | 70 ++++++++++ map/app/public/admin.html | 51 +++++++ map/app/public/css/admin.css | 2 + map/app/public/css/modules/dashboard.css | 85 ++++++++++++ map/app/public/js/dashboard.js | 150 +++++++++++++++++++++ map/app/routes/admin.js | 4 + map/app/routes/dashboard.js | 7 + map/files-explainer.md | 16 +++ 9 files changed, 393 insertions(+) create mode 100644 map/app/controllers/dashboardController.js create mode 100644 map/app/public/css/modules/dashboard.css create mode 100644 map/app/public/js/dashboard.js create mode 100644 map/app/routes/dashboard.js diff --git a/map/README.md b/map/README.md index 3ea19f5..417b210 100644 --- a/map/README.md +++ b/map/README.md @@ -296,6 +296,14 @@ Users with admin privileges can access the admin panel at `/admin.html` to confi ### Features +#### Dashboard Analytics + +- **Campaign Overview**: Real-time statistics and metrics +- **Support Distribution**: Visual breakdown of support levels (1-4) +- **Sign Tracking**: Monitor lawn sign requests +- **User Analytics**: Track user growth and daily entries +- **Performance Score**: Overall campaign performance metric + #### Start Location Configuration - **Interactive Map**: Visual interface for selecting coordinates diff --git a/map/app/controllers/dashboardController.js b/map/app/controllers/dashboardController.js new file mode 100644 index 0000000..1e9e3bf --- /dev/null +++ b/map/app/controllers/dashboardController.js @@ -0,0 +1,70 @@ +const nocodbService = require('../services/nocodb'); +const logger = require('../utils/logger'); +const config = require('../config'); + +class DashboardController { + async getStats(req, res) { + try { + // Get all locations for support level stats + const locationsResponse = await nocodbService.getAll(config.nocodb.tableId); + const locations = locationsResponse.list || []; + + // Calculate support level distribution + const supportLevels = { '1': 0, '2': 0, '3': 0, '4': 0 }; + let signRequests = 0; + + locations.forEach(loc => { + if (loc['Support Level']) { + supportLevels[loc['Support Level']]++; + } + if (loc.Sign || loc.sign) { + signRequests++; + } + }); + + // Calculate overall score (weighted average) + const totalResponses = Object.values(supportLevels).reduce((a, b) => a + b, 0); + const weightedScore = (supportLevels['1'] * 4 + supportLevels['2'] * 3 + + supportLevels['3'] * 2 + supportLevels['4'] * 1) / + (totalResponses || 1); + + // Get user stats + const usersResponse = await nocodbService.getAll(config.nocodb.loginSheetId); + const users = usersResponse.list || []; + + // Get daily entry counts for the last 30 days + const thirtyDaysAgo = new Date(); + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); + + const dailyEntries = {}; + locations.forEach(loc => { + const createdAt = new Date(loc.CreatedAt || loc.created_at); + if (createdAt >= thirtyDaysAgo) { + const dateKey = createdAt.toISOString().split('T')[0]; + dailyEntries[dateKey] = (dailyEntries[dateKey] || 0) + 1; + } + }); + + res.json({ + success: true, + data: { + supportLevels, + signRequests, + totalLocations: locations.length, + overallScore: weightedScore.toFixed(2), + totalUsers: users.length, + dailyEntries + } + }); + + } catch (error) { + logger.error('Error fetching dashboard stats:', error); + res.status(500).json({ + success: false, + error: 'Failed to fetch dashboard statistics' + }); + } + } +} + +module.exports = new DashboardController(); diff --git a/map/app/public/admin.html b/map/app/public/admin.html index ebc3880..304c09d 100644 --- a/map/app/public/admin.html +++ b/map/app/public/admin.html @@ -43,6 +43,10 @@