Skip to content

Commit

Permalink
⚙️ 📈 statics server side added
Browse files Browse the repository at this point in the history
  • Loading branch information
sinanptm committed Oct 7, 2024
1 parent 9d17148 commit 8b051c4
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ export default interface IAppointmentRepository extends IRepository<IAppointment
): Promise<PaginatedResult<IAppointment>>;
findManyByIds(ids: string[]): Promise<IAppointment[] | null>;
findPatientsByDoctorId(doctorId: string, limit: number, offset: number): Promise<PaginatedResult<IPatient>>;
findManyAsExtendedByPatientId(patientId: string, limit: number, offset: number): Promise<PaginatedResult<IExtendedAppointment>>
findManyAsExtendedByPatientId(patientId: string, limit: number, offset: number): Promise<PaginatedResult<IExtendedAppointment>>;
getCountByRange(startTime:Date,endTime:Date):Promise<number>;
getCountsByStatus(status:AppointmentStatus):Promise<number>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export default interface IDoctorRepository extends IRepository<IDoctor> {
findByEmail(email: string): Promise<IDoctor | null>;
findByEmailWithCredentials(email: string): Promise<IDoctor | null>;
findMany(offset: number, limit: number, isVerified: boolean, isBlocked: boolean): Promise<PaginatedResult<IDoctor>>;
getCountInTimeRange(startTime: Date, endTime: Date): Promise<number>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export default interface IPatientRepository extends IRepository<IPatient> {
findMany(offset: number, limit: number): Promise<PaginatedResult<IPatient>>;
findAll(): Promise<IPatient[] | []>;
findPatientGenders():Promise<PatientGenderStatics>;
getCountInTimeRange(startTime: Date, endTime: Date): Promise<number>;
}
36 changes: 36 additions & 0 deletions server/src/infrastructure/repositories/AppointmentRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,42 @@ export default class AppointmentRepository implements IAppointmentRepository {
return await this.model.find({ _id: { $in: ids } });
}

async getCountsByStatus(status: AppointmentStatus): Promise<number> {
const result = await this.model.aggregate([
{
$match: {
status: status
}
},
{
$group: {
_id: null,
count: { $sum: 1 }
}
}
]);

return result.length > 0 ? result[0].count : 0;
}

async getCountByRange(startTime: Date, endTime: Date): Promise<number> {
const result = await this.model.aggregate([
{
$match: {
appointmentDate: { $gte: startTime, $lte: endTime }
}
},
{
$group: {
_id: null,
count: { $sum: 1 }
}
}
]);
return result.length > 0 ? result[0].count : 0;
}


async findManyAsExtendedByPatientId(
patientId: string,
limit: number,
Expand Down
17 changes: 17 additions & 0 deletions server/src/infrastructure/repositories/DoctorRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,21 @@ export default class DoctorRepository implements IDoctorRepository {

return getPaginatedResult(totalItems, offset, limit, items);
}
async getCountInTimeRange(startTime: Date, endTime: Date): Promise<number> {
const result = await this.model.aggregate([
{
$match: {
createdAt: { $gte: startTime, $lte: endTime }
}
},
{
$group: {
_id: null,
count: { $sum: 1 }
}
}
]);

return result.length > 0 ? result[0].count : 0;
};
}
20 changes: 19 additions & 1 deletion server/src/infrastructure/repositories/PatientRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@ export default class PatientRepository implements IPatientRepository {
return getPaginatedResult(totalItems, offset, limit, items);
}

async getCountInTimeRange(startTime: Date, endTime: Date): Promise<number> {
const result = await this.model.aggregate([
{
$match: {
createdAt: { $gte: startTime, $lte: endTime }
}
},
{
$group: {
_id: null,
count: { $sum: 1 }
}
}
]);

return result.length > 0 ? result[0].count : 0;
};

async create(patient: IPatient): Promise<IPatient> {
try {
const patientModel = new this.model(patient);
Expand Down Expand Up @@ -74,5 +92,5 @@ export default class PatientRepository implements IPatientRepository {
});
return initialCounts;
}

}
30 changes: 28 additions & 2 deletions server/src/presentation/controllers/admin/AdminController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,34 @@ export default class AdminController {

async getGenderStatics(req: Request, res: Response, next: NextFunction) {
try {
const statics = await this.dashboardUseCase.getPatientGenderStatics()
res.status(StatusCode.Success).json({ statics });
const statistics = await this.dashboardUseCase.getPatientGenderStatics();
res.status(StatusCode.Success).json({ statistics });
} catch (error) {
next(error)
}
}
async getUsersStatics(req: Request, res: Response, next: NextFunction) {
try {
const statistics = await this.dashboardUseCase.getUsersStatics();
res.status(StatusCode.Success).json({ statistics });
} catch (error) {
next(error)
}
}

async getAppointmentsStatisticsByStatus(req: Request, res: Response, next: NextFunction) {
try {
const statistics = await this.dashboardUseCase.getAppointmentsStatisticsByStatus()
res.status(StatusCode.Success).json({ statistics })
} catch (error) {
next(error);
}
}

async getAppointmentsByMonth(req: Request, res: Response, next: NextFunction) {
try {
const statistics = await this.dashboardUseCase.getAppointmentsPerMonthStatics();
res.status(StatusCode.Success).json({ statistics })
} catch (error) {
next(error)
}
Expand Down
15 changes: 8 additions & 7 deletions server/src/presentation/routers/admin/AdminRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { Router } from "express";
import AppointmentRepository from "../../../infrastructure/repositories/AppointmentRepository";
import PatientRepository from "../../../infrastructure/repositories/PatientRepository";
import AdminPatientController from "../../controllers/admin/PatientController";
import AdminPatientUseCase from "../../../use_case/admin/PatientUseCase";

import DoctorRepository from "../../../infrastructure/repositories/DoctorRepository";
import NodeMailerService from "../../../infrastructure/services/NodeMailerService";
import AdminPatientController from "../../controllers/admin/PatientController";
import AdminDoctorController from "../../controllers/admin/DoctorController";
import AdminDoctorUseCase from "../../../use_case/admin/DoctorUseCase";
import JoiService from "../../../infrastructure/services/JoiService";
import AdminDashBoardUseCase from "../../../use_case/admin/DashboardUseCase";
import AppointmentRepository from "../../../infrastructure/repositories/AppointmentRepository";
import AdminPatientUseCase from "../../../use_case/admin/PatientUseCase";
import AdminDoctorUseCase from "../../../use_case/admin/DoctorUseCase";
import AdminController from "../../controllers/admin/AdminController";
import JoiService from "../../../infrastructure/services/JoiService";

const router = Router();

Expand All @@ -30,7 +29,9 @@ const adminController = new AdminController(adminDashBoardUseCase);


router.get('/patient-gender', adminController.getGenderStatics.bind(adminController));

router.get('/users-months', adminController.getUsersStatics.bind(adminController));
router.get('/appointment-status',adminController.getAppointmentsStatisticsByStatus.bind(adminController));
router.get('/appointment-month',adminController.getAppointmentsByMonth.bind(adminController));
router
.route("/patient")
.get(adminPatientController.getPatients.bind(adminPatientController))
Expand Down
33 changes: 33 additions & 0 deletions server/src/types/statics.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
import { AppointmentStatus } from "../domain/entities/IAppointment";

export enum Months {
January = "January",
February = "February",
March = "March",
April = "April",
May = "May",
June = "June",
July = "July",
August = "August",
September = "September",
October = "October",
November = "November",
December = "December",
}

export type PatientGenderStatics = {
male: number;
female: number;
others: number;
}

export type UserStatistics = {
month: Months;
doctors: number;
patients: number;
};

export type AppointmentsPerMonthStatics = {
month:Months;
count:number;
}

export type AppointmentsByStatusStatistics = {
status:AppointmentStatus;
count:number
}
60 changes: 56 additions & 4 deletions server/src/use_case/admin/DashboardUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,70 @@
import IAppointmentRepository from "../../domain/interface/repositories/IAppointmentRepository";
import IDoctorRepository from "../../domain/interface/repositories/IDoctorRepository";
import IPatientRepository from "../../domain/interface/repositories/IPatientRepository";
import IDoctorRepository from "../../domain/interface/repositories/IDoctorRepository";
import { Months, PatientGenderStatics, UserStatistics, AppointmentsPerMonthStatics, AppointmentsByStatusStatistics } from "../../types/statics";
import IValidatorService from "../../domain/interface/services/IValidatorService";
import { PatientGenderStatics } from "../../types/statics";
import { endOfMonth, startOfMonth } from "../../utils/date-formatter";
import { AppointmentStatus } from "../../domain/entities/IAppointment";

export default class DashboardUseCase {
constructor(
private validatorService: IValidatorService,
private patientRepository: IPatientRepository,
private appointmentRepository: IAppointmentRepository,
private doctorRepository: IDoctorRepository
){}
) { }

async getPatientGenderStatics():Promise<PatientGenderStatics>{
async getPatientGenderStatics(): Promise<PatientGenderStatics> {
return await this.patientRepository.findPatientGenders();
}
async getUsersStatics(): Promise<UserStatistics[]> {
const year = new Date().getFullYear();
const statistics: UserStatistics[] = [];

for (const month of Object.values(Months)) {
const startTime = startOfMonth(new Date(year, Object.keys(Months).indexOf(month), 1));
const endTime = endOfMonth(startTime);

const patients = await this.patientRepository.getCountInTimeRange(startTime, endTime);
const doctors = await this.doctorRepository.getCountInTimeRange(startTime, endTime);

statistics.push({
month,
doctors,
patients,
});
}
return statistics;
}

async getAppointmentsPerMonthStatics(): Promise<AppointmentsPerMonthStatics[]> {
const year = new Date().getFullYear();
const statistics: AppointmentsPerMonthStatics[] = [];

for (const month of Object.values(Months)) {
const startTime = startOfMonth(new Date(year, Object.keys(Months).indexOf(month), 1));
const endTime = endOfMonth(startTime);

const count = await this.appointmentRepository.getCountByRange(startTime, endTime);

statistics.push({
month,
count
})
};

return statistics;
}

async getAppointmentsStatisticsByStatus(): Promise<AppointmentsByStatusStatistics[]> {
const statistics: AppointmentsByStatusStatistics[] = [];
for (let status of Object.values(AppointmentStatus)) {
const count = await this.appointmentRepository.getCountsByStatus(status)
statistics.push({
status,
count
})
}
return statistics;
}
}
2 changes: 1 addition & 1 deletion server/src/utils/date-formatter.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { parse, format, addMinutes, addHours, addDays, getDay, getDate, isAfter } from "date-fns";
export { parse, format, addMinutes, addHours, addDays, getDay, getDate, isAfter, endOfMonth, startOfMonth } from "date-fns";

1 comment on commit 8b051c4

@vercel
Copy link

@vercel vercel bot commented on 8b051c4 Oct 7, 2024

Choose a reason for hiding this comment

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

Please sign in to comment.