// Modified in AgentDeskFixes: safe, reviewed setup repairs and honest routing diagnostics. "use client" import { AlertTriangleIcon, ArrowRightIcon, CheckCircle2Icon, ExternalLinkIcon, Loader2Icon, PlayIcon, RefreshCwIcon, ShieldAlertIcon, SparklesIcon, UserCheckIcon, XCircleIcon, } from "lucide-react" import Link from "next/link" import { useCallback, useEffect, useMemo, useRef, useState } from "react" import { toast } from "sonner" import { DashboardPage } from "@/components/dashboard-page" import { notifySetupReadinessUpdated, SETUP_READINESS_UPDATED_EVENT, } from "@/components/operator-readiness-indicator" import { OptionCombobox } from "@/components/option-combobox" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { availabilityStatusLabel } from "@/lib/support-availability-i18n" import { useI18n } from "@/i18n/provider" import { applySetupQuickFix, fetchSetupReadiness, simulateSetupRoute, type SetupQuickFixAction, type SetupQuickFixResponse, type SetupReadinessResponse, type SetupSimulateRouteResponse, type SetupStepStatus, } from "@/lib/api/setup-readiness" import { cn } from "@/lib/utils" function StatusIcon({ status }: { status: SetupStepStatus }) { if (status === "ok") { return ( ) } if (status === "warning") { return ( ) } return ( ) } function StatusBadge({ status }: { status: SetupStepStatus }) { const t = useI18n() if (status === "ok") { return ( {t("setupWizard.stepBadgeOk")} ) } if (status === "warning") { return ( {t("setupWizard.stepBadgeWarning")} ) } return ( {t("setupWizard.stepBadgeError")} ) } export function SetupWizardView() { const t = useI18n() const [readiness, setReadiness] = useState(null) const [loading, setLoading] = useState(true) const [fixingAction, setFixingAction] = useState(null) const fixingRef = useRef(false) const selectedChannelRef = useRef("") const simulationRequestRef = useRef(0) const readinessRequestRef = useRef(0) const [pendingFix, setPendingFix] = useState<{ action: SetupQuickFixAction entityId?: number preview: SetupQuickFixResponse } | null>(null) const [selectedChannelId, setSelectedChannelId] = useState("") const [simulation, setSimulation] = useState(null) const [simulating, setSimulating] = useState(false) const runSimulation = useCallback(async (channelIdNum?: number) => { const requestId = ++simulationRequestRef.current setSimulating(true) setSimulation(null) try { const sim = await simulateSetupRoute({ channel_id: channelIdNum && channelIdNum > 0 ? channelIdNum : undefined, bypass_ai: false, }) if (requestId !== simulationRequestRef.current) return setSimulation({ ...sim, candidate_operators: sim.candidate_operators ?? [] }) if (sim.channel_id > 0) { selectedChannelRef.current = String(sim.channel_id) setSelectedChannelId(String(sim.channel_id)) } } catch (error) { if (requestId !== simulationRequestRef.current) return toast.error( error instanceof Error ? error.message : t("common.operationFailed"), ) } finally { if (requestId === simulationRequestRef.current) setSimulating(false) } }, [t]) const loadAll = useCallback(async () => { const requestId = ++readinessRequestRef.current setLoading(true) try { const data = await fetchSetupReadiness() if (requestId !== readinessRequestRef.current) return setReadiness(data) const currentNum = Number(selectedChannelRef.current) const targetChannelId = currentNum > 0 ? currentNum : data.channels.find((ch) => ch.status === 0)?.id ?? data.channels[0]?.id ?? 0 if (targetChannelId > 0) { setSelectedChannelId(String(targetChannelId)) } await runSimulation(targetChannelId) } catch (error) { if (requestId !== readinessRequestRef.current) return toast.error( error instanceof Error ? error.message : t("common.loadFailed"), ) } finally { if (requestId === readinessRequestRef.current) setLoading(false) } }, [runSimulation, t]) const invalidateRequests = useCallback(() => { simulationRequestRef.current++ readinessRequestRef.current++ }, []) useEffect(() => { void loadAll() const handleUpdated = () => { void loadAll() } window.addEventListener(SETUP_READINESS_UPDATED_EVENT, handleUpdated) return () => { window.removeEventListener(SETUP_READINESS_UPDATED_EVENT, handleUpdated) invalidateRequests() } }, [invalidateRequests, loadAll]) async function handleQuickFix(action: SetupQuickFixAction, entityId?: number) { if (fixingRef.current) return fixingRef.current = true setFixingAction(entityId ? `${action}:${entityId}` : action) try { const preview = await applySetupQuickFix({ action, entity_id: entityId }) setPendingFix({ action, entityId, preview }) } catch (error) { toast.error(error instanceof Error ? error.message : t("common.operationFailed")) } finally { fixingRef.current = false setFixingAction(null) } } async function confirmQuickFix() { if (!pendingFix || fixingRef.current) return fixingRef.current = true setFixingAction(pendingFix.action) try { const result = await applySetupQuickFix({ action: pendingFix.action, entity_id: pendingFix.entityId, apply: true, preview_token: pendingFix.preview.preview_token, }) if (!result.applied) throw new Error(t("setupWizard.preview.notApplied")) if (result.readiness) setReadiness(result.readiness) setPendingFix(null) notifySetupReadinessUpdated() if (result.warning_codes.length) { toast.warning(result.warning_codes.map((code) => t(`setupWizard.repairWarnings.${code}`)).join(" ")) } else { toast.success(t("setupWizard.quickFixSuccess")) } } catch (error) { toast.error(error instanceof Error ? error.message : t("common.operationFailed")) // A failed/stale preview must be reviewed again, not silently reapplied. setPendingFix(null) } finally { fixingRef.current = false setFixingAction(null) } } const canQuickSetupAll = useMemo(() => { return ( readiness?.steps.some((s) => s.quick_fix_actions.includes("quick_setup_all"), ) ?? false ) }, [readiness]) const canEnableMyProfile = useMemo(() => { return ( readiness?.steps.some((s) => s.quick_fix_actions.includes("enable_my_operator_profile"), ) ?? false ) }, [readiness]) const channelOptions = useMemo(() => { if (!readiness) { return [] } return readiness.channels.map((ch) => ({ value: String(ch.id), label: `${ch.name} (${ch.channel_type})`, })) }, [readiness]) if (loading && !readiness) { return (
{t("common.loadingData")}
) } if (!readiness) { return null } const progressPercent = Math.round( (readiness.ready_steps / Math.max(readiness.total_steps, 1)) * 100, ) return ( {/* Top Overview Header */}

{t("setupWizard.title")}

{readiness.can_receive_requests_now ? t("setupWizard.statusReady") : t("setupWizard.statusNeedsSetup", { ready: readiness.ready_steps, total: readiness.total_steps, })}

{t("setupWizard.description")}

{canQuickSetupAll ? ( ) : null}
{/* Progress Bar */}
{t("setupWizard.stepsProgress", { ready: readiness.ready_steps, total: readiness.total_steps, })} {progressPercent}%
{/* Current Operator Personal Diagnostic Card */}

{t("setupWizard.currentOperatorTitle")}:{" "} {readiness.current_operator.nickname || readiness.current_operator.username}

{t("setupWizard.currentOperatorTeam", { team: readiness.current_operator.team_name || t("setupWizard.currentOperatorNoTeam"), })} {t("setupWizard.currentOperatorLoad", { active: readiness.current_operator.active_conversation_count, max: readiness.current_operator.max_concurrent_count, })}
{readiness.current_operator.can_receive_now ? (

{t("setupWizard.currentOperatorReady")}

) : (

{t("setupWizard.currentOperatorBlocked")}

{readiness.current_operator.blocker_codes.map((code) => ( {t(`setupWizard.operatorBlockers.${code}`)} ))}
)}
{!readiness.current_operator.can_receive_now && canEnableMyProfile ? (
) : null}
{/* 6-Step Checklist Grid */}

{t("setupWizard.checklistSectionTitle")}

{readiness.steps.map((step) => { const primaryQuickFix = (step.key === "ai_agents" || step.key === "channels") && step.total_count > 0 ? undefined : step.quick_fix_actions[0] return (

{step.step_number}.{" "} {t(`setupWizard.steps.${step.key}.title`)}

{t("setupWizard.readyCountLabel", { ready: step.ready_count, total: step.total_count, })}

{t(`setupWizard.steps.${step.key}.description`)}

{step.issues.length > 0 ? (
{step.issues.map((issue, idx) => (
{issue.entity_name ? ( [{issue.entity_name}]{" "} ) : null} {t(`setupWizard.issues.${issue.code}`)}
{issue.quick_fix_action && issue.entity_id > 0 && issue.entity_type !== "operator" ? ( ) : null}
))}
) : null}
{step.key !== "end_to_end" ? ( ) : null} {primaryQuickFix ? ( ) : null}
) })}
{/* Interactive Route Simulator */}

{t("setupWizard.simulator.title")}

{t("setupWizard.simulator.description")}

{channelOptions.length > 0 ? ( { selectedChannelRef.current = val setSelectedChannelId(val) void runSimulation(Number(val)) }} placeholder={t("setupWizard.simulator.selectChannelPlaceholder")} triggerClassName="w-64 rounded-md" /> ) : null}
{simulation ? (
{/* Outcome Banner */}
{simulation.will_reach_operator ? ( ) : ( )} {simulation.will_reach_operator ? t("setupWizard.simulator.outcomeSuccess", { operator: simulation.matched_operator?.display_name ?? "", }) : t("setupWizard.simulator.outcomeBlocked")}
{t( `setupWizard.simulator.outcomes.${simulation.final_outcome_code}`, )}
{/* 5-Hop Visual Trace Pipeline */}
{simulation.hops.map((hop, idx) => (
{idx + 1}.{" "} {t(`setupWizard.simulator.hops.${hop.hop_key}`)}
{hop.entity_name ? (

{hop.entity_name}

) : null}

{t(`setupWizard.simulator.hopReasons.${hop.reason_code}`)}

{hop.quick_fix_action && hop.status !== "ok" ? ( ) : null}
))}
{/* Candidate Operators Evaluation Table */} {simulation.candidate_operators.length > 0 ? (

{t("setupWizard.simulator.candidateTableTitle")}

{t("setupWizard.simulator.colOperator")} {t("setupWizard.simulator.colTeam")} {t("setupWizard.simulator.colStatus")} {t("setupWizard.simulator.colAutoAssign")} {t("setupWizard.simulator.colLoad")} {t("setupWizard.simulator.colResult")} {simulation.candidate_operators.map((cand) => ( {cand.display_name} {cand.team_name || t("setupWizard.currentOperatorNoTeam")} {availabilityStatusLabel(cand.service_status, t)} {cand.auto_assign_enabled ? t("common.enabled") : t("common.disabled")} {cand.active_count} / {cand.max_concurrent_count} {cand.eligible ? ( {t("setupWizard.simulator.eligibleBadge")} ) : ( {t( `setupWizard.simulator.skipReasons.${cand.skip_reason_code}`, )} )} ))}
) : null}
) : null}
{ if (!open && !fixingRef.current) setPendingFix(null) }}> {t("setupWizard.preview.title")} {t("setupWizard.preview.description")}
{pendingFix?.preview.changes.length === 0 ?

{t("setupWizard.preview.noChanges")}

: null} {pendingFix?.preview.changes.map((change, index) => (

{t(`setupWizard.preview.${change.operation}`)}: {change.entity_name}{change.entity_id > 0 ? ` (#${change.entity_id})` : ""}

{Object.entries(change.after).map(([field, value]) => (
{t(`setupWizard.repairFields.${field}`)}
{change.before && field in change.before ? `${String(change.before[field])} → ` : ""}{String(value)}
))}
))} {pendingFix?.preview.warning_codes.map((code) =>

{t(`setupWizard.repairWarnings.${code}`)}

)} {t("setupWizard.preview.manageSchedules")}
) } export { ArrowRightIcon }