mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 13:52:16 +01:00
Enhances data handling and geographic mapping
Refactors dashboard to use actual metrics for country data, removing dummy data for improved accuracy. Integrates the country-code-lookup package for geographic mapping, adding comprehensive country coordinates. Increases performance and data validation across API endpoints and adjusts WordCloud component size for better visualization. Enhances session handling with improved validation logic, and updates configuration for allowed origins.
This commit is contained in:
@ -5,66 +5,72 @@ import { prisma } from "../../../lib/prisma";
|
||||
import { SessionFilterOptions } from "../../../lib/types";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<SessionFilterOptions | { error: string; details?: string; }>
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<
|
||||
SessionFilterOptions | { error: string; details?: string }
|
||||
>
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const authSession = await getServerSession(req, res, authOptions);
|
||||
const authSession = await getServerSession(req, res, authOptions);
|
||||
|
||||
if (!authSession || !authSession.user?.companyId) {
|
||||
return res.status(401).json({ error: "Unauthorized" });
|
||||
}
|
||||
if (!authSession || !authSession.user?.companyId) {
|
||||
return res.status(401).json({ error: "Unauthorized" });
|
||||
}
|
||||
|
||||
const companyId = authSession.user.companyId;
|
||||
const companyId = authSession.user.companyId;
|
||||
|
||||
try {
|
||||
const categories = await prisma.session.findMany({
|
||||
where: {
|
||||
companyId,
|
||||
category: {
|
||||
not: null, // Ensure category is not null
|
||||
},
|
||||
},
|
||||
distinct: ["category"],
|
||||
select: {
|
||||
category: true,
|
||||
},
|
||||
orderBy: {
|
||||
category: "asc",
|
||||
},
|
||||
});
|
||||
try {
|
||||
const categories = await prisma.session.findMany({
|
||||
where: {
|
||||
companyId,
|
||||
category: {
|
||||
not: null, // Ensure category is not null
|
||||
},
|
||||
},
|
||||
distinct: ["category"],
|
||||
select: {
|
||||
category: true,
|
||||
},
|
||||
orderBy: {
|
||||
category: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
const languages = await prisma.session.findMany({
|
||||
where: {
|
||||
companyId,
|
||||
language: {
|
||||
not: null, // Ensure language is not null
|
||||
},
|
||||
},
|
||||
distinct: ["language"],
|
||||
select: {
|
||||
language: true,
|
||||
},
|
||||
orderBy: {
|
||||
language: "asc",
|
||||
},
|
||||
});
|
||||
const languages = await prisma.session.findMany({
|
||||
where: {
|
||||
companyId,
|
||||
language: {
|
||||
not: null, // Ensure language is not null
|
||||
},
|
||||
},
|
||||
distinct: ["language"],
|
||||
select: {
|
||||
language: true,
|
||||
},
|
||||
orderBy: {
|
||||
language: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
const distinctCategories = categories.map((s) => s.category).filter(Boolean) as string[]; // Filter out any nulls and assert as string[]
|
||||
const distinctLanguages = languages.map((s) => s.language).filter(Boolean) as string[]; // Filter out any nulls and assert as string[]
|
||||
const distinctCategories = categories
|
||||
.map((s) => s.category)
|
||||
.filter(Boolean) as string[]; // Filter out any nulls and assert as string[]
|
||||
const distinctLanguages = languages
|
||||
.map((s) => s.language)
|
||||
.filter(Boolean) as string[]; // Filter out any nulls and assert as string[]
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
.json({ categories: distinctCategories, languages: distinctLanguages });
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "An unknown error occurred";
|
||||
return res.status(500).json({
|
||||
error: "Failed to fetch filter options",
|
||||
details: errorMessage,
|
||||
});
|
||||
}
|
||||
return res
|
||||
.status(200)
|
||||
.json({ categories: distinctCategories, languages: distinctLanguages });
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "An unknown error occurred";
|
||||
return res.status(500).json({
|
||||
error: "Failed to fetch filter options",
|
||||
details: errorMessage,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,15 @@ import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getServerSession } from "next-auth/next";
|
||||
import { authOptions } from "../auth/[...nextauth]";
|
||||
import { prisma } from "../../../lib/prisma";
|
||||
import { ChatSession, SessionApiResponse, SessionQuery } from "../../../lib/types";
|
||||
import {
|
||||
ChatSession,
|
||||
SessionApiResponse,
|
||||
SessionQuery,
|
||||
} from "../../../lib/types";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<SessionApiResponse | { error: string; details?: string; }>
|
||||
res: NextApiResponse<SessionApiResponse | { error: string; details?: string }>
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
@ -19,25 +23,25 @@ export default async function handler(
|
||||
}
|
||||
|
||||
const companyId = authSession.user.companyId;
|
||||
const {
|
||||
searchTerm,
|
||||
category,
|
||||
language,
|
||||
startDate,
|
||||
endDate,
|
||||
sortKey,
|
||||
sortOrder,
|
||||
page: queryPage,
|
||||
pageSize: queryPageSize,
|
||||
} = req.query as SessionQuery;
|
||||
const {
|
||||
searchTerm,
|
||||
category,
|
||||
language,
|
||||
startDate,
|
||||
endDate,
|
||||
sortKey,
|
||||
sortOrder,
|
||||
page: queryPage,
|
||||
pageSize: queryPageSize,
|
||||
} = req.query as SessionQuery;
|
||||
|
||||
const page = Number(queryPage) || 1;
|
||||
const pageSize = Number(queryPageSize) || 10;
|
||||
const page = Number(queryPage) || 1;
|
||||
const pageSize = Number(queryPageSize) || 10;
|
||||
|
||||
try {
|
||||
const whereClause: any = { companyId };
|
||||
|
||||
// Search Term
|
||||
// Search Term
|
||||
if (
|
||||
searchTerm &&
|
||||
typeof searchTerm === "string" &&
|
||||
@ -45,7 +49,7 @@ export default async function handler(
|
||||
) {
|
||||
const searchConditions = [
|
||||
{ id: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ sessionId: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ sessionId: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ category: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ initialMsg: { contains: searchTerm, mode: "insensitive" } },
|
||||
{ transcriptContent: { contains: searchTerm, mode: "insensitive" } },
|
||||
@ -53,54 +57,54 @@ export default async function handler(
|
||||
whereClause.OR = searchConditions;
|
||||
}
|
||||
|
||||
// Category Filter
|
||||
if (category && typeof category === "string" && category.trim() !== "") {
|
||||
whereClause.category = category;
|
||||
}
|
||||
// Category Filter
|
||||
if (category && typeof category === "string" && category.trim() !== "") {
|
||||
whereClause.category = category;
|
||||
}
|
||||
|
||||
// Language Filter
|
||||
if (language && typeof language === "string" && language.trim() !== "") {
|
||||
whereClause.language = language;
|
||||
}
|
||||
// Language Filter
|
||||
if (language && typeof language === "string" && language.trim() !== "") {
|
||||
whereClause.language = language;
|
||||
}
|
||||
|
||||
// Date Range Filter
|
||||
if (startDate && typeof startDate === "string") {
|
||||
if (!whereClause.startTime) whereClause.startTime = {};
|
||||
whereClause.startTime.gte = new Date(startDate);
|
||||
}
|
||||
if (endDate && typeof endDate === "string") {
|
||||
if (!whereClause.startTime) whereClause.startTime = {};
|
||||
const inclusiveEndDate = new Date(endDate);
|
||||
inclusiveEndDate.setDate(inclusiveEndDate.getDate() + 1);
|
||||
whereClause.startTime.lt = inclusiveEndDate;
|
||||
}
|
||||
// Date Range Filter
|
||||
if (startDate && typeof startDate === "string") {
|
||||
if (!whereClause.startTime) whereClause.startTime = {};
|
||||
whereClause.startTime.gte = new Date(startDate);
|
||||
}
|
||||
if (endDate && typeof endDate === "string") {
|
||||
if (!whereClause.startTime) whereClause.startTime = {};
|
||||
const inclusiveEndDate = new Date(endDate);
|
||||
inclusiveEndDate.setDate(inclusiveEndDate.getDate() + 1);
|
||||
whereClause.startTime.lt = inclusiveEndDate;
|
||||
}
|
||||
|
||||
// Sorting
|
||||
let orderByClause: any = { startTime: "desc" };
|
||||
if (sortKey && typeof sortKey === "string") {
|
||||
const order =
|
||||
sortOrder === "asc" || sortOrder === "desc" ? sortOrder : "desc";
|
||||
const validSortKeys: { [key: string]: string; } = {
|
||||
startTime: "startTime",
|
||||
category: "category",
|
||||
language: "language",
|
||||
sentiment: "sentiment",
|
||||
messagesSent: "messagesSent",
|
||||
avgResponseTime: "avgResponseTime",
|
||||
};
|
||||
if (validSortKeys[sortKey]) {
|
||||
orderByClause = { [validSortKeys[sortKey]]: order };
|
||||
}
|
||||
// Sorting
|
||||
let orderByClause: any = { startTime: "desc" };
|
||||
if (sortKey && typeof sortKey === "string") {
|
||||
const order =
|
||||
sortOrder === "asc" || sortOrder === "desc" ? sortOrder : "desc";
|
||||
const validSortKeys: { [key: string]: string } = {
|
||||
startTime: "startTime",
|
||||
category: "category",
|
||||
language: "language",
|
||||
sentiment: "sentiment",
|
||||
messagesSent: "messagesSent",
|
||||
avgResponseTime: "avgResponseTime",
|
||||
};
|
||||
if (validSortKeys[sortKey]) {
|
||||
orderByClause = { [validSortKeys[sortKey]]: order };
|
||||
}
|
||||
}
|
||||
|
||||
const prismaSessions = await prisma.session.findMany({
|
||||
where: whereClause,
|
||||
orderBy: orderByClause,
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
orderBy: orderByClause,
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
});
|
||||
|
||||
const totalSessions = await prisma.session.count({ where: whereClause });
|
||||
const totalSessions = await prisma.session.count({ where: whereClause });
|
||||
|
||||
const sessions: ChatSession[] = prismaSessions.map((ps) => ({
|
||||
id: ps.id,
|
||||
@ -127,7 +131,7 @@ export default async function handler(
|
||||
transcriptContent: ps.transcriptContent ?? null,
|
||||
}));
|
||||
|
||||
return res.status(200).json({ sessions, totalSessions });
|
||||
return res.status(200).json({ sessions, totalSessions });
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "An unknown error occurred";
|
||||
|
||||
Reference in New Issue
Block a user