@@ -366,6 +366,19 @@ export const DashboardGroupZone = memo(function DashboardGroupZone({
366366 return (
367367 < section className = "v11-card px-4 py-4 sm:px-6 sm:py-6 lg:px-8" >
368368 < div className = "sm:hidden" >
369+ < MobileSessionFirstDashboardZone
370+ locale = { locale }
371+ selectedGroup = { selectedGroup }
372+ selectedMembers = { selectedMembers }
373+ selectedActiveSession = { selectedActiveSession }
374+ selectedNextSession = { selectedNextSession }
375+ sessionHref = { sessionHref }
376+ canStartSelectedGroup = { canStartSelectedGroup }
377+ labels = { labels }
378+ />
379+ </ div >
380+
381+ < div className = "hidden sm:block" >
369382 < div className = "flex items-center justify-between gap-3" >
370383 < div ref = { groupMenuRef } className = "relative min-w-0 flex-1" >
371384 < button
@@ -1428,6 +1441,187 @@ export const DashboardGroupZone = memo(function DashboardGroupZone({
14281441 ) ;
14291442} ) ;
14301443
1444+ function MobileSessionFirstDashboardZone ( {
1445+ locale,
1446+ selectedGroup,
1447+ selectedMembers,
1448+ selectedActiveSession,
1449+ selectedNextSession,
1450+ sessionHref,
1451+ canStartSelectedGroup,
1452+ labels,
1453+ } : {
1454+ locale : string ;
1455+ selectedGroup : DashboardGroupZoneGroup | null ;
1456+ selectedMembers : DashboardGroupZoneGroup [ 'membersPreview' ] ;
1457+ selectedActiveSession : DashboardGroupZoneSession | null ;
1458+ selectedNextSession : DashboardGroupZoneSession | null ;
1459+ sessionHref : string | null ;
1460+ canStartSelectedGroup : boolean ;
1461+ labels : DashboardGroupZoneProps [ 'labels' ] ;
1462+ } ) {
1463+ const primarySession = selectedActiveSession ?? selectedNextSession ;
1464+ const secondarySession =
1465+ selectedNextSession && selectedNextSession . id !== primarySession ?. id
1466+ ? selectedNextSession
1467+ : ( selectedGroup ?. recentSessions ?? [ ] ) . find (
1468+ ( session ) => session . id !== primarySession ?. id ,
1469+ ) ;
1470+ const primaryHref = primarySession
1471+ ? `/${ locale } /sessions/${ primarySession . id } `
1472+ : ( sessionHref ?? `/${ locale } /dashboard` ) ;
1473+
1474+ if ( ! selectedGroup ) {
1475+ return (
1476+ < div className = "rounded-[16px] border border-dashed border-white/[0.08] px-4 py-5 text-sm font-semibold text-[#8fa7a2]" >
1477+ { labels . noGroups }
1478+ </ div >
1479+ ) ;
1480+ }
1481+
1482+ return (
1483+ < div className = "space-y-3" >
1484+ < section className = "rounded-[15px] border border-white/[0.045] bg-[#071a18]/75 px-4 py-3" >
1485+ < div className = "flex items-center justify-between" >
1486+ < h2 className = "text-[13px] font-semibold text-[#d7e3df]" >
1487+ { locale === 'fr' ? 'Score de calibration' : 'Calibration score' }
1488+ </ h2 >
1489+ < a
1490+ href = { `/${ locale } /dashboard/progression` }
1491+ className = "text-[11px] font-semibold text-[#20D9A3]"
1492+ >
1493+ { locale === 'fr' ? 'Voir plus' : 'View more' }
1494+ </ a >
1495+ </ div >
1496+ < div className = "mt-3 grid grid-cols-2 divide-x divide-white/[0.06]" >
1497+ < div className = "pr-3 text-center" >
1498+ < p className = "text-[25px] font-semibold leading-none text-[#20D9A3]" >
1499+ { primarySession ?. accuracyPercent ?? 0 } %
1500+ </ p >
1501+ < p className = "mt-1 text-[11px] text-[#8fa7a2]" >
1502+ { labels . accuracy }
1503+ </ p >
1504+ </ div >
1505+ < div className = "pl-3 text-center" >
1506+ < p className = "text-[25px] font-semibold leading-none text-[#9FF0CE]" >
1507+ { primarySession ?. completionPercent ?? 0 } %
1508+ </ p >
1509+ < p className = "mt-1 text-[11px] text-[#8fa7a2]" >
1510+ { labels . completion }
1511+ </ p >
1512+ </ div >
1513+ </ div >
1514+ </ section >
1515+
1516+ < section className = "relative rounded-[18px] border border-white/[0.045] bg-[#0b2a25] px-4 pb-5 pt-4 shadow-[0_18px_60px_rgba(0,0,0,0.2)]" >
1517+ < h2 className = "truncate text-[15px] font-semibold leading-none text-[#d7e3df]" >
1518+ { selectedGroup . name }
1519+ </ h2 >
1520+
1521+ < div className = "mt-3 space-y-2.5 pr-[58px]" >
1522+ < a
1523+ href = { primaryHref }
1524+ className = "grid min-h-[58px] grid-cols-[96px_minmax(0,1fr)_44px] items-center gap-2 rounded-[13px] border border-white/[0.055] bg-white/[0.018] px-2 py-2"
1525+ >
1526+ < span className = "flex min-w-0 items-center" >
1527+ < CompactAvatarStack members = { selectedMembers ?. slice ( 0 , 3 ) } />
1528+ </ span >
1529+ < span className = "min-w-0" >
1530+ < span
1531+ className = { `block truncate text-[12px] font-semibold ${
1532+ selectedActiveSession ? 'text-[#20D9A3]' : 'text-[#8fa7a2]'
1533+ } `}
1534+ >
1535+ { selectedActiveSession ? labels . live : labels . nextSession }
1536+ </ span >
1537+ < span className = "block truncate text-[13px] font-semibold text-[#e8f4f0]" >
1538+ { primarySession ?. name ?? labels . noUpcomingSession }
1539+ </ span >
1540+ < span className = "block truncate text-[10px] text-[#8fa7a2]" >
1541+ { primarySession
1542+ ? getCompactSessionMeta ( primarySession )
1543+ : `${ selectedGroup . memberCount } ${ labels . members } ` }
1544+ </ span >
1545+ </ span >
1546+ < span className = "flex flex-col items-center justify-center" >
1547+ < span className = "flex h-8 w-8 items-center justify-center rounded-full bg-[#20D9A3] text-[#062b22]" >
1548+ < Play className = "h-4 w-4 fill-current" aria-hidden = "true" />
1549+ </ span >
1550+ < span className = "mt-0.5 text-[10px] font-semibold text-[#20D9A3]" >
1551+ { selectedActiveSession ? getCompactJoinLabel ( labels . joinLiveSession ) : 'Start' }
1552+ </ span >
1553+ </ span >
1554+ </ a >
1555+
1556+ < button
1557+ type = "button"
1558+ disabled = { ! canStartSelectedGroup }
1559+ onClick = { ( ) => {
1560+ if ( ! canStartSelectedGroup ) return ;
1561+ window . dispatchEvent (
1562+ new CustomEvent ( 'activeboard:open-create-session' , {
1563+ detail : { groupId : selectedGroup . id } ,
1564+ } ) ,
1565+ ) ;
1566+ } }
1567+ className = "grid min-h-[58px] w-full grid-cols-[96px_minmax(0,1fr)_68px] items-center gap-2 rounded-[13px] border border-white/[0.035] bg-white/[0.012] px-2 py-2 text-left transition disabled:opacity-70"
1568+ >
1569+ < span className = "flex items-center gap-1" >
1570+ < PlaceholderAvatar />
1571+ < PlaceholderAvatar />
1572+ < PlaceholderAvatar />
1573+ </ span >
1574+ < span className = "min-w-0" >
1575+ < span className = "block truncate text-[13px] font-semibold text-[#e8f4f0]" >
1576+ { secondarySession ?. name ?? labels . scheduleSession }
1577+ </ span >
1578+ < span className = "block truncate text-[10px] text-[#8fa7a2]" >
1579+ { secondarySession
1580+ ? `${ secondarySession . question_goal } Q · ${ secondarySession . timer_seconds } sec`
1581+ : `20Q · ${ labels . timerLabel . replace ( '{seconds}' , '90' ) } ` }
1582+ </ span >
1583+ </ span >
1584+ < span className = "truncate text-right text-[10px] font-semibold text-[#8fa7a2]" >
1585+ { secondarySession
1586+ ? formatSessionDate ( secondarySession . scheduled_at , locale )
1587+ : labels . scheduledFor . replace ( '{date}' , '' ) }
1588+ </ span >
1589+ </ button >
1590+ </ div >
1591+
1592+ < button
1593+ type = "button"
1594+ disabled = { ! canStartSelectedGroup }
1595+ onClick = { ( ) => {
1596+ if ( ! canStartSelectedGroup ) return ;
1597+ window . dispatchEvent (
1598+ new CustomEvent ( 'activeboard:open-create-session' , {
1599+ detail : { groupId : selectedGroup . id } ,
1600+ } ) ,
1601+ ) ;
1602+ } }
1603+ className = { `absolute bottom-4 right-4 flex h-[52px] w-[52px] items-center justify-center rounded-full border text-[#9FF0CE] shadow-[0_18px_44px_rgba(0,0,0,0.35)] transition ${
1604+ canStartSelectedGroup
1605+ ? 'border-[#20D9A3]/30 bg-[#0d3a34] hover:bg-[#114940]'
1606+ : 'cursor-not-allowed border-white/[0.06] bg-white/[0.04] text-[#5f7b75]'
1607+ } `}
1608+ aria-label = { labels . startSession }
1609+ >
1610+ < Plus className = "h-7 w-7" aria-hidden = "true" />
1611+ </ button >
1612+ </ section >
1613+ </ div >
1614+ ) ;
1615+ }
1616+
1617+ function PlaceholderAvatar ( ) {
1618+ return (
1619+ < span className = "flex h-8 w-8 items-center justify-center rounded-full border-2 border-[#0e2c28] bg-white/[0.045] text-[#8fa7a2]" >
1620+ < UsersRound className = "h-3.5 w-3.5" aria-hidden = "true" />
1621+ </ span >
1622+ ) ;
1623+ }
1624+
14311625function MobileSessionList ( {
14321626 locale,
14331627 labels,
0 commit comments