feat: render sessions grouped by day with styled header bars

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-23 11:34:41 -04:00
parent ad8efc0fbf
commit bfabf390b4

View File

@@ -1,9 +1,9 @@
import React, { useState, useEffect, useCallback, useRef } from 'react'; import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext'; import { useAuth } from '../context/AuthContext';
import { useToast } from '../components/Toast'; import { useToast } from '../components/Toast';
import api from '../api/axios'; import api from '../api/axios';
import { formatLocalDate, isSunday } from '../utils/dateUtils'; import { formatDayHeader, formatTimeOnly, getLocalDateKey, isSunday } from '../utils/dateUtils';
import { prefixKey } from '../utils/adminPrefs'; import { prefixKey } from '../utils/adminPrefs';
function History() { function History() {
@@ -150,6 +150,23 @@ function History() {
} }
}; };
const groupedSessions = useMemo(() => {
const groups = [];
let currentKey = null;
sessions.forEach(session => {
const dateKey = getLocalDateKey(session.created_at);
if (dateKey !== currentKey) {
currentKey = dateKey;
groups.push({ dateKey, sessions: [session] });
} else {
groups[groups.length - 1].sessions.push(session);
}
});
return groups;
}, [sessions]);
if (loading) { if (loading) {
return ( return (
<div className="flex justify-center items-center h-64"> <div className="flex justify-center items-center h-64">
@@ -220,12 +237,41 @@ function History() {
<p className="text-gray-500 dark:text-gray-400">No sessions found</p> <p className="text-gray-500 dark:text-gray-400">No sessions found</p>
) : ( ) : (
<div className="space-y-2"> <div className="space-y-2">
{sessions.map(session => { {groupedSessions.map((group, groupIdx) => {
const isSundayGroup = isSunday(group.sessions[0].created_at);
const isContinued = groupIdx === 0 && page > 1 && prevLastDate &&
getLocalDateKey(prevLastDate) === group.dateKey;
return (
<div key={group.dateKey}>
{/* Day header bar */}
<div className="bg-gray-100 dark:bg-[#1e2a3a] rounded-md px-3.5 py-2 mb-2 flex justify-between items-center border-l-[3px] border-indigo-500">
<div className="flex items-center gap-2">
<span className="text-sm font-semibold text-indigo-700 dark:text-indigo-300">
{formatDayHeader(group.sessions[0].created_at)}
</span>
{isContinued && (
<span className="text-xs text-gray-400 dark:text-gray-500 italic">(continued)</span>
)}
</div>
{!isContinued && (
<div className="flex items-center gap-2">
<span className="text-xs text-gray-500 dark:text-gray-400">
{group.sessions.length} session{group.sessions.length !== 1 ? 's' : ''}
</span>
{isSundayGroup && (
<span className="text-xs font-semibold text-amber-700 dark:text-amber-300">🎲 Game Night</span>
)}
</div>
)}
</div>
{/* Session cards under this day */}
<div className="ml-3 space-y-1.5 mb-4">
{group.sessions.map(session => {
const isActive = session.is_active === 1; const isActive = session.is_active === 1;
const isSelected = selectedIds.has(session.id); const isSelected = selectedIds.has(session.id);
const isSundaySession = isSunday(session.created_at);
const isArchived = session.archived === 1; const isArchived = session.archived === 1;
const canSelect = selectMode && !isActive;
return ( return (
<div <div
@@ -280,11 +326,6 @@ function History() {
Active Active
</span> </span>
)} )}
{isSundaySession && (
<span className="bg-amber-100 dark:bg-amber-900 text-amber-800 dark:text-amber-200 text-xs px-2 py-0.5 rounded font-semibold">
🎲 Game Night
</span>
)}
{isArchived && (filter === 'all' || filter === 'archived') && ( {isArchived && (filter === 'all' || filter === 'archived') && (
<span className="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 text-xs px-2 py-0.5 rounded"> <span className="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 text-xs px-2 py-0.5 rounded">
Archived Archived
@@ -296,10 +337,7 @@ function History() {
</span> </span>
</div> </div>
<div className="text-sm text-gray-500 dark:text-gray-400"> <div className="text-sm text-gray-500 dark:text-gray-400">
{formatLocalDate(session.created_at)} {formatTimeOnly(session.created_at)}
{isSundaySession && (
<span className="text-gray-400 dark:text-gray-500"> · Sunday</span>
)}
</div> </div>
{session.has_notes && session.notes_preview && ( {session.has_notes && session.notes_preview && (
<div className="mt-2 text-sm text-indigo-400 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/20 px-3 py-2 rounded border-l-2 border-indigo-500"> <div className="mt-2 text-sm text-indigo-400 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/20 px-3 py-2 rounded border-l-2 border-indigo-500">
@@ -327,6 +365,10 @@ function History() {
); );
})} })}
</div> </div>
</div>
);
})}
</div>
)} )}
{/* Multi-select Action Bar */} {/* Multi-select Action Bar */}