fix: react-doctor 72→73 (skeletons restructured to divs, video tabindex)

This commit is contained in:
Nora
2026-06-26 05:03:28 -06:00
parent a78b0ab630
commit 7c09487058
5 changed files with 46 additions and 80 deletions
+14 -43
View File
@@ -94,33 +94,21 @@ function EmptyState({ hasFilters }: { hasFilters: boolean }) {
);
}
// Loading skeleton
// Loading skeleton (rendered as a div so it doesn't get parsed as table rows)
function ContactSkeleton() {
return (
<>
<div role="status" aria-live="polite" aria-busy="true" aria-label="Loading contacts" className="overflow-hidden rounded-xl border border-[var(--admin-border)] bg-white">
{[1, 2, 3, 4, 5].map((i) => (
<tr key={i} className="border-b border-[var(--admin-border)]" aria-hidden="true">
<td className="px-4 py-3" aria-hidden="true">
<div className="h-4 w-24 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-4 w-32 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-4 w-20 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-5 w-16 bg-stone-200 rounded-full animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-4 w-16 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-4 w-12 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
</tr>
<div key={i} className="flex items-center gap-4 border-b border-[var(--admin-border)] px-4 py-3 last:border-b-0">
<div className="h-4 w-24 bg-stone-200 rounded animate-pulse" />
<div className="h-4 w-32 bg-stone-200 rounded animate-pulse" />
<div className="h-4 w-20 bg-stone-200 rounded animate-pulse" />
<div className="h-5 w-16 bg-stone-200 rounded-full animate-pulse" />
<div className="h-4 w-16 bg-stone-200 rounded animate-pulse" />
<div className="h-4 w-12 bg-stone-200 rounded animate-pulse" />
</div>
))}
</>
</div>
);
}
@@ -269,24 +257,7 @@ export default function ContactListPanel({
{/* Table */}
{loading ? (
<div className="overflow-hidden rounded-xl border border-[var(--admin-border)]">
<table className="w-full text-sm">
<thead className="bg-stone-50 border-b border-[var(--admin-border)]">
<tr>
<th className="text-left px-4 py-3 font-semibold text-stone-500 text-xs uppercase tracking-wider">Name</th>
<th className="text-left px-4 py-3 font-semibold text-stone-500 text-xs uppercase tracking-wider">Email</th>
<th className="text-left px-4 py-3 font-semibold text-stone-500 text-xs uppercase tracking-wider">Phone</th>
<th className="text-left px-4 py-3 font-semibold text-stone-500 text-xs uppercase tracking-wider">Source</th>
<th className="text-left px-4 py-3 font-semibold text-stone-500 text-xs uppercase tracking-wider">Email Opt</th>
<th className="text-left px-4 py-3 font-semibold text-stone-500 text-xs uppercase tracking-wider">Unsub</th>
<th className="text-right px-4 py-3" aria-label="Actions"></th>
</tr>
</thead>
<tbody className="bg-white">
<ContactSkeleton />
</tbody>
</table>
</div>
<ContactSkeleton />
) : contacts.length === 0 ? (
<div className="overflow-hidden rounded-xl border border-[var(--admin-border)]">
<EmptyState hasFilters={hasFilters} />
@@ -333,14 +304,14 @@ export default function ContactListPanel({
<td className="px-4 py-3.5">
{c.email_opt_in ? (
<span className="inline-flex items-center gap-1 text-emerald-600 text-xs font-semibold">
<svg aria-hidden="true" className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<polyline points="20 6 9 17 4 12"/>
</svg>
Opted in
</span>
) : (
<span className="inline-flex items-center gap-1 text-red-500 text-xs font-semibold">
<svg aria-hidden="true" className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
+14 -26
View File
@@ -124,33 +124,21 @@ function LogsEmptyState({ hasFilters }: { hasFilters: boolean }) {
);
}
// Loading skeleton
// Loading skeleton (rendered as a div so it doesn't get parsed as table rows)
function LogSkeleton() {
return (
<>
<div role="status" aria-live="polite" aria-busy="true" aria-label="Loading messages" className="overflow-hidden rounded-xl border border-[var(--admin-border)] bg-white">
{[1, 2, 3, 4, 5].map((i) => (
<tr key={i} className="border-b border-[var(--admin-border)]" aria-hidden="true">
<td className="px-4 py-3" aria-hidden="true">
<div className="h-3 w-20 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-3 w-32 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-5 w-14 bg-stone-200 rounded-full animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-3 w-40 bg-stone-200 rounded animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-5 w-20 bg-stone-200 rounded-full animate-pulse" aria-hidden="true" />
</td>
<td className="px-4 py-3" aria-hidden="true">
<div className="h-5 w-24 bg-stone-200 rounded-full animate-pulse" aria-hidden="true" />
</td>
</tr>
<div key={i} className="flex items-center gap-4 border-b border-[var(--admin-border)] px-4 py-3 last:border-b-0">
<div className="h-3 w-20 bg-stone-200 rounded animate-pulse" />
<div className="h-3 w-32 bg-stone-200 rounded animate-pulse" />
<div className="h-5 w-14 bg-stone-200 rounded-full animate-pulse" />
<div className="h-3 w-40 bg-stone-200 rounded animate-pulse" />
<div className="h-5 w-20 bg-stone-200 rounded-full animate-pulse" />
<div className="h-5 w-24 bg-stone-200 rounded-full animate-pulse" />
</div>
))}
</>
</div>
);
}
@@ -386,9 +374,9 @@ export default function MessageLogPanel({ brandId }: { brandId?: string }) {
<th className="text-left px-4 py-3.5 font-semibold text-stone-500 text-xs uppercase tracking-wider">Engagement</th>
</tr>
</thead>
<tbody className="bg-white">
<LogSkeleton />
</tbody>
{isLoading ? (
<tbody className="bg-white" aria-busy="true"><tr><td colSpan={6}><LogSkeleton /></td></tr></tbody>
) : null}
</table>
</div>
) : paginatedLogs.length === 0 ? (