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

93.24% Statements 69/74
66.66% Branches 8/12
100% Functions 4/4
93.24% Lines 69/74

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 751x 1x 1x 1x 1x 1x 1x 3x 3x       1x 1x 1x 2x 2x 1x 1x 1x 1x 1x 1x 1x 6x 6x 2x 2x 4x 4x 4x 4x     1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x  
'use client'
 
import Link from 'next/link'
import type { LinearReadinessState } from '@/hooks/useLinearReadiness'
import { css } from '../../../../styled-system/css'
 
export function joinNames(names: string[]): string {
  if (names.length === 0) return ''
  if (names.length === 1) return names[0]
  if (names.length === 2) return `${names[0]} and ${names[1]}`
  return `${names.slice(0, -1).join(', ')}, and ${names[names.length - 1]}`
}
 
/** Where "See what's needed" goes: the dashboard's Skills tab, Number sentences panel. */
export function numberSentencesPanelHref(studentId: string): string {
  return `/practice/${studentId}/dashboard?tab=skills#number-sentences`
}
 
/**
 * One line on why number sentences are locked. Two cases:
 * - nothing has graduated yet → name the frontier stage and how close it is
 * - something graduated but the teacher said "not yet" → say so
 */
export function describeLinearLock(state: LinearReadinessState): string {
  const vetoed = state.categories.filter((c) => c.status === 'vetoed')
  if (vetoed.length > 0) {
    return `You said 'not yet' to number sentences for ${joinNames(vetoed.map((c) => c.name))}.`
  }
  const { frontier } = state
  if (frontier) {
    return `Number sentences unlock when your ${frontier.name} are practiced and mastered. ${frontier.solidCount} of ${frontier.total} there.`
  }
  return 'Number sentences are not available yet.'
}
 
/** Popover body for the locked Linear segment (tier 1 of the disclosure). */
export function LinearLockNote({
  state,
  studentId,
  isDark,
  onNavigate,
}: {
  state: LinearReadinessState
  studentId: string
  isDark: boolean
  /**
   * Fired when "See what's needed" is tapped. The link targets the dashboard the
   * modal usually sits on, so the modal has to get out of the way itself.
   */
  onNavigate?: () => void
}) {
  return (
    <div
      data-component="linear-lock-note"
      className={css({ display: 'flex', flexDirection: 'column', gap: '0.5rem' })}
    >
      <p data-element="linear-lock-reason">{describeLinearLock(state)}</p>
      <Link
        href={numberSentencesPanelHref(studentId)}
        onClick={onNavigate}
        data-action="see-linear-requirements"
        className={css({
          alignSelf: 'flex-start',
          fontWeight: '600',
          textDecoration: 'underline',
          textUnderlineOffset: '2px',
        })}
        style={{ color: isDark ? '#86efac' : '#166534' }}
      >
        See what's needed
      </Link>
    </div>
  )
}