App.AddComboModal = function AddComboModal({ shareCode, onComboAdded, onClose }) { const [name, setName] = React.useState(''); const [selectedCarIds, setSelectedCarIds] = React.useState([]); const [selectedCategoryIds, setSelectedCategoryIds] = React.useState([]); const [selectedConfig, setSelectedConfig] = React.useState(null); const [saving, setSaving] = React.useState(false); const [error, setError] = React.useState(''); const [activeTab, setActiveTab] = React.useState('cars'); const [generating, setGenerating] = React.useState(false); const [showNamePrompt, setShowNamePrompt] = React.useState(false); const [allCars, setAllCars] = React.useState([]); const [allCategories, setAllCategories] = React.useState([]); const nameInputRef = React.useRef(null); // Load cars and categories for summary strip display and name generation React.useEffect(() => { App.API.get('cars').then(data => setAllCars(data)); App.API.get('categories').then(data => setAllCategories(data)); }, []); const isValid = name.trim() && selectedConfig && (selectedCarIds.length > 0 || selectedCategoryIds.length > 0); const generateName = () => { setGenerating(true); let url = 'name-generator?type=combo&count=1'; const selectedCars = allCars.filter(c => selectedCarIds.includes(c.id)); selectedCars.forEach(c => { url += '&cars[]=' + encodeURIComponent(c.name); }); const selectedCats = allCategories.filter(c => selectedCategoryIds.includes(c.id)); selectedCats.forEach(c => { url += '&categories[]=' + encodeURIComponent(c.name); }); if (selectedConfig) url += '&track=' + encodeURIComponent(selectedConfig.trackName); App.API.get(url).then(data => { if (data.names && data.names.length > 0) { setName(data.names[0]); } setGenerating(false); }).catch(() => { setGenerating(false); }); }; const handleSubmit = () => { setError(''); if (!name.trim()) { setShowNamePrompt(true); return; } if (!selectedConfig) { setError('Please select a track'); return; } if (selectedCarIds.length === 0 && selectedCategoryIds.length === 0) { setError('Please select at least one car or category'); return; } setSaving(true); // Step 1: Create the combo App.API.post('combos', { name: name.trim(), trackId: selectedConfig.id, cars: selectedCarIds, categories: selectedCategoryIds, fingerprint: App.fingerprint, }).then(comboData => { // Step 2: Add the combo to the poll return App.API.post('polls/' + shareCode, { _action: 'add-combo', comboId: comboData.id, fingerprint: App.fingerprint, }); }).then(() => { onComboAdded(); }).catch(err => { setError(err.message); setSaving(false); }); }; const handleNamePromptEnter = () => { setShowNamePrompt(false); if (nameInputRef.current) nameInputRef.current.focus(); }; const handleNamePromptGenerate = () => { setShowNamePrompt(false); generateName(); }; const removeCarFromSummary = (carId) => { setSelectedCarIds(prev => prev.filter(id => id !== carId)); }; // Build summary data const selectedCarObjects = allCars.filter(c => selectedCarIds.includes(c.id)); const trackDisplay = selectedConfig ? (selectedConfig.configName ? selectedConfig.trackName + ' - ' + selectedConfig.configName : selectedConfig.trackName) : null; const carTabLabel = selectedCarIds.length + selectedCategoryIds.length > 0 ? 'Select Cars (' + (selectedCarIds.length + selectedCategoryIds.length) + ')' : 'Select Cars'; const trackTabLabel = selectedConfig ? 'Select Track \u2713' : 'Select Track'; return (

Add Combo to Poll

Pick cars and a track to create a race combination

{error &&
{error}
}
setName(e.target.value)} maxLength={200} />
{trackDisplay ? {trackDisplay} : No track selected }
{selectedCarObjects.length > 0 ? ( selectedCarObjects.map(car => (
{car.name} removeCarFromSummary(car.id)} /> {car.name}
)) ) : ( No cars selected )} {selectedCategoryIds.length > 0 && ( + {selectedCategoryIds.length} category(ies) )}
{activeTab === 'cars' && ( )} {activeTab === 'track' && ( )} {showNamePrompt && ( setShowNamePrompt(false)} /> )}
); };