/** * VariablesStep — collects all required variable values for invitation import. * * This runs after role selection and before input selection so cashasm * expressions can resolve required variables during `getSatsOut()`. */ import React, { useMemo, useState, useCallback } from "react"; import { Box, Text } from "ink"; import { colors } from "../../../../theme.js"; import { useLayeredInput } from "../../../../hooks/useInputLayer.js"; import { VariableInputField } from "../../../../components/VariableInputField.js"; import type { VariablesStepProps } from "../types.js"; /** * Build a user-facing validation error for empty required fields. */ function validateVariables( variables: VariablesStepProps["variables"], ): string | null { const empty = variables.filter((v) => v.value.trim() === ""); if (empty.length === 0) return null; return `Please enter values for: ${empty.map((v) => v.name).join(", ")}`; } export function VariablesStep({ variables, onUpdateVariable, onComplete, onCancel, isActive, }: VariablesStepProps): React.ReactElement { const [focusedInput, setFocusedInput] = useState(0); const [validationError, setValidationError] = useState(null); const helpText = useMemo(() => { if (variables.length === 0) { return "No variables required for this role."; } return "Enter a value for each variable, then press Enter on the last field to continue."; }, [variables.length]); /** * Move focus to next input, or finish the step if this is the last one. */ const handleInputSubmit = useCallback(() => { if (variables.length === 0) { onComplete(); return; } if (focusedInput < variables.length - 1) { setFocusedInput((prev) => prev + 1); return; } const validation = validateVariables(variables); setValidationError(validation); if (!validation) { onComplete(); } }, [variables, focusedInput, onComplete]); // Keyboard navigation for non-text actions. useLayeredInput( "import-flow", (input, key) => { if (key.upArrow || input === "k") { setFocusedInput((prev) => Math.max(0, prev - 1)); } else if (key.downArrow || input === "j") { setFocusedInput((prev) => Math.min(variables.length - 1, prev + 1)); } else if (key.escape) { onCancel(); } }, { isActive }, ); return ( Required Variables {variables.map((variable, index) => ( ))} {validationError && ( {validationError} )} {helpText} ↑↓: Change field • Esc: Cancel ); }