// instruction-form.tsx
import { useState } from 'react';
import { useSubmitInstruction, useTemplates } from '@keystoneos/react';
import { TemplateSelector } from './template-selector';
import { TradeReferenceInput } from './trade-reference-input';
import { PendingMatchResult } from './pending-match-result';
import { MatchedResult } from './matched-result';
interface FormData {
role: 'seller' | 'buyer';
partyReference: string;
partyName: string;
walletAddress: string;
instrumentId: string;
quantity: string;
chainId: number;
templateSlug: string;
tradeReference: string;
}
const INITIAL_FORM: FormData = {
role: 'seller',
partyReference: '',
partyName: '',
walletAddress: '',
instrumentId: '',
quantity: '',
chainId: 11155111,
templateSlug: '',
tradeReference: '',
};
export function InstructionForm() {
const [form, setForm] = useState<FormData>(INITIAL_FORM);
const { submit, result, isSubmitting, error, reset } = useSubmitInstruction();
const updateField = <K extends keyof FormData>(field: K, value: FormData[K]) => {
setForm(prev => ({ ...prev, [field]: value }));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await submit({
role: form.role,
party: {
external_reference: form.partyReference,
name: form.partyName,
wallet_address: form.walletAddress,
},
legs: [{
instrument_id: form.instrumentId,
quantity: form.quantity,
direction: 'deliver',
chain_id: form.chainId,
}],
templateSlug: form.templateSlug,
timeoutAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
tradeReference: form.tradeReference || undefined,
});
};
const handleReset = () => {
reset();
setForm(INITIAL_FORM);
};
// Show result screens after submission
if (result?.status === 'pending_match') {
return <PendingMatchResult result={result} onReset={handleReset} />;
}
if (result?.status === 'matched') {
return <MatchedResult result={result} />;
}
return (
<form onSubmit={handleSubmit} style={{ maxWidth: '600px', display: 'flex', flexDirection: 'column', gap: '20px' }}>
<h2 style={{ fontSize: '20px', fontWeight: 700 }}>Submit Settlement Instruction</h2>
{/* Role selection */}
<div>
<label style={{ display: 'block', marginBottom: '4px', fontWeight: 600, fontSize: '14px' }}>Role</label>
<div style={{ display: 'flex', gap: '12px' }}>
{(['seller', 'buyer'] as const).map(role => (
<label key={role} style={{ display: 'flex', alignItems: 'center', gap: '6px', cursor: 'pointer' }}>
<input
type="radio"
name="role"
value={role}
checked={form.role === role}
onChange={() => updateField('role', role)}
/>
<span style={{ textTransform: 'capitalize' }}>{role}</span>
</label>
))}
</div>
</div>
{/* Party details */}
<fieldset style={{ border: '1px solid #e5e7eb', borderRadius: '8px', padding: '16px' }}>
<legend style={{ fontWeight: 600, fontSize: '14px', padding: '0 8px' }}>Party Details</legend>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
<div>
<label style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>Account Reference</label>
<input
type="text"
value={form.partyReference}
onChange={e => updateField('partyReference', e.target.value)}
placeholder="e.g. KSFI-II-4401"
required
style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db' }}
/>
</div>
<div>
<label style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>Display Name</label>
<input
type="text"
value={form.partyName}
onChange={e => updateField('partyName', e.target.value)}
placeholder="e.g. Securitize Fund I"
style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db' }}
/>
</div>
<div>
<label style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>Wallet Address</label>
<input
type="text"
value={form.walletAddress}
onChange={e => updateField('walletAddress', e.target.value)}
placeholder="e.g. 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"
required
style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db', fontFamily: 'monospace', fontSize: '13px' }}
/>
</div>
</div>
</fieldset>
{/* Leg details */}
<fieldset style={{ border: '1px solid #e5e7eb', borderRadius: '8px', padding: '16px' }}>
<legend style={{ fontWeight: 600, fontSize: '14px', padding: '0 8px' }}>
{form.role === 'seller' ? 'What You Are Delivering' : 'What You Are Delivering (Payment)'}
</legend>
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
<div>
<label style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>Instrument ID</label>
<input
type="text"
value={form.instrumentId}
onChange={e => updateField('instrumentId', e.target.value)}
placeholder={form.role === 'seller' ? 'e.g. OUSG or US09311A1007' : 'e.g. USDC'}
required
style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db' }}
/>
</div>
<div>
<label style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>Quantity</label>
<input
type="text"
value={form.quantity}
onChange={e => updateField('quantity', e.target.value)}
placeholder="e.g. 12000000"
required
style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db', fontFamily: 'monospace' }}
/>
<p style={{ fontSize: '12px', color: '#6b7280', marginTop: '4px' }}>
Amount in the token's smallest unit (e.g., 12000000 for 12M tokens with 0 decimals, or 12000000000000 for 12M USDC with 6 decimals).
</p>
</div>
<div>
<label style={{ display: 'block', marginBottom: '4px', fontSize: '13px' }}>Chain ID</label>
<select
value={form.chainId}
onChange={e => updateField('chainId', Number(e.target.value))}
style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db' }}
>
<option value={1}>Ethereum Mainnet (1)</option>
<option value={137}>Polygon (137)</option>
<option value={43114}>Avalanche (43114)</option>
<option value={11155111}>Sepolia Testnet (11155111)</option>
</select>
</div>
</div>
</fieldset>
{/* Template and trade reference */}
<TemplateSelector value={form.templateSlug || undefined} onChange={slug => updateField('templateSlug', slug)} />
<TradeReferenceInput value={form.tradeReference} onChange={val => updateField('tradeReference', val)} />
{/* Submit */}
{error && (
<div style={{ padding: '12px', backgroundColor: '#fee2e2', color: '#991b1b', borderRadius: '6px', fontSize: '14px' }}>
{error}
</div>
)}
<button
type="submit"
disabled={isSubmitting || !form.templateSlug}
style={{
padding: '12px 24px',
backgroundColor: isSubmitting ? '#9ca3af' : '#2DD4A8',
color: '#fff',
border: 'none',
borderRadius: '8px',
fontWeight: 600,
cursor: isSubmitting ? 'not-allowed' : 'pointer',
}}
>
{isSubmitting ? 'Submitting...' : 'Submit Instruction'}
</button>
</form>
);
}