From 216e871b221da8fb50f1023c2cf49f4287fb85d7 Mon Sep 17 00:00:00 2001 From: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:09:22 +0100 Subject: [PATCH] fix: improve empty screen for call history (#27231) * Improve empty screen * fix type error --------- Co-authored-by: CarinaWolli --- .../views/insights-call-history-view.tsx | 105 +++++++++++++++--- apps/web/public/static/locales/en/common.json | 3 +- 2 files changed, 89 insertions(+), 19 deletions(-) diff --git a/apps/web/modules/insights/views/insights-call-history-view.tsx b/apps/web/modules/insights/views/insights-call-history-view.tsx index f562a06741..9ab0644faf 100644 --- a/apps/web/modules/insights/views/insights-call-history-view.tsx +++ b/apps/web/modules/insights/views/insights-call-history-view.tsx @@ -1,6 +1,12 @@ "use client"; -import { getCoreRowModel, getSortedRowModel, useReactTable, type ColumnDef } from "@tanstack/react-table"; +import { + getCoreRowModel, + getSortedRowModel, + useReactTable, + type ColumnDef, +} from "@tanstack/react-table"; +import Link from "next/link"; import { usePathname } from "next/navigation"; import { useMemo, useState, useReducer } from "react"; @@ -10,15 +16,23 @@ import { convertFacetedValuesToMap, useDataTable, } from "@calcom/features/data-table"; -import { DataTableWrapper, DataTableToolbar, DataTableFilters } from "~/data-table/components"; +import { + DataTableWrapper, + DataTableToolbar, + DataTableFilters, +} from "~/data-table/components"; import { useSegments } from "@calcom/features/data-table/hooks/useSegments"; import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider"; -import type { CallDetailsState, CallDetailsAction } from "@calcom/features/ee/workflows/lib/types"; +import type { + CallDetailsState, + CallDetailsAction, +} from "@calcom/features/ee/workflows/lib/types"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import type { RouterOutputs } from "@calcom/trpc/react"; import { Badge } from "@calcom/ui/components/badge"; +import { Button } from "@calcom/ui/components/button"; import { EmptyScreen } from "@calcom/ui/components/empty-screen"; import { CallDetailsSheet } from "@calcom/web/modules/ee/workflows/components/CallDetailsSheet"; @@ -47,7 +61,10 @@ const initialState: CallDetailsState = { }, }; -function reducer(state: CallDetailsState, action: CallDetailsAction): CallDetailsState { +function reducer( + state: CallDetailsState, + action: CallDetailsAction +): CallDetailsState { switch (action.type) { case "OPEN_CALL_DETAILS": return { ...state, callDetailsSheet: action.payload }; @@ -65,7 +82,11 @@ function CallHistoryTable(props: CallHistoryProps) { const pathname = usePathname(); if (!pathname) return null; return ( - + ); @@ -95,20 +116,29 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { return callsData.calls.map((call) => ({ id: call.call_id || Math.random().toString(), - time: call.start_timestamp ? new Date(call.start_timestamp).toISOString() : new Date().toISOString(), + time: call.start_timestamp + ? new Date(call.start_timestamp).toISOString() + : new Date().toISOString(), duration: Math.round((call.duration_ms || 0) / 1000), - channelType: (call.call_type || "phone_call") as "web_call" | "phone_call", + channelType: (call.call_type || "phone_call") as + | "web_call" + | "phone_call", sessionId: call.call_id || t("unknown"), endReason: call.disconnection_reason || t("unknown"), sessionStatus: - call.call_status === "ended" ? "completed" : call.call_status === "ongoing" ? "ongoing" : "failed", + call.call_status === "ended" + ? "completed" + : call.call_status === "ongoing" + ? "ongoing" + : "failed", userSentiment: call.call_analysis?.user_sentiment?.toLowerCase() === "positive" ? "positive" : call.call_analysis?.user_sentiment?.toLowerCase() === "negative" ? "negative" : "neutral", - from: "from_number" in call ? call.from_number || t("unknown") : t("unknown"), + from: + "from_number" in call ? call.from_number || t("unknown") : t("unknown"), to: "to_number" in call ? call.to_number || t("unknown") : t("unknown"), callCreated: call.call_analysis?.call_successful ?? true, inVoicemail: call.call_analysis?.in_voicemail ?? false, @@ -141,7 +171,11 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { const seconds = row.original.duration; const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; - return {`${minutes}:${remainingSeconds.toString().padStart(2, "0")}`}; + return ( + {`${minutes}:${remainingSeconds + .toString() + .padStart(2, "0")}`} + ); }, }, { @@ -159,7 +193,9 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { accessorKey: "sessionId", header: t("session_id"), size: 210, - cell: ({ row }) => {row.original.sessionId}, + cell: ({ row }) => ( + {row.original.sessionId} + ), }, { id: "endReason", @@ -178,7 +214,12 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { }, cell: ({ row }) => { const status = row.original.sessionStatus; - const variant = status === "completed" ? "green" : status === "ongoing" ? "blue" : "red"; + const variant = + status === "completed" + ? "green" + : status === "ongoing" + ? "blue" + : "red"; return {status}; }, }, @@ -192,7 +233,12 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { }, cell: ({ row }) => { const sentiment = row.original.userSentiment; - const variant = sentiment === "positive" ? "green" : sentiment === "negative" ? "red" : "gray"; + const variant = + sentiment === "positive" + ? "green" + : sentiment === "negative" + ? "red" + : "gray"; return {sentiment}; }, }, @@ -216,7 +262,11 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { cell: ({ row }) => { const created = row.original.callCreated; const variant = created ? "green" : "red"; - return {created ? t("successful") : t("unsuccessful")}; + return ( + + {created ? t("successful") : t("unsuccessful")} + + ); }, }, { @@ -227,7 +277,9 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { cell: ({ row }) => { const inVoicemail = row.original.inVoicemail; const variant = inVoicemail ? "blue" : "gray"; - return {inVoicemail ? t("yes") : t("no")}; + return ( + {inVoicemail ? t("yes") : t("no")} + ); }, }, ], @@ -286,7 +338,9 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { paginationMode="standard" rowClassName="cursor-pointer hover:bg-subtle" onRowMouseclick={(row) => { - const callIndex = callHistoryData.findIndex((call) => call.id === row.original.id); + const callIndex = callHistoryData.findIndex( + (call) => call.id === row.original.id + ); if (callIndex !== -1 && callsData?.calls?.[callIndex]) { dispatch({ type: "OPEN_CALL_DETAILS", @@ -312,14 +366,29 @@ function CallHistoryContent({ org: _org }: CallHistoryProps) { EmptyView={ + + {t("create_first_workflow")} + + + ) + } /> } /> - {state.callDetailsSheet.showModal && } + {state.callDetailsSheet.showModal && ( + + )} ); } diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index d169cbef2b..4305e9cbe1 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -1016,7 +1016,8 @@ "new_team_event_type_description": "Event types enable the team to share links that show available times on their calendars and allow people to make bookings with the team.", "event_type_created_successfully": "{{eventTypeTitle}} event type created successfully", "no_call_history": "No call history", - "no_call_history_description": "No matching call history found for the particular account/search query.", + "no_call_history_description": "Create your first Cal.ai workflow and view your call history here.", + "create_first_workflow": "Create a Cal.ai workflow", "event_type_updated_successfully": "{{eventTypeTitle}} event type updated successfully", "event_type_deleted_successfully": "Event type deleted successfully", "hours": "Hours",