fix: redesign session review as card layout instead of cramped table

This commit is contained in:
Usman Baig
2026-03-22 13:25:02 +01:00
parent 42b7363cf9
commit 0878bde259

View File

@@ -1369,104 +1369,66 @@ export default function SiteSettingsPage() {
</div> </div>
)} )}
{/* Sessions table */} {/* Session cards */}
<div className="overflow-x-auto"> <div className="space-y-2">
<table className="w-full text-left text-sm"> {(sessions?.sessions || [])
<thead className="border-b border-neutral-800"> .filter(s => botView === 'blocked' ? s.bot_filtered : !s.bot_filtered)
<tr> .map((session) => (
<th className="pb-2 pr-2 w-8"> <div key={session.session_id} className="flex items-center gap-3 p-3 rounded-xl border border-neutral-800 hover:border-neutral-700 transition-colors">
<input <input
type="checkbox" type="checkbox"
onChange={(e) => { checked={selectedSessions.has(session.session_id)}
if (e.target.checked) { onChange={(e) => {
const allIds = new Set((sessions?.sessions || []).map(s => s.session_id)) const next = new Set(selectedSessions)
setSelectedSessions(allIds) if (e.target.checked) next.add(session.session_id)
} else { else next.delete(session.session_id)
setSelectedSessions(new Set()) setSelectedSessions(next)
} }}
}} className="rounded border-neutral-600 bg-neutral-800 text-brand-orange focus:ring-brand-orange shrink-0"
checked={selectedSessions.size > 0 && selectedSessions.size === (sessions?.sessions || []).length} />
className="rounded border-neutral-600 bg-neutral-800 text-brand-orange focus:ring-brand-orange"
/> <div className="flex-1 min-w-0">
</th> <div className="flex items-center gap-2 mb-1">
<th className="pb-2 text-neutral-400 font-medium">Session</th> <span className="text-sm font-medium text-white truncate">{session.first_page}</span>
<th className="pb-2 text-neutral-400 font-medium">Pages</th> <span className={`shrink-0 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${
<th className="pb-2 text-neutral-400 font-medium">Duration</th> session.suspicion_score >= 5 ? 'bg-red-900/30 text-red-400' :
<th className="pb-2 text-neutral-400 font-medium">Location</th> session.suspicion_score >= 3 ? 'bg-yellow-900/30 text-yellow-400' :
<th className="pb-2 text-neutral-400 font-medium">Browser</th> 'bg-neutral-800 text-neutral-400'
<th className="pb-2 text-neutral-400 font-medium">Referrer</th> }`}>
<th className="pb-2 text-neutral-400 font-medium">Score</th> {session.suspicion_score >= 5 ? 'High risk' : session.suspicion_score >= 3 ? 'Suspicious' : 'Low risk'}
<th className="pb-2 text-neutral-400 font-medium">Action</th> </span>
</tr> </div>
</thead> <div className="flex items-center gap-3 text-xs text-neutral-500">
<tbody className="divide-y divide-neutral-800"> <span>{session.pageviews} page{session.pageviews !== 1 ? 's' : ''}</span>
{(sessions?.sessions || []) <span>{session.duration != null ? `${Math.round(session.duration)}s` : 'No duration'}</span>
.filter(s => botView === 'blocked' ? s.bot_filtered : !s.bot_filtered) <span>{[session.city, session.country].filter(Boolean).join(', ') || 'Unknown location'}</span>
.map((session) => ( <span>{session.browser || 'Unknown browser'}</span>
<tr key={session.session_id} className="hover:bg-neutral-800/50"> <span>{session.referrer || 'Direct'}</span>
<td className="py-2.5 pr-2"> </div>
<input </div>
type="checkbox"
checked={selectedSessions.has(session.session_id)} {botView === 'review' ? (
onChange={(e) => { <button
const next = new Set(selectedSessions) onClick={() => handleBotFilter([session.session_id])}
if (e.target.checked) next.add(session.session_id) className="shrink-0 px-3 py-1.5 text-xs font-medium text-red-400 hover:text-white hover:bg-red-500/20 rounded-lg border border-red-500/20 transition-colors"
else next.delete(session.session_id) >
setSelectedSessions(next) Flag as bot
}} </button>
className="rounded border-neutral-600 bg-neutral-800 text-brand-orange focus:ring-brand-orange" ) : (
/> <button
</td> onClick={() => handleBotUnfilter([session.session_id])}
<td className="py-2.5"> className="shrink-0 px-3 py-1.5 text-xs font-medium text-green-400 hover:text-white hover:bg-green-500/20 rounded-lg border border-green-500/20 transition-colors"
<div className="font-mono text-xs text-neutral-300">{session.session_id.slice(0, 12)}...</div> >
<div className="text-xs text-neutral-500 mt-0.5">{session.first_page}</div> Unblock
</td> </button>
<td className="py-2.5 text-neutral-300">{session.pageviews}</td>
<td className="py-2.5 text-neutral-300">
{session.duration != null ? `${Math.round(session.duration)}s` : <span className="text-neutral-600">&mdash;</span>}
</td>
<td className="py-2.5 text-neutral-300 text-xs">
{[session.city, session.country].filter(Boolean).join(', ') || '\u2014'}
</td>
<td className="py-2.5 text-neutral-300 text-xs">{session.browser || '\u2014'}</td>
<td className="py-2.5 text-neutral-300 text-xs">{session.referrer || <span className="text-neutral-600">Direct</span>}</td>
<td className="py-2.5">
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${
session.suspicion_score >= 5 ? 'bg-red-900/30 text-red-400' :
session.suspicion_score >= 3 ? 'bg-yellow-900/30 text-yellow-400' :
'bg-neutral-800 text-neutral-400'
}`}>
{session.suspicion_score}
</span>
</td>
<td className="py-2.5">
{botView === 'review' ? (
<button
onClick={() => handleBotFilter([session.session_id])}
className="text-xs font-medium text-red-400 hover:text-red-300"
>
Flag
</button>
) : (
<button
onClick={() => handleBotUnfilter([session.session_id])}
className="text-xs font-medium text-green-400 hover:text-green-300"
>
Unblock
</button>
)}
</td>
</tr>
))}
{(sessions?.sessions || []).filter(s => botView === 'blocked' ? s.bot_filtered : !s.bot_filtered).length === 0 && (
<tr>
<td colSpan={9} className="py-8 text-center text-neutral-500 text-sm">
{botView === 'blocked' ? 'No blocked sessions' : 'No suspicious sessions found'}
</td>
</tr>
)} )}
</tbody> </div>
</table> ))}
{(sessions?.sessions || []).filter(s => botView === 'blocked' ? s.bot_filtered : !s.bot_filtered).length === 0 && (
<div className="py-12 text-center text-neutral-500 text-sm">
{botView === 'blocked' ? 'No blocked sessions' : 'No suspicious sessions found'}
</div>
)}
</div> </div>
</div> </div>
</div> </div>