diff --git a/app/dashboard/overview/page.tsx b/app/dashboard/overview/page.tsx index de14944..3df6a23 100644 --- a/app/dashboard/overview/page.tsx +++ b/app/dashboard/overview/page.tsx @@ -4,6 +4,7 @@ import { useEffect, useState, useCallback, useRef } from "react"; import { signOut, useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { Company, MetricsResult, WordCloudWord } from "../../../lib/types"; +import { formatEnumValue } from "@/lib/format-enums"; import MetricCard from "../../../components/ui/metric-card"; import ModernLineChart from "../../../components/charts/line-chart"; import ModernBarChart from "../../../components/charts/bar-chart"; @@ -259,10 +260,13 @@ function DashboardContent() { const getCategoriesData = () => { if (!metrics?.categories) return []; - return Object.entries(metrics.categories).map(([name, value]) => ({ - name: name.length > 15 ? name.substring(0, 15) + "..." : name, - value: value as number, - })); + return Object.entries(metrics.categories).map(([name, value]) => { + const formattedName = formatEnumValue(name) || name; + return { + name: formattedName.length > 15 ? formattedName.substring(0, 15) + "..." : formattedName, + value: value as number, + }; + }); }; const getLanguagesData = () => { diff --git a/app/dashboard/sessions/[id]/page.tsx b/app/dashboard/sessions/[id]/page.tsx index a24742c..4f93a07 100644 --- a/app/dashboard/sessions/[id]/page.tsx +++ b/app/dashboard/sessions/[id]/page.tsx @@ -7,6 +7,7 @@ import SessionDetails from "../../../../components/SessionDetails"; import TranscriptViewer from "../../../../components/TranscriptViewer"; import MessageViewer from "../../../../components/MessageViewer"; import { ChatSession } from "../../../../lib/types"; +import { formatCategory } from "@/lib/format-enums"; import Link from "next/link"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; @@ -181,10 +182,10 @@ export default function SessionViewPage() {
- {session.category && session.category !== 'UNRECOGNIZED_OTHER' && session.category !== 'ACCESS_LOGIN' && ( + {session.category && ( - {session.category.replace(/_/g, ' ').toLowerCase().replace(/\b\w/g, l => l.toUpperCase())} + {formatCategory(session.category)} )} {session.language && ( diff --git a/app/dashboard/sessions/page.tsx b/app/dashboard/sessions/page.tsx index 0f88934..731d4e4 100644 --- a/app/dashboard/sessions/page.tsx +++ b/app/dashboard/sessions/page.tsx @@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; +import { formatCategory } from "@/lib/format-enums"; import { MessageSquare, Search, @@ -223,7 +224,7 @@ export default function SessionsPage() { {filterOptions.categories.map((cat) => ( ))} @@ -377,69 +378,81 @@ export default function SessionsPage() { )} - {/* Sessions List */} - {!loading && !error && sessions.length > 0 && ( -
- {sessions.map((session) => ( - - -
-
-
- - ID - - - {session.sessionId || session.id} - -
-
- - - {new Date(session.startTime).toLocaleDateString()} - - - {new Date(session.startTime).toLocaleTimeString()} - -
-
- - - -
+ {/* Sessions List */} + {!loading && !error && sessions.length > 0 && ( +
    + {sessions.map((session) => ( +
  • + + +
    +
    +
    +

    + Session {session.sessionId || session.id} from {new Date(session.startTime).toLocaleDateString()} +

    +
    + + ID + + + {session.sessionId || session.id} + +
    +
    + + + + {new Date(session.startTime).toLocaleTimeString()} + +
    +
    + + + +
    -
    - {session.category && session.category !== 'UNRECOGNIZED_OTHER' && session.category !== 'ACCESS_LOGIN' && ( - - - {session.category.replace(/_/g, ' ').toLowerCase().replace(/\b\w/g, l => l.toUpperCase())} - - )} - {session.language && ( - - - {session.language.toUpperCase()} - - )} -
    +
    + {session.category && ( + + + )} + {session.language && ( + + + )} +
    - {session.summary ? ( -

    - {session.summary} -

    - ) : session.initialMsg ? ( -

    - {session.initialMsg} -

    - ) : null} - - - ))} -
- )} + {session.summary ? ( +

+ {session.summary} +

+ ) : session.initialMsg ? ( +

+ {session.initialMsg} +

+ ) : null} + + + + + ))} + + )} {/* Pagination */} {totalPages > 0 && ( diff --git a/app/globals.css b/app/globals.css index 9b62b83..936cc22 100644 --- a/app/globals.css +++ b/app/globals.css @@ -105,13 +105,13 @@ --secondary: oklch(0.97 0 0); --secondary-foreground: oklch(0.205 0 0); --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); + --muted-foreground: oklch(0.45 0 0); --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); + --accent-foreground: oklch(0.15 0 0); + --destructive: oklch(0.55 0.245 27.325); + --border: oklch(0.85 0 0); + --input: oklch(0.85 0 0); + --ring: oklch(0.6 0 0); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); --chart-3: oklch(0.398 0.07 227.392); @@ -139,13 +139,13 @@ --secondary: oklch(0.269 0 0); --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.65 0 0); + --muted-foreground: oklch(0.75 0 0); --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 15%); - --input: oklch(1 0 0 / 20%); - --ring: oklch(0.556 0 0); + --destructive: oklch(0.75 0.191 22.216); + --border: oklch(1 0 0 / 25%); + --input: oklch(1 0 0 / 30%); + --ring: oklch(0.75 0 0); --chart-1: oklch(0.488 0.243 264.376); --chart-2: oklch(0.696 0.17 162.48); --chart-3: oklch(0.769 0.188 70.08); diff --git a/components/SessionDetails.tsx b/components/SessionDetails.tsx index 103add5..e54878a 100644 --- a/components/SessionDetails.tsx +++ b/components/SessionDetails.tsx @@ -3,6 +3,7 @@ import { ChatSession } from "../lib/types"; import LanguageDisplay from "./LanguageDisplay"; import CountryDisplay from "./CountryDisplay"; +import { formatCategory } from "@/lib/format-enums"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Separator } from "@/components/ui/separator"; @@ -16,13 +17,7 @@ interface SessionDetailsProps { * Component to display session details with formatted country and language names */ export default function SessionDetails({ session }: SessionDetailsProps) { - // Helper function to format category names - const formatCategory = (category: string) => { - if (category === 'UNRECOGNIZED_OTHER' || category === 'ACCESS_LOGIN') { - return null; // Don't show these internal enum values - } - return category.replace(/_/g, ' ').toLowerCase().replace(/\b\w/g, l => l.toUpperCase()); - }; + // Using centralized formatCategory utility return ( @@ -55,7 +50,7 @@ export default function SessionDetails({ session }: SessionDetailsProps) {
)} - {session.category && formatCategory(session.category) && ( + {session.category && (

Category

diff --git a/lib/format-enums.ts b/lib/format-enums.ts new file mode 100644 index 0000000..d901a92 --- /dev/null +++ b/lib/format-enums.ts @@ -0,0 +1,69 @@ +/** + * Utility functions for formatting database enums into user-friendly text + */ + +// Custom mappings for specific enum values that need special formatting +const ENUM_MAPPINGS: Record = { + // HR/Employment related + 'SALARY_COMPENSATION': 'Salary & Compensation', + 'CONTRACT_HOURS': 'Contract & Hours', + 'SCHEDULE_HOURS': 'Schedule & Hours', + 'LEAVE_VACATION': 'Leave & Vacation', + 'SICK_LEAVE_RECOVERY': 'Sick Leave & Recovery', + 'WORKWEAR_STAFF_PASS': 'Workwear & Staff Pass', + 'TEAM_CONTACTS': 'Team & Contacts', + 'PERSONAL_QUESTIONS': 'Personal Questions', + 'PERSONALQUESTIONS': 'Personal Questions', + + // Process related + 'ONBOARDING': 'Onboarding', + 'OFFBOARDING': 'Offboarding', + + // Access related + 'ACCESS_LOGIN': 'Access & Login', + + // Technical/Other + 'UNRECOGNIZED_OTHER': 'General Inquiry', + + // Add more mappings as needed +}; + +/** + * Formats a database enum value into user-friendly text + * @param enumValue - The raw enum value from the database + * @returns Formatted string or null if input is empty + */ +export function formatEnumValue(enumValue: string | null | undefined): string | null { + if (!enumValue) return null; + + // Check for custom mapping first + if (ENUM_MAPPINGS[enumValue]) { + return ENUM_MAPPINGS[enumValue]; + } + + // Fallback: convert snake_case to Title Case + return enumValue + .replace(/_/g, ' ') + .toLowerCase() + .replace(/\b\w/g, l => l.toUpperCase()); +} + +/** + * Formats a category enum specifically for display + * @param category - The category enum value + * @returns Formatted category name or null if empty + */ +export function formatCategory(category: string | null | undefined): string | null { + return formatEnumValue(category); +} + +/** + * Formats an array of enum values into user-friendly text + * @param enumValues - Array of enum values + * @returns Array of formatted values (filters out null/undefined) + */ +export function formatEnumArray(enumValues: (string | null | undefined)[]): string[] { + return enumValues + .map(value => formatEnumValue(value)) + .filter((value): value is string => Boolean(value)); +} \ No newline at end of file