All files / web/src/app/create/worksheets displayRules.ts

90% Statements 81/90
70% Branches 7/10
100% Functions 2/2
90% Lines 81/90

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 78 79 80 81 82 83 84 85 86 87 88 89 90 911x 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 140x 140x             140x 140x 77x 140x 140x 34x 140x 140x 29x 29x 22x 7x 140x 140x     140x 140x   140x 140x 1x 1x 1x 1x 1x 1x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x  
// Display rules for conditional per-problem scaffolding
 
import type { ProblemMeta, SubtractionProblemMeta } from './problemAnalysis'
 
export type AnyProblemMeta = ProblemMeta | SubtractionProblemMeta
 
export type RuleMode =
  | 'auto' // Defer to mastery progression (should be resolved before rendering)
  | 'always' // Always show this display option
  | 'never' // Never show this display option
  | 'whenRegrouping' // Show when problem requires any regrouping
  | 'whenMultipleRegroups' // Show when 2+ place values regroup
  | 'when3PlusDigits' // Show when maxDigits >= 3
 
export interface DisplayRules {
  carryBoxes: RuleMode
  answerBoxes: RuleMode
  placeValueColors: RuleMode
  tenFrames: RuleMode
  problemNumbers: RuleMode
  cellBorders: RuleMode
  borrowNotation: RuleMode // Subtraction: scratch boxes showing borrowed 10s
  borrowingHints: RuleMode // Subtraction: arrows and visual hints
}
 
export interface ResolvedDisplayOptions {
  showCarryBoxes: boolean
  showAnswerBoxes: boolean
  showPlaceValueColors: boolean
  showTenFrames: boolean
  showProblemNumbers: boolean
  showCellBorder: boolean
  showBorrowNotation: boolean // Subtraction: scratch work boxes in minuend
  showBorrowingHints: boolean // Subtraction: hints with arrows
}
 
/**
 * Evaluate a single display rule against a problem's metadata
 * Works for both addition (regrouping = carrying) and subtraction (regrouping = borrowing)
 */
export function evaluateRule(mode: RuleMode, problem: AnyProblemMeta): boolean {
  switch (mode) {
    case 'auto':
      // 'auto' should have been resolved to a concrete value in validation
      // If it reaches here, something went wrong - default to 'always' to avoid breaking
      console.error(
        '[evaluateRule] BUG: "auto" mode should have been resolved before rendering. Defaulting to "always".'
      )
      return true
 
    case 'always':
      return true
 
    case 'never':
      return false
 
    case 'whenRegrouping':
      // Works for both: requiresRegrouping (addition) or requiresBorrowing (subtraction)
      return 'requiresRegrouping' in problem
        ? problem.requiresRegrouping
        : problem.requiresBorrowing
 
    case 'whenMultipleRegroups':
      // Works for both: regroupCount (addition) or borrowCount (subtraction)
      return 'regroupCount' in problem ? problem.regroupCount >= 2 : problem.borrowCount >= 2
 
    case 'when3PlusDigits':
      return problem.maxDigits >= 3
  }
}
 
/**
 * Resolve all display rules for a specific problem
 * Returns concrete boolean flags for rendering
 */
export function resolveDisplayForProblem(
  rules: DisplayRules,
  problem: AnyProblemMeta
): ResolvedDisplayOptions {
  return {
    showCarryBoxes: evaluateRule(rules.carryBoxes, problem),
    showAnswerBoxes: evaluateRule(rules.answerBoxes, problem),
    showPlaceValueColors: evaluateRule(rules.placeValueColors, problem),
    showTenFrames: evaluateRule(rules.tenFrames, problem),
    showProblemNumbers: evaluateRule(rules.problemNumbers, problem),
    showCellBorder: evaluateRule(rules.cellBorders, problem),
    showBorrowNotation: evaluateRule(rules.borrowNotation, problem),
    showBorrowingHints: evaluateRule(rules.borrowingHints, problem),
  }
}