'use client';
import { useEffect, useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import AdminLayout from '../../../components/AdminLayout';
import { getDeployment } from '../../../lib/api';
export default function DeploymentDetailPage() {
const { id } = useParams();
const router = useRouter();
const [deployment, setDeployment] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
if (id) loadDeployment();
}, [id]);
const loadDeployment = async () => {
try {
const data = await getDeployment(id);
setDeployment(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
if (loading) {
return (
Loading...
);
}
if (error || !deployment) {
return (
Deployment not found
);
}
const ownerName = deployment.owner?.first_name || deployment.owner?.last_name
? `${deployment.owner.first_name || ''} ${deployment.owner.last_name || ''}`.trim()
: deployment.owner?.email || 'No owner';
return (
{/* Header */}
Deployment #{deployment.deployment_id}
{deployment.address && (
{deployment.address}
)}
{/* Info Cards */}
{/* Deployment Info */}
Deployment Information
{/* Owner Info */}
Owner
{deployment.owner ? (
<>
>
) : (
No owner assigned
)}
{/* Stats */}
{/* Devices */}
{deployment.devices?.length > 0 && (
Devices ({deployment.devices.length})
{deployment.devices.map((device) => (
))}
)}
{/* Users with Access */}
{deployment.users_with_access?.length > 0 && (
Users with Access
User
Email
Role
Granted
{deployment.users_with_access.map((access, idx) => (
{access.user?.first_name || access.user?.last_name
? `${access.user.first_name || ''} ${access.user.last_name || ''}`.trim()
: 'Unnamed'}
{access.user?.email || '—'}
{access.granted_at ? new Date(access.granted_at).toLocaleDateString() : '—'}
))}
)}
{/* Events */}
{deployment.events?.length > 0 && (
Recent Events
Type
Description
Device
Time
{deployment.events.map((event, idx) => (
{event.description || '—'}
{event.device_id || '—'}
{new Date(event.created_at).toLocaleString()}
))}
)}
);
}
function InfoRow({ label, value }) {
return (
{label}
{value}
);
}
function StatCard({ icon, label, value, color }) {
return (
);
}
function DeviceCard({ device }) {
const isOnline = device.status === 'online' || device.status === 'active';
return (
{device.device_id}
{device.device_type || 'Unknown Type'}
Status: {device.status || 'unknown'}
{device.last_seen_at && (
Last seen: {new Date(device.last_seen_at).toLocaleString()}
)}
);
}
function StatusBadge({ status }) {
const colors = {
active: '#10B981',
installed: '#059669',
pending: '#F59E0B',
inactive: '#6B7280',
};
const color = colors[status] || '#6B7280';
return (
{status || 'unknown'}
);
}
function RoleBadge({ role }) {
const colors = {
owner: '#EF4444',
caretaker: '#6366F1',
installer: '#8B5CF6',
};
const color = colors[role] || '#6B7280';
return (
{role}
);
}
function EventTypeBadge({ type }) {
const colors = {
alert: '#EF4444',
motion: '#F59E0B',
door: '#3B82F6',
system: '#6B7280',
};
const color = colors[type] || '#6B7280';
return (
{type || 'event'}
);
}
const styles = {
loading: {
textAlign: 'center',
padding: '48px',
color: 'var(--text-muted)',
},
error: {
textAlign: 'center',
padding: '48px',
},
backBtn: {
marginTop: '16px',
padding: '10px 20px',
background: 'var(--primary)',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
},
header: {
marginBottom: '24px',
},
backLink: {
background: 'none',
border: 'none',
color: 'var(--primary)',
fontSize: '14px',
cursor: 'pointer',
padding: 0,
marginBottom: '12px',
display: 'block',
},
titleRow: {
display: 'flex',
alignItems: 'center',
gap: '16px',
flexWrap: 'wrap',
},
title: {
fontSize: '28px',
fontWeight: '700',
margin: 0,
},
address: {
color: 'var(--text-secondary)',
marginTop: '8px',
fontSize: '15px',
},
grid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))',
gap: '20px',
},
card: {
background: 'white',
borderRadius: '12px',
padding: '20px',
},
cardTitle: {
fontSize: '14px',
fontWeight: '600',
marginBottom: '16px',
color: 'var(--text-secondary)',
},
infoRow: {
display: 'flex',
justifyContent: 'space-between',
padding: '10px 0',
borderBottom: '1px solid var(--border)',
},
infoLabel: {
color: 'var(--text-muted)',
fontSize: '14px',
},
infoValue: {
fontWeight: '500',
fontSize: '14px',
},
statsRow: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))',
gap: '16px',
marginTop: '24px',
},
statCard: {
background: 'white',
borderRadius: '12px',
padding: '20px',
display: 'flex',
alignItems: 'center',
gap: '16px',
},
statIcon: {
fontSize: '32px',
},
statValue: {
fontSize: '28px',
fontWeight: '700',
},
statLabel: {
fontSize: '13px',
color: 'var(--text-muted)',
},
section: {
marginTop: '32px',
},
sectionTitle: {
fontSize: '18px',
fontWeight: '600',
marginBottom: '16px',
},
deviceGrid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
gap: '16px',
},
deviceCard: {
background: 'white',
borderRadius: '12px',
padding: '16px',
},
deviceHeader: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '8px',
},
deviceId: {
fontFamily: 'monospace',
fontSize: '14px',
fontWeight: '600',
},
statusDot: {
width: '10px',
height: '10px',
borderRadius: '50%',
},
deviceType: {
fontSize: '15px',
fontWeight: '500',
marginBottom: '8px',
},
deviceMeta: {
fontSize: '12px',
color: 'var(--text-muted)',
display: 'flex',
flexDirection: 'column',
gap: '4px',
},
table: {
background: 'white',
borderRadius: '12px',
overflow: 'hidden',
},
tableHeader: {
display: 'grid',
gridTemplateColumns: '1.5fr 2fr 1fr 1fr',
gap: '16px',
padding: '14px 20px',
background: 'var(--surface)',
fontSize: '12px',
fontWeight: '600',
color: 'var(--text-muted)',
textTransform: 'uppercase',
},
tableRow: {
display: 'grid',
gridTemplateColumns: '1.5fr 2fr 1fr 1fr',
gap: '16px',
padding: '14px 20px',
borderBottom: '1px solid var(--border)',
alignItems: 'center',
fontSize: '14px',
},
userName: {
fontWeight: '500',
},
email: {
color: 'var(--text-secondary)',
},
mono: {
fontFamily: 'monospace',
fontSize: '13px',
},
muted: {
color: 'var(--text-muted)',
fontSize: '13px',
},
viewBtn: {
padding: '8px 16px',
background: 'var(--primary)',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '13px',
cursor: 'pointer',
},
};