'use client'; import { useState, useEffect } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Input } from '@/components/ui/input'; import { Skeleton } from '@/components/ui/skeleton'; import { Network, Building2, CheckCircle, XCircle, AlertCircle, Save, Trash2, Search, RefreshCw } from 'lucide-react'; import { AuvikTenantMapping } from '@/lib/types/auvik'; import { Company } from '@/lib/types/autotask'; // Simple toast implementation const useToast = () => { return { toast: ({ title, description, variant }: { title: string; description: string; variant?: string }) => { // For now, use console and alert - can be enhanced with a proper toast library later if (variant === 'destructive') { console.error(`${title}: ${description}`); alert(`Error: ${description}`); } else { console.log(`${title}: ${description}`); } } }; }; interface TenantRow extends Partial { auvikTenantId: string; auvikTenantName: string; isMapped: boolean; deviceCount?: number; } interface CompanyWithCounts extends Company { nmsDeviceCount?: number; } export default function AuvikMappingsPage() { const [tenants, setTenants] = useState([]); const [companies, setCompanies] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(null); const [searchTerm, setSearchTerm] = useState(''); const [filterStatus, setFilterStatus] = useState<'all' | 'mapped' | 'unmapped'>('all'); const { toast } = useToast(); useEffect(() => { fetchData(); }, []); const fetchData = async () => { setLoading(true); try { // Fetch tenant mappings (including unmapped) const mappingsRes = await fetch('/api/auvik/tenant-mappings?includeUnmapped=true'); const mappingsData = await mappingsRes.json(); // Fetch all companies const companiesRes = await fetch('/api/companies'); const companiesData = await companiesRes.json(); // Fetch device counts for each tenant const auvikDevicesRes = await fetch('/api/auvik/devices'); let auvikDevices: any[] = []; if (auvikDevicesRes.ok) { const auvikData = await auvikDevicesRes.json(); auvikDevices = auvikData.devices || []; } // Count devices per tenant const deviceCountsByTenant: Record = {}; auvikDevices.forEach((device: any) => { const tenantId = device.tenantId; if (tenantId) { deviceCountsByTenant[tenantId] = (deviceCountsByTenant[tenantId] || 0) + 1; } }); const tenantRows: TenantRow[] = mappingsData.mappings.map((m: any) => ({ ...m, isMapped: m.autotaskCompanyId > 0, deviceCount: deviceCountsByTenant[m.auvikTenantId] || 0, })); setTenants(tenantRows); setCompanies(companiesData.companies || []); } catch (error) { console.error('Error fetching data:', error); toast({ title: 'Error', description: 'Failed to load tenant mappings', variant: 'destructive', }); } finally { setLoading(false); } }; const handleSaveMapping = async (tenantId: string, tenantName: string, companyId: number) => { setSaving(tenantId); try { const company = companies.find((c) => c.id === companyId); if (!company) { throw new Error('Company not found'); } const response = await fetch('/api/auvik/tenant-mappings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ auvikTenantId: tenantId, auvikTenantName: tenantName, autotaskCompanyId: companyId, autotaskCompanyName: company.companyName, }), }); if (!response.ok) { throw new Error('Failed to save mapping'); } toast({ title: 'Success', description: `Mapped ${tenantName} to ${company.companyName}`, }); await fetchData(); } catch (error) { console.error('Error saving mapping:', error); toast({ title: 'Error', description: 'Failed to save mapping', variant: 'destructive', }); } finally { setSaving(null); } }; const handleDeleteMapping = async (mappingId: number) => { try { const response = await fetch(`/api/auvik/tenant-mappings?id=${mappingId}`, { method: 'DELETE', }); if (!response.ok) { throw new Error('Failed to delete mapping'); } toast({ title: 'Success', description: 'Mapping deleted successfully', }); await fetchData(); } catch (error) { console.error('Error deleting mapping:', error); toast({ title: 'Error', description: 'Failed to delete mapping', variant: 'destructive', }); } }; const filteredTenants = tenants.filter((tenant) => { const matchesSearch = tenant.auvikTenantName.toLowerCase().includes(searchTerm.toLowerCase()) || tenant.autotaskCompanyName?.toLowerCase().includes(searchTerm.toLowerCase()); const matchesFilter = filterStatus === 'all' || (filterStatus === 'mapped' && tenant.isMapped) || (filterStatus === 'unmapped' && !tenant.isMapped); return matchesSearch && matchesFilter; }); const stats = { total: tenants.length, mapped: tenants.filter((t) => t.isMapped).length, unmapped: tenants.filter((t) => !t.isMapped).length, }; return (
{/* Header */}

NMS Tenant Mappings

Map NMS (Auvik) tenants to Autotask companies for device synchronization

{/* Stats Cards */}
Total Tenants
{stats.total}
Mapped
{stats.mapped}
Unmapped
{stats.unmapped}
{/* Filters */} Tenant Mappings Select an Autotask company for each NMS tenant to enable device matching
setSearchTerm(e.target.value)} className="pl-10" />
{/* Table */} {loading ? (
) : (
NMS Tenant
Autotask Company
Status Actions
{filteredTenants.length === 0 ? ( No tenants found ) : ( filteredTenants.map((tenant) => ( )) )}
)}
); } interface TenantMappingRowProps { tenant: TenantRow; companies: Company[]; saving: boolean; onSave: (tenantId: string, tenantName: string, companyId: number) => void; onDelete: (mappingId: number) => void; } function TenantMappingRow({ tenant, companies, saving, onSave, onDelete, }: TenantMappingRowProps) { const [selectedCompanyId, setSelectedCompanyId] = useState( tenant.autotaskCompanyId || 0 ); const [hasChanges, setHasChanges] = useState(false); const handleCompanyChange = (value: string) => { const companyId = parseInt(value); setSelectedCompanyId(companyId); setHasChanges(companyId !== tenant.autotaskCompanyId); }; const handleSave = () => { if (selectedCompanyId > 0) { onSave(tenant.auvikTenantId, tenant.auvikTenantName, selectedCompanyId); setHasChanges(false); } }; return (
{tenant.auvikTenantName}
{tenant.auvikTenantId}
{tenant.deviceCount !== undefined && tenant.deviceCount > 0 && ( {tenant.deviceCount} {tenant.deviceCount === 1 ? 'device' : 'devices'} )}
{tenant.isMapped ? ( Mapped ) : ( Unmapped )}
{hasChanges && ( )} {tenant.isMapped && tenant.id && ( )}
); }