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