feat(sessions): add missing language, sortKey, and sortOrder filtering support

- Add language field with ISO 639-1 validation to sessionFilterSchema
- Add sortKey enum with startTime, category, language, sentiment, sessionId options
- Add sortOrder enum with asc/desc options
- Update tRPC router to support new filtering and sorting parameters
- Uncomment frontend code to enable full filtering functionality
- Add comprehensive validation tests for new schema fields

Resolves commented out filter options in app/dashboard/sessions/page.tsx lines 491-502
This commit is contained in:
2025-07-13 23:07:28 +02:00
parent 1427f05390
commit 04d415f2cc
4 changed files with 58 additions and 6 deletions

View File

@ -504,11 +504,11 @@ export default function SessionsPage() {
category: selectedCategory category: selectedCategory
? (selectedCategory as z.infer<typeof sessionFilterSchema>["category"]) ? (selectedCategory as z.infer<typeof sessionFilterSchema>["category"])
: undefined, : undefined,
// language: selectedLanguage || undefined, // Not supported in schema yet language: selectedLanguage || undefined,
startDate: startDate || undefined, startDate: startDate || undefined,
endDate: endDate || undefined, endDate: endDate || undefined,
// sortKey: sortKey || undefined, // Not supported in schema yet sortKey: sortKey || undefined,
// sortOrder: sortOrder || undefined, // Not supported in schema yet sortOrder: sortOrder || undefined,
page: currentPage, page: currentPage,
limit: pageSize, limit: pageSize,
}, },

View File

@ -71,8 +71,16 @@ export const sessionFilterSchema = z.object({
"UNRECOGNIZED_OTHER", "UNRECOGNIZED_OTHER",
]) ])
.optional(), .optional(),
language: z
.string()
.regex(/^[a-z]{2}$/)
.optional(),
startDate: z.string().datetime().optional(), startDate: z.string().datetime().optional(),
endDate: z.string().datetime().optional(), endDate: z.string().datetime().optional(),
sortKey: z
.enum(["startTime", "category", "language", "sentiment", "sessionId"])
.default("startTime"),
sortOrder: z.enum(["asc", "desc"]).default("desc"),
page: z.number().int().min(1).default(1), page: z.number().int().min(1).default(1),
limit: z.number().int().min(1).max(100).default(20), limit: z.number().int().min(1).max(100).default(20),
}); });

View File

@ -21,8 +21,18 @@ export const dashboardRouter = router({
getSessions: companyProcedure getSessions: companyProcedure
.input(sessionFilterSchema) .input(sessionFilterSchema)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const { search, sentiment, category, startDate, endDate, page, limit } = const {
input; search,
sentiment,
category,
language,
startDate,
endDate,
sortKey,
sortOrder,
page,
limit,
} = input;
// Build where clause // Build where clause
const where: Prisma.SessionWhereInput = { const where: Prisma.SessionWhereInput = {
@ -44,6 +54,10 @@ export const dashboardRouter = router({
where.category = category; where.category = category;
} }
if (language) {
where.language = language;
}
if (startDate || endDate) { if (startDate || endDate) {
where.startTime = {}; where.startTime = {};
if (startDate) { if (startDate) {
@ -89,7 +103,7 @@ export const dashboardRouter = router({
orderBy: { order: "asc" }, orderBy: { order: "asc" },
}, },
}, },
orderBy: { startTime: "desc" }, orderBy: { [sortKey]: sortOrder },
skip: (page - 1) * limit, skip: (page - 1) * limit,
take: limit, take: limit,
}); });

View File

@ -176,6 +176,36 @@ describe("Validation Schemas", () => {
const data = { limit: 101 }; const data = { limit: 101 };
expect(sessionFilterSchema.safeParse(data).success).toBe(false); expect(sessionFilterSchema.safeParse(data).success).toBe(false);
}); });
it("should validate valid language code", () => {
const data = { language: "en" };
expect(sessionFilterSchema.safeParse(data).success).toBe(true);
});
it("should invalidate invalid language code", () => {
const data = { language: "invalid" };
expect(sessionFilterSchema.safeParse(data).success).toBe(false);
});
it("should validate valid sortKey", () => {
const data = { sortKey: "startTime" };
expect(sessionFilterSchema.safeParse(data).success).toBe(true);
});
it("should invalidate invalid sortKey", () => {
const data = { sortKey: "invalid" };
expect(sessionFilterSchema.safeParse(data).success).toBe(false);
});
it("should validate valid sortOrder", () => {
const data = { sortOrder: "asc" };
expect(sessionFilterSchema.safeParse(data).success).toBe(true);
});
it("should invalidate invalid sortOrder", () => {
const data = { sortOrder: "invalid" };
expect(sessionFilterSchema.safeParse(data).success).toBe(false);
});
}); });
describe("companySettingsSchema", () => { describe("companySettingsSchema", () => {