All files / web/src/app/api/create/worksheets/addition/example route.ts

0% Statements 0/176
0% Branches 0/1
0% Functions 0/1
0% Lines 0/176

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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177                                                                                                                                                                                                                                                                                                                                                                 
// API route for generating compact addition problem examples for display option previews
//
// REUSABLE FOR BLOG POSTS: The generateExampleTypst function below is also used
// to generate static single-problem examples for blog posts. See:
// - scripts/generateTenFrameExamples.ts for the blog post example generator
// - scripts/generateBlogExamples.ts for difficulty progression examples
//
// This ensures blog post examples use the EXACT same rendering as the live UI preview,
// maintaining consistency between what users see in documentation vs. the actual tool.

import { execSync } from 'child_process'
import { NextResponse } from 'next/server'
import type { WorksheetOperator } from '@/app/create/worksheets/types'
import {
  generatePlaceValueColors,
  generateProblemStackFunction,
  generateSubtractionProblemStackFunction,
  generateTypstHelpers,
} from '@/app/create/worksheets/typstHelpers'
import { withAuth } from '@/lib/auth/withAuth'

export const dynamic = 'force-dynamic'

interface ExampleRequest {
  showCarryBoxes?: boolean
  showAnswerBoxes?: boolean
  showPlaceValueColors?: boolean
  showProblemNumbers?: boolean
  showCellBorder?: boolean
  showTenFrames?: boolean
  showTenFramesForAll?: boolean
  showBorrowNotation?: boolean
  showBorrowingHints?: boolean
  fontSize?: number
  operator?: WorksheetOperator
  // For addition
  addend1?: number
  addend2?: number
  // For subtraction
  minuend?: number
  subtrahend?: number
}

/**
 * Generate a single compact problem example showing the combined display options
 * Uses the EXACT same Typst structure as the full worksheet generator
 */
function generateExampleTypst(config: ExampleRequest): string {
  const operator = config.operator ?? 'addition'
  const fontSize = config.fontSize || 14
  const cellSize = 0.35 // Compact cell size for examples

  // Boolean flags matching worksheet generator
  const showCarries = config.showCarryBoxes ?? false
  const showAnswers = config.showAnswerBoxes ?? false
  const showColors = config.showPlaceValueColors ?? false
  const showNumbers = config.showProblemNumbers ?? false
  const showTenFrames = config.showTenFrames ?? false
  const showTenFramesForAll = config.showTenFramesForAll ?? false
  const showBorrowNotation = config.showBorrowNotation ?? true
  const showBorrowingHints = config.showBorrowingHints ?? false

  if (operator === 'addition') {
    // Use custom addends if provided, otherwise use a 3-digit problem with multiple regroups
    let a: number
    let b: number

    if (config.addend1 !== undefined && config.addend2 !== undefined) {
      a = config.addend1
      b = config.addend2
    } else {
      // Use a 3-digit problem with multiple regroups to demonstrate all scaffolding features
      // 456 + 789 = 1245 (3 digits, 3 regroups: ones, tens, hundreds)
      a = 456
      b = 789
    }

    return String.raw`
#set page(width: auto, height: auto, margin: 8pt, fill: white)
#set text(size: ${fontSize}pt, font: "New Computer Modern Math")

#let heavy-stroke = 0.8pt
#let show-carries = ${showCarries ? 'true' : 'false'}
#let show-answers = ${showAnswers ? 'true' : 'false'}
#let show-colors = ${showColors ? 'true' : 'false'}
#let show-numbers = ${showNumbers ? 'true' : 'false'}
#let show-ten-frames = ${showTenFrames ? 'true' : 'false'}
#let show-ten-frames-for-all = ${showTenFramesForAll ? 'true' : 'false'}

${generatePlaceValueColors()}

${generateTypstHelpers(cellSize)}

${generateProblemStackFunction(cellSize, 3)}

#let a = ${a}
#let b = ${b}

#align(center + horizon)[
  #problem-stack(a, b, if show-numbers { 0 } else { none }, show-carries, show-answers, show-colors, show-ten-frames, show-numbers)
]
`
  } else {
    // Subtraction
    let minuend: number
    let subtrahend: number

    if (config.minuend !== undefined && config.subtrahend !== undefined) {
      minuend = config.minuend
      subtrahend = config.subtrahend
    } else {
      // Use a 3-digit problem with multiple borrows to demonstrate all scaffolding features
      // 832 - 456 = 376 (3 digits, 2 borrows: ones and tens)
      minuend = 832
      subtrahend = 456
    }

    return String.raw`
#set page(width: auto, height: auto, margin: 8pt, fill: white)
#set text(size: ${fontSize}pt, font: "New Computer Modern Math")

#let heavy-stroke = 0.8pt
#let show-borrows = ${showCarries ? 'true' : 'false'}
#let show-answers = ${showAnswers ? 'true' : 'false'}
#let show-colors = ${showColors ? 'true' : 'false'}
#let show-numbers = ${showNumbers ? 'true' : 'false'}
#let show-ten-frames = ${showTenFrames ? 'true' : 'false'}
#let show-ten-frames-for-all = ${showTenFramesForAll ? 'true' : 'false'}
#let show-borrow-notation = ${showBorrowNotation ? 'true' : 'false'}
#let show-borrowing-hints = ${showBorrowingHints ? 'true' : 'false'}

${generatePlaceValueColors()}

${generateTypstHelpers(cellSize)}

${generateSubtractionProblemStackFunction(cellSize, 3)}

#let minuend = ${minuend}
#let subtrahend = ${subtrahend}

#align(center + horizon)[
  #subtraction-problem-stack(minuend, subtrahend, if show-numbers { 0 } else { none }, show-borrows, show-answers, show-colors, show-ten-frames, show-numbers, show-borrow-notation, show-borrowing-hints)
]
`
  }
}

export const POST = withAuth(async (request) => {
  try {
    const body: ExampleRequest = await request.json()

    // Generate Typst source with all display options
    const typstSource = generateExampleTypst(body)

    // Compile to SVG
    const svg = execSync('typst compile --format svg - -', {
      input: typstSource,
      encoding: 'utf8',
      maxBuffer: 2 * 1024 * 1024,
    })

    return NextResponse.json({ svg })
  } catch (error) {
    console.error('Error generating example:', error)

    const errorMessage = error instanceof Error ? error.message : String(error)

    return NextResponse.json(
      {
        error: 'Failed to generate example',
        message: errorMessage,
      },
      { status: 500 }
    )
  }
})