mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-12 02:38:15 +00:00
feat: dashboard restructure, integrations, settings, UI fixes
Dashboard:
- Split into components (kpi-cards, agent-table, missed-queue)
- Add collapsible AI panel on right (same pattern as Call Desk)
- Add tabs: Agent Performance | Missed Queue | Campaigns
- Date range filter in header
Integrations page:
- Ozonetel (connected), WhatsApp, Facebook, Google, Instagram, Website, Email
- Status badges, config details, webhook URL with copy button
Settings page:
- Employee table from workspaceMembers GraphQL query
- Name, email, roles, status, reset password action
Fixes:
- Fix CALLS_QUERY: callerNumber needs { primaryPhoneNumber }, recordingUrl → recording { primaryLinkUrl }
- Remove duplicate AI Assistant header
- Remove Follow-ups from CC agent sidebar (already in worklist tabs)
- Remove global search from TopBar (decorative, unused)
- Slim down TopBar height
- Fix search/table gap in worklist
- Add brand border to active nav item
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
176
src/pages/integrations.tsx
Normal file
176
src/pages/integrations.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faPhone,
|
||||
faWhatsapp,
|
||||
faFacebook,
|
||||
faGoogle,
|
||||
faInstagram,
|
||||
} from '@fortawesome/free-brands-svg-icons';
|
||||
import { faGlobe, faEnvelope, faCopy, faCircleCheck, faCircleXmark } from '@fortawesome/pro-duotone-svg-icons';
|
||||
import { Badge } from '@/components/base/badges/badges';
|
||||
import { Button } from '@/components/base/buttons/button';
|
||||
import { TopBar } from '@/components/layout/top-bar';
|
||||
import { notify } from '@/lib/toast';
|
||||
|
||||
type IntegrationStatus = 'connected' | 'disconnected' | 'configured';
|
||||
|
||||
type IntegrationCardProps = {
|
||||
name: string;
|
||||
description: string;
|
||||
icon: any;
|
||||
iconColor: string;
|
||||
status: IntegrationStatus;
|
||||
details: { label: string; value: string }[];
|
||||
webhookUrl?: string;
|
||||
};
|
||||
|
||||
const statusConfig: Record<IntegrationStatus, { color: 'success' | 'error' | 'warning'; label: string }> = {
|
||||
connected: { color: 'success', label: 'Connected' },
|
||||
disconnected: { color: 'error', label: 'Not Connected' },
|
||||
configured: { color: 'warning', label: 'Configured' },
|
||||
};
|
||||
|
||||
const IntegrationCard = ({ name, description, icon, iconColor, status, details, webhookUrl }: IntegrationCardProps) => {
|
||||
const statusCfg = statusConfig[status];
|
||||
|
||||
const copyWebhook = () => {
|
||||
if (webhookUrl) {
|
||||
navigator.clipboard.writeText(webhookUrl);
|
||||
notify.success('Copied', 'Webhook URL copied to clipboard');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-secondary bg-primary p-5 shadow-xs">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex size-10 items-center justify-center rounded-lg bg-secondary">
|
||||
<FontAwesomeIcon icon={icon} className={`size-5 ${iconColor}`} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-primary">{name}</h3>
|
||||
<p className="text-xs text-tertiary">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Badge size="sm" color={statusCfg.color} type="pill-color">
|
||||
<FontAwesomeIcon icon={status === 'connected' ? faCircleCheck : faCircleXmark} className="mr-1 size-3" />
|
||||
{statusCfg.label}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{details.length > 0 && (
|
||||
<div className="mt-4 space-y-2">
|
||||
{details.map((d) => (
|
||||
<div key={d.label} className="flex items-center justify-between text-xs">
|
||||
<span className="text-tertiary">{d.label}</span>
|
||||
<span className="font-medium text-secondary">{d.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{webhookUrl && (
|
||||
<div className="mt-4 flex items-center gap-2 rounded-lg bg-secondary p-3">
|
||||
<code className="flex-1 truncate text-xs text-secondary">{webhookUrl}</code>
|
||||
<Button size="sm" color="secondary" iconLeading={({ className }: { className?: string }) => (
|
||||
<FontAwesomeIcon icon={faCopy} className={className} />
|
||||
)} onClick={copyWebhook}>
|
||||
Copy
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const IntegrationsPage = () => {
|
||||
const webhookBase = 'https://engage-api.srv1477139.hstgr.cloud';
|
||||
|
||||
return (
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
<TopBar title="Integrations" subtitle="Manage external service connections" />
|
||||
|
||||
<div className="flex-1 overflow-y-auto p-6 space-y-4">
|
||||
{/* Telephony */}
|
||||
<IntegrationCard
|
||||
name="Ozonetel CloudAgent"
|
||||
description="Cloud telephony — inbound/outbound calls, SIP softphone, IVR"
|
||||
icon={faPhone}
|
||||
iconColor="text-fg-brand-primary"
|
||||
status="connected"
|
||||
details={[
|
||||
{ label: 'Account', value: 'global_healthx' },
|
||||
{ label: 'Agent ID', value: 'global' },
|
||||
{ label: 'SIP Extension', value: '523590' },
|
||||
{ label: 'Inbound Campaign', value: 'Inbound_918041763265' },
|
||||
{ label: 'DID Number', value: '+91 804 176 3265' },
|
||||
]}
|
||||
webhookUrl={`${webhookBase}/webhooks/ozonetel/missed-call`}
|
||||
/>
|
||||
|
||||
{/* WhatsApp */}
|
||||
<IntegrationCard
|
||||
name="WhatsApp Business"
|
||||
description="Send templates, receive messages, automate outreach"
|
||||
icon={faWhatsapp}
|
||||
iconColor="text-green-600"
|
||||
status="disconnected"
|
||||
details={[]}
|
||||
/>
|
||||
|
||||
{/* Facebook Lead Ads */}
|
||||
<IntegrationCard
|
||||
name="Facebook Lead Ads"
|
||||
description="Auto-import leads from Facebook ad campaigns"
|
||||
icon={faFacebook}
|
||||
iconColor="text-blue-600"
|
||||
status="disconnected"
|
||||
details={[]}
|
||||
/>
|
||||
|
||||
{/* Google Ads */}
|
||||
<IntegrationCard
|
||||
name="Google Ads"
|
||||
description="Sync leads from Google Search and Display campaigns"
|
||||
icon={faGoogle}
|
||||
iconColor="text-red-500"
|
||||
status="disconnected"
|
||||
details={[]}
|
||||
/>
|
||||
|
||||
{/* Instagram */}
|
||||
<IntegrationCard
|
||||
name="Instagram Lead Ads"
|
||||
description="Capture leads from Instagram ad forms"
|
||||
icon={faInstagram}
|
||||
iconColor="text-pink-600"
|
||||
status="disconnected"
|
||||
details={[]}
|
||||
/>
|
||||
|
||||
{/* Website */}
|
||||
<IntegrationCard
|
||||
name="Website Lead Forms"
|
||||
description="Capture leads from website contact forms via webhook"
|
||||
icon={faGlobe}
|
||||
iconColor="text-fg-brand-primary"
|
||||
status="configured"
|
||||
details={[
|
||||
{ label: 'Method', value: 'POST webhook' },
|
||||
]}
|
||||
webhookUrl={`${webhookBase}/webhooks/website/lead`}
|
||||
/>
|
||||
|
||||
{/* Email */}
|
||||
<IntegrationCard
|
||||
name="Email (SMTP)"
|
||||
description="Outbound email for campaigns and notifications"
|
||||
icon={faEnvelope}
|
||||
iconColor="text-fg-quaternary"
|
||||
status="disconnected"
|
||||
details={[]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user