feat(polls): let creators set max selections for multiple-choice
The poll creator only offered single (max_selections 1) or multiple = pick ALL
options — no way to run a "pick your top 2" poll, even though the display side
already enforces an arbitrary max_selections ("Select up to N"). Add a "Voters
can pick up to N of M options" control shown for multiple-choice polls. Defaults
to the option count (preserving the old select-all behavior) until lowered;
clamped to [2, filled option count] on submit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,10 @@ export function PollCreator({ roomId, onClose }: PollCreatorProps) {
|
||||
const [question, setQuestion] = useState('');
|
||||
const [options, setOptions] = useState<string[]>(['', '']);
|
||||
const [isMultiple, setIsMultiple] = useState(false);
|
||||
// For multiple-choice polls: the most options a voter may pick. Defaults high
|
||||
// so an untouched multiple poll means "select all that apply" (the previous
|
||||
// behavior); the effective value is clamped to the current option count.
|
||||
const [maxSelections, setMaxSelections] = useState(10);
|
||||
// Results visibility: disclosed (live results, default) vs undisclosed (hidden
|
||||
// until the poll is ended).
|
||||
const [disclosed, setDisclosed] = useState(true);
|
||||
@@ -85,7 +89,9 @@ export function PollCreator({ roomId, onClose }: PollCreatorProps) {
|
||||
'm.poll': {
|
||||
question: { 'm.text': trimmedQuestion },
|
||||
answers: filledOptions.map((o, i) => ({ 'm.id': `${i}`, 'm.text': o })),
|
||||
max_selections: isMultiple ? filledOptions.length : 1,
|
||||
max_selections: isMultiple
|
||||
? Math.min(Math.max(2, maxSelections), filledOptions.length)
|
||||
: 1,
|
||||
kind: disclosed ? 'm.poll.disclosed' : 'm.poll.undisclosed',
|
||||
},
|
||||
body: fallbackBody,
|
||||
@@ -222,6 +228,32 @@ export function PollCreator({ roomId, onClose }: PollCreatorProps) {
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
{isMultiple && (
|
||||
<Box alignItems="Center" gap="200" style={{ marginTop: config.space.S200 }}>
|
||||
<Text as="label" htmlFor="poll-max-select" size="T200" priority="400">
|
||||
Voters can pick up to
|
||||
</Text>
|
||||
<Input
|
||||
id="poll-max-select"
|
||||
variant="Background"
|
||||
size="300"
|
||||
type="number"
|
||||
min={2}
|
||||
max={options.length}
|
||||
value={Math.min(maxSelections, options.length)}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setMaxSelections(
|
||||
Math.min(options.length, Math.max(2, parseInt(e.target.value, 10) || 2)),
|
||||
)
|
||||
}
|
||||
style={{ width: '4rem' }}
|
||||
aria-label="Maximum selections per voter"
|
||||
/>
|
||||
<Text size="T200" priority="300">
|
||||
of {options.length} options
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* Results visibility */}
|
||||
|
||||
Reference in New Issue
Block a user