Merged in ENCOA-83_MasterStatistical (pull request #74)
ENCOA-83 MasterStatistical Approved-by: Tiago Ribeiro
This commit is contained in:
@@ -13,30 +13,34 @@ import {
|
|||||||
} from "firebase/firestore";
|
} from "firebase/firestore";
|
||||||
import { withIronSessionApiRoute } from "iron-session/next";
|
import { withIronSessionApiRoute } from "iron-session/next";
|
||||||
import { sessionOptions } from "@/lib/session";
|
import { sessionOptions } from "@/lib/session";
|
||||||
import ReactPDF from "@react-pdf/renderer";
|
|
||||||
import GroupTestReport from "@/exams/pdf/group.test.report";
|
|
||||||
import { ref, uploadBytes, getDownloadURL } from "firebase/storage";
|
import { ref, uploadBytes, getDownloadURL } from "firebase/storage";
|
||||||
import { Stat, CorporateUser } from "@/interfaces/user";
|
import { CorporateUser, MasterCorporateUser } from "@/interfaces/user";
|
||||||
import { User, DemographicInformation } from "@/interfaces/user";
|
import { User } from "@/interfaces/user";
|
||||||
import { Module } from "@/interfaces";
|
import { Module } from "@/interfaces";
|
||||||
import { ModuleScore, StudentData } from "@/interfaces/module.scores";
|
|
||||||
import { SkillExamDetails } from "@/exams/pdf/details/skill.exam";
|
|
||||||
import { LevelExamDetails } from "@/exams/pdf/details/level.exam";
|
|
||||||
import { calculateBandScore, getLevelScore } from "@/utils/score";
|
|
||||||
import {
|
|
||||||
generateQRCode,
|
|
||||||
getRadialProgressPNG,
|
|
||||||
streamToBuffer,
|
|
||||||
} from "@/utils/pdf";
|
|
||||||
import { Group } from "@/interfaces/user";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import ExcelJS from "exceljs";
|
import ExcelJS from "exceljs";
|
||||||
|
import { getStudentGroupsForUsersWithoutAdmin } from "@/utils/groups.be";
|
||||||
|
import { getSpecificUsers, getUser } from "@/utils/users.be";
|
||||||
|
import { getUserName } from "@/utils/users";
|
||||||
interface GroupScoreSummaryHelper {
|
interface GroupScoreSummaryHelper {
|
||||||
score: [number, number];
|
score: [number, number];
|
||||||
label: string;
|
label: string;
|
||||||
sessions: string[];
|
sessions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AssignmentData {
|
||||||
|
assigner: string;
|
||||||
|
assignees: string[];
|
||||||
|
results: any;
|
||||||
|
exams: { module: Module }[];
|
||||||
|
startDate: string;
|
||||||
|
excel: {
|
||||||
|
path: string;
|
||||||
|
version: string;
|
||||||
|
};
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
|
|
||||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||||
@@ -55,63 +59,31 @@ function logWorksheetData(worksheet: any) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
function commonExcel({
|
||||||
// verify if it's a logged user that is trying to export
|
data,
|
||||||
if (req.session.user) {
|
userName,
|
||||||
const { id } = req.query as { id: string };
|
users,
|
||||||
|
sectionName,
|
||||||
const docSnap = await getDoc(doc(db, "assignments", id));
|
customTable,
|
||||||
const data = docSnap.data() as {
|
customTableHeaders,
|
||||||
assigner: string;
|
renderCustomTableData,
|
||||||
assignees: string[];
|
}: {
|
||||||
results: any;
|
data: AssignmentData;
|
||||||
exams: { module: Module }[];
|
userName: string;
|
||||||
startDate: string;
|
users: User[];
|
||||||
excel: {
|
sectionName: string;
|
||||||
path: string;
|
customTable: string[][];
|
||||||
version: string;
|
customTableHeaders: string[];
|
||||||
};
|
renderCustomTableData: (data: any) => string[];
|
||||||
name: string;
|
}) {
|
||||||
};
|
|
||||||
if (!data) {
|
|
||||||
res.status(400).end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (
|
|
||||||
// data.excel &&
|
|
||||||
// data.excel.path &&
|
|
||||||
// data.excel.version === process.env.EXCEL_VERSION
|
|
||||||
// ) {
|
|
||||||
// // if it does, return the excel url
|
|
||||||
// const fileRef = ref(storage, data.excel.path);
|
|
||||||
// const url = await getDownloadURL(fileRef);
|
|
||||||
// res.status(200).end(url);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const docsSnap = await getDocs(
|
|
||||||
query(collection(db, "users"), where(documentId(), "in", data.assignees))
|
|
||||||
);
|
|
||||||
const users = docsSnap.docs.map((d) => ({
|
|
||||||
...d.data(),
|
|
||||||
id: d.id,
|
|
||||||
})) as User[];
|
|
||||||
|
|
||||||
const docUser = await getDoc(doc(db, "users", req.session.user.id));
|
|
||||||
if (docUser.exists()) {
|
|
||||||
// we'll need the user in order to get the user data (name, email, focus, etc);
|
|
||||||
const user = docUser.data() as CorporateUser;
|
|
||||||
|
|
||||||
const allStats = data.results.flatMap((r: any) => r.stats);
|
const allStats = data.results.flatMap((r: any) => r.stats);
|
||||||
|
|
||||||
const uniqueExercises = [
|
const uniqueExercises = [...new Set(allStats.map((s: any) => s.exercise))];
|
||||||
...new Set(allStats.map((s: any) => s.exercise)),
|
|
||||||
];
|
|
||||||
|
|
||||||
const assigneesData = data.assignees
|
const assigneesData = data.assignees
|
||||||
.map((assignee: string) => {
|
.map((assignee: string) => {
|
||||||
const userStats = allStats.filter((s: any) => s.user === assignee);
|
const userStats = allStats.filter((s: any) => s.user === assignee);
|
||||||
|
const dates = userStats.map((s: any) => moment(s.date));
|
||||||
return {
|
return {
|
||||||
userId: assignee,
|
userId: assignee,
|
||||||
user: users.find((u) => u.id === assignee),
|
user: users.find((u) => u.id === assignee),
|
||||||
@@ -126,6 +98,8 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
},
|
},
|
||||||
{ correct: 0, missing: 0, total: 0 }
|
{ correct: 0, missing: 0, total: 0 }
|
||||||
),
|
),
|
||||||
|
firstDate: moment.min(...dates),
|
||||||
|
lastDate: moment.max(...dates),
|
||||||
stats: userStats,
|
stats: userStats,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -135,18 +109,13 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const highestScore = Math.max(...results);
|
const highestScore = Math.max(...results);
|
||||||
const lowestScore = Math.min(...results);
|
const lowestScore = Math.min(...results);
|
||||||
const averageScore = results.reduce((a, b) => a + b, 0) / results.length;
|
const averageScore = results.reduce((a, b) => a + b, 0) / results.length;
|
||||||
|
const firstDate = moment.min(assigneesData.map((r: any) => r.firstDate));
|
||||||
const dates = assigneesData
|
const lastDate = moment.max(assigneesData.map((r: any) => r.lastDate));
|
||||||
.flatMap((r: any) => r.stats)
|
|
||||||
.map((r: any) => r.date)
|
|
||||||
.map((d: number) => moment(d));
|
|
||||||
const firstDate = moment.min(dates);
|
|
||||||
const lastDate = moment.max(dates);
|
|
||||||
|
|
||||||
const firstSectionData = [
|
const firstSectionData = [
|
||||||
{
|
{
|
||||||
label: "Corporate Name :",
|
label: sectionName,
|
||||||
value: user.corporateInformation?.companyInformation?.name || "",
|
value: userName,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Report Download date :",
|
label: "Report Download date :",
|
||||||
@@ -182,6 +151,12 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
worksheet.getCell(`B${index + 1}`).value = value; // Second column (values)
|
worksheet.getCell(`B${index + 1}`).value = value; // Second column (values)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// added empty arrays to force row spacings
|
||||||
|
const customTableAndLine = [[],...customTable, []];
|
||||||
|
customTableAndLine.forEach((row: string[], index) => {
|
||||||
|
worksheet.addRow(row);
|
||||||
|
});
|
||||||
|
|
||||||
// Define the static part of the headers (before "Test Sections")
|
// Define the static part of the headers (before "Test Sections")
|
||||||
const staticHeaders = [
|
const staticHeaders = [
|
||||||
"Sr N",
|
"Sr N",
|
||||||
@@ -190,10 +165,11 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
"Passport/ID",
|
"Passport/ID",
|
||||||
"Email ID",
|
"Email ID",
|
||||||
"Gender",
|
"Gender",
|
||||||
|
...customTableHeaders,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Define additional headers after "Test Sections"
|
// Define additional headers after "Test Sections"
|
||||||
const additionalHeaders = ["Time Spent", "Score"];
|
const additionalHeaders = ["Time Spent", "Date", "Score"];
|
||||||
|
|
||||||
// Calculate the dynamic columns based on the testSectionsArray
|
// Calculate the dynamic columns based on the testSectionsArray
|
||||||
const testSectionHeaders = uniqueExercises.map(
|
const testSectionHeaders = uniqueExercises.map(
|
||||||
@@ -212,30 +188,34 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
worksheet.addRow(tableColumnHeaders);
|
worksheet.addRow(tableColumnHeaders);
|
||||||
|
|
||||||
// 1 headers rows
|
// 1 headers rows
|
||||||
const startIndexTable = firstSectionData.length + 1;
|
const startIndexTable = firstSectionData.length + customTableAndLine.length + 1;
|
||||||
|
|
||||||
// // Merge "Test Sections" over dynamic number of columns
|
// // Merge "Test Sections" over dynamic number of columns
|
||||||
// const tableColumns = staticHeaders.length + numberOfTestSections;
|
// const tableColumns = staticHeaders.length + numberOfTestSections;
|
||||||
|
|
||||||
|
// K10:M12 = 10,11,12,13
|
||||||
|
// horizontally group Test Sections
|
||||||
worksheet.mergeCells(
|
worksheet.mergeCells(
|
||||||
1,
|
startIndexTable,
|
||||||
staticHeaders.length + 1,
|
staticHeaders.length + 1,
|
||||||
1,
|
startIndexTable,
|
||||||
tableColumnHeadersFirstPart.length
|
tableColumnHeadersFirstPart.length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Add the dynamic second and third header rows for test sections and sub-columns
|
// Add the dynamic second and third header rows for test sections and sub-columns
|
||||||
worksheet.addRow([
|
worksheet.addRow([
|
||||||
...Array(staticHeaders.length).fill(""),
|
...Array(staticHeaders.length).fill(""),
|
||||||
...testSectionHeaders,
|
...testSectionHeaders,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
]);
|
]);
|
||||||
worksheet.addRow([
|
worksheet.addRow([
|
||||||
...Array(staticHeaders.length).fill(""),
|
...Array(staticHeaders.length).fill(""),
|
||||||
...uniqueExercises.map(() => "Grammar & Vocabulary"),
|
...uniqueExercises.map(() => "Grammar & Vocabulary"),
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
]);
|
]);
|
||||||
worksheet.addRow([
|
worksheet.addRow([
|
||||||
...Array(staticHeaders.length).fill(""),
|
...Array(staticHeaders.length).fill(""),
|
||||||
@@ -244,15 +224,13 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
),
|
),
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Merging static headers and "Test Sections" over dynamic columns
|
// vertically group based on the part, exercise and type
|
||||||
worksheet.mergeCells(`A${startIndexTable}:A${startIndexTable + 3}`); // "Sr N"
|
staticHeaders.forEach((header, index) => {
|
||||||
worksheet.mergeCells(`B${startIndexTable}:B${startIndexTable + 3}`); // "Candidate ID"
|
worksheet.mergeCells(startIndexTable, index + 1, startIndexTable + 3, index + 1);
|
||||||
worksheet.mergeCells(`C${startIndexTable}:C${startIndexTable + 3}`); // "First and Last Name"
|
});
|
||||||
worksheet.mergeCells(`D${startIndexTable}:D${startIndexTable + 3}`); // "Passport/ID"
|
|
||||||
worksheet.mergeCells(`E${startIndexTable}:E${startIndexTable + 3}`); // "Email ID"
|
|
||||||
worksheet.mergeCells(`F${startIndexTable}:F${startIndexTable + 3}`); // "Gender"
|
|
||||||
|
|
||||||
assigneesData.forEach((data, index) => {
|
assigneesData.forEach((data, index) => {
|
||||||
worksheet.addRow([
|
worksheet.addRow([
|
||||||
@@ -262,18 +240,18 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
data.user.demographicInformation?.passportId,
|
data.user.demographicInformation?.passportId,
|
||||||
data.user.email,
|
data.user.email,
|
||||||
data.user.demographicInformation?.gender,
|
data.user.demographicInformation?.gender,
|
||||||
|
...renderCustomTableData(data),
|
||||||
...uniqueExercises.map((exercise) => {
|
...uniqueExercises.map((exercise) => {
|
||||||
const score = data.stats.find(
|
const score = data.stats.find(
|
||||||
(s: any) => s.exercise === exercise && s.user === data.userId
|
(s: any) => s.exercise === exercise && s.user === data.userId
|
||||||
).score;
|
).score;
|
||||||
return `${score.correct}/${score.total}`;
|
return `${score.correct}/${score.total}`;
|
||||||
}),
|
}),
|
||||||
`${
|
`${Math.ceil(
|
||||||
Math.ceil(data.stats.reduce(
|
data.stats.reduce((acc: number, curr: any) => acc + curr.timeSpent, 0) /
|
||||||
(acc: number, curr: any) => acc + curr.timeSpent,
|
60
|
||||||
0
|
)} minutes`,
|
||||||
) / 60)
|
data.lastDate.format("DD/MM/YYYY HH:mm"),
|
||||||
} minutes`,
|
|
||||||
data.correct,
|
data.correct,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -304,12 +282,142 @@ async function post(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
worksheet.addRow(["info@encoach.com"]);
|
worksheet.addRow(["info@encoach.com"]);
|
||||||
|
|
||||||
// Convert workbook to Buffer (Node.js) or Blob (Browser)
|
// Convert workbook to Buffer (Node.js) or Blob (Browser)
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
return workbook.xlsx.writeBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function corporateAssignment(
|
||||||
|
user: CorporateUser,
|
||||||
|
data: AssignmentData,
|
||||||
|
users: User[]
|
||||||
|
) {
|
||||||
|
return commonExcel({
|
||||||
|
data,
|
||||||
|
userName: user.corporateInformation?.companyInformation?.name || "",
|
||||||
|
users,
|
||||||
|
sectionName: "Corporate Name :",
|
||||||
|
customTable: [],
|
||||||
|
customTableHeaders: [],
|
||||||
|
renderCustomTableData: () => [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mastercorporateAssignment(
|
||||||
|
user: MasterCorporateUser,
|
||||||
|
data: AssignmentData,
|
||||||
|
users: User[]
|
||||||
|
) {
|
||||||
|
const userGroups = await getStudentGroupsForUsersWithoutAdmin(
|
||||||
|
user.id,
|
||||||
|
data.assignees
|
||||||
|
);
|
||||||
|
const adminUsers = [...new Set(userGroups.map((g) => g.admin))];
|
||||||
|
|
||||||
|
const userGroupsParticipants = userGroups.flatMap((g) => g.participants);
|
||||||
|
const adminsData = await getSpecificUsers(adminUsers);
|
||||||
|
const companiesData = adminsData.map((user) => {
|
||||||
|
const name = getUserName(user);
|
||||||
|
const users = userGroupsParticipants
|
||||||
|
.filter((p) => data.assignees.includes(p));
|
||||||
|
|
||||||
|
const stats = data.results
|
||||||
|
.flatMap((r: any) => r.stats)
|
||||||
|
.filter((s: any) => users.includes(s.user));
|
||||||
|
const correct = stats.reduce((acc: number, s: any) => acc + s.score.correct, 0);
|
||||||
|
const total = stats.reduce(
|
||||||
|
(acc: number, curr: any) => acc + curr.score.total,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
correct,
|
||||||
|
total,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const customTable = [
|
||||||
|
...companiesData,
|
||||||
|
{
|
||||||
|
name: "Total",
|
||||||
|
correct: companiesData.reduce((acc, curr) => acc + curr.correct, 0),
|
||||||
|
total: companiesData.reduce((acc, curr) => acc + curr.total, 0),
|
||||||
|
},
|
||||||
|
].map((c) => [c.name, `${c.correct}/${c.total}`])
|
||||||
|
|
||||||
|
const customTableHeaders = [{ name: "Corporate", helper: (data: any) => data.user.corporateName}];
|
||||||
|
return commonExcel({
|
||||||
|
data,
|
||||||
|
userName: user.corporateInformation?.companyInformation?.name || "",
|
||||||
|
users: users.map((u) => {
|
||||||
|
const userGroup = userGroups.find((g) => g.participants.includes(u.id));
|
||||||
|
const admin = adminsData.find((a) => a.id === userGroup?.admin);
|
||||||
|
return {
|
||||||
|
...u,
|
||||||
|
corporateName: getUserName(admin),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
sectionName: "Master Corporate Name :",
|
||||||
|
customTable: [['Corporate Summary'], ...customTable],
|
||||||
|
customTableHeaders: customTableHeaders.map((h) => h.name),
|
||||||
|
renderCustomTableData: (data) => customTableHeaders.map((h) => h.helper(data)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
// verify if it's a logged user that is trying to export
|
||||||
|
if (req.session.user) {
|
||||||
|
const { id } = req.query as { id: string };
|
||||||
|
|
||||||
|
const docSnap = await getDoc(doc(db, "assignments", id));
|
||||||
|
const data = docSnap.data() as AssignmentData;
|
||||||
|
if (!data) {
|
||||||
|
res.status(400).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (
|
||||||
|
// data.excel &&
|
||||||
|
// data.excel.path &&
|
||||||
|
// data.excel.version === process.env.EXCEL_VERSION
|
||||||
|
// ) {
|
||||||
|
// // if it does, return the excel url
|
||||||
|
// const fileRef = ref(storage, data.excel.path);
|
||||||
|
// const url = await getDownloadURL(fileRef);
|
||||||
|
// res.status(200).end(url);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
const docsSnap = await getDocs(
|
||||||
|
query(collection(db, "users"), where(documentId(), "in", data.assignees))
|
||||||
|
);
|
||||||
|
const users = docsSnap.docs.map((d) => ({
|
||||||
|
...d.data(),
|
||||||
|
id: d.id,
|
||||||
|
})) as User[];
|
||||||
|
|
||||||
|
const docUser = await getDoc(doc(db, "users", data.assigner));
|
||||||
|
if (docUser.exists()) {
|
||||||
|
// we'll need the user in order to get the user data (name, email, focus, etc);
|
||||||
|
const user = docUser.data() as User;
|
||||||
|
|
||||||
// generate the file ref for storage
|
// generate the file ref for storage
|
||||||
const fileName = `${Date.now().toString()}.xlsx`;
|
const fileName = `${Date.now().toString()}.xlsx`;
|
||||||
const refName = `assignment_report/${fileName}`;
|
const refName = `assignment_report/${fileName}`;
|
||||||
const fileRef = ref(storage, refName);
|
const fileRef = ref(storage, refName);
|
||||||
|
|
||||||
|
const getExcelFn = () => {
|
||||||
|
switch (user.type) {
|
||||||
|
case "teacher":
|
||||||
|
case "corporate":
|
||||||
|
return corporateAssignment(user as CorporateUser, data, users);
|
||||||
|
case "mastercorporate":
|
||||||
|
return mastercorporateAssignment(user as MasterCorporateUser, data, users);
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid user type");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const buffer = await getExcelFn();
|
||||||
|
|
||||||
// upload the pdf to storage
|
// upload the pdf to storage
|
||||||
const snapshot = await uploadBytes(fileRef, buffer, {
|
const snapshot = await uploadBytes(fileRef, buffer, {
|
||||||
contentType:
|
contentType:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { withIronSessionApiRoute } from "iron-session/next";
|
|||||||
import { sessionOptions } from "@/lib/session";
|
import { sessionOptions } from "@/lib/session";
|
||||||
import { Group } from "@/interfaces/user";
|
import { Group } from "@/interfaces/user";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import { updateExpiryDateOnGroup } from "@/utils/groups.be";
|
import { updateExpiryDateOnGroup, getGroupsForUser } from "@/utils/groups.be";
|
||||||
|
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
|
|
||||||
@@ -30,30 +30,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
if (req.method === "POST") await post(req, res);
|
if (req.method === "POST") await post(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getGroupsForUser = async (admin: string, participant: string) => {
|
|
||||||
try {
|
|
||||||
const queryConstraints = [
|
|
||||||
...(admin ? [where("admin", "==", admin)] : []),
|
|
||||||
...(participant
|
|
||||||
? [where("participants", "array-contains", participant)]
|
|
||||||
: []),
|
|
||||||
];
|
|
||||||
const snapshot = await getDocs(
|
|
||||||
queryConstraints.length > 0
|
|
||||||
? query(collection(db, "groups"), ...queryConstraints)
|
|
||||||
: collection(db, "groups")
|
|
||||||
);
|
|
||||||
const groups = snapshot.docs.map((doc) => ({
|
|
||||||
id: doc.id,
|
|
||||||
...doc.data(),
|
|
||||||
})) as Group[];
|
|
||||||
|
|
||||||
return groups;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
async function get(req: NextApiRequest, res: NextApiResponse) {
|
async function get(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const { admin, participant } = req.query as {
|
const { admin, participant } = req.query as {
|
||||||
admin: string;
|
admin: string;
|
||||||
|
|||||||
@@ -54,3 +54,54 @@ export const getAllAssignersByCorporate = async (corporateID: string): Promise<s
|
|||||||
|
|
||||||
return teacherPromises.filter((x) => !!x).flat() as string[];
|
return teacherPromises.filter((x) => !!x).flat() as string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getGroupsForUser = async (admin: string, participant: string) => {
|
||||||
|
try {
|
||||||
|
const queryConstraints = [
|
||||||
|
...(admin ? [where("admin", "==", admin)] : []),
|
||||||
|
...(participant
|
||||||
|
? [where("participants", "array-contains", participant)]
|
||||||
|
: []),
|
||||||
|
];
|
||||||
|
const snapshot = await getDocs(
|
||||||
|
queryConstraints.length > 0
|
||||||
|
? query(collection(db, "groups"), ...queryConstraints)
|
||||||
|
: collection(db, "groups")
|
||||||
|
);
|
||||||
|
const groups = snapshot.docs.map((doc) => ({
|
||||||
|
id: doc.id,
|
||||||
|
...doc.data(),
|
||||||
|
})) as Group[];
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStudentGroupsForUsersWithoutAdmin = async (admin: string, participants: string[]) => {
|
||||||
|
try {
|
||||||
|
const queryConstraints = [
|
||||||
|
...(admin ? [where("admin", "!=", admin)] : []),
|
||||||
|
...(participants
|
||||||
|
? [where("participants", "array-contains-any", participants)]
|
||||||
|
: []),
|
||||||
|
where("name", "==", "Students"),
|
||||||
|
];
|
||||||
|
const snapshot = await getDocs(
|
||||||
|
queryConstraints.length > 0
|
||||||
|
? query(collection(db, "groups"), ...queryConstraints)
|
||||||
|
: collection(db, "groups")
|
||||||
|
);
|
||||||
|
const groups = snapshot.docs.map((doc) => ({
|
||||||
|
id: doc.id,
|
||||||
|
...doc.data(),
|
||||||
|
})) as Group[];
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
import { app } from "@/firebase";
|
import { app } from "@/firebase";
|
||||||
|
|
||||||
import {collection, doc, getDoc, getDocs, getFirestore} from "firebase/firestore";
|
import {
|
||||||
|
collection,
|
||||||
|
doc,
|
||||||
|
getDoc,
|
||||||
|
getDocs,
|
||||||
|
getFirestore,
|
||||||
|
query,
|
||||||
|
where,
|
||||||
|
} from "firebase/firestore";
|
||||||
import { User } from "@/interfaces/user";
|
import { User } from "@/interfaces/user";
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
|
|
||||||
@@ -18,3 +26,18 @@ export async function getUser(id: string) {
|
|||||||
|
|
||||||
return { ...userDoc.data(), id } as User;
|
return { ...userDoc.data(), id } as User;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getSpecificUsers(ids: string[]) {
|
||||||
|
if (ids.length === 0) return [];
|
||||||
|
|
||||||
|
const snapshot = await getDocs(
|
||||||
|
query(collection(db, "users"), where("id", "in", ids))
|
||||||
|
);
|
||||||
|
|
||||||
|
const groups = snapshot.docs.map((doc) => ({
|
||||||
|
id: doc.id,
|
||||||
|
...doc.data(),
|
||||||
|
})) as User[];
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user