-
Notifications
You must be signed in to change notification settings - Fork 0
Adding missing features #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
867b8c3
feat: implement MasonryGrid component for responsive item layout and …
ZanDev32 f760197
fix: enhance item selection logic to avoid duplicates and improve end…
ZanDev32 da00951
fix: double slider visual problem
ZanDev32 5f24b41
style: override Mapbox popup styles for a cleaner look
ZanDev32 32fc517
fix: add crossOrigin attribute to images for better CORS handling
ZanDev32 8bb8c49
fix: update max-width values for responsive design in MapPlacePopup a…
ZanDev32 51a1600
feat: implement admin dashboard API, promotions, and user management
ZanDev32 2a098f5
feat: Implementing admin dashboard with new sections and improved nav…
ZanDev32 58ba93a
feat: Enhance admin routes with role-based access control and update …
ZanDev32 803f1f8
Feat: Implement traffic analytics, online presence tracking, and dash…
ZanDev32 7e84713
Feat: Add user deletion capability for admins
ZanDev32 2b1c159
Refactor: Implement database seeding for Ads and Env Users
ZanDev32 1428a54
Feat: Add password visibility toggle to auth forms
ZanDev32 eea4540
feat: Update endpoints for users, places, and promotions
ZanDev32 7a70a33
feat: add AdminModal and ConfirmationOverlay components
ZanDev32 7fbb0be
feat: implement edit functionality for users and ads
ZanDev32 5343f5a
feat: implement detailed place editing form with responsive layout
ZanDev32 0cbef5c
style: improve dashboard responsiveness and navigation elements
ZanDev32 d82d75f
style: add hover animation to profile button
ZanDev32 977daba
feat: enhance location update functionality with image handling and p…
ZanDev32 1135480
feat: update shared hooks and modal component styles
ZanDev32 e74ca3e
feat: implement admin reviews management with status workflow
ZanDev32 4eeaaac
feat: add avatar editing, role management, and sorting to admin users…
ZanDev32 0e20f86
feat: add type column and sorting options to admin places table
ZanDev32 906f6ba
feat: refactor ads storage to 'ads_images', add create capability, an…
ZanDev32 db3f977
feat: add detail view to reviews admin section
ZanDev32 29a89c1
fix: clean up modal button rendering when text is empty
ZanDev32 3a946b0
feat: integrate Docker management features in admin panel
ZanDev32 16eeb7e
feat: implement system alert management with CRUD operations and moni…
ZanDev32 92ead57
feat: enhance ControlSection UI with improved container status displa…
ZanDev32 a294f02
feat: update button styles across admin sections for improved UI cons…
ZanDev32 c5df74c
feat: enhance UI with new SearchTab component and animations for impr…
ZanDev32 28716c2
feat: enhance MapTab UI with improved styling and additional controls…
ZanDev32 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| const User = require('../models/User'); | ||
| const Location = require('../models/Location'); | ||
| const Promotion = require('../models/Promotion'); | ||
| const DailyStat = require('../models/DailyStat'); | ||
| const { Op } = require('sequelize'); | ||
| const dockerService = require('../services/docker.service'); | ||
|
|
||
| const getDashboardStats = async (req, res) => { | ||
| try { | ||
| const totalUsers = await User.count(); | ||
| const totalPlaces = await Location.count(); | ||
| const totalAds = await Promotion.count({ where: { active: true } }); | ||
|
|
||
| // Fetch actual traffic data | ||
| const last7DaysStats = await DailyStat.findAll({ | ||
| order: [['date', 'DESC']], | ||
| limit: 7, | ||
| raw: true | ||
| }); | ||
|
|
||
| // Fill in missing days for the last 7 days for a complete chart | ||
| const weeklyTraffic = []; | ||
| const today = new Date(); | ||
|
|
||
| for (let i = 6; i >= 0; i--) { | ||
| const d = new Date(today); | ||
| d.setDate(d.getDate() - i); | ||
| const dateStr = d.toISOString().split('T')[0]; | ||
| const stat = last7DaysStats.find(s => { | ||
| const sDate = s.date instanceof Date | ||
| ? s.date.toISOString().split('T')[0] | ||
| : s.date; | ||
| return sDate === dateStr; | ||
| }); | ||
|
|
||
| weeklyTraffic.push({ | ||
| name: d.toLocaleDateString('en-US', { weekday: 'short' }), | ||
| uv: stat ? stat.uniqueVisitors : 0, | ||
| pv: stat ? stat.requests : 0 | ||
| }); | ||
| } | ||
|
|
||
| const totalVisits = await DailyStat.sum('uniqueVisitors') || 0; | ||
| const totalPageViews = await DailyStat.sum('requests') || 0; | ||
|
|
||
| const todaysStat = last7DaysStats.find(s => { | ||
| const sDate = s.date instanceof Date | ||
| ? s.date.toISOString().split('T')[0] | ||
| : s.date; | ||
| return sDate === today.toISOString().split('T')[0]; | ||
| }); | ||
| const dailyVisitors = todaysStat ? todaysStat.uniqueVisitors : 0; | ||
|
|
||
| // Online Members (Active in last 15 minutes) | ||
| const onlineMemberThreshold = new Date(Date.now() - 15 * 60 * 1000); | ||
| let onlineMembers = await User.count({ | ||
| where: { | ||
| lastActive: { | ||
| [Op.gte]: onlineMemberThreshold | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| // Add Root Admin if active | ||
| if (global.lastRootAdminActive && global.lastRootAdminActive >= onlineMemberThreshold) { | ||
| onlineMembers++; | ||
| } | ||
|
|
||
| // Trends (Today vs Yesterday) | ||
| const yesterday = new Date(today); | ||
| yesterday.setDate(yesterday.getDate() - 1); | ||
| const yesterdayStr = yesterday.toISOString().split('T')[0]; | ||
|
|
||
| const yesterdaysStat = last7DaysStats.find(s => { | ||
| const sDate = s.date instanceof Date | ||
| ? s.date.toISOString().split('T')[0] | ||
| : s.date; | ||
| return sDate === yesterdayStr; | ||
| }); | ||
| const yesterdayVisitors = yesterdaysStat ? yesterdaysStat.uniqueVisitors : 0; | ||
|
|
||
| let trend = 0; | ||
| if (yesterdayVisitors > 0) { | ||
| trend = ((dailyVisitors - yesterdayVisitors) / yesterdayVisitors) * 100; | ||
| } else if (dailyVisitors > 0) { | ||
| trend = 100; | ||
| } | ||
|
|
||
| const stats = { | ||
| totalUsers, | ||
| totalPlaces, | ||
| totalAds, | ||
| visitors: totalVisits, | ||
| onlineMembers, | ||
| dailyVisitors, | ||
| trend: Math.round(trend), | ||
| weeklyTraffic | ||
| }; | ||
|
|
||
| res.json(stats); | ||
| } catch (error) { | ||
| console.error('Error fetching dashboard stats:', error); | ||
| res.status(500).json({ message: 'Error fetching stats' }); | ||
| } | ||
| }; | ||
|
|
||
| const getSystemContainers = async (req, res) => { | ||
| try { | ||
| const containers = await dockerService.listContainers(); | ||
| res.json(containers); | ||
| } catch (error) { | ||
| console.error('Error fetching system containers:', error); | ||
| res.status(500).json({ message: 'Failed to fetch containers info', error: error.message }); | ||
| } | ||
| }; | ||
|
|
||
| const getContainerLogs = async (req, res) => { | ||
| try { | ||
| const { id } = req.params; | ||
| const { tail } = req.query; | ||
| const logs = await dockerService.getContainerLogs(id, tail ? parseInt(tail) : 200); | ||
| res.json({ logs }); | ||
| } catch (error) { | ||
| res.status(500).json({ message: 'Failed to fetch logs', error: error.message }); | ||
| } | ||
| }; | ||
|
|
||
| const restartSystemContainer = async (req, res) => { | ||
| try { | ||
| const { id } = req.params; | ||
| await dockerService.restartContainer(id); | ||
| res.json({ message: 'Container restarting initiated' }); | ||
| } catch (error) { | ||
| res.status(500).json({ message: 'Failed to restart container', error: error.message }); | ||
| } | ||
| }; | ||
|
|
||
| const startSystemContainer = async (req, res) => { | ||
| try { | ||
| const { id } = req.params; | ||
| await dockerService.startContainer(id); | ||
| res.json({ message: 'Container started successfully' }); | ||
| } catch (error) { | ||
| res.status(500).json({ message: 'Failed to start container', error: error.message }); | ||
| } | ||
| }; | ||
|
|
||
| const stopSystemContainer = async (req, res) => { | ||
| try { | ||
| const { id } = req.params; | ||
| await dockerService.stopContainer(id); | ||
| res.json({ message: 'Container stopped successfully' }); | ||
| } catch (error) { | ||
| res.status(500).json({ message: 'Failed to stop container', error: error.message }); | ||
| } | ||
| }; | ||
|
|
||
| module.exports = { | ||
| getDashboardStats, | ||
| getSystemContainers, | ||
| getContainerLogs, | ||
| restartSystemContainer, | ||
| startSystemContainer, | ||
| stopSystemContainer | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,76 @@ | ||||
| const SysAlert = require('../models/SysAlert'); | ||||
| const { Op } = require('sequelize'); | ||||
|
||||
| const { Op } = require('sequelize'); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable totalPageViews.