Description
Invoices involving multiple recipients often require complex split logic that accounts for jurisdiction-specific tax withholding before each payout is calculated. Currently creators must compute net amounts externally and paste results in. This issue adds an interactive split calculator panel on /invoice/new and /invoice/[id] that takes a gross total, applies configurable tax and fee deduction rates per recipient line, and outputs the resulting net XLM/USDC amounts in real time. The calculator state must be serialised into the invoice payload so the breakdown persists on reload.
Technical Context
Create components/invoice/SplitCalculator.tsx backed by hooks/useSplitCalculator.ts containing pure calculation logic unit-tested independently. The hook should accept an array of RecipientLine objects with { address, sharePercent, taxRatePercent, fixedFeeXLM } and return derived netAmount and effectiveTaxAmount per line. Wire the component into app/invoice/new/page.tsx beneath the recipient list. Persist calculator state inside the invoice JSON schema under a splitMeta key via app/api/invoices/[id]/route.ts. The calculation must re-run reactively on any change to totalAmount, assetCode, or any RecipientLine field. Use zod for schema validation of the splitMeta payload.
Acceptance Criteria
Description
Invoices involving multiple recipients often require complex split logic that accounts for jurisdiction-specific tax withholding before each payout is calculated. Currently creators must compute net amounts externally and paste results in. This issue adds an interactive split calculator panel on
/invoice/newand/invoice/[id]that takes a gross total, applies configurable tax and fee deduction rates per recipient line, and outputs the resulting net XLM/USDC amounts in real time. The calculator state must be serialised into the invoice payload so the breakdown persists on reload.Technical Context
Create
components/invoice/SplitCalculator.tsxbacked byhooks/useSplitCalculator.tscontaining pure calculation logic unit-tested independently. The hook should accept an array ofRecipientLineobjects with{ address, sharePercent, taxRatePercent, fixedFeeXLM }and return derivednetAmountandeffectiveTaxAmountper line. Wire the component intoapp/invoice/new/page.tsxbeneath the recipient list. Persist calculator state inside the invoice JSON schema under asplitMetakey viaapp/api/invoices/[id]/route.ts. The calculation must re-run reactively on any change tototalAmount,assetCode, or anyRecipientLinefield. Usezodfor schema validation of thesplitMetapayload.Acceptance Criteria
sharePercentvalues is validated to equal 100% and a blocking inline error prevents form submission when the constraint is violated