Skip to content

Commit

Permalink
feat: add phase filter and fetch only villages with particular phase
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjyhy committed Oct 2, 2024
1 parent fb6cb11 commit b2b4735
Show file tree
Hide file tree
Showing 7 changed files with 443 additions and 415 deletions.
110 changes: 55 additions & 55 deletions server/controllers/statistics.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,55 @@
import type { Request } from 'express';

import {
getClassroomsInfos,
getConnectedClassroomsCount,
getContributedClassroomsCount,
getRegisteredClassroomsCount,
} from '../stats/classroomStats';
import {
getAverageConnections,
getAverageDuration,
getMaxConnections,
getMaxDuration,
getMedianConnections,
getMedianDuration,
getMinConnections,
getMinDuration,
} from '../stats/sessionStats';
import { getChildrenCodesCount, getFamilyAccountsCount, getConnectedFamiliesCount } from '../stats/villageStats';
import { Controller } from './controller';

export const statisticsController = new Controller('/statistics');

statisticsController.get({ path: '/sessions/:phase' }, async (req: Request, res) => {
const phase = req.params.phase ? parseInt(req.params.phase) : null;

res.sendJSON({
minDuration: await getMinDuration(), // TODO - add phase
maxDuration: await getMaxDuration(), // TODO - add phase
averageDuration: await getAverageDuration(), // TODO - add phase
medianDuration: await getMedianDuration(), // TODO - add phase
minConnections: await getMinConnections(), // TODO - add phase
maxConnections: await getMaxConnections(), // TODO - add phase
averageConnections: await getAverageConnections(), // TODO - add phase
medianConnections: await getMedianConnections(), // TODO - add phase
registeredClassroomsCount: await getRegisteredClassroomsCount(),
connectedClassroomsCount: await getConnectedClassroomsCount(), // TODO - add phase
contributedClassroomsCount: await getContributedClassroomsCount(phase),
});
});

statisticsController.get({ path: '/classrooms' }, async (_req, res) => {
res.sendJSON({
classrooms: await getClassroomsInfos(),
});
});

statisticsController.get({ path: '/villages/:villageId' }, async (_req, res) => {
const villageId = parseInt(_req.params.villageId);
res.sendJSON({
familyAccountsCount: await getFamilyAccountsCount(villageId),
childrenCodesCount: await getChildrenCodesCount(villageId),
connectedFamiliesCount: await getConnectedFamiliesCount(villageId),
});
});
import type { Request } from 'express';

import {
getClassroomsInfos,
getConnectedClassroomsCount,
getContributedClassroomsCount,
getRegisteredClassroomsCount,
} from '../stats/classroomStats';
import {
getAverageConnections,
getAverageDuration,
getMaxConnections,
getMaxDuration,
getMedianConnections,
getMedianDuration,
getMinConnections,
getMinDuration,
} from '../stats/sessionStats';
import { getChildrenCodesCount, getFamilyAccountsCount, getConnectedFamiliesCount } from '../stats/villageStats';
import { Controller } from './controller';

export const statisticsController = new Controller('/statistics');

statisticsController.get({ path: '/sessions/:phase' }, async (req: Request, res) => {
const phase = req.params.phase ? parseInt(req.params.phase) : null;

res.sendJSON({
minDuration: await getMinDuration(), // TODO - add phase
maxDuration: await getMaxDuration(), // TODO - add phase
averageDuration: await getAverageDuration(), // TODO - add phase
medianDuration: await getMedianDuration(), // TODO - add phase
minConnections: await getMinConnections(), // TODO - add phase
maxConnections: await getMaxConnections(), // TODO - add phase
averageConnections: await getAverageConnections(), // TODO - add phase
medianConnections: await getMedianConnections(), // TODO - add phase
registeredClassroomsCount: await getRegisteredClassroomsCount(),
connectedClassroomsCount: await getConnectedClassroomsCount(), // TODO - add phase
contributedClassroomsCount: await getContributedClassroomsCount(phase),
});
});

