Skip to content

Commit

Permalink
Merge branch 'feature/daily-channel' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Darmody committed Apr 6, 2016
2 parents 8d5ff4a + 5dd2ffa commit 5c4c463
Show file tree
Hide file tree
Showing 12 changed files with 821 additions and 17 deletions.
17 changes: 17 additions & 0 deletions src/actionTypes/daily.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const FETCH_REQUEST = 'DAILY/FETCH_REQUEST';
export const FETCH_SUCCESS = 'DAILY/FETCH_SUCCESS';
export const FETCH_FAILURE = 'DAILY/FETCH_FAILURE';
export const LIKE_REQUEST = 'DAILY/LIKE_REQUEST';
export const LIKE_SUCCESS = 'DAILY/LIKE_SUCCESS';
export const LIKE_FAILURE = 'DAILY/LIKE_FAILURE';
export const DISLIKE_REQUEST = 'DAILY/DISLIKE_REQUEST';
export const DISLIKE_SUCCESS = 'DAILY/DISLIKE_SUCCESS';
export const DISLIKE_FAILURE = 'DAILY/DISLIKE_FAILURE';
export const BAN_REQUEST = 'DAILY/BAN_REQUEST';
export const BAN_SUCCESS = 'DAILY/BAN_SUCCESS';
export const BAN_FAILURE = 'DAILY/BAN_FAILURE';
export const JUMP = 'DAILY/JUMP';
export const NEXT = 'DAILY/NEXT';
export const PLAY = 'DAILY/PLAY';
export const PAUSE = 'DAILY/PAUSE';
export const REFUSE = 'DAILY/REFUSE';
2 changes: 1 addition & 1 deletion src/actionTypes/favorite.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const DISLIKE_FAILURE = 'FAVORITE/DISLIKE_FAILURE';
export const BAN_REQUEST = 'FAVORITE/BAN_REQUEST';
export const BAN_SUCCESS = 'FAVORITE/BAN_SUCCESS';
export const BAN_FAILURE = 'FAVORITE/BAN_FAILURE';
export const JUMP = 'CHANNEL/JUMP';
export const JUMP = 'FAVORITE/JUMP';
export const NEXT = 'FAVORITE/NEXT';
export const PLAY = 'FAVORITE/PLAY';
export const PAUSE = 'FAVORITE/PAUSE';
Expand Down
127 changes: 127 additions & 0 deletions src/containers/Daily/Daily.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Player } from 'components';
import { fetch, next, like, dislike, ban, play, pause, jump } from 'reducers/daily';
import { shortcut } from 'utils';
import styles from './Daily.scss';

@connect(
state => ({
currentUser: state.auth.user,
song: state.daily.song,
playing: state.daily.playing,
playList: state.daily.playList,
}),
dispatch => ({
...bindActionCreators({ fetch, next, play, pause, ban, like, dislike, jump }, dispatch)
})
)
export default class Favorite extends Component {
static propTypes = {
currentUser: PropTypes.object.isRequired,
song: PropTypes.object.isRequired,
playList: PropTypes.array.isRequired,
playing: PropTypes.bool.isRequired,
fetch: PropTypes.func.isRequired,
next: PropTypes.func.isRequired,
play: PropTypes.func.isRequired,
pause: PropTypes.func.isRequired,
like: PropTypes.func.isRequired,
dislike: PropTypes.func.isRequired,
ban: PropTypes.func.isRequired,
jump: PropTypes.func.isRequired,
}

constructor(props) {
super(props);

const shortcutListener = shortcut.listen(
0, this.onTaste, this.onControl, this.onBan, this.onNext
);

this.state = { shortcutListener };
}

componentDidMount() {
this.props.fetch();
}

componentWillReceiveProps(nextProps) {
if (this.props.currentUser.id === 0 && nextProps.currentUser.id !== 0) {
this.props.fetch();
}
}

componentWillUnmount() {
shortcut.stop(this.state.shortcutListener);
}

onNext = () => {
this.props.next(this.props.song.id);
}

onControl = () => {
if (this.props.playing) {
this.props.pause();
} else {
this.props.play();
}
}

onTaste = (action) => {
if (action === 'dislike') {
this.props.dislike(this.props.song.id);
} else if (action === 'like') {
this.props.like(this.props.song.id);
} else if (this.props.song.favorite) {
this.props.dislike(this.props.song.id);
} else {
this.props.like(this.props.song.id);
}
}

onBan = () => {
this.props.ban(this.props.song.id);
}

onJump = (song) => () => {
this.props.jump(song);
}

renderContent = (props) => {
const { playing, currentUser, song, playList } = props;
const available = currentUser.id !== 0 && song.id !== 0;

if (available) {
return (
<div className={styles.content} >
<div className="player">
<Player
song={song}
listTitle="每日歌单"
playList={playList}
playing={playing}
onControl={this.onControl}
onTaste={this.onTaste}
onBan={this.onBan}
onNext={this.onNext}
onEnd={this.onNext}
onJump={this.onJump}
/>
</div>
</div>
);
}
return (
<div className={styles.mask} >
<i className="material-icons" > announcement </i>
Oops, 是不是忘记登录了?
</div>
);
}

render() {
return this.renderContent(this.props);
}
}
21 changes: 21 additions & 0 deletions src/containers/Daily/Daily.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@import '~sass-flex-mixin/flex';

