index.jsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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(["home", "createCommunityStation"], { 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. if (this.isOwner("fd")) official.push({
  49. "_id": "59b522222634af57e8e2fffdbcf",
  50. "name": "pr_o",
  51. "displayName": "PrivateOfficial",
  52. "description": "Test official station. Private.",
  53. "type": "official",
  54. "queue": [],
  55. "locked": false,
  56. "privacy": "private",
  57. "blacklistedGenres": [],
  58. "genres": [],
  59. "playlist": [],
  60. "startedAt": 0,
  61. "pausedAt": 0,
  62. "timePaused": 0,
  63. "currentSongIndex": 0,
  64. userCount: 0,
  65. "currentSong": {
  66. "songId": "60ItHLz5WEA",
  67. "title": "Faded - Alan Walker",
  68. "duration": 212,
  69. "skipDuration": 0,
  70. "skipVotes": [],
  71. "dislikes": -1,
  72. "likes": -1,
  73. "artists": [],
  74. thumbnail: "/assets/images/notes-transparent.png"
  75. },
  76. "paused": false,
  77. "__v": 0
  78. });
  79. if (this.isOwner("fd")) official.push({
  80. "_id": "59b52sss2222634af57e8e2dbcf",
  81. "name": "un_o",
  82. "displayName": "UnlistedOfficial",
  83. "description": "Test official station. Unlisted.",
  84. "type": "official",
  85. "queue": [],
  86. "locked": false,
  87. "privacy": "unlisted",
  88. "blacklistedGenres": [],
  89. "genres": [],
  90. "playlist": [],
  91. "startedAt": 0,
  92. "pausedAt": 0,
  93. "timePaused": 0,
  94. "currentSongIndex": 0,
  95. userCount: 0,
  96. "currentSong": {
  97. "songId": "60ItHLz5WEA",
  98. "title": "Faded - Alan Walker",
  99. "duration": 212,
  100. "skipDuration": 0,
  101. "skipVotes": [],
  102. "dislikes": -1,
  103. "likes": -1,
  104. "artists": [],
  105. thumbnail: "/assets/images/notes-transparent.png"
  106. },
  107. "paused": false,
  108. "__v": 0
  109. });
  110. official.push({
  111. "_id": "59b5222ggfg22634afe7e8e2dbcf",
  112. "name": "pu_o",
  113. "displayName": "PublicOfficial",
  114. "description": "Test official station. Public.",
  115. "type": "official",
  116. "queue": [],
  117. "locked": false,
  118. "privacy": "public",
  119. "blacklistedGenres": [],
  120. "genres": [],
  121. "playlist": [],
  122. "startedAt": 0,
  123. "pausedAt": 0,
  124. "timePaused": 0,
  125. "currentSongIndex": 0,
  126. userCount: 0,
  127. "currentSong": {
  128. "songId": "60ItHLz5WEA",
  129. "title": "Faded - Alan Walker",
  130. "duration": 212,
  131. "skipDuration": 0,
  132. "skipVotes": [],
  133. "dislikes": -1,
  134. "likes": -1,
  135. "artists": [],
  136. thumbnail: "/assets/images/notes-transparent.png"
  137. },
  138. "paused": false,
  139. "__v": 0
  140. });
  141. community.push({
  142. "_id": "59b5221222634afe7e8e2dbcf",
  143. "name": "pu_c",
  144. "displayName": "PublicCommunity",
  145. "description": "Test community station. Public.",
  146. "type": "community",
  147. "queue": [],
  148. "locked": false,
  149. "privacy": "public",
  150. "blacklistedGenres": [],
  151. "genres": [],
  152. "playlist": [],
  153. "startedAt": 0,
  154. "pausedAt": 0,
  155. "timePaused": 0,
  156. "currentSongIndex": 0,
  157. userCount: 0,
  158. "currentSong": {
  159. "songId": "60ItHLz5WEA",
  160. "title": "Faded - Alan Walker",
  161. "duration": 212,
  162. "skipDuration": 0,
  163. "skipVotes": [],
  164. "dislikes": -1,
  165. "likes": -1,
  166. "artists": [],
  167. thumbnail: "/assets/images/notes-transparent.png"
  168. },
  169. "paused": false,
  170. "__v": 0
  171. });
  172. if (this.isOwner("fd")) community.push({
  173. "_id": "59b522222634af3e7e8e2dbcf",
  174. "name": "un_c",
  175. "displayName": "UnlistedCommunity",
  176. "description": "Test community station. Unlisted.",
  177. "type": "community",
  178. "queue": [],
  179. "locked": false,
  180. "privacy": "unlisted",
  181. "blacklistedGenres": [],
  182. "genres": [],
  183. "playlist": [],
  184. "startedAt": 0,
  185. "pausedAt": 0,
  186. "timePaused": 0,
  187. "currentSongIndex": 0,
  188. userCount: 0,
  189. "currentSong": {
  190. "songId": "60ItHLz5WEA",
  191. "title": "Faded - Alan Walker",
  192. "duration": 212,
  193. "skipDuration": 0,
  194. "skipVotes": [],
  195. "dislikes": -1,
  196. "likes": -1,
  197. "artists": [],
  198. thumbnail: "/assets/images/notes-transparent.png"
  199. },
  200. "paused": false,
  201. "__v": 0
  202. });
  203. if (this.isOwner("fd")) community.push({
  204. "_id": "59b522222634afe7e8e2dbcf",
  205. "name": "pr_c",
  206. "displayName": "PrivateCommunity",
  207. "description": "Test community station. Private.",
  208. "type": "community",
  209. "queue": [],
  210. "locked": false,
  211. "privacy": "private",
  212. "blacklistedGenres": [],
  213. "genres": [],
  214. "playlist": [],
  215. "startedAt": 0,
  216. "pausedAt": 0,
  217. "timePaused": 0,
  218. "currentSongIndex": 0,
  219. userCount: 0,
  220. "currentSong": {
  221. "songId": "60ItHLz5WEA",
  222. "title": "Faded - Alan Walker",
  223. "duration": 212,
  224. "skipDuration": 0,
  225. "skipVotes": [],
  226. "dislikes": -1,
  227. "likes": -1,
  228. "artists": [],
  229. thumbnail: "/assets/images/notes-transparent.png"
  230. },
  231. "paused": false,
  232. "__v": 0
  233. });
  234. this.setState({
  235. stations: {
  236. official,
  237. community,
  238. }
  239. });
  240. }
  241. });
  242. });
  243. }
  244. isOwner = (ownerId) => {
  245. if (this.props.loggedIn) {
  246. if (this.props.user.role === "admin") return true;
  247. if (this.props.user.userId === ownerId) return true;
  248. }
  249. return false;
  250. };
  251. listStations = (type) => {
  252. let stations = [];
  253. this.state.stations[type].forEach((station) => {
  254. let icon = null;
  255. if (station.type === "official") {
  256. if (station.privacy !== "public") icon =
  257. <i className="material-icons" title={ this.props.t("home:thisStationIsNotVisible") }>lock</i>;
  258. } else {
  259. // TODO Add isOwner function globally
  260. if (this.isOwner(station.ownerId)) icon =
  261. <i className="material-icons" title={ this.props.t("home:thisIsYourStation") }>home</i>;
  262. if (station.privacy !== "public") icon =
  263. <i className="material-icons" title={ this.props.t("home:thisStationIsNotVisible") }>lock</i>;
  264. }
  265. stations.push(
  266. (
  267. <div key={station._id} className="station-card">
  268. <div className="station-media">
  269. <img src={station.currentSong.thumbnail}/>
  270. </div>
  271. <div className="station-body">
  272. <h3 className="displayName">{station.displayName}</h3>
  273. <p className="description">{station.description}</p>
  274. </div>
  275. <div className="station-footer">
  276. <div className="user-count" title={ this.props.t("home:howManyOtherUsers") }>
  277. <i className="material-icons">people</i>
  278. <span>{station.userCount}</span>
  279. </div>
  280. { icon }
  281. </div>
  282. <a href={station.type + "/" + station.name}/>
  283. </div>
  284. )
  285. );
  286. });
  287. return stations;
  288. };
  289. togglePrivate = () => {
  290. this.setState({
  291. createStation: {
  292. private: !this.state.createStation.private,
  293. },
  294. });
  295. };
  296. createCommunity = () => {
  297. this.messages.clearErrorSuccess();
  298. if (CustomInput.hasInvalidInput(this.input)) {
  299. this.messages.clearAddError(this.props.t("general:someFieldsAreIncorrectError"));
  300. } else {
  301. io.getSocket(socket => {
  302. //TODO Add private value
  303. socket.emit("stations.create", {
  304. name: this.input.stationName.getValue(),
  305. type: "community",
  306. displayName: this.input.stationDisplayName.getValue(),
  307. description: this.input.stationDescription.getValue(),
  308. }, res => {
  309. if (res.status === "success") {
  310. location.href = "/community/" + this.input.stationName.getValue();//TODO Remove
  311. } else {
  312. this.messages.addError(res.message);
  313. }
  314. });
  315. });
  316. }
  317. };
  318. render() {
  319. const { t } = this.props;
  320. //TODO Make this not re-render a lot
  321. return (
  322. <main id="homepage">
  323. <h1>{ t("home:title") }</h1>
  324. <CustomMessages onRef={ ref => (this.messages = ref) } />
  325. <h2>{ t("home:officialStations") }</h2>
  326. <div className="official-stations stations">
  327. { this.listStations("official") }
  328. </div>
  329. <h2>{ t("home:communityStations") }</h2>
  330. <div className="community-stations stations">
  331. { (this.props.loggedIn) ? (
  332. <div className="station-card">
  333. <div className="station-media station-media-icon">
  334. <i className="material-icons" title={ this.props.t("createCommunityStation:addCommunityStation") } onClick={ this.createCommunity }>add</i>
  335. </div>
  336. <div className="station-body">
  337. <CustomInput key="stationDisplayName" type="stationDisplayName" name="stationDisplayName" showLabel={ false } placeholder={ this.props.t("createCommunityStation:displayNameHere") } onRef={ ref => (this.input.stationDisplayName = ref) } />
  338. <CustomInput key="stationDescription" type="stationDescription" name="stationDescription" showLabel={ false } placeholder={ this.props.t("createCommunityStation:descriptionHere") } onRef={ ref => (this.input.stationDescription = ref) } />
  339. </div>
  340. <div className="station-footer">
  341. <div className="nameContainer">
  342. <span>musare.com/c/</span>
  343. <CustomInput key="stationName" type="stationName" name="stationName" showLabel={ false } placeholder={ this.props.t("createCommunityStation:nameHere") } onRef={ ref => (this.input.stationName = ref) } />
  344. </div>
  345. {(this.state.createStation.private) ? <i className="material-icons" title={ this.props.t("createCommunityStation:makeThisStationPublic") } onClick={ this.togglePrivate }>lock</i> : <i className="material-icons active" title={ this.props.t("createCommunityStation:makeThisStationPrivate") } onClick={ this.togglePrivate }>lock</i>}
  346. </div>
  347. </div>
  348. ) : null }
  349. { this.listStations("community") }
  350. </div>
  351. </main>
  352. );
  353. }
  354. }