]> git.localhorst.tv Git - alttp.git/blob - resources/js/components/episodes/Item.js
events overview
[alttp.git] / resources / js / components / episodes / Item.js
1 import PropTypes from 'prop-types';
2 import React from 'react';
3 import { Button } from 'react-bootstrap';
4 import { useTranslation } from 'react-i18next';
5 import { Link } from 'react-router-dom';
6
7 import Channels from './Channels';
8 import Crew from './Crew';
9 import MultiLink from './MultiLink';
10 import Players from './Players';
11 import Icon from '../common/Icon';
12 import { hasPassed, hasSGRestream, isActive } from '../../helpers/Episode';
13 import { getLink } from '../../helpers/Event';
14 import { canApplyForEpisode, canRestreamEpisode } from '../../helpers/permissions';
15 import { withUser } from '../../helpers/UserContext';
16
17 const Item = ({ episode, onAddRestream, onApply, onEditRestream, user }) => {
18         const { t } = useTranslation();
19
20         const classNames = [
21                 'episodes-item',
22                 'my-3',
23                 'p-2',
24                 'border',
25                 'rounded',
26         ];
27         if (isActive(episode)) {
28                 classNames.push('is-active');
29         }
30
31         const style = React.useMemo(() => {
32                 if (episode.event && episode.event.corner) {
33                         return {
34                                 backgroundImage: `url(${episode.event.corner})`,
35                         };
36                 }
37                 return null;
38         }, [episode.event && episode.event.corner]);
39
40         const hasChannels = episode.channels && episode.channels.length;
41         const hasPlayers = episode.players && episode.players.length;
42
43         return <div className={classNames.join(' ')} style={style}>
44                 <div className="d-flex align-items-stretch">
45                         <div className="episode-start me-3 fs-5 fs-md-4 text-end">
46                                 {t('schedule.startTime', { date: new Date(episode.start) })}
47                         </div>
48                         <div className="episode-titlebar">
49                                 {episode.title || episode.event ?
50                                         <div className="episode-title fs-5 fs-md-4">
51                                                 {episode.title || episode.event.title}
52                                         </div>
53                                 : null}
54                                 {episode.comment ?
55                                         <div className="episode-comment">
56                                                 {episode.comment}
57                                         </div>
58                                 : null}
59                         </div>
60                         <div className="episode-channel-links ms-auto text-end">
61                                 {hasChannels ?
62                                         <Channels
63                                                 channels={episode.channels}
64                                                 episode={episode}
65                                                 onEditRestream={onEditRestream}
66                                         />
67                                 : null}
68                                 {!hasChannels && hasPlayers ?
69                                         <MultiLink players={episode.players} />
70                                 : null}
71                                 {episode.raceroom ?
72                                         <div>
73                                                 <Button
74                                                         href={episode.raceroom}
75                                                         target="_blank"
76                                                         title={t('episodes.raceroom')}
77                                                         variant="outline-secondary"
78                                                 >
79                                                         <Icon.RACETIME title="" />
80                                                         {' '}
81                                                         {t('episodes.raceroom')}
82                                                 </Button>
83                                         </div>
84                                 : null}
85                                 {onAddRestream && canRestreamEpisode(user, episode) ?
86                                         <div>
87                                                 <Button
88                                                         onClick={() => onAddRestream(episode)}
89                                                         title={t('episodes.addRestream')}
90                                                         variant="outline-secondary"
91                                                 >
92                                                         <Icon.ADD title="" />
93                                                 </Button>
94                                         </div>
95                                 : null}
96                         </div>
97                 </div>
98                 <div className="episode-body d-flex flex-column flex-fill">
99                         {hasPlayers ?
100                                 <Players players={episode.players} />
101                         : null}
102                         {(episode.crew && episode.crew.length) || (!hasPassed(episode) && (
103                                         hasSGRestream(episode)
104                                         || canApplyForEpisode(user, episode, 'commentary')
105                                         || canApplyForEpisode(user, episode, 'tracking')
106                         )) ?
107                                 <div className="mb-3">
108                                         <Crew episode={episode} onApply={onApply} />
109                                 </div>
110                         : null}
111                         {episode.event ?
112                                 <div className="episode-event mt-auto">
113                                         {episode.event.description_id ?
114                                                 <Link className="event-link" to={getLink(episode.event)}>
115                                                         {episode.event.title}
116                                                 </Link>
117                                         :
118                                                 episode.event.title
119                                         }
120                                 </div>
121                         : null}
122                 </div>
123         </div>;
124 };
125
126 Item.propTypes = {
127         episode: PropTypes.shape({
128                 channels: PropTypes.arrayOf(PropTypes.shape({
129                 })),
130                 comment: PropTypes.string,
131                 crew: PropTypes.arrayOf(PropTypes.shape({
132                 })),
133                 event: PropTypes.shape({
134                         corner: PropTypes.string,
135                         description_id: PropTypes.number,
136                         name: PropTypes.string,
137                         title: PropTypes.string,
138                 }),
139                 players: PropTypes.arrayOf(PropTypes.shape({
140                 })),
141                 raceroom: PropTypes.string,
142                 start: PropTypes.string,
143                 title: PropTypes.string,
144         }),
145         onAddRestream: PropTypes.func,
146         onApply: PropTypes.func,
147         onEditRestream: PropTypes.func,
148         user: PropTypes.shape({
149         }),
150 };
151
152 export default withUser(Item);