training.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import theme from '../styles/theme'
  2. function calculateRating(ratings) {
  3. const numberOfRatings = ratings.length
  4. const sumOfRatings = ratings.reduce(
  5. (accumulator, rating) => accumulator + rating.value,
  6. 0
  7. )
  8. return numberOfRatings ? sumOfRatings / numberOfRatings : '-'
  9. }
  10. const TrainingArchive = props => (
  11. <div>
  12. <h2>Training Archive</h2>
  13. <ol>
  14. {props.trainings.map(training => (
  15. <TrainingHint key={training.id} training={training} />
  16. ))}
  17. </ol>
  18. </div>
  19. )
  20. const TrainingHint = props => (
  21. <div>
  22. <div>{props.training.date}</div>
  23. <div>{props.training.title}</div>
  24. </div>
  25. )
  26. const Training = props => (
  27. <article>
  28. <h2>{props.title}</h2>
  29. <aside>
  30. <div id='trainingType'>
  31. <span className='caption'>Type: </span>
  32. <span className='data'>{props.type.name}</span>
  33. </div>
  34. <div id='trainingDate'>
  35. <span className='caption'>Date: </span>
  36. <span className='data'>
  37. {new Date(props.trainingDate).toLocaleDateString()}
  38. </span>
  39. </div>
  40. <div id='trainingLocation'>
  41. <span className='caption'>Location: </span>
  42. <span className='data'>{props.location}</span>
  43. </div>
  44. <div id='trainingRegistrations'>
  45. <span className='caption'>Registrations: </span>
  46. <span className='data'> {props.registration.length} </span>
  47. </div>
  48. <div id='trainingAttendance'>
  49. <span className='caption'>Attendance: </span>
  50. <span className='data'>{props.attendance}</span>
  51. </div>
  52. <div id='trainingRatings'>
  53. <span className='caption'>Rating: </span>
  54. <span className='data'>
  55. {calculateRating(props.ratings)} [
  56. <a href=''>{props.ratings.length}</a>] Rate it!
  57. <a href=''>*</a>
  58. <a href=''>*</a>
  59. <a href=''>*</a>
  60. <a href=''>*</a>
  61. <a href=''>*</a>
  62. </span>
  63. </div>
  64. <button>Register now!</button>
  65. </aside>
  66. <section>
  67. <h3>Content</h3>
  68. <ol>
  69. {props.content
  70. .sort(block => block.sequence)
  71. .map(block => (
  72. <Block key={block.id} {...block} />
  73. ))}
  74. </ol>
  75. </section>
  76. <style jsx>
  77. {`
  78. article {
  79. display: grid;
  80. grid-template-areas:
  81. "title"
  82. "information"
  83. "content";
  84. background-color: rgba(127, 127, 127, 0.5);
  85. background-image: url('media/man_working_out.jpg');
  86. background-size: auto 400px;
  87. background-repeat: no-repeat;
  88. margin: 2em 0;
  89. }
  90. article > * {
  91. padding: 0.2em 1em;
  92. }
  93. article > h2 {
  94. grid-area: title;
  95. font-weight: 900;
  96. font-size: 120%;
  97. background: ${theme.colors.darkerblue};
  98. color: ${theme.colors.offWhite};
  99. }
  100. aside {
  101. grid-area: information;
  102. padding: 1em 2em;
  103. height: 400px;
  104. }
  105. section {
  106. grid-area: content;
  107. padding: 1em 2em;
  108. background: rgba(127, 0, 0, 0.5);
  109. }
  110. span.caption {
  111. display: none;
  112. }
  113. `}
  114. </style>
  115. </article>
  116. )
  117. const Youtube = props => {
  118. const { link, rest } = props
  119. const [crap, src] = props.link.match(/\?v=(.*)/)
  120. return (
  121. <iframe
  122. width='285'
  123. height='160'
  124. src={`https://www.youtube.com/embed/${src}`}
  125. frameBorder='0'
  126. allow='accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture'
  127. allowFullScreen
  128. {...rest}
  129. />
  130. )
  131. }
  132. const Spotify = props => {
  133. const { link, rest } = props
  134. const [crap, src] = props.link.match(/track\/(.*)/)
  135. return (
  136. <iframe
  137. src={`https://open.spotify.com/embed/track/${src}`}
  138. width='300'
  139. height='80'
  140. frameborder='0'
  141. allowtransparency='true'
  142. allow='encrypted-media'
  143. />
  144. )
  145. }
  146. const Media = props => {
  147. if (props.link.includes('youtube.com')) {
  148. return <Youtube {...props} />
  149. } else if (props.link.includes('spotify.com')) {
  150. return <Spotify {...props} />
  151. } else {
  152. return <p>Link not recognized.</p>
  153. }
  154. }
  155. const Block = props => (
  156. <li>
  157. <h2>{props.title}</h2>
  158. <p>
  159. <span className='caption'>Duration: </span>
  160. <span className='data'>{props.duration}</span>
  161. </p>
  162. <p>
  163. <span className='caption'>Variation: </span>
  164. <span className='data'>{props.variation}</span>
  165. </p>
  166. <p>
  167. <span className='caption'>Description: </span>
  168. <span className='data'>{props.description}</span>
  169. </p>
  170. <p>
  171. <span className='caption'>Format: </span>
  172. <span className='data'>
  173. {props.format.name}{' '}
  174. <sup>
  175. <a title={props.format.description}>[?]</a>
  176. </sup>
  177. </span>
  178. </p>
  179. <section>
  180. <h2>Tracks</h2>
  181. <ol>
  182. {props.tracks.map(track => (
  183. <Track key={track.id} {...track} />
  184. ))}
  185. </ol>
  186. </section>
  187. <section>
  188. <h2>Exercises</h2>
  189. <ol>
  190. {props.exercises.map(exercise => (
  191. <Exercise key={exercise.id} {...exercise} />
  192. ))}
  193. </ol>
  194. </section>
  195. <style jsx>
  196. {`
  197. section {
  198. display: grid;
  199. }
  200. `}
  201. </style>
  202. </li>
  203. )
  204. const Track = props => {
  205. return (
  206. <section>
  207. <p>
  208. Track {props.id}: {props.title} ({props.artist})
  209. </p>
  210. <Media link={props.link} />
  211. </section>
  212. )
  213. }
  214. const Exercise = props => {
  215. return (
  216. <section>
  217. <p>
  218. Exercise {props.id}: {props.name}
  219. </p>
  220. </section>
  221. )
  222. }
  223. class TrainingCreateForm extends React.Component {
  224. render() {
  225. return (
  226. <form>
  227. <label htmlFor='title'>
  228. Title
  229. <input type='text' id='title' />
  230. </label>
  231. <label htmlFor='title'>
  232. Title
  233. <input type='text' id='title' />
  234. </label>
  235. <label htmlFor='title'>
  236. Title
  237. <input type='text' id='title' />
  238. </label>
  239. </form>
  240. )
  241. }
  242. }
  243. export { TrainingArchive }
  244. export default Training