Files
xo-cli/src/tui/screens/action-wizard/steps/ReviewStep.tsx
2026-04-27 08:42:51 +00:00

123 lines
3.4 KiB
TypeScript

import React from 'react';
import { Box, Text } from 'ink';
import { colors, formatSatoshis } from '../../../theme.js';
import { useSatoshisConversion } from '../../../hooks/useSatoshisConversion.js';
import type { VariableInput, SelectableUTXO } from '../types.js';
import type { XOTemplate } from '@xo-cash/types';
interface ReviewStepProps {
template: XOTemplate;
actionName: string;
roleIdentifier: string;
variables: VariableInput[];
availableUtxos: SelectableUTXO[];
changeAmount: bigint;
}
export function ReviewStep({
template,
actionName,
roleIdentifier,
variables,
availableUtxos,
changeAmount,
}: ReviewStepProps): React.ReactElement {
const selectedUtxos = availableUtxos.filter((u) => u.selected);
const { formatSatoshisToFiat } = useSatoshisConversion('USD');
const getFiatSuffix = (satoshis: bigint): string => {
const fiatValue = formatSatoshisToFiat(satoshis);
return fiatValue ? ` (~${fiatValue})` : '';
};
const getVariableFiatSuffix = (variable: VariableInput): string => {
if (variable.type !== 'integer') {
return '';
}
if (variable.hint?.toLowerCase().includes('satoshi') !== true) {
return '';
}
if (!/^[-]?\d+$/.test(variable.value.trim())) {
return '';
}
try {
return getFiatSuffix(BigInt(variable.value));
} catch {
return '';
}
};
return (
<Box flexDirection='column'>
<Text color={colors.text} bold>
Review your invitation:
</Text>
{/* Summary */}
<Box marginTop={1} flexDirection='column'>
<Text color={colors.textMuted}>Template: {template?.name}</Text>
<Text color={colors.textMuted}>Action: {actionName}</Text>
<Text color={colors.textMuted}>Role: {roleIdentifier}</Text>
</Box>
{/* Variables */}
{variables.length > 0 && (
<Box marginTop={1} flexDirection='column'>
<Text color={colors.text}>Variables:</Text>
{variables.map((v) => (
<Text key={v.id} color={colors.textMuted}>
{' '}
{v.name}: {v.value || '(empty)'}
{v.value ? getVariableFiatSuffix(v) : ''}
</Text>
))}
</Box>
)}
{/* Inputs */}
{selectedUtxos.length > 0 && (
<Box marginTop={1} flexDirection='column'>
<Text color={colors.text}>
Inputs ({selectedUtxos.length}):
</Text>
{selectedUtxos.slice(0, 3).map((u) => (
<Text
key={`${u.outpointTransactionHash}:${u.outpointIndex}`}
color={colors.textMuted}
>
{' '}
{formatSatoshis(u.valueSatoshis)}
{getFiatSuffix(u.valueSatoshis)}
</Text>
))}
{selectedUtxos.length > 3 && (
<Text color={colors.textMuted}>
{' '}...and {selectedUtxos.length - 3} more
</Text>
)}
</Box>
)}
{/* Outputs */}
{changeAmount > 0n && (
<Box marginTop={1} flexDirection='column'>
<Text color={colors.text}>Outputs:</Text>
<Text color={colors.textMuted}>
{' '}Change: {formatSatoshis(changeAmount)}
{getFiatSuffix(changeAmount)}
</Text>
</Box>
)}
{/* Confirmation prompt */}
<Box marginTop={1}>
<Text color={colors.warning}>
Press Next to create and publish the invitation.
</Text>
</Box>
</Box>
);
}