Enhances dashboard metrics and session handling with word cloud data and country metrics

This commit is contained in:
2025-05-22 07:31:24 +02:00
parent 7762061850
commit 2b75c53241
6 changed files with 509 additions and 128 deletions

View File

@ -4,6 +4,7 @@ import { getServerSession } from "next-auth";
import { prisma } from "../../../lib/prisma";
import { sessionMetrics } from "../../../lib/metrics";
import { authOptions } from "../auth/[...nextauth]";
import { ChatSession } from "../../../lib/types"; // Import ChatSession
interface SessionUser {
email: string;
@ -32,13 +33,47 @@ export default async function handler(
if (!user) return res.status(401).json({ error: "No user" });
const sessions = await prisma.session.findMany({
const prismaSessions = await prisma.session.findMany({
where: { companyId: user.companyId },
});
// Convert Prisma sessions to ChatSession[] type for sessionMetrics
const chatSessions: ChatSession[] = prismaSessions.map((ps) => ({
id: ps.id, // Map Prisma's id to ChatSession.id
sessionId: ps.id, // Map Prisma's id to ChatSession.sessionId
companyId: ps.companyId,
startTime: new Date(ps.startTime), // Ensure startTime is a Date object
endTime: ps.endTime ? new Date(ps.endTime) : null, // Ensure endTime is a Date object or null
transcriptContent: ps.transcriptContent || "", // Ensure transcriptContent is a string
createdAt: new Date(ps.createdAt), // Map Prisma's createdAt
updatedAt: new Date(ps.createdAt), // Use createdAt for updatedAt as Session model doesn't have updatedAt
category: ps.category || undefined,
language: ps.language || undefined,
country: ps.country || undefined,
ipAddress: ps.ipAddress || undefined,
sentiment: ps.sentiment === null ? undefined : ps.sentiment,
messagesSent: ps.messagesSent === null ? undefined : ps.messagesSent, // Handle null messagesSent
avgResponseTime:
ps.avgResponseTime === null ? undefined : ps.avgResponseTime,
tokens: ps.tokens === null ? undefined : ps.tokens,
tokensEur: ps.tokensEur === null ? undefined : ps.tokensEur,
escalated: ps.escalated || false,
forwardedHr: ps.forwardedHr || false,
initialMsg: ps.initialMsg || undefined,
fullTranscriptUrl: ps.fullTranscriptUrl || undefined,
// userId is missing in Prisma Session model, assuming it's not strictly needed for metrics or can be null
userId: undefined, // Or some other default/mapping if available
}));
// Pass company config to metrics
// @ts-expect-error - Type conversion is needed between prisma session and ChatSession
const metrics = sessionMetrics(sessions, user.company);
const companyConfigForMetrics = {
sentimentAlert:
user.company.sentimentAlert === null
? undefined
: user.company.sentimentAlert,
};
const metrics = sessionMetrics(chatSessions, companyConfigForMetrics);
res.json({
metrics,

View File

@ -3,60 +3,66 @@ import { prisma } from "../../../../lib/prisma";
import { ChatSession } from "../../../../lib/types";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
req: NextApiRequest,
res: NextApiResponse
) {
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 { id } = req.query;
if (!id || typeof id !== "string") {
return res.status(400).json({ error: "Session ID is required" });
}
try {
const prismaSession = await prisma.session.findUnique({
where: { id },
});
if (!prismaSession) {
return res.status(404).json({ error: "Session not found" });
}
const { id } = req.query;
// Map Prisma session object to ChatSession type
const session: ChatSession = {
// Spread prismaSession to include all its properties
...prismaSession,
// Override properties that need conversion or specific mapping
id: prismaSession.id, // ChatSession.id from Prisma.Session.id
sessionId: prismaSession.id, // ChatSession.sessionId from Prisma.Session.id
startTime: new Date(prismaSession.startTime),
endTime: prismaSession.endTime ? new Date(prismaSession.endTime) : null,
createdAt: new Date(prismaSession.createdAt),
// Prisma.Session does not have an `updatedAt` field. We'll use `createdAt` as a fallback.
// Or, if your business logic implies an update timestamp elsewhere, use that.
updatedAt: new Date(prismaSession.createdAt), // Fallback to createdAt
// Prisma.Session does not have a `userId` field.
userId: null, // Explicitly set to null or map if available from another source
// Ensure nullable fields from Prisma are correctly mapped to ChatSession's optional or nullable fields
category: prismaSession.category ?? null,
language: prismaSession.language ?? null,
country: prismaSession.country ?? null,
ipAddress: prismaSession.ipAddress ?? null,
sentiment: prismaSession.sentiment ?? null,
messagesSent: prismaSession.messagesSent ?? undefined, // Use undefined if ChatSession expects number | undefined
avgResponseTime: prismaSession.avgResponseTime ?? null,
escalated: prismaSession.escalated ?? undefined,
forwardedHr: prismaSession.forwardedHr ?? undefined,
tokens: prismaSession.tokens ?? undefined,
tokensEur: prismaSession.tokensEur ?? undefined,
initialMsg: prismaSession.initialMsg ?? undefined,
fullTranscriptUrl: prismaSession.fullTranscriptUrl ?? null,
transcriptContent: prismaSession.transcriptContent ?? null,
};
if (!id || typeof id !== "string") {
return res.status(400).json({ error: "Session ID is required" });
}
try {
const prismaSession = await prisma.session.findUnique({
where: { id },
});
if (!prismaSession) {
return res.status(404).json({ error: "Session not found" });
}
// Map Prisma session object to ChatSession type
const session: ChatSession = {
...prismaSession,
sessionId: prismaSession.id, // Assuming ChatSession's sessionId is Prisma's id
startTime: new Date(prismaSession.startTime),
endTime: prismaSession.endTime ? new Date(prismaSession.endTime) : null,
createdAt: new Date(prismaSession.createdAt),
updatedAt: new Date(prismaSession.updatedAt),
userId: prismaSession.userId === undefined ? null : prismaSession.userId,
category: prismaSession.category === undefined ? null : prismaSession.category,
language: prismaSession.language === undefined ? null : prismaSession.language,
country: prismaSession.country === undefined ? null : prismaSession.country,
ipAddress: prismaSession.ipAddress === undefined ? null : prismaSession.ipAddress,
sentiment: prismaSession.sentiment === undefined ? null : prismaSession.sentiment,
messagesSent: prismaSession.messagesSent === undefined ? undefined : prismaSession.messagesSent,
avgResponseTime: prismaSession.avgResponseTime === undefined ? null : prismaSession.avgResponseTime,
escalated: prismaSession.escalated === undefined ? undefined : prismaSession.escalated,
forwardedHr: prismaSession.forwardedHr === undefined ? undefined : prismaSession.forwardedHr,
tokens: prismaSession.tokens === undefined ? undefined : prismaSession.tokens,
tokensEur: prismaSession.tokensEur === undefined ? undefined : prismaSession.tokensEur,
initialMsg: prismaSession.initialMsg === undefined ? null : prismaSession.initialMsg,
fullTranscriptUrl: prismaSession.fullTranscriptUrl === undefined ? null : prismaSession.fullTranscriptUrl,
transcriptContent: prismaSession.transcriptContent === undefined ? null : prismaSession.transcriptContent,
};
return res.status(200).json({ session });
} catch (error) {
console.error(`Failed to fetch session ${id}:`, error);
const errorMessage =
error instanceof Error ? error.message : "An unknown error occurred";
return res
.status(500)
.json({ error: "Failed to fetch session", details: errorMessage });
}
return res.status(200).json({ session });
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "An unknown error occurred";
return res
.status(500)
.json({ error: "Failed to fetch session", details: errorMessage });
}
}

View File

@ -1,73 +1,81 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../auth/[...nextauth]";
import { prisma } from "../../../lib/prisma";
import { ChatSession } from "../../../lib/types";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
req: NextApiRequest,
res: NextApiResponse
) {
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);
if (!authSession || !authSession.user?.companyId) {
return res.status(401).json({ error: "Unauthorized" });
}
const companyId = authSession.user.companyId;
const { searchTerm } = req.query;
try {
const whereClause: any = { companyId };
if (
searchTerm &&
typeof searchTerm === "string" &&
searchTerm.trim() !== ""
) {
const searchConditions = [
{ id: { contains: searchTerm, mode: "insensitive" } },
{ category: { contains: searchTerm, mode: "insensitive" } },
{ initialMsg: { contains: searchTerm, mode: "insensitive" } },
{ transcriptContent: { contains: searchTerm, mode: "insensitive" } },
];
whereClause.OR = searchConditions;
}
const { searchTerm } = req.query;
const prismaSessions = await prisma.session.findMany({
where: whereClause,
orderBy: {
startTime: "desc",
},
});
try {
let prismaSessions;
const sessions: ChatSession[] = prismaSessions.map((ps) => ({
id: ps.id,
sessionId: ps.id,
companyId: ps.companyId,
startTime: new Date(ps.startTime),
endTime: ps.endTime ? new Date(ps.endTime) : null,
createdAt: new Date(ps.createdAt),
updatedAt: new Date(ps.createdAt),
userId: null,
category: ps.category ?? null,
language: ps.language ?? null,
country: ps.country ?? null,
ipAddress: ps.ipAddress ?? null,
sentiment: ps.sentiment ?? null,
messagesSent: ps.messagesSent ?? undefined,
avgResponseTime: ps.avgResponseTime ?? null,
escalated: ps.escalated ?? undefined,
forwardedHr: ps.forwardedHr ?? undefined,
tokens: ps.tokens ?? undefined,
tokensEur: ps.tokensEur ?? undefined,
initialMsg: ps.initialMsg ?? undefined,
fullTranscriptUrl: ps.fullTranscriptUrl ?? null,
transcriptContent: ps.transcriptContent ?? null,
}));
if (searchTerm && typeof searchTerm === "string" && searchTerm.trim() !== "") {
const searchConditions = [
{ id: { contains: searchTerm, mode: "insensitive" } },
{ category: { contains: searchTerm, mode: "insensitive" } },
{ initialMsg: { contains: searchTerm, mode: "insensitive" } },
{ transcriptContent: { contains: searchTerm, mode: "insensitive" } },
];
prismaSessions = await prisma.session.findMany({
where: {
OR: searchConditions,
},
orderBy: {
startTime: "desc",
},
});
} else {
prismaSessions = await prisma.session.findMany({
orderBy: {
startTime: "desc",
},
});
}
const sessions: ChatSession[] = prismaSessions.map(ps => ({
...ps,
sessionId: ps.id,
startTime: new Date(ps.startTime),
endTime: ps.endTime ? new Date(ps.endTime) : null,
createdAt: new Date(ps.createdAt),
updatedAt: new Date(ps.updatedAt),
userId: ps.userId === undefined ? null : ps.userId,
category: ps.category === undefined ? null : ps.category,
language: ps.language === undefined ? null : ps.language,
country: ps.country === undefined ? null : ps.country,
ipAddress: ps.ipAddress === undefined ? null : ps.ipAddress,
sentiment: ps.sentiment === undefined ? null : ps.sentiment,
messagesSent: ps.messagesSent === undefined ? undefined : ps.messagesSent,
avgResponseTime: ps.avgResponseTime === undefined ? null : ps.avgResponseTime,
escalated: ps.escalated === undefined ? undefined : ps.escalated,
forwardedHr: ps.forwardedHr === undefined ? undefined : ps.forwardedHr,
tokens: ps.tokens === undefined ? undefined : ps.tokens,
tokensEur: ps.tokensEur === undefined ? undefined : ps.tokensEur,
initialMsg: ps.initialMsg === undefined ? null : ps.initialMsg,
fullTranscriptUrl: ps.fullTranscriptUrl === undefined ? null : ps.fullTranscriptUrl,
transcriptContent: ps.transcriptContent === undefined ? null : ps.transcriptContent,
}));
return res.status(200).json({ sessions });
} catch (error) {
console.error("Failed to fetch sessions:", error);
const errorMessage =
error instanceof Error ? error.message : "An unknown error occurred";
return res.status(500).json({ error: "Failed to fetch sessions", details: errorMessage });
}
return res.status(200).json({ sessions });
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "An unknown error occurred";
return res
.status(500)
.json({ error: "Failed to fetch sessions", details: errorMessage });
}
}