This commit is contained in:
rgrgogu
2026-05-09 22:17:24 +08:00
parent 58ccecd28a
commit 4e6017c79b
17 changed files with 2659 additions and 652 deletions
+143
View File
@@ -0,0 +1,143 @@
/***********************************************************************************************************************************************************************
* File Name: dashboard.controller.js (admin)
* Type of Program: Controller
* Description: Admin dashboard — users and groups stats + breakdowns.
*
* Author: rgrgogu
* Date Created: Oct. 6, 2025
***********************************************************************************************************************************************************************/
const { Op, fn, col, literal } = require('sequelize');
const mdl_Users = require('../../models/users/users.mdl');
const { mdl_UserGroups, mdl_UserGroupMembers } = require('../../models/users/user_groups.mdl');
// ─── USERS DASHBOARD ──────────────────────────────────────────────────────────
exports.getUsersDashboard = async (req, res) => {
try {
const [
totalUsers,
activeUsers,
verifiedUsers,
archivedUsers,
accTypeBreakdown,
regTypeBreakdown,
] = await Promise.all([
mdl_Users.count({ paranoid: false }),
mdl_Users.count({ where: { is_active: true } }),
mdl_Users.count({ where: { is_verified: true } }),
mdl_Users.count({ where: { deletedAt: { [Op.ne]: null } }, paranoid: false }),
mdl_Users.findAll({
attributes: ['acc_type', [fn('COUNT', col('user_id')), 'count']],
group: ['acc_type'],
raw: true,
}),
mdl_Users.findAll({
attributes: ['reg_type', [fn('COUNT', col('user_id')), 'count']],
group: ['reg_type'],
raw: true,
}),
]);
return res.status(200).json({
status: 'success',
message: 'Users dashboard data fetched.',
data: {
stats: [
{ key: 'total', label: 'Total Users', value: totalUsers },
{ key: 'active', label: 'Active Users', value: activeUsers },
{ key: 'inactive', label: 'Inactive Users', value: totalUsers - archivedUsers - activeUsers },
{ key: 'verified', label: 'Verified', value: verifiedUsers },
{ key: 'archived', label: 'Archived', value: archivedUsers },
],
breakdowns: [
{
key: 'acc_type',
label: 'By Account Type',
data: accTypeBreakdown.map((r) => ({ label: r.acc_type, value: parseInt(r.count, 10) })),
},
{
key: 'reg_type',
label: 'By Registration Type',
data: regTypeBreakdown.map((r) => ({ label: r.reg_type, value: parseInt(r.count, 10) })),
},
],
},
});
} catch (err) {
console.error('[ADMIN][DASHBOARD][USERS]', err);
return res.status(500).json({ status: 'error', message: 'Could not fetch users dashboard data.' });
}
};
// ─── GROUPS DASHBOARD ─────────────────────────────────────────────────────────
exports.getGroupsDashboard = async (req, res) => {
try {
const [
totalGroups,
activeGroups,
archivedGroups,
emptyGroups,
memberCountBreakdown,
] = await Promise.all([
mdl_UserGroups.count({ paranoid: false }),
mdl_UserGroups.count({ where: { is_active: true } }),
mdl_UserGroups.count({ where: { deletedAt: { [Op.ne]: null } }, paranoid: false }),
mdl_UserGroups.count({
where: { is_active: true },
include: [{
model: mdl_UserGroupMembers,
required: false,
where: { deletedAt: null },
}],
having: literal('COUNT("UserGroupMembers"."user_id") = 0'),
group: ['UserGroup.group_id'],
subQuery: false,
}).catch(() => 0),
mdl_UserGroupMembers.findAll({
attributes: [
'group_id',
[fn('COUNT', col('user_id')), 'member_count'],
],
where: { deletedAt: null },
include: [{
model: mdl_UserGroups,
attributes: ['name'],
where: { is_active: true },
}],
group: ['UserGroupMember.group_id', 'UserGroup.group_id', 'UserGroup.name'],
order: [[literal('member_count'), 'DESC']],
limit: 10,
raw: true,
nest: true,
}),
]);
return res.status(200).json({
status: 'success',
message: 'Groups dashboard data fetched.',
data: {
stats: [
{ key: 'total', label: 'Total Groups', value: totalGroups },
{ key: 'active', label: 'Active Groups', value: activeGroups },
{ key: 'inactive', label: 'Inactive Groups', value: totalGroups - archivedGroups - activeGroups },
{ key: 'archived', label: 'Archived', value: archivedGroups },
{ key: 'empty', label: 'Empty Groups', value: Array.isArray(emptyGroups) ? emptyGroups.length : emptyGroups },
],
breakdowns: [
{
key: 'top_groups',
label: 'Top Groups by Members',
data: memberCountBreakdown.map((r) => ({
label: r.UserGroup?.name ?? `Group ${r.group_id}`,
value: parseInt(r.member_count, 10),
})),
},
],
},
});
} catch (err) {
console.error('[ADMIN][DASHBOARD][GROUPS]', err);
return res.status(500).json({ status: 'error', message: 'Could not fetch groups dashboard data.' });
}
};