Skip to content

Feat/call statistics - #59

Merged
XuanHanTan-School merged 16 commits into
devfrom
feat/call-statistics
Jan 30, 2026
Merged

Feat/call statistics#59
XuanHanTan-School merged 16 commits into
devfrom
feat/call-statistics

Conversation

@eronxng

@eronxng eronxng commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

Complete call statistics frontend and backend.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end “call statistics” functionality (admin-only) including new backend analytics endpoints and a new admin dashboard page to visualize call volume and resolution metrics.

Changes:

  • Added backend analytics model + admin-protected routes under /api/calls/analytics/*.
  • Added a new admin UI page at /admin/calls-statistics with charts and filters, plus a dashboard link.
  • Minor admin dashboard UI tweaks (fraud report tabs styling/labeling; show assigned fraud reports only for non-admin users).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
8cbc_frontend/lib/api/call-statistics.ts Adds frontend API client + types for call statistics endpoints.
8cbc_frontend/components/dashboard/admin/AssignedFraudReports.tsx Updates tabs layout/styling and label for “Under Review”.
8cbc_frontend/app/(admin)/admin/page.tsx Adds navigation action to call statistics; gates AssignedFraudReports to non-admins.
8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx New admin call statistics dashboard page with charts and month filtering.
8cbc_backend/model/calls/call-statistics.model.ts Implements analytics aggregation queries and summary composition.
8cbc_backend/controllers/calls/calls.controller.ts Mounts the call statistics controller under the calls router.
8cbc_backend/controllers/calls/call-statistics.controller.ts New admin-only analytics endpoints with zod query validation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread 8cbc_backend/model/calls/call-statistics.model.ts
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx Outdated
Comment thread 8cbc_backend/model/calls/call-statistics.model.ts
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx Outdated
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx Outdated
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx Outdated
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx
Comment thread 8cbc_frontend/lib/api/call-statistics.ts

@XuanHanTan-School XuanHanTan-School left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice feature but some usability improvements in addition to algorithmic improvements:

  • Completion vs no-show vs cancellation graph could be displayed in a way that does not induce cognitive overload - Try a 7 day rolling average as the main highlighted line, and the daily values as dotted low-opacity lines.
  • Can put some key call stats on the home page

Comment thread 8cbc_backend/model/calls/call-statistics.model.ts
Comment thread 8cbc_backend/model/calls/call-statistics.model.ts
Comment thread 8cbc_backend/model/calls/call-statistics.model.ts
Comment on lines +320 to +331
if (completedCallsData.length > 0) {
const durations = completedCallsData
.map(call => {
// Use history timestamp if available, otherwise use updatedAt
const completionTimestamp = call.completionAt || call.updatedAt;
if (!completionTimestamp) return NaN;
const created = new Date(call.createdAt).getTime();
const completed = new Date(completionTimestamp).getTime();
return completed - created;
})
.filter((ms) => Number.isFinite(ms) && ms >= 0)
.map((ms) => ms / 1000);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we compare the average scheduled time to call start time? Since booking is subject to customer preferences. Also please use SQL aggregation queries.

Comment on lines +70 to +100
const formatDuration = (iso: string) => {
const match = iso.match(/P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?/);
if (!match) return iso;

const [, d, h, m, s] = match;

const days = parseInt(d || "0", 10);
const hours = parseInt(h || "0", 10);
const minutes = parseInt(m || "0", 10);
const seconds = parseInt(s || "0", 10);

const totalSeconds =
days * 86_400 + hours * 3_600 + minutes * 60 + seconds;

if (totalSeconds >= 86_400) {
const totalDays = totalSeconds / 86_400;
return totalDays >= 10 ? `${Math.round(totalDays)}d` : `${totalDays.toFixed(1)}d`;
}

if (totalSeconds >= 3_600) {
const totalHours = totalSeconds / 3_600;
return totalHours >= 10 ? `${Math.round(totalHours)}h` : `${totalHours.toFixed(1)}h`;
}

if (totalSeconds >= 60) {
const totalMinutes = totalSeconds / 60;
return `${Math.round(totalMinutes)}m`;
}

return `${seconds}s`;
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't your API just return duration in seconds? Like 80000s for example. This would make it so much easier to parse.

Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx Outdated
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx Outdated
Comment thread 8cbc_frontend/app/(admin)/admin/calls-statistics/page.tsx Outdated

@XuanHanTan-School XuanHanTan-School left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@XuanHanTan-School
XuanHanTan-School changed the base branch from main to dev January 29, 2026 15:04
@XuanHanTan-School
XuanHanTan-School merged commit 6f27c24 into dev Jan 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants