training.js 5.4 KB

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