statisticsController.get({ path: '/classrooms' }, async (_req, res) => {
res.sendJSON({
classrooms: await getClassroomsInfos(),
});
});

statisticsController.get({ path: '/villages/:villageId' }, async (_req, res) => {
const villageId = parseInt(_req.params.villageId);
res.sendJSON({
familyAccountsCount: await getFamilyAccountsCount(villageId),
childrenCodesCount: await getChildrenCodesCount(villageId),
connectedFamiliesCount: await getConnectedFamiliesCount(villageId),
});
});
25 changes: 15 additions & 10 deletions server/controllers/village.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { JSONSchemaType } from 'ajv';
import type { NextFunction, Request, Response } from 'express';

import { UserType } from '../entities/user';
import { Village } from '../entities/village';
import { Village, VillagePhase } from '../entities/village';
import { createVillagesFromPLM } from '../legacy-plm/api';
import { AppError, ErrorCode } from '../middlewares/handleErrors';
import { valueOrDefault } from '../utils';
Expand All @@ -15,17 +15,22 @@ const villageController = new Controller('/villages');
//--- Get all villages ---
villageController.get({ path: '', userType: UserType.OBSERVATOR }, async (_req: Request, res: Response) => {
const countryIsoCode = _req.query.countryIsoCode as string;
const phase = _req.query.phase as string;
try {
// Fetch villages based on countryIsoCode if it's provided
const villageRepository = AppDataSource.getRepository(Village);
const villages = countryIsoCode
? await villageRepository
.createQueryBuilder('village')
.where('village.countryCodes LIKE :countryIsoCode', { countryIsoCode: `%${countryIsoCode.toUpperCase()}%` })
.getMany()
: await villageRepository // Fetch all villages if no countryIsoCode is provided
.createQueryBuilder('student')
.getMany();
let query;
if (countryIsoCode && phase) {
query = villageRepository.createQueryBuilder('village');
query.where('village.countryCodes LIKE :countryIsoCode', { countryIsoCode: `%${countryIsoCode.toUpperCase()}%` });

if (Object.values(VillagePhase).includes(+phase)) {
query.andWhere('village.activePhase = :phase', { phase });
}
} else {
query = villageRepository.createQueryBuilder('student');
}

const villages = await query.getMany();
res.sendJSON(villages);
} catch (e) {
console.error(e);
Expand Down
78 changes: 39 additions & 39 deletions server/stats/villageStats.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
import { Student } from '../entities/student';
import { User } from '../entities/user';
import { AppDataSource } from '../utils/data-source';

const userRepository = AppDataSource.getRepository(User);
const studentRepository = AppDataSource.getRepository(Student);

export const getChildrenCodesCount = async (villageId: number) => {
const childrenCodeCount = await studentRepository
.createQueryBuilder('student')
.innerJoin('student.classroom', 'classroom')
.innerJoin('classroom.village', 'village')
.where('classroom.villageId = :villageId', { villageId })
.getCount();
return childrenCodeCount;
};

export const getFamilyAccountsCount = async (villageId: number) => {
const familyAccountsCount = await userRepository
.createQueryBuilder('user')
.innerJoin('user.village', 'village')
.innerJoin('classroom', 'classroom', 'classroom.villageId = village.id')
.innerJoin('student', 'student', 'student.classroomId = classroom.id')
.where('classroom.villageId = :villageId', { villageId })
.groupBy('user.id')
.getCount();
return familyAccountsCount;
};

export const getConnectedFamiliesCount = async (villageId: number) => {
const connectedFamiliesCount = await studentRepository
.createQueryBuilder('student')
.innerJoin('classroom', 'classroom', 'classroom.id = student.classroomId')
.where('classroom.villageId = :villageId', { villageId })
.andWhere('student.numLinkedAccount >= 1')
.getCount();

return connectedFamiliesCount;
};
import { Student } from '../entities/student';
import { User } from '../entities/user';
import { AppDataSource } from '../utils/data-source';

const userRepository = AppDataSource.getRepository(User);
const studentRepository = AppDataSource.getRepository(Student);

export const getChildrenCodesCount = async (villageId: number) => {
const childrenCodeCount = await studentRepository
.createQueryBuilder('student')
.innerJoin('student.classroom', 'classroom')
.innerJoin('classroom.village', 'village')
.where('classroom.villageId = :villageId', { villageId })
.getCount();
return childrenCodeCount;
};

export const getFamilyAccountsCount = async (villageId: number) => {
const familyAccountsCount = await userRepository
.createQueryBuilder('user')
.innerJoin('user.village', 'village')
.innerJoin('classroom', 'classroom', 'classroom.villageId = village.id')
.innerJoin('student', 'student', 'student.classroomId = classroom.id')
.where('classroom.villageId = :villageId', { villageId })
.groupBy('user.id')
.getCount();
return familyAccountsCount;
};

export const getConnectedFamiliesCount = async (villageId: number) => {
const connectedFamiliesCount = await studentRepository
.createQueryBuilder('student')
.innerJoin('classroom', 'classroom', 'classroom.id = student.classroomId')
.where('classroom.villageId = :villageId', { villageId })
.andWhere('student.numLinkedAccount >= 1')
.getCount();

return connectedFamiliesCount;
};
96 changes: 48 additions & 48 deletions src/api/statistics/statistics.get.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
import { useQuery } from 'react-query';

import { axiosRequest } from 'src/utils/axiosRequest';
import type { ClassroomsStats, SessionsStats, VillageStats } from 'types/statistics.type';

async function getSessionsStats(phase: number | null): Promise<SessionsStats> {
return (
await axiosRequest({
method: 'GET',
baseURL: '/api',
url: `/statistics/sessions/${phase}`,
})
).data;
}

async function getVillagesStats(villageId: number | null): Promise<VillageStats> {
return (
await axiosRequest({
method: 'GET',
baseURL: '/api',
url: `/statistics/villages/${villageId}`,
})
).data;
}

export const useGetSessionsStats = (phase: number | null) => {
return useQuery(['sessions-stats'], () => getSessionsStats(phase));
};

export const useGetVillagesStats = (villageId: number | null) => {
return useQuery(['villages-stats', villageId], () => getVillagesStats(villageId), {
enabled: villageId !== null,
});
};

async function getClassroomsStats(): Promise<ClassroomsStats[]> {
return (
await axiosRequest({
method: 'GET',
baseURL: '/api',
url: '/statistics/classrooms',
})
).data;
}

export const useGetClassroomsStats = () => {
return useQuery(['classrooms-stats'], () => getClassroomsStats());
};
import { useQuery } from 'react-query';

import { axiosRequest } from 'src/utils/axiosRequest';
import type { ClassroomsStats, SessionsStats, VillageStats } from 'types/statistics.type';

async function getSessionsStats(phase: number | null): Promise<SessionsStats> {
return (
await axiosRequest({
method: 'GET',
baseURL: '/api',
url: `/statistics/sessions/${phase}`,
})
).data;
}

async function getVillagesStats(villageId: number | null): Promise<VillageStats> {
return (
await axiosRequest({
method: 'GET',
baseURL: '/api',
url: `/statistics/villages/${villageId}`,
})
).data;
}

export const useGetSessionsStats = (phase: number | null) => {
return useQuery(['sessions-stats'], () => getSessionsStats(phase));
};

export const useGetVillagesStats = (villageId: number | null) => {
return useQuery(['villages-stats', villageId], () => getVillagesStats(villageId), {
enabled: villageId !== null,
});
};

async function getClassroomsStats(): Promise<ClassroomsStats[]> {
return (
await axiosRequest({
method: 'GET',
baseURL: '/api',
url: '/statistics/classrooms',
})
).data;
}

export const useGetClassroomsStats = () => {
return useQuery(['classrooms-stats'], () => getClassroomsStats());
};
Loading

0 comments on commit b2b4735

Please sign in to comment.