2025-12-02 15:27:41 +01:00
|
|
|
import { AppError, ErrorCodes } from '@api/utils/errors';
|
2026-04-12 08:58:41 +01:00
|
|
|
import {
|
|
|
|
|
getCourseStats,
|
|
|
|
|
getDashOrgStats,
|
|
|
|
|
getRecentCertifications,
|
|
|
|
|
getTotalCertificatesIssued
|
|
|
|
|
} from '@cio/db/queries/dash';
|
2025-12-02 15:27:41 +01:00
|
|
|
|
|
|
|
|
import { OrganisationAnalytics } from '@api/types';
|
2026-03-22 18:42:23 +01:00
|
|
|
import { getOrgIdBySiteName } from '@cio/db/queries';
|
2025-12-02 15:27:41 +01:00
|
|
|
|
|
|
|
|
export async function getOrganisationAnalytics(orgId?: string, siteName?: string): Promise<OrganisationAnalytics> {
|
|
|
|
|
const analytics: OrganisationAnalytics = {
|
2026-04-12 08:58:41 +01:00
|
|
|
totalCertificates: 0,
|
2025-12-02 15:27:41 +01:00
|
|
|
numberOfCourses: 0,
|
|
|
|
|
totalStudents: 0,
|
|
|
|
|
topCourses: [],
|
2026-04-12 08:58:41 +01:00
|
|
|
recentCertifications: []
|
2025-12-02 15:27:41 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let resolvedOrgId = orgId;
|
|
|
|
|
|
|
|
|
|
if (!resolvedOrgId && siteName) {
|
|
|
|
|
const [org] = await getOrgIdBySiteName(siteName);
|
|
|
|
|
|
|
|
|
|
if (org) {
|
|
|
|
|
resolvedOrgId = org.id;
|
|
|
|
|
} else {
|
|
|
|
|
throw new AppError('Organization not found for the given site name', ErrorCodes.ORG_NOT_FOUND, 404);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2026-04-12 08:58:41 +01:00
|
|
|
const [stats, topCourses, recentCertificationRows, certificateCountRows] = await Promise.all([
|
2025-12-02 15:27:41 +01:00
|
|
|
getDashOrgStats(resolvedOrgId!),
|
|
|
|
|
getCourseStats(resolvedOrgId!),
|
2026-04-12 08:58:41 +01:00
|
|
|
getRecentCertifications(resolvedOrgId!),
|
|
|
|
|
getTotalCertificatesIssued(resolvedOrgId!)
|
2025-12-02 15:27:41 +01:00
|
|
|
]);
|
|
|
|
|
|
2026-04-12 08:58:41 +01:00
|
|
|
analytics.totalCertificates = certificateCountRows[0]?.count ?? 0;
|
2025-12-02 15:27:41 +01:00
|
|
|
analytics.numberOfCourses = stats?.[0]?.noOfCourses ?? 0;
|
|
|
|
|
analytics.totalStudents = stats?.[0]?.enrolledStudents ?? 0;
|
|
|
|
|
|
|
|
|
|
analytics.topCourses = topCourses.map((c) => ({
|
|
|
|
|
id: c.courseId,
|
|
|
|
|
title: c.courseTitle,
|
|
|
|
|
enrollments: c.totalStudents,
|
2026-04-12 08:58:41 +01:00
|
|
|
completion: c.completionPercentage,
|
|
|
|
|
certification: c.certificationPercentage
|
2025-12-02 15:27:41 +01:00
|
|
|
}));
|
|
|
|
|
|
2026-04-12 08:58:41 +01:00
|
|
|
analytics.recentCertifications = recentCertificationRows.map((row) => ({
|
|
|
|
|
id: row.profileId,
|
|
|
|
|
avatarUrl: row.avatarUrl,
|
|
|
|
|
name: row.fullname,
|
|
|
|
|
courseId: row.courseId,
|
|
|
|
|
course: row.courseTitle,
|
|
|
|
|
date: row.earnedAt ?? ''
|
2025-12-02 15:27:41 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
return analytics;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to load organisation analytics:', error);
|
|
|
|
|
throw new AppError('Failed to load organisation analytics', ErrorCodes.ORG_ANALYTICS_FETCH_FAILED, 500);
|
|
|
|
|
}
|
|
|
|
|
}
|