38 lines
1.7 KiB
TypeScript
38 lines
1.7 KiB
TypeScript
'use client';
|
|
|
|
import { Input } from './ui/input';
|
|
|
|
/** Validation is about the public question, never the respondent's private purse. */
|
|
export function pledgeClaimInputError(minimum: unknown): string | null {
|
|
return typeof minimum === 'number' && Number.isSafeInteger(minimum) && minimum > 0
|
|
? null : 'Choose a positive whole spice amount within the safe integer range.';
|
|
}
|
|
|
|
/** The recipient is the respondent's current public reciprocal ally. */
|
|
export function PledgeClaimFields(props: {
|
|
minimum: number;
|
|
allyName: string;
|
|
disabled: boolean;
|
|
onChange: (minimum: number) => void;
|
|
}) {
|
|
const error = pledgeClaimInputError(props.minimum);
|
|
return <fieldset className="grid gap-2" disabled={props.disabled} aria-label="Future ally funding condition">
|
|
<legend>Future ally funding update</legend>
|
|
<p>Current ally: {props.allyName}</p>
|
|
<label htmlFor="truth-pledge-minimum">Minimum future ally funding in spice</label>
|
|
<Input id="truth-pledge-minimum" type="number" min={1} max={Number.MAX_SAFE_INTEGER} step={1} required
|
|
disabled={props.disabled} value={Number.isFinite(props.minimum) ? props.minimum : ''}
|
|
aria-invalid={!!error} aria-describedby="truth-pledge-help"
|
|
onChange={event => {
|
|
const next = event.currentTarget.valueAsNumber;
|
|
if (!props.disabled && !pledgeClaimInputError(next)) props.onChange(next);
|
|
}} />
|
|
{error && <p role="alert">{error}</p>}
|
|
<p className="fine" id="truth-pledge-help">
|
|
Count an accepted funding update after the answer during this phase. Setting the same total again counts;
|
|
an earlier pledge alone does not. Funding sets spice aside for your ally and is not a payment or a promise
|
|
that your ally will spend it.
|
|
</p>
|
|
</fieldset>;
|
|
}
|