feat: split AI Input Agent into Copy/Type Agent submenu with settings
Renames the sidebar entry to "AI Copy/Type Agent" with Copy Agent, Type Agent, and Settings sub-pages. Settings shows the server's LAN IP address (via a new /api/ai/network-info endpoint) since it changes depending on which office the app is running in. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,9 @@ const CloudStoragePage = lazy(() => import("./pages/cloud-storage-page"));
|
||||
const JobMonitorPage = lazy(() => import("./pages/job-monitor-page"));
|
||||
const ChartPage = lazy(() => import("./pages/chart-page"));
|
||||
const DentalEducationPage = lazy(() => import("./pages/dental-education-page"));
|
||||
const AiInputAgentPage = lazy(() => import("./pages/ai-input-agent-page"));
|
||||
const AiCopyAgentPage = lazy(() => import("./pages/ai-copy-agent-page"));
|
||||
const AiTypeAgentPage = lazy(() => import("./pages/ai-type-agent-page"));
|
||||
const AiAgentSettingsPage = lazy(() => import("./pages/ai-agent-settings-page"));
|
||||
const DentalShoppingSearchTagPage = lazy(() => import("./pages/dental-shopping-search-tag-page"));
|
||||
const DentalShoppingLoginInfoPage = lazy(() => import("./pages/dental-shopping-login-info-page"));
|
||||
const ActivationPage = lazy(() => import("./pages/activation-page"));
|
||||
@@ -67,7 +69,10 @@ function Router() {
|
||||
<ProtectedRoute path="/reports" component={() => <ReportsPage />} />
|
||||
<ProtectedRoute path="/cloud-storage" component={() => <CloudStoragePage />} />
|
||||
<ProtectedRoute path="/dental-education" component={() => <DentalEducationPage />} />
|
||||
<ProtectedRoute path="/ai-input-agent" component={() => <AiInputAgentPage />} />
|
||||
<ProtectedRoute path="/ai-input-agent/copy-agent" component={() => <AiCopyAgentPage />} />
|
||||
<ProtectedRoute path="/ai-input-agent/type-agent" component={() => <AiTypeAgentPage />} />
|
||||
<ProtectedRoute path="/ai-input-agent/settings" component={() => <AiAgentSettingsPage />} />
|
||||
<ProtectedRoute path="/ai-input-agent" component={() => <Redirect to="/ai-input-agent/copy-agent" />} />
|
||||
<ProtectedRoute path="/dental-shopping/search-tag" component={() => <DentalShoppingSearchTagPage />} />
|
||||
<ProtectedRoute path="/dental-shopping/login-info" component={() => <DentalShoppingLoginInfoPage />} />
|
||||
<ProtectedRoute path="/activation" component={() => <ActivationPage />} adminOnly />
|
||||
|
||||
@@ -35,6 +35,8 @@ import {
|
||||
ShoppingCart,
|
||||
Search,
|
||||
KeyRound,
|
||||
Copy,
|
||||
Keyboard,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useMemo, useState, useEffect } from "react";
|
||||
@@ -68,6 +70,7 @@ export function Sidebar() {
|
||||
if (location.startsWith("/chart")) s.add("/chart");
|
||||
if (location.startsWith("/settings")) s.add("/settings");
|
||||
if (location.startsWith("/dental-shopping")) s.add("/dental-shopping");
|
||||
if (location.startsWith("/ai-input-agent")) s.add("/ai-input-agent");
|
||||
return s;
|
||||
});
|
||||
|
||||
@@ -81,6 +84,9 @@ export function Sidebar() {
|
||||
if (location.startsWith("/dental-shopping")) {
|
||||
setExpandedPaths((prev) => new Set([...prev, "/dental-shopping"]));
|
||||
}
|
||||
if (location.startsWith("/ai-input-agent")) {
|
||||
setExpandedPaths((prev) => new Set([...prev, "/ai-input-agent"]));
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
const togglePath = (path: string) => {
|
||||
@@ -177,9 +183,26 @@ export function Sidebar() {
|
||||
icon: <GraduationCap className="h-5 w-5 text-lime-600" />,
|
||||
},
|
||||
{
|
||||
name: "AI Input Agent",
|
||||
name: "AI Copy/Type Agent",
|
||||
path: "/ai-input-agent",
|
||||
icon: <Bot className="h-5 w-5 text-violet-500" />,
|
||||
children: [
|
||||
{
|
||||
name: "Copy Agent",
|
||||
path: "/ai-input-agent/copy-agent",
|
||||
icon: <Copy className="h-4 w-4 text-violet-400" />,
|
||||
},
|
||||
{
|
||||
name: "Type Agent",
|
||||
path: "/ai-input-agent/type-agent",
|
||||
icon: <Keyboard className="h-4 w-4 text-violet-400" />,
|
||||
},
|
||||
{
|
||||
name: "Settings",
|
||||
path: "/ai-input-agent/settings",
|
||||
icon: <Settings className="h-4 w-4 text-violet-400" />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "AI Dental Shopping",
|
||||
|
||||
63
apps/Frontend/src/pages/ai-agent-settings-page.tsx
Normal file
63
apps/Frontend/src/pages/ai-agent-settings-page.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { apiRequest } from "@/lib/queryClient";
|
||||
import { Settings as SettingsIcon, Network, Loader2 } from "lucide-react";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
|
||||
interface NetworkInfo {
|
||||
ipAddress: string | null;
|
||||
addresses: string[];
|
||||
}
|
||||
|
||||
export default function AiAgentSettingsPage() {
|
||||
const { data: networkInfo, isLoading } = useQuery<NetworkInfo>({
|
||||
queryKey: ["/api/ai/network-info"],
|
||||
queryFn: async () => {
|
||||
const res = await apiRequest("GET", "/api/ai/network-info");
|
||||
return res.json();
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto px-4 py-10 space-y-6">
|
||||
<div className="text-center space-y-3">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-violet-100 mb-2">
|
||||
<SettingsIcon className="h-8 w-8 text-violet-600" />
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Copy/Type Agent Settings</h1>
|
||||
<p className="text-muted-foreground text-base max-w-xl mx-auto">
|
||||
Configuration options for the Copy Agent and Type Agent will appear here.
|
||||
</p>
|
||||
<span className="inline-block bg-amber-100 text-amber-700 text-xs font-semibold px-3 py-1 rounded-full border border-amber-200">
|
||||
Coming Soon
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="flex items-center gap-2 text-base">
|
||||
<Network className="h-5 w-5 text-violet-500" />
|
||||
IP Address
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
Detecting IP address...
|
||||
</div>
|
||||
) : networkInfo?.ipAddress ? (
|
||||
<p className="text-2xl font-mono font-semibold tracking-wide">
|
||||
{networkInfo.ipAddress}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">Unable to detect an IP address.</p>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground">
|
||||
This is the app's current network address. It changes depending on which office
|
||||
the app is running in.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
81
apps/Frontend/src/pages/ai-copy-agent-page.tsx
Normal file
81
apps/Frontend/src/pages/ai-copy-agent-page.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Copy, FileCheck, CreditCard, Shield, Zap } from "lucide-react";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
|
||||
const CAPABILITIES = [
|
||||
{
|
||||
icon: <Shield className="h-5 w-5 text-teal-600" />,
|
||||
title: "Eligibility Results",
|
||||
description:
|
||||
"Automatically read insurance eligibility information — coverage status, plan details, deductibles, and co-pays — from the insurance portal.",
|
||||
},
|
||||
{
|
||||
icon: <FileCheck className="h-5 w-5 text-blue-600" />,
|
||||
title: "Claim Information",
|
||||
description:
|
||||
"Extract claim numbers, claim status updates, and denial reasons from the insurance portal so they can be reused elsewhere without manual re-entry.",
|
||||
},
|
||||
{
|
||||
icon: <CreditCard className="h-5 w-5 text-indigo-600" />,
|
||||
title: "Insurance Payments",
|
||||
description:
|
||||
"Capture ERA / EOB payment details — amounts, adjustments, patient responsibility — straight from the source document or portal.",
|
||||
},
|
||||
];
|
||||
|
||||
export default function AiCopyAgentPage() {
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto px-4 py-10 space-y-10">
|
||||
|
||||
{/* Hero */}
|
||||
<div className="text-center space-y-3">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-violet-100 mb-2">
|
||||
<Copy className="h-8 w-8 text-violet-600" />
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Copy Agent</h1>
|
||||
<p className="text-muted-foreground text-base max-w-xl mx-auto">
|
||||
An AI agent reads and copies data including images and brings them to this app
|
||||
automatically. No manual input required.
|
||||
</p>
|
||||
<span className="inline-block bg-amber-100 text-amber-700 text-xs font-semibold px-3 py-1 rounded-full border border-amber-200">
|
||||
Coming Soon
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* What it will copy */}
|
||||
<div className="space-y-3">
|
||||
<h2 className="text-base font-semibold">What it will copy</h2>
|
||||
<div className="grid gap-4 sm:grid-cols-3">
|
||||
{CAPABILITIES.map((cap) => (
|
||||
<Card key={cap.title}>
|
||||
<CardContent className="py-5 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{cap.icon}
|
||||
<span className="text-sm font-medium">{cap.title}</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground leading-relaxed">
|
||||
{cap.description}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Why */}
|
||||
<Card className="border-violet-200 bg-violet-50/50">
|
||||
<CardContent className="py-5 flex items-start gap-3">
|
||||
<Zap className="h-5 w-5 text-violet-500 mt-0.5 flex-shrink-0" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm font-medium text-violet-900">Why this matters</p>
|
||||
<p className="text-sm text-violet-700 leading-relaxed">
|
||||
Staff currently check eligibility or look up a claim on an insurance portal, then
|
||||
manually copy every value into this app. This agent eliminates that step entirely —
|
||||
one click pulls the data straight in.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Bot, Keyboard, FileCheck, CreditCard, Shield, Zap, ArrowRight } from "lucide-react";
|
||||
import { Keyboard, FileCheck, CreditCard, Shield, Zap, ArrowRight } from "lucide-react";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
|
||||
const SOFTWARE_TARGETS = [
|
||||
@@ -29,16 +29,16 @@ const CAPABILITIES = [
|
||||
},
|
||||
];
|
||||
|
||||
export default function AiInputAgentPage() {
|
||||
export default function AiTypeAgentPage() {
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto px-4 py-10 space-y-10">
|
||||
|
||||
{/* Hero */}
|
||||
<div className="text-center space-y-3">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-violet-100 mb-2">
|
||||
<Bot className="h-8 w-8 text-violet-600" />
|
||||
<Keyboard className="h-8 w-8 text-violet-600" />
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">AI Input Agent</h1>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Type Agent</h1>
|
||||
<p className="text-muted-foreground text-base max-w-xl mx-auto">
|
||||
An AI-powered agent that reads data from this app and types it directly into your
|
||||
current dental management software — no copy-paste, no manual re-entry.
|
||||
Reference in New Issue
Block a user