Fixes #289 * docs: add batch qualifying results entry design spec Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add batch qualifying results entry implementation plan Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: ignore .worktrees directory * feat: add qualifying results text parser with tests * fix: handle no-space after dot separator, tighten T-prefix to uppercase only * feat: add batch-add-results server intent with duplicate filtering Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add create-participant intent for inline participant creation * fix: trim sportsSeasonId validation in create-participant intent * feat: fill 0-QP rows for unplaced participants on qualifying event finalize Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * perf: use bulk insert for 0-QP rows on qualifying event finalize * feat: add BatchResultEntry component for paste-and-parse batch result import Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: disable add participant button while create request is in flight * feat: render BatchResultEntry on qualifying event pages Add BatchResultEntry component import and render it on event pages when the event is a qualifying event, not a final_standings/playoff_game type, and not yet complete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address final review issues (sportsSeasonId authority, participant validation, CRLF, unused prop) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
export interface ParsedLine {
|
|
placement: number;
|
|
rawName: string;
|
|
}
|
|
|
|
/**
|
|
* Parse a pasted results text into placement + name pairs.
|
|
*
|
|
* Supported formats per line:
|
|
* 1. Name (dot separator)
|
|
* 1, Name (comma separator)
|
|
* 1 Name (space separator)
|
|
* T3. Name (T-prefix tie, dot separator)
|
|
* T3, Name (T-prefix tie, comma separator)
|
|
* T3 Name (T-prefix tie, space separator)
|
|
*
|
|
* Repeated rank numbers across consecutive lines are both emitted
|
|
* with the same placement (treated as ties automatically).
|
|
* Blank lines are ignored.
|
|
*/
|
|
export function parseResultsText(text: string): ParsedLine[] {
|
|
const results: ParsedLine[] = [];
|
|
|
|
for (const rawLine of text.split(/\r?\n/)) {
|
|
const line = rawLine.trim();
|
|
if (!line) continue;
|
|
|
|
// Try to match: optional T, digits, optional separator (. or ,), then whitespace and the name
|
|
// Pattern 1: "1. Name", "1, Name", "T3. Name", "T3, Name"
|
|
const match = line.match(/^T?(\d+)[.,]\s*(.+)$/);
|
|
if (match) {
|
|
results.push({
|
|
placement: parseInt(match[1], 10),
|
|
rawName: match[2].trim(),
|
|
});
|
|
continue;
|
|
}
|
|
|
|
// Pattern 2: "1 Name", "T3 Name" (space-only separator)
|
|
const spaceMatch = line.match(/^T?(\d+)\s+(.+)$/);
|
|
if (spaceMatch) {
|
|
results.push({
|
|
placement: parseInt(spaceMatch[1], 10),
|
|
rawName: spaceMatch[2].trim(),
|
|
});
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|