refactor
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useParams, Link } from 'react-router-dom';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useAuth } from '../AuthContext';
|
||||
import api from '../api';
|
||||
import { useClickOutside } from '../hooks/useClickOutside';
|
||||
|
||||
export default function ChallengeDetail() {
|
||||
const { id } = useParams();
|
||||
@@ -15,6 +17,11 @@ export default function ChallengeDetail() {
|
||||
const [showInvite, setShowInvite] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [searchTimeout, setSearchTimeout] = useState(null);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [validating, setValidating] = useState(null);
|
||||
const searchRef = useRef(null);
|
||||
|
||||
useClickOutside(searchRef, () => setSearchResults([]));
|
||||
|
||||
useEffect(() => {
|
||||
loadChallenge();
|
||||
@@ -55,25 +62,33 @@ export default function ChallengeDetail() {
|
||||
e.preventDefault();
|
||||
if (!newPrediction.trim()) return;
|
||||
|
||||
setSubmitting(true);
|
||||
try {
|
||||
await api.createPrediction({
|
||||
challenge_id: id,
|
||||
content: newPrediction
|
||||
});
|
||||
toast.success('Prediction submitted!');
|
||||
setNewPrediction('');
|
||||
await loadPredictions();
|
||||
} catch (err) {
|
||||
alert('Failed to create prediction: ' + err.message);
|
||||
toast.error('Failed to create prediction: ' + err.message);
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleValidate = async (predictionId, status) => {
|
||||
setValidating(predictionId);
|
||||
try {
|
||||
await api.validatePrediction(predictionId, status);
|
||||
toast.success(status === 'validated' ? 'Prediction validated!' : 'Prediction invalidated');
|
||||
await loadPredictions();
|
||||
await loadLeaderboard();
|
||||
} catch (err) {
|
||||
alert('Failed to validate: ' + err.message);
|
||||
toast.error('Failed to validate: ' + err.message);
|
||||
} finally {
|
||||
setValidating(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -106,11 +121,11 @@ export default function ChallengeDetail() {
|
||||
const handleInvite = async (userId) => {
|
||||
try {
|
||||
await api.inviteToChallenge(id, { user_ids: [userId] });
|
||||
toast.success('Invitation sent!');
|
||||
setInviteQuery('');
|
||||
setSearchResults([]);
|
||||
alert('Invitation sent!');
|
||||
} catch (err) {
|
||||
alert('Failed to send invite: ' + err.message);
|
||||
toast.error('Failed to send invite: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -154,7 +169,7 @@ export default function ChallengeDetail() {
|
||||
|
||||
{/* Invite Section */}
|
||||
{showInvite && (
|
||||
<div className="card" style={{ marginBottom: '2rem', position: 'relative' }}>
|
||||
<div className="card" style={{ marginBottom: '2rem', position: 'relative' }} ref={searchRef}>
|
||||
<h3 style={{ marginBottom: '1rem' }}>Invite Someone</h3>
|
||||
<input
|
||||
type="text"
|
||||
@@ -232,8 +247,8 @@ export default function ChallengeDetail() {
|
||||
onChange={(e) => setNewPrediction(e.target.value)}
|
||||
style={{ minHeight: '80px' }}
|
||||
/>
|
||||
<button type="submit" className="btn btn-primary" style={{ marginTop: '1rem' }}>
|
||||
Submit Prediction
|
||||
<button type="submit" className="btn btn-primary" style={{ marginTop: '1rem' }} disabled={submitting}>
|
||||
{submitting ? 'Submitting...' : 'Submit Prediction'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -261,14 +276,16 @@ export default function ChallengeDetail() {
|
||||
<button
|
||||
className="btn btn-success btn-sm"
|
||||
onClick={() => handleValidate(pred.id, 'validated')}
|
||||
disabled={validating === pred.id}
|
||||
>
|
||||
✓ Validate
|
||||
{validating === pred.id ? '...' : '✓ Validate'}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-danger btn-sm"
|
||||
onClick={() => handleValidate(pred.id, 'invalidated')}
|
||||
disabled={validating === pred.id}
|
||||
>
|
||||
✗ Invalidate
|
||||
{validating === pred.id ? '...' : '✗ Invalidate'}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user