.content {
@extend %flexbox;
@include justify-content(center);
}

.mask {
height: 20rem;
text-align: center;
line-height: 20rem;
font-size: 0.8rem;
font-weight: 400;
color: #9b9b9b;
text-decoration: underline;

> i {
font-size: 2rem;
margin-right: 0.5rem;
}
}
39 changes: 25 additions & 14 deletions src/containers/HomePage/Navbar/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,35 @@ function UserItem({ currentUser = {}, showSigninModal, logoutUser }) {
);
}

export default ({ currentUser, currentLocation, showSigninModal, logoutUser }) => {
function NavItem({ title, link, active }) {
const activeIcon = (<i className="material-icons" > volume_up </i>);
return (
<Link to={link} className="navItem" >
{ title }
{ active && activeIcon }
</Link>
);
}

export default ({ currentUser, currentLocation, showSigninModal, logoutUser }) => {
return (
<nav className={styles.navbar} >
<div className={styles.navItems} >
<button className="navItem disabled" > 更多 MHz </button>
<Link to="channels/0" className="navItem" >
私人 MHz
{
(currentLocation === '/channels/0' || currentLocation === '/') && activeIcon
}
</Link>
<Link to="favorite" className="navItem" >
红心 MHz
{
(currentLocation === '/favorite') && activeIcon
}
</Link>
<NavItem
title="私人 MHz"
link="/channels/0"
active={currentLocation === '/' || currentLocation === '/channels/0' }
/>
<NavItem
title="每日私人歌单"
link="/daily"
active={currentLocation === '/daily'}
/>
<NavItem
title="红心 MHz"
link="/favorite"
active={currentLocation === '/favorite'}
/>
</div>
<div className={styles.userItem} >
<UserItem
Expand Down
1 change: 1 addition & 0 deletions src/containers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export App from './App/App';
export HomePage from './HomePage/HomePage';
export Channel from './Channel/Channel';
export Favorite from './Favorite/Favorite';
export Daily from './Daily/Daily';
export Signin from './Auth/Signin/Signin';
7 changes: 7 additions & 0 deletions src/middlewares/apiMiddlewareHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import {
BAN_REQUEST as FAVORITE_BAN_REQUEST,
REFUSE as FAVORITE_REFUSE,
} from '../actionTypes/favorite';
import {
BAN_REQUEST as DAILY_BAN_REQUEST,
REFUSE as DAILY_REFUSE,
} from '../actionTypes/daily';

const decamelizeBody = (action) => {
const callAPI = action[CALL_API];
Expand Down Expand Up @@ -71,6 +75,9 @@ const pendingRefuse = (action, store) => {
if (FAVORITE_BAN_REQUEST === callAPI.types[0]) {
if (store.getState().favorite.loading) return { type: FAVORITE_REFUSE };
}
if (DAILY_BAN_REQUEST === callAPI.types[0]) {
if (store.getState().favorite.loading) return { type: DAILY_REFUSE };
}

return action;
};
Expand Down
2 changes: 1 addition & 1 deletion src/reducers/__tests__/auth.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('Auth Actions', function actions() {
setTimeout(() => {
expect(_.last(store.getActions()).type).to.equal(LOGIN_SUCCESS);
done();
}, 20);
}, 50);
});

it('LOGIN_FAILURE', function loginFailure(done) {
Expand Down
Loading

0 comments on commit 5c4c463

Please sign in to comment.