All files / web/src/components/practice/start-practice-modal PracticeModesSelector.tsx

85.71% Statements 66/77
77.77% Branches 7/9
66.66% Functions 2/3
85.71% Lines 66/77

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 781x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 27x 27x 27x 27x 27x 27x 27x 27x                       27x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x  
'use client'
 
import { useMemo } from 'react'
import { useTheme } from '@/contexts/ThemeContext'
import { useLinearReadiness } from '@/hooks/useLinearReadiness'
import { PART_TYPES, useStartPracticeModal } from '../StartPracticeModalContext'
import { LinearGraduationBanner } from './LinearGraduationBanner'
import { LinearLockNote } from './LinearLockNote'
import { ProportionBar, type ProportionBarSegment } from './ProportionBar'
 
const GREEN_COLORS: ProportionBarSegment['colors'] = {
  lightBg: 'rgba(22, 163, 74, 0.08)',
  lightBgBoosted: 'rgba(22, 163, 74, 0.15)',
  darkBg: 'rgba(34, 197, 94, 0.15)',
  darkBgBoosted: 'rgba(34, 197, 94, 0.25)',
  lightAccent: '#16a34a',
  darkAccent: '#4ade80',
}
 
export function PracticeModesSelector() {
  const { resolvedTheme } = useTheme()
  const isDark = resolvedTheme === 'dark'
  const {
    studentId,
    partWeights,
    linearLocked,
    closeModal,
    cyclePartWeight,
    disablePart,
    problemsPerType,
    enabledPartCount,
  } = useStartPracticeModal()
  // Same query the context's lock decision came from (deduped by React Query);
  // read here only for the popover copy.
  const { data: readiness } = useLinearReadiness(studentId)
 
  const segments = useMemo<ProportionBarSegment[]>(
    () =>
      PART_TYPES.map(({ type, emoji, label }) => ({
        key: type,
        emoji,
        label,
        weight: partWeights[type],
        badgeContent: partWeights[type] > 0 ? problemsPerType[type] : undefined,
        colors: GREEN_COLORS,
        locked:
          type === 'linear' && linearLocked && readiness
            ? {
                ariaLabel: 'Linear locked — tap to see why',
                content: (
                  <LinearLockNote
                    state={readiness}
                    studentId={studentId}
                    isDark={isDark}
                    onNavigate={closeModal}
                  />
                ),
              }
            : undefined,
      })),
    [partWeights, problemsPerType, linearLocked, readiness, studentId, isDark, closeModal]
  )
 
  return (
    <>
      <LinearGraduationBanner />
      <ProportionBar
        label="Practice Modes"
        dataSetting="practice-modes"
        segments={segments}
        onCycleWeight={(key) => cyclePartWeight(key as keyof typeof partWeights)}
        onDisable={(key) => disablePart(key as keyof typeof partWeights)}
        enabledCount={enabledPartCount}
      />
    </>
  )
}