feat(frontend): implement step 11 — pages, components, and routing with React Query

This commit is contained in:
2026-03-26 19:19:08 -03:00
parent 45fc176f32
commit a4dc8577ba
9 changed files with 332 additions and 8 deletions

View File

@@ -0,0 +1,78 @@
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { getLogs, getLogsByEntity } from '../api/logsApi'
import { getEntities } from '../api/entitiesApi'
export default function LogsPage() {
const [selectedEntityId, setSelectedEntityId] = useState<string>('')
const { data: entities = [] } = useQuery({ queryKey: ['entities'], queryFn: getEntities })
const { data: logs = [] } = useQuery({
queryKey: ['logs', selectedEntityId],
queryFn: () => selectedEntityId ? getLogsByEntity(selectedEntityId) : getLogs(),
})
return (
<div className="p-8">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold text-gray-900">Dispatch Logs</h1>
<select
value={selectedEntityId}
onChange={(e) => setSelectedEntityId(e.target.value)}
className="rounded border border-gray-300 px-3 py-2 text-sm"
>
<option value="">All Entities</option>
{entities.map((entity) => (
<option key={entity.id} value={entity.id}>
{entity.name}
</option>
))}
</select>
</div>
<div className="mt-6 overflow-hidden rounded-lg border bg-white shadow-sm">
<table className="w-full text-sm">
<thead className="bg-gray-50 text-left text-xs font-medium uppercase tracking-wide text-gray-500">
<tr>
<th className="px-4 py-3">Subject</th>
<th className="px-4 py-3">Entity</th>
<th className="px-4 py-3">Status</th>
<th className="px-4 py-3">Dispatched At</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
{logs.map((log) => (
<tr key={log.id}>
<td className="px-4 py-3 font-medium">{log.emailSubject}</td>
<td className="px-4 py-3 text-gray-500">{log.entityName}</td>
<td className="px-4 py-3">
<span
className={`rounded-full px-2 py-0.5 text-xs font-medium ${
log.status === 'SENT'
? 'bg-green-100 text-green-700'
: log.status === 'FAILED'
? 'bg-red-100 text-red-700'
: 'bg-yellow-100 text-yellow-700'
}`}
>
{log.status}
</span>
</td>
<td className="px-4 py-3 text-gray-400">
{new Date(log.dispatchedAt).toLocaleString()}
</td>
</tr>
))}
{logs.length === 0 && (
<tr>
<td colSpan={4} className="px-4 py-6 text-center text-gray-400">
No logs found.
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
)
}