]> git.localhorst.tv Git - alttp.git/blob - resources/js/pages/Tournament.js
limits for huge tournaments
[alttp.git] / resources / js / pages / Tournament.js
1 import axios from 'axios';
2 import React, { useEffect, useState } from 'react';
3 import { Helmet } from 'react-helmet';
4 import { useParams } from 'react-router-dom';
5
6 import CanonicalLinks from '../components/common/CanonicalLinks';
7 import ErrorBoundary from '../components/common/ErrorBoundary';
8 import ErrorMessage from '../components/common/ErrorMessage';
9 import Loading from '../components/common/Loading';
10 import NotFound from '../pages/NotFound';
11 import Detail from '../components/tournament/Detail';
12 import {
13         canLoadMoreRounds,
14         getLastRound,
15         patchApplication,
16         patchParticipant,
17         patchResult,
18         patchRound,
19         patchUser,
20         removeApplication,
21         sortParticipants,
22 } from '../helpers/Tournament';
23
24 export const Component = () => {
25         const params = useParams();
26         const { id } = params;
27
28         const [error, setError] = useState(null);
29         const [loading, setLoading] = useState(true);
30         const [tournament, setTournament] = useState(null);
31
32         useEffect(() => {
33                 const ctrl = new AbortController();
34                 setLoading(true);
35                 axios
36                         .get(`/api/tournaments/${id}`, { signal: ctrl.signal })
37                         .then(response => {
38                                 setError(null);
39                                 setLoading(false);
40                                 setTournament(sortParticipants(response.data));
41                         })
42                         .catch(error => {
43                                 setError(error);
44                                 setLoading(false);
45                                 setTournament(null);
46                         });
47                 return () => {
48                         ctrl.abort();
49                 };
50         }, [id]);
51
52         useEffect(() => {
53                 window.Echo.channel(`Tournament.${id}`)
54                         .listen('ApplicationAdded', e => {
55                                 if (e.application) {
56                                         setTournament(tournament => patchApplication(tournament, e.application));
57                                 }
58                         })
59                         .listen('ApplicationChanged', e => {
60                                 if (e.application) {
61                                         setTournament(tournament => patchApplication(tournament, e.application));
62                                 }
63                         })
64                         .listen('ApplicationRemoved', e => {
65                                 if (e.application_id) {
66                                         setTournament(tournament => removeApplication(tournament, e.application_id));
67                                 }
68                         })
69                         .listen('ParticipantChanged', e => {
70                                 if (e.participant) {
71                                         setTournament(tournament => patchParticipant(tournament, e.participant));
72                                 }
73                         })
74                         .listen('ResultChanged', e => {
75                                 if (e.result) {
76                                         setTournament(tournament => patchResult(tournament, e.result));
77                                 }
78                         })
79                         .listen('RoundAdded', e => {
80                                 if (e.round) {
81                                         setTournament(tournament => ({
82                                                 ...tournament,
83                                                 rounds: [e.round, ...tournament.rounds],
84                                         }));
85                                 }
86                         })
87                         .listen('RoundChanged', e => {
88                                 if (e.round) {
89                                         setTournament(tournament => patchRound(tournament, e.round));
90                                 }
91                         })
92                         .listen('TournamentChanged', e => {
93                                 if (e.tournament) {
94                                         setTournament(tournament => ({ ...tournament, ...e.tournament }));
95                                 }
96                         });
97                 return () => {
98                         window.Echo.leave(`Tournament.${id}`);
99                 };
100         }, [id]);
101
102         const moreRounds = React.useCallback(async () => {
103                 const last_round = getLastRound(tournament);
104                 if (!last_round) return;
105                 console.log(last_round);
106                 const last_known = last_round.number;
107                 const rsp = await axios.get(
108                         `/api/tournaments/${id}/more-rounds`,
109                         { params: { last_known } },
110                 );
111                 setTournament(tournament => ({
112                         ...tournament,
113                         rounds: [...tournament.rounds, ...rsp.data],
114                 }));
115         }, [id, tournament]);
116
117         useEffect(() => {
118                 const cb = (e) => {
119                         if (e.user) {
120                                 setTournament(tournament => patchUser(tournament, e.user));
121                         }
122                 };
123                 window.Echo.channel('App.Control')
124                         .listen('UserChanged', cb);
125                 return () => {
126                         window.Echo.channel('App.Control')
127                                 .stopListening('UserChanged', cb);
128                 };
129         }, []);
130
131         if (loading) {
132                 return <Loading />;
133         }
134
135         if (error) {
136                 return <ErrorMessage error={error} />;
137         }
138
139         if (!tournament) {
140                 return <NotFound />;
141         }
142
143         const addRound = async () => {
144                 await axios.post('/api/rounds', { tournament_id: tournament.id });
145         };
146
147         return <ErrorBoundary>
148                 <Helmet>
149                         <title>{tournament.title}</title>
150                 </Helmet>
151                 <CanonicalLinks base={`/tournaments/${tournament.id}`} />
152                 <Detail
153                         addRound={addRound}
154                         moreRounds={canLoadMoreRounds(tournament) ? moreRounds : null}
155                         tournament={tournament}
156                 />
157         </ErrorBoundary>;
158 };