瀏覽代碼

Started transitioning to Redux everywhere, and started using ducks.

KrisVos130 7 年之前
父節點
當前提交
07cf23950f

+ 12 - 3
frontend/app/js/app.jsx

@@ -2,6 +2,8 @@ import React, { Component } from "react";
 import { Route, Switch, withRouter } from "react-router-dom";
 import PropTypes from "prop-types";
 import { connect } from "react-redux";
+import { bindActionCreators } from "redux";
+import { actionCreators as volumeActionCreators } from "ducks/volume";
 import { translate } from "react-i18next";
 
 import { ban, authenticate } from "actions/auth";
@@ -12,9 +14,13 @@ import config from "config";
 import AuthRoute from "components/AuthRoute";
 import io from "./io";
 
-import { asyncComponent } from 'react-async-component';
+import { asyncComponent } from "react-async-component";
 
-@connect()
+@connect(null, (dispatch) => ({
+	onVolumeLoudnessChange: bindActionCreators(volumeActionCreators.changeVolumeLoudness, dispatch),
+	onVolumeMute: bindActionCreators(volumeActionCreators.muteVolume, dispatch),
+	onVolumeUnmute: bindActionCreators(volumeActionCreators.unmuteVolume, dispatch),
+}))
 @translate(["pages"], { wait: false })
 class App extends Component { // eslint-disable-line react/no-multi-comp
 	static propTypes = {
@@ -49,9 +55,12 @@ class App extends Component { // eslint-disable-line react/no-multi-comp
 		}
 
 		let volume = parseFloat(localStorage.getItem("volume"));
+		let muted = (localStorage.getItem("muted"));
 		volume = (typeof volume === "number" && !isNaN(volume)) ? volume : 20;
 		localStorage.setItem("volume", volume);
-		dispatch(initializeVolume(volume));
+
+		this.props.onVolumeLoudnessChange(volume);
+		muted ? this.props.onVolumeMute() : this.props.onVolumeUnmute();
 	}
 
 	render() {

+ 90 - 0
frontend/app/js/ducks/homepage.js

@@ -0,0 +1,90 @@
+import { Map, List } from "immutable";
+
+const STATION_REMOVE = "HOMEPAGE::STATION_REMOVE";
+const STATION_SONG_UPDATE = "HOMEPAGE::STATION_SONG_UPDATE";
+const STATION_USER_COUNT_UPDATE = "HOMEPAGE::STATION_USER_COUNT_UPDATE";
+
+function stationRemove(stationId) {
+	return {
+		type: STATION_REMOVE,
+		stationId,
+	}
+}
+
+function stationSongUpdate(stationId, song) {
+	return {
+		type: STATION_SONG_UPDATE,
+		stationId,
+		thumbnail: song.thumbnail,
+	}
+}
+
+function stationUserCountUpdate(stationId, userCount) {
+	return {
+		type: STATION_USER_COUNT_UPDATE,
+		stationId,
+		userCount,
+	}
+}
+
+
+
+const initialState = Map({
+	stations: Map({
+		official: List([]),
+		community: List([]),
+	}),
+});
+
+function reducer(state = initialState, action) {
+	switch (action.type) {
+	case STATION_REMOVE:
+		const { stationId } = action;
+		const indexOfficial = state.getIn(["stations", "official"]).findIndex(function (station) {
+			return station.get("stationId") === stationId;
+		});
+		if (indexOfficial > -1) {
+			state.updateIn(["stations", "official"], (list) => {
+				list.delete(indexOfficial);
+			});
+		}
+		const indexCommunity = state.getIn(["stations", "community"]).findIndex(function (station) {
+			return station.get("stationId") === stationId;
+		});
+		if (indexCommunity > -1) {
+			state.updateIn(["stations", "community"], (list) => {
+				list.delete(indexCommunity);
+			});
+		}
+
+		return state;
+	case STATION_SONG_UPDATE:
+		/*return state.merge({
+			muted: true,
+		});*/
+	case STATION_USER_COUNT_UPDATE:
+		/*return state.merge({
+			muted: false,
+		});*/
+	}
+	return state;
+}
+
+const actionCreators = {
+	changeVolumeLoudness,
+	muteVolume,
+	unmuteVolume,
+};
+
+const actionTypes = {
+	CHANGE_VOLUME_LOUDNESS,
+	MUTE_VOLUME,
+	UNMUTE_VOLUME,
+};
+
+export {
+	actionCreators,
+	actionTypes,
+};
+
+export default reducer;

+ 97 - 0
frontend/app/js/ducks/session.js

@@ -0,0 +1,97 @@
+import { Map } from "immutable";
+
+const LOGOUT = "SESSION::LOGOUT";
+const LOGIN = "SESSION::LOGIN";
+const BANNED = "SESSION::BANNED";
+const UNBANNED = "SESSION::UNBANNED";
+
+function logout() {
+	return {
+		type: LOGOUT,
+	}
+}
+
+function login(userId, username, role) {
+	return {
+		type: LOGIN,
+		userId,
+		username,
+		role,
+	}
+}
+
+function banned(reason) {
+	return {
+		type: BANNED,
+		reason,
+	}
+}
+
+function unbanned() {
+	return {
+		type: UNBANNED,
+	}
+}
+
+const initialState = Map({
+	loggedIn: false,
+	userId: "",
+	username: "",
+	role: "default",
+	banned: {
+		status: false,
+		reason: "",
+	},
+});
+
+function reducer(state = initialState, action) {
+	switch (action.type) {
+	case LOGOUT:
+		return state.merge({
+			loggedIn: initialState.get("loggedIn"),
+			userId: initialState.get("userId"),
+			username: initialState.get("username"),
+			role: initialState.get("role"),
+		});
+	case LOGIN:
+		const { userId, username, role } = action;
+		return state.merge({
+			userId,
+			username,
+			role,
+		});
+	case BANNED:
+		const { reason } = action;
+		return state.merge({
+			banned: true,
+			reason,
+		});
+	case UNBANNED:
+		return state.merge({
+			banned: false,
+			reason: initialState.get("reason"),
+		});
+	}
+	return state;
+}
+
+const actionCreators = {
+	logout,
+	login,
+	banned,
+	unbanned,
+};
+
+const actionTypes = {
+	LOGOUT,
+	LOGIN,
+	BANNED,
+	UNBANNED,
+};
+
+export {
+	actionCreators,
+	actionTypes,
+};
+
+export default reducer;

+ 67 - 0
frontend/app/js/ducks/volume.js

@@ -0,0 +1,67 @@
+import { Map } from "immutable";
+
+const CHANGE_VOLUME_LOUDNESS = "VOLUME::CHANGE_VOLUME_LOUDNESS";
+const MUTE_VOLUME = "VOLUME::MUTE_VOLUME";
+const UNMUTE_VOLUME = "VOLUME::UNMUTE_VOLUME";
+
+function changeVolumeLoudness(loudness) {
+	return {
+		type: CHANGE_VOLUME_LOUDNESS,
+		loudness,
+	}
+}
+
+function muteVolume() {
+	return {
+		type: MUTE_VOLUME,
+	}
+}
+
+function unmuteVolume() {
+	return {
+		type: UNMUTE_VOLUME,
+	}
+}
+
+const initialState = Map({
+	loudness: 25,
+	muted: false,
+});
+
+function reducer(state = initialState, action) {
+	switch (action.type) {
+	case CHANGE_VOLUME_LOUDNESS:
+		const { loudness } = action;
+		return state.merge({
+			loudness,
+		});
+	case MUTE_VOLUME:
+		return state.merge({
+			muted: true,
+		});
+	case UNMUTE_VOLUME:
+		return state.merge({
+			muted: false,
+		});
+	}
+	return state;
+}
+
+const actionCreators = {
+	changeVolumeLoudness,
+	muteVolume,
+	unmuteVolume,
+};
+
+const actionTypes = {
+	CHANGE_VOLUME_LOUDNESS,
+	MUTE_VOLUME,
+	UNMUTE_VOLUME,
+};
+
+export {
+	actionCreators,
+	actionTypes,
+};
+
+export default reducer;

+ 3 - 2
frontend/app/js/reducers/index.js

@@ -1,14 +1,15 @@
 import { combineReducers } from "redux";
 import user from "reducers/user";
-import volume from "reducers/volume";
+//import volume from "reducers/volume";
 import songPlayer from "reducers/songPlayer";
 import station from "reducers/station";
 import stationOverlay from "reducers/stationOverlay";
 import playlistQueue from "reducers/playlistQueue";
+import volume from "../ducks/volume";
 
 export default combineReducers({
-	user,
 	volume,
+	user,
 	songPlayer,
 	station,
 	stationOverlay,

+ 0 - 35
frontend/app/js/reducers/volume.js

@@ -1,35 +0,0 @@
-import { Map } from "immutable";
-
-import {
-	INITIALIZE,
-	CHANGE_VOLUME,
-	CHANGE_VOLUME_MUTED,
-} from "actions/volume";
-
-const initialState = Map({
-	volume: 0,
-	muted: false, //TODO Store muted and initialize it
-});
-
-const actionsMap = {
-	[INITIALIZE]: (state, action) => {
-		return state.merge({
-			volume: action.volume,
-		});
-	},
-	[CHANGE_VOLUME]: (state, action) => {
-		return state.merge({
-			volume: action.volume,
-		});
-	},
-	[CHANGE_VOLUME_MUTED]: (state, action) => {
-		return state.merge({
-			muted: action.muted,
-		});
-	},
-};
-
-export default function reducer(state = initialState, action = {}) {
-	const fn = actionsMap[action.type];
-	return fn ? fn(state, action) : state;
-}

+ 14 - 8
frontend/app/js/views/Station/VolumeSlider.jsx

@@ -1,31 +1,37 @@
 import React, { Component } from "react";
+import { bindActionCreators } from "redux";
 import PropTypes from "prop-types";
 
 import { connect } from "react-redux";
 
-import { changeVolume, changeVolumeMuted } from "actions/volume";
+import { actionCreators as volumeActionCreators } from "ducks/volume";
 
 @connect(state => ({
-	volume: state.volume.get("volume"),
+	volume: state.volume.get("loudness"),
 	muted: state.volume.get("muted"),
+}),
+(dispatch) => ({
+	onVolumeLoudnessChange: bindActionCreators(volumeActionCreators.changeVolumeLoudness, dispatch),
+	onVolumeMute: bindActionCreators(volumeActionCreators.muteVolume, dispatch),
+	onVolumeUnmute: bindActionCreators(volumeActionCreators.unmuteVolume, dispatch),
 }))
 export default class VolumeSlider extends Component {
 	constructor(props) {
 		super(props);
 	}
 
-	changeVolumeHandler = (volume) => {
-		volume = volume / 100;
-		localStorage.setItem("volume", volume);
-		this.props.dispatch(changeVolume(volume));
+	changeVolumeHandler = (loudness) => {
+		loudness = loudness / 100;
+		localStorage.setItem("volume", loudness);
+		this.props.onVolumeLoudnessChange(loudness);
 	};
 
 	muteVolume = () => {
-		this.props.dispatch(changeVolumeMuted(true));
+		this.props.onVolumeMute();
 	};
 
 	unmuteVolume = () => {
-		this.props.dispatch(changeVolumeMuted(false));
+		this.props.onVolumeUnmute();
 	};
 
 	render() {