index.jsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import React, { Component } from "react";
  2. import { NavLink } from "react-router-dom";
  3. import CustomInput from "components/CustomInput.jsx";
  4. import CustomMessages from "components/CustomMessages.jsx";
  5. import PropTypes from "prop-types";
  6. import { translate, Trans } from "react-i18next";
  7. import { connect } from "react-redux";
  8. import io from "io";
  9. import config from "config";
  10. @connect(state => ({
  11. user: {
  12. userId: state.user.get("userId"),
  13. role: state.user.get("role"),
  14. },
  15. loggedIn: state.user.get("loggedIn"),
  16. }))
  17. @translate(["homepage"], { wait: true })
  18. export default class Homepage extends Component {
  19. static propTypes = {
  20. t: PropTypes.func,
  21. };
  22. static defaultProps = {
  23. t: () => {},
  24. };
  25. constructor() {
  26. super();
  27. CustomInput.initialize(this);
  28. this.state = {
  29. stations: {
  30. official: [],
  31. community: [],
  32. },
  33. createStation: {
  34. private: false,
  35. }
  36. };
  37. io.getSocket(socket => {
  38. socket.emit("stations.index", data => {
  39. if (data.status === "success") {
  40. let community = [];
  41. let official = [];
  42. data.stations.forEach(station => {
  43. if (!station.currentSong) station.currentSong = { thumbnail: '/assets/images/notes-transparent.png' };
  44. if (station.currentSong && !station.currentSong.thumbnail) station.currentSong.thumbnail = "/assets/images/notes-transparent.png";
  45. if (station.type === 'official') official.push(station);
  46. else community.push(station);
  47. });
  48. official.push({
  49. "_id": "59b522222634af57e8e2dbcf",
  50. "name": "kridsads",
  51. "displayName": "KrisVossad130",
  52. "description": "Test123asd",
  53. "type": "official",
  54. "queue": [],
  55. "locked": false,
  56. "privacy": "public",
  57. "blacklistedGenres": [],
  58. "genres": [],
  59. "playlist": [],
  60. "startedAt": 0,
  61. "pausedAt": 0,
  62. "timePaused": 0,
  63. "currentSongIndex": 0,
  64. "currentSong": {
  65. "songId": "60ItHLz5WEA",
  66. "title": "Faded - Alan Walker",
  67. "duration": 212,
  68. "skipDuration": 0,
  69. "skipVotes": [],
  70. "dislikes": -1,
  71. "likes": -1,
  72. "artists": [],
  73. thumbnail: "/assets/images/notes-transparent.png"
  74. },
  75. "paused": false,
  76. "__v": 0
  77. });
  78. this.setState({
  79. stations: {
  80. official,
  81. community,
  82. }
  83. });
  84. }
  85. });
  86. });
  87. }
  88. isOwner = (ownerId) => {
  89. if (this.props.loggedIn) {
  90. if (this.props.user.role === "admin") return true;
  91. if (this.props.user.userId === ownerId) return true;
  92. }
  93. return false;
  94. };
  95. listStations = (type) => {
  96. let stations = [];
  97. this.state.stations[type].forEach((station) => {
  98. let icon = null;
  99. if (station.type === "official") {
  100. if (station.privacy !== "public") icon =
  101. <i className="material-icons" title="This station is not visible to other users.">lock</i>;
  102. } else {
  103. // TODO Add isOwner function globally
  104. if (this.isOwner(station.ownerId)) icon =
  105. <i className="material-icons" title="This is your station.">home</i>;
  106. if (station.privacy !== "public") icon =
  107. <i className="material-icons" title="This station is not visible to other users.">lock</i>;
  108. }
  109. stations.push(
  110. (
  111. <div key={station._id} className="station-card">
  112. <div className="station-media">
  113. <img src={station.currentSong.thumbnail}/>
  114. </div>
  115. <div className="station-body">
  116. <h3 className="displayName">{station.displayName}</h3>
  117. <p className="description">{station.description}</p>
  118. </div>
  119. <div className="station-footer">
  120. <div className="user-count" title="How many users there are in the station.">
  121. <i className="material-icons">people</i>
  122. <span>{station.userCount}</span>
  123. </div>
  124. { icon }
  125. </div>
  126. <a href={station.type + "/" + station.name}/>
  127. </div>
  128. )
  129. );
  130. });
  131. return stations;
  132. };
  133. togglePrivate = () => {
  134. this.setState({
  135. createStation: {
  136. private: !this.state.createStation.private,
  137. },
  138. });
  139. };
  140. createCommunity = () => {
  141. this.messages.clearErrorSuccess();
  142. if (CustomInput.hasInvalidInput(this.input)) {
  143. this.messages.clearAddError(this.props.t("general:someFieldsAreIncorrectError"));
  144. } else {
  145. io.getSocket(socket => {
  146. socket.emit("stations.create", {
  147. name: this.input.title.getValue().toLowerCase(),
  148. type: "community",
  149. displayName: this.input.title.getValue(),
  150. description: this.input.description.getValue(),
  151. }, res => {
  152. if (res.status === "success") {
  153. location.href = "/community/" + this.input.title.getValue().toLowerCase();//TODO Remove
  154. } else {
  155. this.messages.addError(res.message);
  156. }
  157. });
  158. });
  159. }
  160. };
  161. render() {
  162. const { t } = this.props;
  163. //TODO Make this not re-render a lot
  164. return (
  165. <main id="homepage">
  166. <h1>{ t("homepage:title") }</h1>
  167. <CustomMessages onRef={ ref => (this.messages = ref) } />
  168. <h2>Official Stations</h2>
  169. <div className="official-stations stations">
  170. { this.listStations("official") }
  171. </div>
  172. <h2>Community Stations</h2>
  173. <div className="community-stations stations">
  174. { (this.props.loggedIn) ? (
  175. <div className="station-card">
  176. <div className="station-media">
  177. <img src="/assets/images/notes-transparent.png"/>
  178. </div>
  179. <CustomInput type="stationDisplayName" name="title" label="Title" placeholder="Title" onRef={ ref => (this.input.title = ref) } />
  180. <CustomInput type="stationDescription" name="description" label="Description" placeholder="Description" onRef={ ref => (this.input.description = ref) } />
  181. <span onClick={this.togglePrivate}>Private</span>
  182. <button onClick={this.createCommunity}>Add</button>
  183. </div>
  184. ) : null }
  185. { this.listStations("community") }
  186. </div>
  187. </main>
  188. );
  189. }
  190. }