{"version":3,"sources":["../call-control-sdk/lib/pages/summaryReport/index.tsx","../call-control-sdk/lib/pages/summaryReport/useSummaryReport.ts","../call-control-sdk/lib/pages/summaryReport/ManagementSummaryView.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useState } from \"react\";\r\nimport {\r\n\tAlert, Box, CircularProgress, Tab, Tabs,\r\n} from \"@mui/material\";\r\nimport type { MRT_ColumnDef } from \"material-react-table\";\r\nimport DownloadIcon from \"@mui/icons-material/Download\";\r\nimport RefreshIcon from \"@mui/icons-material/Refresh\";\r\nimport dayjs, { Dayjs } from \"dayjs\";\r\nimport { LocalizationProvider } from \"@mui/x-date-pickers/LocalizationProvider\";\r\nimport { AdapterDayjs } from \"@mui/x-date-pickers/AdapterDayjs\";\r\n\r\nimport PageHeader from \"../common/components/PageHeader\";\r\nimport ReportFilterBar, { type DidOption, type QuickRange } from \"../common/components/ReportFilterBar\";\r\nimport AppButton from \"../common/components/AppButton\";\r\nimport AppTable from \"../common/components/AppTable\";\r\nimport { headCellSx } from \"../common/utils/tableStyles\";\r\nimport { SDKProvider } from \"../../components/SDKProvider\";\r\nimport { useSDKPermissions } from \"../../hooks/useSDKPermissions\";\r\nimport { SDK_PERMISSIONS } from \"../../permissions\";\r\nimport { useGetAuthorizationToken } from \"../../hooks/useGetAuthorizationToken\";\r\nimport { getCdrFilterDids } from \"../cdrReport/useCdrReport\";\r\nimport { exportSummaryReportToExcel, getSummaryReport } from \"./useSummaryReport\";\r\nimport type { SummaryReportParams, SummaryReportRow, SummaryReportType } from \"./types\";\r\nimport ManagementSummaryView from \"./ManagementSummaryView\";\r\n\r\n/* ═══════════════════════ TABS ═══════════════════════ */\r\n\r\n/* Each tab has its own read/export pair: the tab shows only with `read`, and the\r\n   Export button only with that tab's `export`. */\r\nconst REPORT_TABS: { type: SummaryReportType; label: string; read: string; export: string }[] = [\r\n\t{ type: \"hourly\", label: \"Hourly Summary\", read: SDK_PERMISSIONS.REPORTS_HOURLY_SUMMARY_READ, export: SDK_PERMISSIONS.REPORTS_HOURLY_SUMMARY_EXPORT },\r\n\t{ type: \"daily\", label: \"Daily Summary\", read: SDK_PERMISSIONS.REPORTS_DAILY_SUMMARY_READ, export: SDK_PERMISSIONS.REPORTS_DAILY_SUMMARY_EXPORT },\r\n\t{ type: \"did\", label: \"DID Summary\", read: SDK_PERMISSIONS.REPORTS_DID_SUMMARY_READ, export: SDK_PERMISSIONS.REPORTS_DID_SUMMARY_EXPORT },\r\n\t{ type: \"management\", label: \"Management Summary\", read: SDK_PERMISSIONS.REPORTS_MANAGEMENT_SUMMARY_READ, export: SDK_PERMISSIONS.REPORTS_MANAGEMENT_SUMMARY_EXPORT },\r\n];\r\n\r\n/* ═══════════════════════ STYLES (match the CDR report) ═══════════════════════ */\r\n\r\nconst FONT = \"'Inter', 'Segoe UI', 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif\";\r\n\r\nconst COLORS = {\r\n\tnavy: \"#0d2a56\",\r\n\tblue: \"#1565c8\",\r\n\tgreen: \"#0a9a62\",\r\n\tamber: \"#c47c00\",\r\n\tred: \"#cc2a2a\",\r\n} as const;\r\n\r\nconst tabsSx = {\r\n\tminHeight: 36,\r\n\tpx: 1,\r\n\tborderBottom: \"1px solid #eef1f6\",\r\n\t\"& .MuiTab-root\": {\r\n\t\ttextTransform: \"none\", fontWeight: 600, fontSize: \"0.78rem\", fontFamily: FONT,\r\n\t\tminHeight: 36, py: 0, px: 1.5, color: \"#4a5568\",\r\n\t},\r\n\t\"& .Mui-selected\": { color: \"#1A5F6C !important\" },\r\n\t\"& .MuiTabs-indicator\": { backgroundColor: \"#1A5F6C\", height: 2, borderRadius: \"2px 2px 0 0\" },\r\n};\r\n\r\nconst tabularSx = { fontSize: \"0.75rem\", fontVariantNumeric: \"tabular-nums\" };\r\n\r\n/* Per-column body styling, same palette the CDR report uses for its numbers and durations. */\r\nfunction cellSxFor(key: string, kind: ColumnKind): Record<string, unknown> {\r\n\tif (kind === \"text\") return { fontSize: \"0.73rem\", color: \"#4a5568\" };\r\n\tif (kind === \"count\") {\r\n\t\treturn { ...tabularSx, fontWeight: 600, color: key.includes(\"abandoned\") || key.includes(\"unanswered\") ? COLORS.red : COLORS.navy };\r\n\t}\r\n\tif (kind === \"pct\") {\r\n\t\treturn { ...tabularSx, fontWeight: 600, color: key.includes(\"answered\") ? COLORS.green : COLORS.navy };\r\n\t}\r\n\t// durations: talk in blue, waiting in amber (the CDR report's talk / hold colours)\r\n\tif (key.includes(\"talk\")) return { ...tabularSx, fontWeight: 600, color: COLORS.blue };\r\n\tif (key.includes(\"wait\")) return { ...tabularSx, fontWeight: 500, color: COLORS.amber };\r\n\treturn { ...tabularSx, fontWeight: 500 };\r\n}\r\n\r\n/* ═══════════════════════ COLUMNS ═══════════════════════ */\r\n\r\ntype ColumnKind = \"text\" | \"count\" | \"pct\" | \"duration\";\r\n\r\ninterface ColumnSpec {\r\n\tkey: string;\r\n\tlabel: string;\r\n\tkind: ColumnKind;\r\n\t/** Two-row header: consecutive columns with the same group sit under one top header. */\r\n\tgroup?: \"Overview\" | \"Inbound\" | \"Outbound\";\r\n}\r\n\r\n/* Known columns in display order. Only the ones present in the response are shown,\r\n   so the daily and DID reports (which group by date / DID instead of hour) reuse\r\n   this list; any key the API adds that isn't listed is appended at the end. */\r\nconst KNOWN_COLUMNS: ColumnSpec[] = [\r\n\t// Overview: what the row is (date / hour / DID) and its call count, under one top header.\r\n\t{ key: \"date\", label: \"Date\", kind: \"text\", group: \"Overview\" },\r\n\t{ key: \"hour_label\", label: \"Hour\", kind: \"text\", group: \"Overview\" },\r\n\t{ key: \"did\", label: \"DID\", kind: \"text\", group: \"Overview\" },\r\n\t{ key: \"did_number\", label: \"DID\", kind: \"text\", group: \"Overview\" },\r\n\t{ key: \"friendly_name\", label: \"DID Name\", kind: \"text\", group: \"Overview\" },\r\n\t{ key: \"total_calls\", label: \"Total Calls\", kind: \"count\", group: \"Overview\" },\r\n\t// DID report: its answered / abandoned counts are inbound, so they head the Inbound group\r\n\t// (followed by queue_abandoned / ivr_abandoned below).\r\n\t{ key: \"answered_calls\", label: \"Answered\", kind: \"count\", group: \"Inbound\" },\r\n\t{ key: \"abandoned_calls\", label: \"Abandoned\", kind: \"count\", group: \"Inbound\" },\r\n\t// Inbound / Outbound: labels are short because the group header names the direction.\r\n\t{ key: \"inbound_answered\", label: \"Answered\", kind: \"count\", group: \"Inbound\" },\r\n\t{ key: \"inbound_abandoned\", label: \"Abandoned\", kind: \"count\", group: \"Inbound\" },\r\n\t{ key: \"queue_abandoned\", label: \"Queue Abandoned\", kind: \"count\", group: \"Inbound\" },\r\n\t{ key: \"ivr_abandoned\", label: \"IVR Abandoned\", kind: \"count\", group: \"Inbound\" },\r\n\t{ key: \"inbound_answered_pct\", label: \"Answered %\", kind: \"pct\", group: \"Inbound\" },\r\n\t{ key: \"outbound_answered\", label: \"Answered\", kind: \"count\", group: \"Outbound\" },\r\n\t{ key: \"outbound_unanswered\", label: \"Unanswered\", kind: \"count\", group: \"Outbound\" },\r\n\t{ key: \"outbound_answered_pct\", label: \"Answered %\", kind: \"pct\", group: \"Outbound\" },\r\n\t{ key: \"unique_callers\", label: \"Unique Callers\", kind: \"count\" },\r\n\t{ key: \"agents_count\", label: \"Agents\", kind: \"count\" },\r\n\t{ key: \"avg_queue_wait\", label: \"Avg Queue Wait\", kind: \"duration\" },\r\n\t{ key: \"avg_talk\", label: \"Avg Talk\", kind: \"duration\" },\r\n\t{ key: \"total_talk\", label: \"Total Talk\", kind: \"duration\" },\r\n];\r\n\r\n/** Keys the API sends that the table deliberately leaves out. */\r\nconst HIDDEN_KEYS = [\"inbound_total\", \"outbound_total\"];\r\n\r\nconst humanize = (key: string) =>\r\n\tkey.replace(/_/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase()).replace(/\\bPct\\b/, \"%\");\r\n\r\nfunction buildColumnSpecs(rows: SummaryReportRow[]): ColumnSpec[] {\r\n\tconst present = new Set<string>();\r\n\trows.forEach((r) => Object.keys(r).forEach((k) => present.add(k)));\r\n\t// `hour` is only the sort key behind `hour_label`; show it only when the label is missing.\r\n\t// Inbound / Outbound totals are not shown (Outbound → Unanswered is still derived from one).\r\n\tconst hidden = new Set([...HIDDEN_KEYS, ...(present.has(\"hour_label\") ? [\"hour\"] : [])]);\r\n\tconst known = KNOWN_COLUMNS.filter((c) => present.has(c.key));\r\n\tconst knownKeys = new Set(KNOWN_COLUMNS.map((c) => c.key));\r\n\tconst extra: ColumnSpec[] = [...present]\r\n\t\t.filter((k) => !knownKeys.has(k) && !hidden.has(k))\r\n\t\t.map((k) => ({\r\n\t\t\tkey: k,\r\n\t\t\tlabel: humanize(k),\r\n\t\t\tkind: typeof rows.find((r) => r[k] != null)?.[k] === \"number\" ? \"count\" : \"text\",\r\n\t\t}));\r\n\treturn [...known, ...extra];\r\n}\r\n\r\nconst num = (v: unknown) => (typeof v === \"number\" ? v : Number(v) || 0);\r\n\r\n/* Counts the API leaves out, derived from the ones it sends (an API-supplied value wins):\r\n   - Inbound → Abandoned: queue + IVR abandons, which the API only sends split.\r\n   - Outbound → Unanswered: outbound total − outbound answered. */\r\nfunction withDerivedCounts(r: SummaryReportRow): SummaryReportRow {\r\n\tconst out = { ...r };\r\n\t// DID rows already carry the combined count as `abandoned_calls` — don't add a duplicate.\r\n\tif (out.inbound_abandoned == null && r.abandoned_calls == null && (r.queue_abandoned != null || r.ivr_abandoned != null)) {\r\n\t\tout.inbound_abandoned = num(r.queue_abandoned) + num(r.ivr_abandoned);\r\n\t}\r\n\tif (out.outbound_unanswered == null && r.outbound_total != null) {\r\n\t\tout.outbound_unanswered = Math.max(0, num(r.outbound_total) - num(r.outbound_answered));\r\n\t}\r\n\treturn out;\r\n}\r\n\r\nfunction formatCell(value: unknown, kind: ColumnKind): string {\r\n\tif (value === null || value === undefined || value === \"\") return kind === \"text\" ? \"-\" : \"\";\r\n\tif (kind === \"pct\") return `${num(value).toFixed(2)}%`;\r\n\tif (kind === \"count\") return num(value).toLocaleString();\r\n\treturn String(value);\r\n}\r\n\r\n/* Cell chrome — the CDR report's table: Inter 0.75rem, #eef1f6 row rules, roomier rows.\r\n   The `&&` keeps this padding ahead of MUI's default cell padding. */\r\nconst cellBaseSx = {\r\n\tfontFamily: FONT,\r\n\tfontSize: \"0.75rem\",\r\n\tborderBottom: \"1px solid #eef1f6\",\r\n\twhiteSpace: \"nowrap\",\r\n\t\"&&\": { px: 1.5, py: 1.25 },\r\n};\r\n/* Header cells: 13px semibold, compact, vertically centred (MRT defaults to top), centred text. */\r\nconst HEAD_RULE = \"1px solid #dfe5ee\";\r\nconst headSx = {\r\n\t...(headCellSx as object),\r\n\t...cellBaseSx,\r\n\tfontSize: \"13px\",\r\n\tverticalAlign: \"middle\",\r\n\ttextAlign: \"center\",\r\n\tborderBottom: HEAD_RULE,\r\n\t\"& .Mui-TableHeadCell-Content\": { justifyContent: \"center\" },\r\n\t// Header rows stay compact; only the body rows get the roomier padding.\r\n\t\"&&\": { px: 1.5, py: 0.6 },\r\n};\r\n/* Top-row group header (Overview / Inbound / Outbound): a slightly darker band, boxed by side rules\r\n   that continue down through its sub-headers and data (see GROUP_EDGE below). */\r\nconst groupHeadSx = {\r\n\t...headSx,\r\n\tbackgroundColor: \"#e6ecf2\",\r\n\tcolor: \"#1A5F6C\",\r\n\tfontWeight: 700,\r\n\tletterSpacing: 0.3,\r\n\tborderLeft: HEAD_RULE,\r\n\tborderRight: HEAD_RULE,\r\n};\r\nconst GROUP_EDGE = { first: { borderLeft: HEAD_RULE }, last: { borderRight: HEAD_RULE } };\r\n\r\nconst PAGE_SIZE_OPTIONS = [10, 15, 25, 50, 100];\r\nconst DEFAULT_PAGE_SIZE = 25;\r\n\r\n/* ═══════════════════════ MAIN CONTENT ═══════════════════════ */\r\n\r\nfunction SummaryReportContent() {\r\n\t// SDK initialization completes after this route can mount — wait for the token\r\n\t// so the first request goes out authenticated.\r\n\tconst authorizationToken = useGetAuthorizationToken();\r\n\r\n\tconst { hasPermission } = useSDKPermissions();\r\n\r\n\tconst [reportType, setReportType] = useState<SummaryReportType>(\"hourly\");\r\n\r\n\tconst visibleTabs = REPORT_TABS.filter((t) => hasPermission(t.read));\r\n\tconst activeTab = visibleTabs.find((t) => t.type === reportType);\r\n\tconst canExport = !!activeTab && hasPermission(activeTab.export);\r\n\r\n\t// Land on the first tab this login may read (permissions can arrive after mount).\r\n\tuseEffect(() => {\r\n\t\tif (!activeTab && visibleTabs.length > 0) setReportType(visibleTabs[0].type);\r\n\t}, [activeTab, visibleTabs]);\r\n\tconst [startDate, setStartDate] = useState<Dayjs | null>(dayjs().startOf(\"day\"));\r\n\tconst [endDate, setEndDate] = useState<Dayjs | null>(dayjs());\r\n\tconst [quickRange, setQuickRange] = useState(\"today\");\r\n\r\n\tconst [dids, setDids] = useState<DidOption[]>([]);\r\n\t/** DID Summary only — the one tab with a DID filter (none = all). */\r\n\tconst [selectedDids, setSelectedDids] = useState<DidOption[]>([]);\r\n\r\n\tconst [rows, setRows] = useState<SummaryReportRow[]>([]);\r\n\t/** Server-side pagination: the API pages the rows and reports the full count. */\r\n\tconst [pagination, setPagination] = useState({ pageIndex: 0, pageSize: DEFAULT_PAGE_SIZE });\r\n\tconst [total, setTotal] = useState(0);\r\n\tconst [loading, setLoading] = useState(false);\r\n\tconst [exporting, setExporting] = useState(false);\r\n\tconst [error, setError] = useState(\"\");\r\n\r\n\tuseEffect(() => {\r\n\t\tif (!authorizationToken) return;\r\n\t\tgetCdrFilterDids().then((data) => setDids(data || [])).catch(() => {});\r\n\t}, [authorizationToken]);\r\n\r\n\tconst buildParams = useCallback((): SummaryReportParams => {\r\n\t\tconst params: SummaryReportParams = { report_type: reportType };\r\n\t\tif (startDate) params.start_date = startDate.format(\"YYYY-MM-DDTHH:mm:ss\");\r\n\t\tif (endDate) params.end_date = endDate.format(\"YYYY-MM-DDTHH:mm:ss\");\r\n\t\t// All DIDs selected is the same as none — let the API default to every DID.\r\n\t\tif (reportType === \"did\" && selectedDids.length > 0 && selectedDids.length < dids.length) {\r\n\t\t\tparams.dids = selectedDids.map((d) => d.didNumber);\r\n\t\t}\r\n\t\treturn params;\r\n\t}, [reportType, startDate, endDate, selectedDids, dids.length]);\r\n\r\n\t/* Any filter change goes back to page 1, set in the same update as the filter so the\r\n\t   report is fetched once, not once for the stale page and again for page 1. */\r\n\tconst resetPage = () => setPagination((p) => (p.pageIndex === 0 ? p : { ...p, pageIndex: 0 }));\r\n\tconst handleStartChange = (v: Dayjs | null) => { setStartDate(v); resetPage(); };\r\n\tconst handleEndChange = (v: Dayjs | null) => { setEndDate(v); resetPage(); };\r\n\tconst handleDidsChange = (v: DidOption[]) => { setSelectedDids(v); resetPage(); };\r\n\r\n\tconst fetchReport = useCallback(async () => {\r\n\t\tif (!authorizationToken) return;\r\n\t\t// Never request a report this login can't read.\r\n\t\tif (!activeTab) {\r\n\t\t\tsetRows([]);\r\n\t\t\tsetTotal(0);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (startDate && endDate && startDate.isAfter(endDate)) {\r\n\t\t\tsetError(\"Start date must be before end date\");\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tsetLoading(true);\r\n\t\tsetError(\"\");\r\n\t\ttry {\r\n\t\t\tconst res = await getSummaryReport({\r\n\t\t\t\t...buildParams(),\r\n\t\t\t\tpage: pagination.pageIndex + 1,\r\n\t\t\t\tpageSize: pagination.pageSize,\r\n\t\t\t});\r\n\t\t\tsetRows(res.data.map(withDerivedCounts));\r\n\t\t\tsetTotal(res.total);\r\n\t\t} catch (err: any) {\r\n\t\t\tsetRows([]);\r\n\t\t\tsetTotal(0);\r\n\t\t\tsetError(err?.response?.data?.detail || err?.message || \"Failed to fetch summary reports\");\r\n\t\t} finally {\r\n\t\t\tsetLoading(false);\r\n\t\t}\r\n\t}, [authorizationToken, activeTab, buildParams, pagination, startDate, endDate]);\r\n\r\n\tuseEffect(() => { fetchReport(); }, [fetchReport]);\r\n\r\n\t/* Each tab starts fresh on Today — the previous tab's date range and DID picks don't\r\n\t   carry over. Batched with the tab change, so it's a single fetch. */\r\n\tconst handleTabChange = (type: SummaryReportType) => {\r\n\t\tif (type === reportType) return;\r\n\t\tsetReportType(type);\r\n\t\tsetStartDate(dayjs().startOf(\"day\"));\r\n\t\tsetEndDate(dayjs());\r\n\t\tsetQuickRange(\"today\");\r\n\t\tsetSelectedDids([]);\r\n\t\tresetPage();\r\n\t};\r\n\r\n\tconst handleExport = async () => {\r\n\t\tsetExporting(true);\r\n\t\ttry {\r\n\t\t\tawait exportSummaryReportToExcel(buildParams());\r\n\t\t} catch {\r\n\t\t\tsetError(\"Failed to export summary reports\");\r\n\t\t} finally {\r\n\t\t\tsetExporting(false);\r\n\t\t}\r\n\t};\r\n\r\n\tconst specs = useMemo(() => buildColumnSpecs(rows), [rows]);\r\n\r\n\t/* Headers and values all centred, one alignment for every column — mixed left/right\r\n\t   alignment in the wide semantic-layout columns left headers and values visibly apart.\r\n\t   Column-level cell props replace the table-level ones in MRT, so each column carries the full sx. */\r\n\tconst columns = useMemo<MRT_ColumnDef<SummaryReportRow>[]>(() => {\r\n\t\t/** `edge` draws the group box's side rule on a group's first / last column. */\r\n\t\tconst leaf = (c: ColumnSpec, edge: object = {}, hideHead = false): MRT_ColumnDef<SummaryReportRow> => ({\r\n\t\t\tid: c.key,\r\n\t\t\theader: c.label,\r\n\t\t\taccessorFn: (r) => r[c.key] as any,\r\n\t\t\tCell: ({ row }) => formatCell(row.original[c.key], c.kind),\r\n\t\t\t// `align: \"center\"` (not just textAlign) so MRT also centres the header's label box —\r\n\t\t\t// header and values then share one centre line.\r\n\t\t\tmuiTableHeadCellProps: {\r\n\t\t\t\talign: \"center\",\r\n\t\t\t\tsx: hideHead ? { display: \"none\" } : { ...headSx, ...edge },\r\n\t\t\t},\r\n\t\t\tmuiTableBodyCellProps: { align: \"center\", sx: { ...cellBaseSx, ...cellSxFor(c.key, c.kind), textAlign: \"center\", ...edge } },\r\n\t\t});\r\n\r\n\t\t/* Split into runs: consecutive columns sharing a group, or a single ungrouped column. */\r\n\t\tconst runs: { group?: string; specs: ColumnSpec[] }[] = [];\r\n\t\tfor (const c of specs) {\r\n\t\t\tconst last = runs[runs.length - 1];\r\n\t\t\tif (c.group && last?.group === c.group) last.specs.push(c);\r\n\t\t\telse runs.push({ group: c.group, specs: [c] });\r\n\t\t}\r\n\t\tconst hasGroups = runs.some((r) => r.group);\r\n\r\n\t\treturn runs.map((run): MRT_ColumnDef<SummaryReportRow> => {\r\n\t\t\tif (run.group) {\r\n\t\t\t\t// \"Inbound\" over Answered / Abandoned / …: boxed from header to last row.\r\n\t\t\t\tconst n = run.specs.length;\r\n\t\t\t\treturn {\r\n\t\t\t\t\tid: `group_${run.group}`,\r\n\t\t\t\t\theader: run.group,\r\n\t\t\t\t\tcolumns: run.specs.map((c, i) =>\r\n\t\t\t\t\t\tleaf(c, { ...(i === 0 && GROUP_EDGE.first), ...(i === n - 1 && GROUP_EDGE.last) })),\r\n\t\t\t\t\tmuiTableHeadCellProps: { align: \"center\", sx: groupHeadSx },\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tconst c = run.specs[0];\r\n\t\t\tif (!hasGroups) return leaf(c);\r\n\t\t\t/* Ungrouped column in a two-row header: its label cell spans both rows (rowSpan 2 on\r\n\t\t\t   the top-row cell) and the bottom-row cell is dropped, so \"Hour\" / \"Total Calls\" sit\r\n\t\t\t   vertically centred instead of under an empty placeholder. */\r\n\t\t\treturn {\r\n\t\t\t\tid: `span_${c.key}`,\r\n\t\t\t\theader: c.label,\r\n\t\t\t\tcolumns: [leaf(c, {}, true)],\r\n\t\t\t\tmuiTableHeadCellProps: { align: \"center\", rowSpan: 2, sx: headSx },\r\n\t\t\t};\r\n\t\t});\r\n\t}, [specs]);\r\n\r\n\t/* MRT keeps its column-order state from the first column set it saw, so switching tabs\r\n\t   (hourly → DID) would reshuffle the new columns. Remount the table whenever the set changes. */\r\n\tconst columnSetKey = useMemo(() => specs.map((c) => c.key).join(\"|\"), [specs]);\r\n\r\n\treturn (\r\n\t\t<LocalizationProvider dateAdapter={AdapterDayjs}>\r\n\t\t\t<Box sx={{ height: \"100%\", display: \"flex\", flexDirection: \"column\", fontFamily: FONT }}>\r\n\t\t\t\t<PageHeader\r\n\t\t\t\t\ttitle=\"Summary Reports\"\r\n\t\t\t\t\tactions={\r\n\t\t\t\t\t\tcanExport && (\r\n\t\t\t\t\t\t\t<AppButton\r\n\t\t\t\t\t\t\t\tstartIcon={exporting ? <CircularProgress size={14} sx={{ color: \"#fff\" }} /> : <DownloadIcon sx={{ fontSize: \"0.95rem !important\" }} />}\r\n\t\t\t\t\t\t\t\tdisabled={exporting || loading || rows.length === 0}\r\n\t\t\t\t\t\t\t\tonClick={handleExport}\r\n\t\t\t\t\t\t\t\tsx={{ height: 36 }}\r\n\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\tExport Excel\r\n\t\t\t\t\t\t\t</AppButton>\r\n\t\t\t\t\t\t)\r\n\t\t\t\t\t}\r\n\t\t\t\t/>\r\n\t\t\r\n\t\t\t\t<Box sx={{ flex: 1, overflow: \"auto\", py: 0.8, px: 0 }}>\r\n\t\t\t\t\t<Box sx={{ mb: 0.8 }}>\r\n\t\t\t\t\t\t<Tabs value={activeTab ? reportType : false} onChange={(_, v: SummaryReportType) => handleTabChange(v)} sx={tabsSx}>\r\n\t\t\t\t\t\t\t{visibleTabs.map((t) => (\r\n\t\t\t\t\t\t\t\t<Tab key={t.type} value={t.type} label={t.label} />\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t</Tabs>\r\n\t\t\r\n\t\t\t\t\t\t<ReportFilterBar\r\n\t\t\t\t\t\t\tstartDate={startDate}\r\n\t\t\t\t\t\t\tendDate={endDate}\r\n\t\t\t\t\t\t\tonStartChange={handleStartChange}\r\n\t\t\t\t\t\t\tonEndChange={handleEndChange}\r\n\t\t\t\t\t\t\tquickRange={quickRange}\r\n\t\t\t\t\t\t\tonQuickRangeChange={(r: QuickRange) => setQuickRange(r)}\r\n\t\t\t\t\t\t\tshowDidSelect={reportType === \"did\"}\r\n\t\t\t\t\t\t\tdids={dids}\r\n\t\t\t\t\t\t\tselectedDids={selectedDids}\r\n\t\t\t\t\t\t\tonDidsChange={handleDidsChange}\r\n\t\t\t\t\t\t\textra={\r\n\t\t\t\t\t\t\t\t<AppButton\r\n\t\t\t\t\t\t\t\t\tstartIcon={<RefreshIcon sx={{ fontSize: \"0.9rem !important\" }} />}\r\n\t\t\t\t\t\t\t\t\tdisabled={loading}\r\n\t\t\t\t\t\t\t\t\tonClick={fetchReport}\r\n\t\t\t\t\t\t\t\t\tsx={{ height: 32 }}\r\n\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\tRefresh\r\n\t\t\t\t\t\t\t\t</AppButton>\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t/>\r\n\t\t\r\n\t\t\t\t\t\t{error && (\r\n\t\t\t\t\t\t\t<Alert severity=\"error\" sx={{ mt: 1, fontFamily: FONT, fontSize: \"0.78rem\" }} onClose={() => setError(\"\")}>\r\n\t\t\t\t\t\t\t\t{error}\r\n\t\t\t\t\t\t\t</Alert>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t</Box>\r\n\t\t\r\n\t\t\t\t\t{reportType === \"management\" ? (\r\n\t\t\t\t\t\t<ManagementSummaryView rows={rows} loading={loading} />\r\n\t\t\t\t\t) : (\r\n\t\t\t\t\t<AppTable\r\n\t\t\t\t\t\tkey={columnSetKey}\r\n\t\t\t\t\t\tcolumns={columns}\r\n\t\t\t\t\t\tdata={rows}\r\n\t\t\t\t\t\tlayoutMode=\"semantic\"\r\n\t\t\t\t\t\tenableTopToolbar={false}\r\n\t\t\t\t\t\tenableColumnActions={false}\r\n\t\t\t\t\t\t// Plain headers: no sorting and no per-column filter (funnel) icons — rows stay\r\n\t\t\t\t\t\t// in the order the API returns them.\r\n\t\t\t\t\t\tenableColumnFilters={false}\r\n\t\t\t\t\t\tenableSorting={false}\r\n\t\t\t\t\t\tenableColumnDragging={false}\r\n\t\t\t\t\t\tenableHiding={false}\r\n\t\t\t\t\t\tenableDensityToggle={false}\r\n\t\t\t\t\t\tenableFullScreenToggle={false}\r\n\t\t\t\t\t\tenableStickyHeader\r\n\t\t\t\t\t\t// Server-side pagination — the API returns one page plus the total row count.\r\n\t\t\t\t\t\tmanualPagination\r\n\t\t\t\t\t\trowCount={total}\r\n\t\t\t\t\t\tonPaginationChange={setPagination}\r\n\t\t\t\t\t\tmuiPaginationProps={{ rowsPerPageOptions: PAGE_SIZE_OPTIONS }}\r\n\t\t\t\t\t\tstate={{ pagination, isLoading: loading }}\r\n\t\t\t\t\t\tlocalization={{ noRecordsToDisplay: \"No data for the selected range\" } as any}\r\n\t\t\t\t\t\tmuiCircularProgressProps={{ sx: { color: COLORS.blue }, size: 28 }}\r\n\t\t\t\t\t\t// The CDR report table card: flat, 8px radius, #e0e7ef border.\r\n\t\t\t\t\t\tmuiTablePaperProps={{ elevation: 0, sx: { borderRadius: \"8px\", border: \"1px solid #e0e7ef\", overflow: \"hidden\", boxShadow: \"none\", mb: 2 } }}\r\n\t\t\t\t\t\tmuiTableProps={{ sx: { fontFamily: FONT, border: \"none\", borderRadius: 0, boxShadow: \"none\" } }}\r\n\t\t\t\t\t\tmuiTableContainerProps={{ sx: { maxHeight: \"calc(100vh - 300px)\" } }}\r\n\t\t\t\t\t\t// MRT draws a drop shadow under the header row by default — flat, like the CDR report.\r\n\t\t\t\t\t\tmuiTableHeadProps={{ sx: { boxShadow: \"none\" } }}\r\n\t\t\t\t\t\tmuiTableHeadRowProps={{ sx: { boxShadow: \"none\" } }}\r\n\t\t\t\t\t\tmuiTableBodyRowProps={{ sx: { backgroundColor: \"#fff\", \"&:hover\": { backgroundColor: \"#f0f7f8\" } } }}\r\n\t\t\t\t\t\tmuiBottomToolbarProps={{\r\n\t\t\t\t\t\t\tsx: {\r\n\t\t\t\t\t\t\t\tborderTop: \"1px solid #eef1f6\",\r\n\t\t\t\t\t\t\t\tboxShadow: \"none\",\r\n\t\t\t\t\t\t\t\tfontFamily: FONT,\r\n\t\t\t\t\t\t\t\t\"& .MuiTablePagination-displayedRows, & .MuiTablePagination-selectLabel, & .MuiInputBase-root\": { fontFamily: FONT, fontSize: \"0.73rem\" },\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t}}\r\n\t\t\t\t\t/>\r\n\t\t\t\t\t)}\r\n\t\t\t\t</Box>\r\n\t\t\t</Box>\r\n\t\t</LocalizationProvider>\r\n\t);\r\n}\r\n\r\nconst SummaryReport: React.FC = () => (\r\n\t<SDKProvider>\r\n\t\t<SummaryReportContent />\r\n\t</SDKProvider>\r\n);\r\n\r\nexport default SummaryReport;\r\n","import axiosInstance from \"../../services/axios\";\nimport { END_POINT } from \"../../services/endPoint\";\nimport type { SummaryReportParams, SummaryReportResponse, SummaryReportRow } from \"./types\";\n\nfunction buildQs(params: SummaryReportParams): string {\n\tconst qs = new URLSearchParams();\n\tqs.append(\"report_type\", params.report_type);\n\tif (params.start_date) qs.append(\"start_date\", params.start_date);\n\tif (params.end_date) qs.append(\"end_date\", params.end_date);\n\tif (params.did) qs.append(\"did\", params.did);\n\tif (params.dids) {\n\t\tfor (const d of params.dids) qs.append(\"dids\", d);\n\t}\n\tif (params.page) qs.append(\"page\", String(params.page));\n\tif (params.pageSize) qs.append(\"pageSize\", String(params.pageSize));\n\treturn `?${qs.toString()}`;\n}\n\nexport async function getSummaryReport(params: SummaryReportParams): Promise<SummaryReportResponse> {\n\tconst res = await axiosInstance.get(`${END_POINT.SUMMARY_REPORT}${buildQs(params)}`);\n\tconst body = res.data;\n\tconst data: SummaryReportRow[] = Array.isArray(body) ? body : (body?.data ?? []);\n\t// Paginated envelope ({ data, total, … }); a bare array or a missing total means one page.\n\tconst total = typeof body?.total === \"number\" ? body.total : (body?.pagination?.total ?? data.length);\n\treturn { report_type: body?.report_type ?? params.report_type, data, total };\n}\n\nexport async function exportSummaryReportToExcel(params: SummaryReportParams): Promise<void> {\n\tconst res = await axiosInstance.get(`${END_POINT.SUMMARY_REPORT_EXPORT_EXCEL}${buildQs(params)}`, {\n\t\tresponseType: \"blob\",\n\t});\n\tconst url = URL.createObjectURL(new Blob([res.data]));\n\tconst a = document.createElement(\"a\");\n\ta.href = url;\n\ta.download = `${params.report_type}-summary-report-${params.start_date?.slice(0, 10) ?? \"export\"}.xlsx`;\n\ta.click();\n\tURL.revokeObjectURL(url);\n}\n","import type { ReactNode } from \"react\";\r\nimport { Box, CircularProgress } from \"@mui/material\";\r\n\r\n/* Management Summary tab of the Summary Reports page. Unlike the other tabs it is not a\r\n\t row-per-period table: the API returns one row per channel (Inbound, Digital (Outbound),\r\n\t Manual (Outbound)) and each is laid out as its own card. Rows follow the\r\n\t business sheet: call counts, % missed, unique phone numbers, 1st-level missed %, the inbound\r\n\t Queue / IVR break-ups and net missed %. Only fields the API sends for a channel are\r\n\t shown — see MetricRow. */\r\n\r\ntype Row = Record<string, unknown>;\r\n\r\nconst FONT = \"'Inter', 'Segoe UI', 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif\";\r\nconst RULE = \"1px solid #dfe5ee\";\r\nconst COLORS = {\r\n\tteal: \"#1A5F6C\",\r\n\tnavy: \"#0d2a56\",\r\n\tgreen: \"#0a9a62\",\r\n\tred: \"#cc2a2a\",\r\n} as const;\r\n\r\nconst num = (v: unknown) => (typeof v === \"number\" ? v : Number(v) || 0);\r\nconst fmtCount = (v: unknown) => (v == null || v === \"\" ? \"–\" : num(v).toLocaleString());\r\n/** 33.3 → \"33.3%\", 80 → \"80%\". */\r\nconst fmtPct = (v: unknown) => (v == null || v === \"\" ? \"–\" : `${Number(num(v).toFixed(1))}%`);\r\n\r\nconst findChannel = (rows: Row[], prefix: string) =>\r\n\trows.find((r) => String(r.channel ?? \"\").toLowerCase().startsWith(prefix));\r\n\r\n/* ═══════════════════════ CELLS ═══════════════════════ */\r\n\r\ntype CellKind = \"head\" | \"label\" | \"pctLabel\" | \"value\";\r\n\r\nconst cellSx: Record<CellKind, object> = {\r\n\thead: { backgroundColor: \"#e6ecf2\", color: COLORS.teal, fontWeight: 700, fontSize: \"0.74rem\" },\r\n\tlabel: { backgroundColor: \"#f5f7fa\", color: \"#2d3748\", fontWeight: 600, fontSize: \"0.74rem\" },\r\n\tpctLabel: { backgroundColor: \"#f3f1fa\", color: \"#2d3748\", fontWeight: 600, fontSize: \"0.74rem\" },\r\n\tvalue: { backgroundColor: \"#fff\", fontWeight: 600, fontSize: \"0.8rem\", fontVariantNumeric: \"tabular-nums\" },\r\n};\r\n\r\ninterface CellProps {\r\n\tkind: CellKind;\r\n\tchildren?: ReactNode;\r\n\tcolSpan?: number;\r\n\ttone?: \"good\" | \"bad\";\r\n}\r\n\r\nfunction Cell({ kind, children, colSpan, tone }: CellProps) {\r\n\tconst color = tone === \"good\" ? COLORS.green : tone === \"bad\" ? COLORS.red : kind === \"value\" ? COLORS.navy : undefined;\r\n\treturn (\r\n\t\t<Box\r\n\t\t\tcomponent={kind === \"head\" ? \"th\" : \"td\"}\r\n\t\t\tcolSpan={colSpan}\r\n\t\t\tsx={{\r\n\t\t\t\tborder: RULE,\r\n\t\t\t\tpx: 1.25,\r\n\t\t\t\tpy: 0.9,\r\n\t\t\t\ttextAlign: \"center\",\r\n\t\t\t\tverticalAlign: \"middle\",\r\n\t\t\t\tlineHeight: 1.3,\r\n\t\t\t\tfontFamily: FONT,\r\n\t\t\t\t...cellSx[kind],\r\n\t\t\t\t...(color && { color }),\r\n\t\t\t}}\r\n\t\t>\r\n\t\t\t{children}\r\n\t\t</Box>\r\n\t);\r\n}\r\n\r\n/* ═══════════════════════ CARD ═══════════════════════ */\r\n\r\nfunction Grid({ children }: { children: ReactNode }) {\r\n\treturn (\r\n\t\t// flex: 1 + height on the table let the rows stretch when the card is taller than its content.\r\n\t\t<Box sx={{ overflow: \"hidden\", flex: 1, display: \"flex\", flexDirection: \"column\" }}>\r\n\t\t\t{/* The card border already frames the table: pull it 1px past each edge so the\r\n\t\t\t\t\touter cell rules are clipped instead of doubling the border. */}\r\n\t\t\t<Box component=\"table\" sx={{ width: \"calc(100% + 2px)\", height: \"calc(100% + 2px)\", m: \"-1px\", borderCollapse: \"collapse\", tableLayout: \"fixed\" }}>\r\n\t\t\t\t<tbody>{children}</tbody>\r\n\t\t\t</Box>\r\n\t\t</Box>\r\n\t);\r\n}\r\n\r\n/** A titled band between two grids of one card (e.g. \"Abandoned Break-up\"). */\r\nfunction SectionTitle({ children }: { children: ReactNode }) {\r\n\treturn (\r\n\t\t<Box\r\n\t\t\tsx={{\r\n\t\t\t\tborderTop: RULE,\r\n\t\t\t\tbackgroundColor: \"#f8fafc\",\r\n\t\t\t\tcolor: COLORS.teal,\r\n\t\t\t\tfontFamily: FONT,\r\n\t\t\t\tfontWeight: 700,\r\n\t\t\t\tfontSize: \"0.74rem\",\r\n\t\t\t\ttextAlign: \"center\",\r\n\t\t\t\tpy: 0.7,\r\n\t\t\t}}\r\n\t\t>\r\n\t\t\t{children}\r\n\t\t</Box>\r\n\t);\r\n}\r\n\r\nfunction ChannelCard({ title, children }: { title: string; children: ReactNode }) {\r\n\treturn (\r\n\t\t<Box sx={{ border: \"1px solid #e0e7ef\", borderRadius: \"8px\", overflow: \"hidden\", backgroundColor: \"#fff\", flex: \"1 0 auto\", display: \"flex\", flexDirection: \"column\" }}>\r\n\t\t\t<Box\r\n\t\t\t\tsx={{\r\n\t\t\t\t\tbackgroundColor: COLORS.teal,\r\n\t\t\t\t\tcolor: \"#fff\",\r\n\t\t\t\t\tfontFamily: FONT,\r\n\t\t\t\t\tfontWeight: 700,\r\n\t\t\t\t\tfontSize: \"0.85rem\",\r\n\t\t\t\t\tletterSpacing: 0.3,\r\n\t\t\t\t\ttextAlign: \"center\",\r\n\t\t\t\t\tpy: 0.9,\r\n\t\t\t\t}}\r\n\t\t\t>\r\n\t\t\t\t{title}\r\n\t\t\t</Box>\r\n\t\t\t{children}\r\n\t\t</Box>\r\n\t);\r\n}\r\n\r\n/** Field name(s) for one cell — the first key present wins (e.g. abandoned_unique / unique_abandoned). null = this channel never has that cell. */\r\ntype CellKey = string | string[] | null;\r\n\r\nconst pick = (r: Row | undefined, key: CellKey) => {\r\n\tif (!key || !r) return undefined;\r\n\tfor (const k of Array.isArray(key) ? key : [key]) if (r[k] !== undefined) return r[k];\r\n\treturn undefined;\r\n};\r\n\r\n/** Metric / Total / Answered / Abandoned (or Unanswered) header row. */\r\nfunction HeadRow({ lostLabel }: { lostLabel: string }) {\r\n\treturn (\r\n\t\t<tr>\r\n\t\t\t<Cell kind=\"head\">Metric</Cell>\r\n\t\t\t<Cell kind=\"head\">Total</Cell>\r\n\t\t\t<Cell kind=\"head\">Answered</Cell>\r\n\t\t\t<Cell kind=\"head\">{lostLabel}</Cell>\r\n\t\t</tr>\r\n\t);\r\n}\r\n\r\nconst TONES = [undefined, \"good\", \"bad\"] as const;\r\n\r\n/* One metric across Total / Answered / Lost. Only fields the response carries are shown:\r\n\t every value stays under its own column (a spanned cell would centre \"Answered %\" between\r\n\t Total and Answered), any column the response doesn't send is left empty, and a row with\r\n\t no fields at all is dropped. Before the report loads (no row) every cell the channel can have reads \"–\". */\r\nfunction MetricRow({ r, label, pct, keys }: { r?: Row; label: string; pct?: boolean; keys: [CellKey, CellKey, CellKey] }) {\r\n\tconst values = keys.map((k) => pick(r, k));\r\n\tconst shown = keys.map((k, i) => (r ? values[i] !== undefined : k !== null));\r\n\tif (!shown.some(Boolean)) return null;\r\n\tconst fmt = pct ? fmtPct : fmtCount;\r\n\treturn (\r\n\t\t<tr>\r\n\t\t\t<Cell kind={pct ? \"pctLabel\" : \"label\"}>{label}</Cell>\r\n\t\t\t{values.map((v, i) => (\r\n\t\t\t\t<Cell key={i} kind=\"value\" tone={TONES[i]}>{shown[i] ? fmt(v) : null}</Cell>\r\n\t\t\t))}\r\n\t\t</tr>\r\n\t);\r\n}\r\n\r\n/* ═══════════════════════ CHANNELS ═══════════════════════ */\r\n\r\nfunction InboundCard({ r }: { r?: Row }) {\r\n\treturn (\r\n\t\t<ChannelCard title=\"Inbound\">\r\n\t\t\t<Grid>\r\n\t\t\t\t<HeadRow lostLabel=\"Abandoned\" />\r\n\t\t\t\t<MetricRow r={r} label=\"Total Call Nos.\" keys={[\"total_calls\", \"answered\", \"abandoned\"]} />\r\n\t\t\t\t<MetricRow r={r} label=\"% Missed Against Calls\" pct keys={[null, \"answered_pct\", \"abandoned_pct\"]} />\r\n\t\t\t\t<MetricRow r={r} label=\"Unique Phone Nos.\" keys={[\"unique_numbers\", [\"answered_unique\", \"unique_answered\"], [\"abandoned_unique\", \"unique_abandoned\"]]} />\r\n\t\t\t\t<MetricRow r={r} label=\"1st Level Missed %\" pct keys={[null, null, \"first_level_missed_pct\"]} />\r\n\t\t\t</Grid>\r\n\t\t\t<SectionTitle>Abandoned Break-up</SectionTitle>\r\n\t\t\t<Grid>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<Cell kind=\"head\">Metric</Cell>\r\n\t\t\t\t\t<Cell kind=\"head\">Queue Abandoned</Cell>\r\n\t\t\t\t\t<Cell kind=\"head\">IVR Abandoned</Cell>\r\n\t\t\t\t</tr>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<Cell kind=\"label\">Nos.</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\" tone=\"bad\">{fmtCount(r?.queue_abandoned)}</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\" tone=\"bad\">{fmtCount(r?.ivr_abandoned)}</Cell>\r\n\t\t\t\t</tr>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<Cell kind=\"pctLabel\">Break-up %</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\">{fmtPct(r?.queue_abandoned_pct)}</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\">{fmtPct(r?.ivr_abandoned_pct)}</Cell>\r\n\t\t\t\t</tr>\r\n\t\t\t</Grid>\r\n\t\t\t<SectionTitle>Call Backs Unanswered</SectionTitle>\r\n\t\t\t<Grid>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<Cell kind=\"head\">Metric</Cell>\r\n\t\t\t\t\t<Cell kind=\"head\">Queue</Cell>\r\n\t\t\t\t\t<Cell kind=\"head\">IVR</Cell>\r\n\t\t\t\t</tr>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<Cell kind=\"label\">Nos.</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\" tone=\"bad\">{fmtCount(r?.queue_callbacks_unanswered)}</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\" tone=\"bad\">{fmtCount(r?.ivr_callbacks_unanswered)}</Cell>\r\n\t\t\t\t</tr>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<Cell kind=\"pctLabel\">Break-up %</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\">{fmtPct(r?.queue_callbacks_unanswered_pct)}</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\">{fmtPct(r?.ivr_callbacks_unanswered_pct)}</Cell>\r\n\t\t\t\t</tr>\r\n\t\t\t\t<tr>\r\n\t\t\t\t\t<Cell kind=\"pctLabel\">Net Missed %</Cell>\r\n\t\t\t\t\t<Cell kind=\"value\" tone=\"bad\" colSpan={2}>{fmtPct(r?.net_missed_pct)}</Cell>\r\n\t\t\t\t</tr>\r\n\t\t\t</Grid>\r\n\t\t</ChannelCard>\r\n\t);\r\n}\r\n\r\n/** Digital and Manual share one layout; rows the response doesn't carry for a channel drop out. */\r\nfunction OutboundCard({ title, r }: { title: string; r?: Row }) {\r\n\treturn (\r\n\t\t<ChannelCard title={title}>\r\n\t\t\t<Grid>\r\n\t\t\t\t<HeadRow lostLabel=\"Unanswered\" />\r\n\t\t\t\t<MetricRow r={r} label=\"Total Call Nos.\" keys={[\"total_calls\", \"answered\", \"unanswered\"]} />\r\n\t\t\t\t<MetricRow r={r} label=\"% Missed Against Calls\" pct keys={[null, \"answered_pct\", \"unanswered_pct\"]} />\r\n\t\t\t\t<MetricRow r={r} label=\"Unique Phone Nos.\" keys={[\"unique_numbers\", \"unique_answered\", \"unique_unanswered\"]} />\r\n\t\t\t\t{/* Digital only, once the API sends them; Manual has neither. */}\r\n\t\t\t\t{r?.first_level_missed_pct !== undefined && (\r\n\t\t\t\t\t<MetricRow r={r} label=\"1st Level Missed %\" pct keys={[null, null, \"first_level_missed_pct\"]} />\r\n\t\t\t\t)}\r\n\t\t\t\t{r?.callbacks_unanswered !== undefined && (\r\n\t\t\t\t\t<MetricRow r={r} label=\"Call Backs Unanswered\" keys={[null, null, \"callbacks_unanswered\"]} />\r\n\t\t\t\t)}\r\n\t\t\t\t<MetricRow r={r} label=\"Net Missed %\" pct keys={[null, \"net_answered_pct\", \"net_missed_pct\"]} />\r\n\t\t\t</Grid>\r\n\t\t</ChannelCard>\r\n\t);\r\n}\r\n\r\n/* ═══════════════════════ VIEW ═══════════════════════ */\r\n\r\nexport default function ManagementSummaryView({ rows, loading }: { rows: Row[]; loading: boolean }) {\r\n\treturn (\r\n\t\t<Box sx={{ position: \"relative\", mb: 2 }}>\r\n\t\t\t<Box\r\n\t\t\t\tsx={{\r\n\t\t\t\t\tdisplay: \"grid\",\r\n\t\t\t\t\tgridTemplateColumns: { xs: \"1fr\", lg: \"minmax(0, 1fr) minmax(0, 1fr)\" },\r\n\t\t\t\t\tgap: 2,\r\n\t\t\t\t\t// Stretch: the Inbound card and the Digital + Manual column end at the same line.\r\n\t\t\t\t\talignItems: \"stretch\",\r\n\t\t\t\t\topacity: loading ? 0.5 : 1,\r\n\t\t\t\t\ttransition: \"opacity 0.15s\",\r\n\t\t\t\t}}\r\n\t\t\t>\r\n\t\t\t\t<Box sx={{ display: \"flex\", flexDirection: \"column\", minWidth: 0 }}>\r\n\t\t\t\t\t<InboundCard r={findChannel(rows, \"inbound\")} />\r\n\t\t\t\t</Box>\r\n\t\t\t\t<Box sx={{ display: \"flex\", flexDirection: \"column\", gap: 2, minWidth: 0 }}>\r\n\t\t\t\t\t<OutboundCard title=\"Digital (Outbound)\" r={findChannel(rows, \"digital\")} />\r\n\t\t\t\t\t<OutboundCard title=\"Manual (Outbound)\" r={findChannel(rows, \"manual\")} />\r\n\t\t\t\t</Box>\r\n\t\t\t</Box>\r\n\t\t\t{loading && (\r\n\t\t\t\t<Box sx={{ position: \"absolute\", inset: 0, display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}>\r\n\t\t\t\t\t<CircularProgress size={28} sx={{ color: \"#1565c8\" }} />\r\n\t\t\t\t</Box>\r\n\t\t\t)}\r\n\t\t</Box>\r\n\t);\r\n}\r\n"],"mappings":"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","names":["jsx","jsxs","FONT","COLORS","num","dayjs","c"]}