<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import Input from '../Input/Input';
import Button from '../Button/Button';
import classes from './SignUpBox.css';

const SignUpBox = (props) => {
  const {
    email,
    isEmailValid,
    emailChangeHandler,
    password,
    isPasswordValid,
    passwordChangeHandler,
    username,
    isUsernameValid,
    usernameChangeHandler,
    repeatPassword,
    isRepeatPasswordValid,
    repeatPasswordChangeHandler,
    submitTrigger,
    submitDisabled,
  } = props;

  let emailValidationClass = classes.signUpBox__input;
  let passwordValidationClass = classes.signUpBox__input;
  let repeatPasswordValidationClass = classes.signUpBox__input;
  let usernameValidationClass = classes.signUpBox__input;

  if (isEmailValid === false) {
    emailValidationClass = classes.signUpBox__emailNotValid;
  }

  if (isPasswordValid === false) {
    passwordValidationClass = classes.signUpBox__passwordNotValid;
  }

  if (isRepeatPasswordValid === false) {
    repeatPasswordValidationClass = classes.signUpBox__repeatPasswordNotValid;
  }

  if (isUsernameValid === false) {
    usernameValidationClass = classes.signUpBox__usernameNotValid;
  }

  return (
    <div className={classes.signUpBox}>
      <div className={emailValidationClass}>
        <p>
          email:
        </p>
        <Input
          maxLength="30"
          value={email}
          placeholder="..."
          onChange={emailChangeHandler}
        />
      </div>
      <div className={usernameValidationClass}>
        <p>
          username:
        </p>
        <Input
          maxLength="30"
          value={username}
          placeholder="..."
          onChange={usernameChangeHandler}
        />
      </div>
      <div className={passwordValidationClass}>
        <p>
          password:
        </p>
        <Input
          maxLength="30"
          type="password"
          value={password}
          placeholder="..."
          onChange={passwordChangeHandler}
        />
      </div>
      <div className={repeatPasswordValidationClass}>
        <p>
          repeat password:
        </p>
        <Input
          maxLength="30"
          type="password"
          value={repeatPassword}
          placeholder="..."
          onChange={repeatPasswordChangeHandler}
        />
      </div>
      <div className={classes.signUpBox__button}>
        <Button
          onClick={submitTrigger}
          disabled={submitDisabled}
        >
          Sign Up
        </Button>
      </div>
    </div>
  );
};

SignUpBox.propTypes = {
  email: PropTypes.string.isRequired,
  isEmailValid: PropTypes.bool.isRequired,
  emailChangeHandler: PropTypes.func.isRequired,
  password: <PASSWORD>.string.isRequired,
  isPasswordValid: PropTypes.bool.isRequired,
  passwordChangeHandler: PropTypes.func.isRequired,
  username: PropTypes.string.isRequired,
  isUsernameValid: PropTypes.bool.isRequired,
  usernameChangeHandler: PropTypes.func.isRequired,
  repeatPassword: PropTypes.string.isRequired,
  isRepeatPasswordValid: PropTypes.bool.isRequired,
  repeatPasswordChangeHandler: PropTypes.func.isRequired,
  submitTrigger: PropTypes.func.isRequired,
  submitDisabled: PropTypes.string.isRequired,
};

export default SignUpBox;
<file_sep>import React, { PureComponent } from 'react';
import Input from '../../components/Input/Input';
import Button from '../../components/Button/Button';
import classes from './ChangePassword.css';

class ChangePassword extends PureComponent {
  state = {
    newPasswordValue: '',
    repeatNewPasswordValue: '',
    newPasswordValidClass: null,
    repeatNewPasswordValidClass: null,
    newPasswordSubmitDisabeld: 'disabled',
  }

  newPasswordChangeHnadler = (event) => {
    const { value } = event.target;
    const { repeatNewPasswordValue } = this.state;
    const pattern = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm;
    let submitDisabled = 'disabled';
    if (value.match(pattern) && value === repeatNewPasswordValue) {
      submitDisabled = null;
    }

    if (!value.match(pattern)) {
      this.setState({
        newPasswordValue: value,
        newPasswordValidClass: classes.notValidNewPassword,
        newPasswordSubmitDisabeld: submitDisabled,
      });
    }

    if (value.match(pattern)) {
      this.setState({
        newPasswordValue: value,
        newPasswordValidClass: null,
        newPasswordSubmitDisabeld: submitDisabled,
      });
    }
  }

  repeatNewPasswordChangeHnadler = (event) => {
    const { value } = event.target;
    const { newPasswordValue } = this.target;
    const pattern = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm;
    let submitDisabled = 'disabled';
    if (value === newPasswordValue && newPasswordValue.match(pattern)) {
      submitDisabled = null;
    }

    if (value !== newPasswordValue) {
      this.setState({
        repeatNewPasswordValue: value,
        repeatNewPasswordValidClass: classes.notValidRepeatNewPassword,
        newPasswordSubmitDisabeld: submitDisabled,
      });
    }

    if (value === newPasswordValue) {
      this.setState({
        repeatNewPasswordValue: value,
        repeatNewPasswordValidClass: null,
        newPasswordSubmitDisabeld: submitDisabled,
      });
    }
  }

  submitNewPassword = () => {
    console.log('NewPassword');
  }

  render() {
    const {
      newPasswordValue,
      repeatNewPasswordValue,
      newPasswordValidClass,
      repeatNewPasswordValidClass,
      newPasswordSubmitDisabeld,
    } = this.state;

    const {
      newPasswordChangeHnadler,
      repeatNewPasswordChangeHnadler,
      submitNewPassword,
    } = this;

    return (
      <div className={classes.changePassword}>
        <p>
          please input your new password:
        </p>
        <div className={newPasswordValidClass}>
          <Input
            maxLength="30"
            type="password"
            placeholder="<PASSWORD>"
            value={newPasswordValue}
            onChange={event => newPasswordChangeHnadler(event)}
          />
        </div>
        <p>
          please repeat your new password:
        </p>
        <div className={repeatNewPasswordValidClass}>
          <Input
            maxLength="30"
            type="password"
            placeholder="<PASSWORD>"
            value={repeatNewPasswordValue}
            onChange={event => repeatNewPasswordChangeHnadler(event)}
          />
        </div>
        <Button
          onClick={submitNewPassword}
          disabled={newPasswordSubmitDisabeld}
        >
          submit
        </Button>
      </div>
    );
  }
}

export default ChangePassword;
<file_sep>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import AlbumsDisplayWithPage from '../../components/AlbumsDisplayWithPage/AbumsDisplayWithPage';
import classes from './UserAllRates.css';

class UserAllRates extends PureComponent {
  state = {
    albums,
    page: 9,
    totalPage: 20,
  }

  componentWillMount() {
    const { albums } = this.props;
    this.setState({
      albums,
    });
  }

  render() {
    const {
      albums,
      page,
      totalPage,
    } = this.state;

    return (
      <div className={classes.userAllRates}>
        <div className={classes.userAllRates__title}>
          <p>
            - My Rates -
          </p>
        </div>
        <AlbumsDisplayWithPage
          albums={albums}
          page={page}
          totalPage={totalPage}
          baseUrl="/user/rates"
        />
      </div>
    );
  }
}

const mapStateToProps = state => ({
  albums: state.user.albums,
});

export default connect(mapStateToProps)(UserAllRates);

UserAllRates.propTypes = {
  albums: PropTypes.arrayOf(PropTypes.object).isRequired,
};

const albums = [
  {
    id: '1',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '2',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '3',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '4',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '5',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '6',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '7',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '8',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '9',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '10',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '11',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '12',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: 'Le<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '13',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: 'Le<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '14',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: 'Leonard Cohen',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '15',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '16',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: 'Leonard Cohen',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '17',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '18',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '19',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '20',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
];
<file_sep>import React from 'react';
import Rate from '../../../assets/icon/rate';
import Labeling from '../../../assets/icon/label';
import Discuss from '../../../assets/icon/discuss';
import classes from './Intro.css';

const Intro = () => (
  <div className={classes.intro}>
    <p className={classes.intro__header}>
      For True Music Lovers.
    </p>
    <div className={classes.intro__feature_1}>
      <Rate />
      <p>
        Comment every single song.
      </p>
    </div>
    <div className={classes.intro__feature_2}>
      <Labeling />
      <p>
        Easy rating and labeling system.
      </p>
    </div>
    <div className={classes.intro__feature_3}>
      <Discuss />
      <p>
        Discuss with others only about music.
      </p>
    </div>
  </div>
);

export default Intro;
<file_sep>import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Layouts from './components/Layouts/Layouts';
import Home from './containers/Home/Home';
import AlbumDetails from './containers/AlbumDetails/AlbumDetails';
import UserSign from './containers/UserSign/UserSign';
import UserDetails from './containers/UserDetails/UserDetails';
import UserAllRates from './containers/UserAllRates/UserAllRates';
import UserAllLabels from './containers/UserAllLabels/UserAllLabels';
import ForgetPassword from './containers/ForgetPassword/ForgetPassword';
import ChangePassword from './containers/ChangePassword/ChangePassword';
import ArtistDetails from './containers/ArtistDetails/ArtistDetails';

const App = () => (
  <BrowserRouter>
    <Layouts>
      <Route path="/album" component={AlbumDetails} />
      <Route path="/signin" component={UserSign} />
      <Route path="/artist" component={ArtistDetails} />
      <Route path="/forgetpassword" component={ForgetPassword} />
      <Route path="/changepassword" component={ChangePassword} />
      <Switch>
        <Route path="/user/rates" component={UserAllRates} />
        <Route path="/user/labels" component={UserAllLabels} />
        <Route path="/user" component={UserDetails} />
      </Switch>
      <Route path="/" exact component={Home} />
    </Layouts>
  </BrowserRouter>
);

export default App;
<file_sep>import React, { PureComponent } from 'react';
import Input from '../../components/Input/Input';
import Button from '../../components/Button/Button';
import classes from './ForgetPassword.css';

class ForgetPassword extends PureComponent {
  state = {
    emailValue: '',
    codeValue: '',
    inputEmailClass: classes.displayShow,
    inputCodeClass: classes.displayNone,
    emailValidClass: null,
    codeValidClass: null,
    emailSubmitDisabled: 'disabled',
    codeSubmitDisabeld: 'disabled',
  }

  emailChangeHnadler = (event) => {
    const { value } = event.target;
    const pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/g;
    if (!value.match(pattern)) {
      console.log('here');
      this.setState({
        emailValue: value,
        emailValidClass: classes.notValidEmail,
        emailSubmitDisabled: 'disabled',
      });
    }

    if (value.match(pattern)) {
      this.setState({
        emailValue: value,
        emailValidClass: null,
        emailSubmitDisabled: null,
      });
    }
  }

  codeChangeHnadler = (event) => {
    const { value } = event.target;
    if (value === '') {
      this.setState({
        codeValue: value,
        codeValidClass: classes.notValidCode,
        codeSubmitDisabeld: 'disabled',
      });
    }

    if (value !== '') {
      this.setState({
        codeValue: value,
        codeValidClass: null,
        codeSubmitDisabeld: null,
      });
    }
  }

  submitEmail = () => {
    console.log('email');
    this.setState({
      inputEmailClass: classes.displayNone,
      inputCodeClass: classes.displayShow,
    });
  }

  submitCode = () => {
    console.log('code');
  }

  render() {
    const {
      emailValue,
      codeValue,
      inputEmailClass,
      inputCodeClass,
      codeSubmitDisabeld,
      emailSubmitDisabled,
      emailValidClass,
      codeValidClass,
    } = this.state;

    const {
      emailChangeHnadler,
      submitEmail,
      codeChangeHnadler,
      submitCode,
    } = this;

    return (
      <div className={classes.forgetPassword}>
        <div className={inputEmailClass}>
          <p>
            please input your sign in email:
          </p>
          <div className={emailValidClass}>
            <Input
              maxLength="30"
              placeholder="your email"
              value={emailValue}
              onChange={event => emailChangeHnadler(event)}
            />
          </div>
          <Button
            onClick={submitEmail}
            disabled={emailSubmitDisabled}
          >
            submit
          </Button>
        </div>
        <div className={inputCodeClass}>
          <p>
            please input your verify code:
          </p>
          <div className={codeValidClass}>
            <Input
              maxLength="6"
              placeholder="verify code"
              value={codeValue}
              onChange={event => codeChangeHnadler(event)}
            />
          </div>
          <Button
            onClick={submitCode}
            disabled={codeSubmitDisabeld}
          >
            submit
          </Button>
        </div>
      </div>
    );
  }
}

export default ForgetPassword;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import classes from './Textarea.css';

const Textarea = (props) => {
  const {
    maxLength,
    value,
    placeholder,
    onChange,
    inputLength,
  } = props;

  return (
    <div className={classes.textarea}>
      <textarea
        className={classes.textarea_area}
        maxLength={maxLength}
        value={value}
        placeholder={placeholder}
        onChange={onChange}
      />
      <p className={classes.textarea_length}>
        {inputLength}
        /
        {maxLength}
      </p>
    </div>
  );
};

Textarea.propTypes = {
  maxLength: PropTypes.string.isRequired,
  value: PropTypes.string.isRequired,
  placeholder: PropTypes.string.isRequired,
  onChange: PropTypes.func.isRequired,
  inputLength: PropTypes.number.isRequired,
};

export default Textarea;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import classes from './AlbumInfo.css';

const AlbumInfo = (props) => {
  const {
    albumCoverSrc,
    albumName,
    description,
    genres,
    musician,
    numbersOfRatings,
    rating,
    tracks,
    type,
    year,
  } = props;

  const tracksList = tracks.map(track => (
    <div
      key={track.id}
      className={classes.albumInfo__leftbar__tracks__single}
    >
      <p>
        {track.id}
        .&nbsp;
      </p>
      <p>
        {track.name}
        &nbsp;&nbsp;
      </p>
      <p>
        {track.duration}
      </p>
    </div>
  ));

  return (
    <div className={classes.albumInfo}>
      <div className={classes.albumInfo__leftbar}>
        <div className={classes.albumInfo__leftbar__cover}>
          <img src={albumCoverSrc} alt="album cover" />
          <p>
            type:&nbsp;
            {type}
          </p>
        </div>
        <div className={classes.albumInfo__leftbar__tracks}>
          <p className={classes.albumInfo__leftbar__tracks__title}>
            tracks:
          </p>
          {tracksList}
        </div>
      </div>
      <div className={classes.albumInfo__rightbar}>
        <p className={classes.albumInfo__rightbar__albumName}>
          {albumName}
        </p>
        <div className={classes.albumInfo__rightbar__details}>
          <p>
            artist:&nbsp;
            {musician}
          </p>
          <p>
            year:&nbsp;
            {year}
          </p>
          <p>
            genres:&nbsp;
            {genres}
          </p>
        </div>
        <div className={classes.albumInfo__rightbar__rating}>
          <p className={classes.albumInfo__rightbar__rating__number}>
            {rating}
          </p>
          <p>
            &nbsp;from&nbsp;
            {numbersOfRatings}
            &nbsp;reviewers
          </p>
        </div>
        <div className={classes.albumInfo__rightbar__description}>
          <p className={classes.albumInfo__rightbar__description__title}>
            Introduction:
          </p>
          <p className={classes.albumInfo__rightbar__description__content}>
            {description}
          </p>
        </div>
      </div>
    </div>
  );
};

AlbumInfo.propTypes = {
  albumCoverSrc: PropTypes.string.isRequired,
  albumName: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired,
  genres: PropTypes.string.isRequired,
  musician: PropTypes.string.isRequired,
  numbersOfRatings: PropTypes.string.isRequired,
  rating: PropTypes.string.isRequired,
  tracks: PropTypes.arrayOf(PropTypes.object).isRequired,
  type: PropTypes.string.isRequired,
  year: PropTypes.string.isRequired,
};

export default AlbumInfo;
<file_sep>import React, { PureComponent } from 'react';
import AlbumInfo from '../../components/AlbumInfo/AlbumInfo';
import RatingBar from '../../components/RatingBar/RatingBar';
import classes from './AlbumDetails.css';
import CommentDisplay from '../../components/CommentDisplay/CommentDisplay';

class AlbumDetails extends PureComponent {
  state = {
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    albumName: 'Ordinary Human Currupt Love',
    description: 'In My Secret Life. I saw you this morning. A Thousand Kisses Deep. for Sandy. That Don\'t Make It Junk. I fought against the bottle, Here It Is. Here is your crown. Love Itself. for L.W. *) The light came through the window, By The Rivers Dark. By the rivers dark. <NAME>. You Have Loved Enough.',
    genres: 'soft rock',
    musician: '<NAME>',
    numbersOfRatings: '138',
    rating: '9.0',
    tracks: [
      {
        id: '1',
        name: 'In My Secret Life',
        duration: '4:55',
      },
      {
        id: '2',
        name: 'A Thousand Kisses Deep',
        duration: '6:29',
      },
      {
        id: '3',
        name: 'That Don\'t Make It Junk',
        duration: '4:28',
      },
      {
        id: '4',
        name: 'Here It Is',
        duration: '4:18',
      },
      {
        id: '5',
        name: 'Love Itself',
        duration: '5:26',
      },
      {
        id: '6',
        name: 'By the Rivers Dark',
        duration: '5:20',
      },
      {
        id: '7',
        name: '<NAME>',
        duration: '5:25',
      },
      {
        id: '8',
        name: 'You Have Loved Enough',
        duration: '5:41',
      },
      {
        id: '9',
        name: '<NAME>',
        duration: '6:04',
      },
      {
        id: '10',
        name: 'The Land of Plenty',
        duration: '4:35',
      },
    ],
    type: 'album',
    year: '2001',
  }

  render() {
    const {
      albumCoverSrc,
      albumName,
      description,
      genres,
      musician,
      numbersOfRatings,
      rating,
      tracks,
      type,
      year,
    } = this.state;

    return (
      <div className={classes.albumDetails}>
        <div className={classes.albumDetails__content}>
          <AlbumInfo
            albumCoverSrc={albumCoverSrc}
            albumName={albumName}
            description={description}
            genres={genres}
            musician={musician}
            numbersOfRatings={numbersOfRatings}
            rating={rating}
            tracks={tracks}
            type={type}
            year={year}
          />
          <RatingBar
            tracks={tracks}
          />
          <CommentDisplay />
        </div>
      </div>
    );
  }
}

export default AlbumDetails;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import NoBorderButton from '../NoBorderButton/NoBorderButton';
import classes from './SmallTitleBar.css';

const SmallTitleBar = (props) => {
  const {
    title,
  } = props;

  return (
    <div className={classes.smallTitleBar}>
      <p className={classes.smallTitleBar__title}>
        {title}
      </p>
      <NoBorderButton>
        show more
      </NoBorderButton>
    </div>
  );
};

SmallTitleBar.propTypes = {
  title: PropTypes.string.isRequired,
};

export default SmallTitleBar;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import classes from './NoBorderButton.css';

const NoBorderButton = (props) => {
  const {
    children,
    onClick,
  } = props;

  return (
    <button
      className={classes.noBorderButton}
      type="button"
      onClick={onClick}
    >
      { children }
    </button>
  );
};

NoBorderButton.propTypes = {
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func.isRequired,
};

export default NoBorderButton;
<file_sep>import * as actionTypes from '../actions/actionTypes';
import updateObject from '../utility';

const user = {
  name: 'WangErMa',
  email: '<EMAIL>',
  labels: [
    'intersting',
    'sad song',
    'one pick',
    'english',
    'traditional',
    'want to buy',
    'LP',
    'jazz',
    'acid jazz',
    'post rock',
    'punk',
    'dont like',
    '80\'s',
    'aisan',
    'rap',
    'pop',
    'art pop',
    'male singer',
    'dead',
    'shit',
  ],
  albums: [
    {
      id: '1',
      albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
      ranking: '01',
      albumName: 'Ten New Songs',
      musician: '<NAME>',
      userRate: 5,
      rating: '9.0',
      labels: [
        'LP',
      ],
    },
    {
      id: '2',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b1963f60a9e325d3f0287/1:1/w_160/lemon%20twigs_go%20to%20school.jpg',
      ranking: '01',
      albumName: 'Go to School',
      musician: 'The Lemon Twigs',
      userRate: 4,
      rating: '7.4',
      labels: [
        'LP',
      ],
    },
    {
      id: '3',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ecd008a8eb536b9b12888/1:1/w_320/maymind.jpg',
      ranking: '01',
      albumName: 'Cheap Storage',
      musician: 'Maymind',
      userRate: 4,
      rating: '8.3',
      labels: [
        'interesting',
        'LP',
      ],
    },
    {
      id: '4',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b254b8a8eb536b9b126be/1:1/w_320/Punishment%20in%20Flesh_Innumerable%20Forms.jpg',
      ranking: '01',
      albumName: 'Punishment in Flesh',
      musician: 'Innumerable Forms',
      userRate: 2,
      rating: '2.9',
      labels: [
        'LP',
      ],
    },
    {
      id: '5',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7735baf60a9e325d3f01d5/1:1/w_320/blood%20orange_negro%20swan.jpg',
      ranking: '01',
      albumName: '<NAME>',
      musician: 'Blood Orange',
      userRate: 3,
      rating: '4.5',
      labels: [
        'LP',
      ],
    },
    {
      id: '6',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7737b6f60a9e325d3f01d7/1:1/w_320/Anna%20Meredith_Anno.jpg',
      ranking: '01',
      albumName: 'Anno',
      musician: '<NAME>',
      userRate: 4,
      rating: '9.1',
      labels: [
        'LP',
      ],
    },
    {
      id: '7',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b731d5e61613f18abb1b3c3/1:1/w_320/Donchristian_Where%20there\'s%20smoke.jpg',
      ranking: '01',
      albumName: 'Where There’s Smoke',
      musician: 'DonChristian',
      userRate: 3,
      rating: '5.7',
      labels: [
        'LP',
      ],
    },
    {
      id: '8',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ecea9f66e723ab75eacf9/1:1/w_320/skinless.jpg',
      ranking: '01',
      albumName: 'Marauder',
      musician: 'Interpol',
      userRate: 4,
      rating: '8.2',
      labels: [
        'interesting',
        'LP',
      ],
    },
    {
      id: '9',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ecea9f66e723ab75eacf9/1:1/w_320/skinless.jpg',
      ranking: '01',
      albumName: 'Skinless X-1',
      musician: 'Fire-Toolz',
      userRate: 1,
      rating: '7.5',
      labels: [
        'interesting',
        'LP',
      ],
    },
    {
      id: '10',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ec49ba78458227bd780cd/1:1/w_320/parts.jpg',
      ranking: '01',
      albumName: 'Parts',
      musician: 'Ohmme',
      userRate: 3,
      rating: '8.2',
      labels: [
        'interesting',
        'LP',
      ],
    },
    {
      id: '11',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b247cbec1b01e6732b3a9/1:1/w_320/VA_Kompakt%20Total%2018.jpg',
      ranking: '01',
      albumName: 'Total 18',
      musician: 'Various Artists',
      userRate: 4,
      rating: '8.7',
      labels: [
        'LP',
      ],
    },
    {
      id: '12',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7af96a8a8eb536b9b12686/1:1/w_320/The%20Hermit%20And%20The%20Recluse_Orpheus%20Vs%20The%20Sirens.jpg',
      ranking: '01',
      albumName: 'Orpheus vs. the Sirens',
      musician: 'Hermit and the Recluse',
      userRate: 4,
      rating: '4.4',
      labels: [
        'LP',
      ],
    },
    {
      id: '13',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b1adfb1f53320b62b998a/1:1/w_320/gabriel%20kahane_book%20of%20travelers.jpg',
      ranking: '01',
      albumName: 'Book of Travelers',
      musician: '<NAME>',
      userRate: 2,
      rating: '6.7',
      labels: [
        'LP',
      ],
    },
    {
      id: '14',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b1c58a78458227bd77ee1/1:1/w_320/Tra%CC%88den_st.jpg',
      ranking: '01',
      albumName: 'Träden',
      musician: 'Träden',
      userRate: 1,
      rating: '2.2',
      labels: [
        'LP',
      ],
    },
    {
      id: '15',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7732f167a8ff3026124467/1:1/w_320/djrum_portrait%20with%20firewood.jpg',
      ranking: '01',
      albumName: 'Portrait With Firewood',
      musician: 'Djrum',
      userRate: 5,
      rating: '9.5',
      labels: [
        'LP',
      ],
    },
    {
      id: '16',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b17a3494ed0265fa9d947/1:1/w_320/lori%20scacco_desire%20loop.jpg',
      ranking: '01',
      albumName: '<NAME>',
      musician: '<NAME>',
      userRate: 2,
      rating: '3.3',
      labels: [
        'LP',
      ],
    },
    {
      id: '17',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b77198cb1f53320b62b980a/1:1/w_320/ariana%20grande_Sweetener.jpg',
      ranking: '01',
      albumName: 'Sweetener',
      musician: '<NAME>',
      userRate: 4,
      rating: '4.7',
      labels: [
        'interesting',
        'LP',
      ],
    },
    {
      id: '18',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b771c3ea78458227bd77dbb/1:1/w_320/Amine%CC%81_ONEPOINTFIVE.jpg',
      ranking: '01',
      albumName: 'ONEPOINTFIVE',
      musician: 'Aminé',
      userRate: 4,
      rating: '8.5',
      labels: [
        'LP',
      ],
    },
    {
      id: '19',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b76d4984aea202eae1ac64e/1:1/w_320/our%20garden%20needs%20its%20flowers_jess%20sah%20bi%20peter%20one.jpg',
      ranking: '01',
      albumName: 'Our Garden Needs Its Flowers',
      musician: '<NAME>',
      userRate: 3,
      rating: '7.2',
      labels: [
        'LP',
      ],
    },
    {
      id: '20',
      albumCoverSrc: 'https://media.pitchfork.com/photos/5b731f5179bedf15f0a107c6/1:1/w_320/prodigy_the%20fat%20of%20the%20land.jpg',
      ranking: '01',
      albumName: 'The Fat Of the Land',
      musician: 'The Prodigy',
      userRate: 3,
      rating: '6.9',
      labels: [
        'LP',
      ],
    },
  ],
};

const initialState = {
  loginStatus: true,
  user,
  comments: null,
};

const updateUser = (state, action) => {
  const valueToChange = {
    loginStatus: action.loginStatus,
    user: action.user,
  };

  return updateObject(state, valueToChange);
};

const updateComment = (state, action) => {
  const valueToChange = {
    comments: action.comments,
  };

  return updateObject(state, valueToChange);
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case actionTypes.LOG_IN:
    case actionTypes.LOG_OUT:
      return updateUser(state, action);
    case actionTypes.POST_COMMENT:
    case actionTypes.PUT_COMMENT:
    case actionTypes.GET_COMMENT:
    case actionTypes.DELETE_COMMENT:
      return updateComment(state, action);
    default:
      return state;
  }
};

export default reducer;
<file_sep>import React, { PureComponent } from 'react';
import SingleItem from '../../components/SingleItem/SingleItem';
import classes from './ArtistDetails.css';

class ArtistDetails extends PureComponent {
  state = {
    artistPhotoSrc: 'https://upload.wikimedia.org/wikipedia/commons/b/b4/Leonard_Cohen%2C_1988_01.jpg',
    name: '<NAME>',
    birthName: '<NAME>',
    birth: '21/09/1934 ~ 07/11/2016',
    genres: 'folk/soft rock',
    intro: '<NAME> CC GOQ (September 21, 1934 – November 7, 2016) was a Canadian singer-songwriter, poet and novelist. His work explored religion, politics, isolation, sexuality and personal relationships.[2] Cohen was inducted into the Canadian Music Hall of Fame, the Canadian Songwriters Hall of Fame, and the Rock and Roll Hall of Fame. He was invested as a Companion of the Order of Canada, the nation\'s highest civilian honour. In 2011, Cohen received one of the Prince of Asturias Awards for literature and the ninth Glenn Gould Prize.',
    albums,
  }

  render() {
    const {
      artistPhotoSrc,
      name,
      birthName,
      birth,
      genres,
      intro,
      albums,
    } = this.state;

    const discographyDisplay = albums.map(album => (
      <SingleItem
        key={album.id}
        albumCoverSrc={album.albumCoverSrc}
        albumName={album.albumName}
        musician={album.musician}
        year={album.year}
        genres={album.genres}
        rating={album.rating}
      />
    ));

    return (
      <div className={classes.artistDetails}>
        <div className={classes.artistDetails__details}>
          <img
            src={artistPhotoSrc}
            alt={name}
          />
          <div className={classes.artistDetails__details__text}>
            <p className={classes.artistDetails__details__text_name}>
              {name}
            </p>
            <p>
              Birth Name:&nbsp;
              {birthName}
            </p>
            <p>
              Birth:&nbsp;
              {birth}
            </p>
            <p>
              Genres:&nbsp;
              {genres}
            </p>
            <div className={classes.artistDetails__details_intro}>
              <p>
                Intro:
              </p>
              <p>
                {intro}
              </p>
            </div>
          </div>
        </div>
        <div className={classes.artistDetails__discography}>
          <p className={classes.artistDetails__discography_title}>
            discography
          </p>
          <div className={classes.artistDetails__discography_albums}>
            {discographyDisplay}
          </div>
        </div>
      </div>
    );
  }
}

export default ArtistDetails;

const albums = [
  {
    id: '1',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    year: '2001',
    genres: 'soft rock',
    rating: '9.0',
  },
  {
    id: '2',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    year: '2001',
    genres: 'soft rock',
    rating: '9.0',
  },
  {
    id: '3',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    year: '2001',
    genres: 'soft rock',
    rating: '9.0',
  },
  {
    id: '4',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    year: '2001',
    genres: 'soft rock',
    rating: '9.0',
  },
  {
    id: '5',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    year: '2001',
    genres: 'soft rock',
    rating: '9.0',
  },
  {
    id: '6',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    year: '2001',
    genres: 'soft rock',
    rating: '9.0',
  },
];
<file_sep># taste-label
This program is based on React.js. This is a website where you can rate every single song of one album. 

### Setup
1. `<EMAIL>:eveshi/taste-label.git`
2. Then, run `npm install`.
3. Run `cd client` and `npm start` for the client. Then check https://localhost:3000.

### Preview

- for computer:

<div align="center">
  <img src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/com_home.png">
</div>
<div align='center'>
  <img src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/com_sign.png">
</div>
<div align='center'>
  <img src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/com_album_comment.png">
</div>
<div align='center'>
  <img src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/com_user.png">
</div>
<div align='center'>
  <img src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/com_rates.png">
</div>


- for mobile: 

<div align="center">
  <img width="250" src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/mobile_home.png">
  <img width="250" style="margin-left:20px" src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/mobile_sign.png"> 
  <img width="250" style="margin-left:20px" src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/mobile_album.png">
</div>
<div align="center">
  <img width="250" src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/mobile_rate.png">
  <img width="250" style="margin-left:20px" src="https://raw.githubusercontent.com/eveshi/taste-label/master/README_IMAGE/mobile_rates.png">
</div>


<file_sep>import axios from 'axios';
import * as actionTypes from './actionTypes';

const LOG_IN_REQUEST = () => ({ type: actionTypes.LOG_IN });

const LOG_IN_FAILURE = error => ({
  type: actionTypes.LOG_IN,
  error,
});

const LOG_IN_SUCCESS = user => ({
  type: actionTypes.LOG_IN,
  loginStatus: true,
  user,
});

export const LOG_IN = userInfo => (dispatch) => {
  dispatch(LOG_IN_REQUEST);
  try {
    axios.get('/login', {
      userInfo,
    }).then(user => user.json())
      .then(user => dispatch(LOG_IN_SUCCESS(user)));
  } catch (error) {
    dispatch(LOG_IN_FAILURE(error));
  }
};

export const LOG_OUT = () => ({
  type: actionTypes.LOG_OUT,
  loginStatus: false,
  user: null,
});
<file_sep>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import RateStar from '../RateStar/RateStar';
import Button from '../Button/Button';
import Input from '../Input/Input';
import LabelItem from '../LabelItem/LabelItem';
import Textarea from '../Textarea/Textarea';
import classes from './RatingBar.css';

class RatingBar extends PureComponent {
  state = {
    showMore: false,
    label: '',
    labelList: [
      'jazz',
      'pop',
      'joy',
    ],
    comment: '',
    inputLength: 0,
  }

  showMoreHandler = () => {
    const { showMore } = this.state;
    this.setState({
      showMore: !showMore,
    });
  }

  quickSave = () => {
    console.log('yes');
  }

  labelInput = (event) => {
    const { key } = event;
    const {
      label,
      labelList,
    } = this.state;
    const list = [...labelList];
    if (key === 'Enter') {
      list.push(label);
      this.setState({
        label: '',
        labelList: list,
      });
    }
  }

  labelChangeHandler = (event) => {
    const { value } = event.target;
    this.setState({
      label: value,
    });
  }

  labelDelete = (index) => {
    const { labelList } = this.state;
    const list = [...labelList];
    list.splice(index, 1);
    this.setState({
      labelList: list,
    });
  }

  commentChangeHandler = (event) => {
    const { value } = event.target;
    const inputLength = value.length;
    this.setState({
      comment: value,
      inputLength,
    });
  }

  render() {
    const {
      showMore,
      label,
      labelList,
      comment,
      inputLength,
    } = this.state;

    const {
      showMoreHandler,
      quickSave,
      labelInput,
      labelChangeHandler,
      labelDelete,
      commentChangeHandler,
    } = this;

    const {
      tracks,
    } = this.props;

    const labelTracks = tracks.map(track => (
      <div
        key={track.id}
        className={classes.ratingBar__more__track_single}
      >
        <div className={classes.ratingBar__more__track_single_text}>
          <p>
            {track.id}
            .&nbsp;
          </p>
          <p>
            {track.name}
          </p>
        </div>
        <RateStar />
      </div>
    ));

    const labels = labelList.map(((item, index) => (
      <LabelItem
        key={item}
        labelItem={item}
        onClick={() => labelDelete(index)}
      />
    )));

    return (
      <div className={classes.ratingBar}>
        <div className={classes.ratingBar__rateNow}>
          <div className={classes.ratingBar__rateNow__text}>
            <p>
              Rate Now
            </p>
          </div>
          <RateStar />
        </div>
        {showMore
          ? (
            <React.Fragment>
              <div className={classes.ratingBar__more}>
                <Input
                  maxLength="20"
                  value={label}
                  placeholder="Enter label here..."
                  onKeyPress={event => labelInput(event)}
                  onChange={event => labelChangeHandler(event)}
                />
                <div className={classes.ratingBar__more__labels}>
                  {labels}
                </div>
                <Textarea
                  maxLength="10000"
                  value={comment}
                  placeholder="Write your comment..."
                  inputLength={inputLength}
                  onChange={event => commentChangeHandler(event)}
                />
                <div className={classes.ratingBar__more__track}>
                  {labelTracks}
                </div>
              </div>
              <div className={classes.ratingBar__button}>
                <Button onClick={quickSave}>
                  save all
                </Button>
                <Button onClick={showMoreHandler}>
                  write less
                </Button>
              </div>
            </React.Fragment>
          )
          : (
            <div className={classes.ratingBar__button}>
              <Button onClick={quickSave}>
                quick save
              </Button>
              <Button onClick={showMoreHandler}>
                write more
              </Button>
            </div>
          )}
      </div>
    );
  }
}

RatingBar.propTypes = {
  tracks: PropTypes.arrayOf(PropTypes.object).isRequired,
};

export default RatingBar;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import Star from '../../assets/icon/star';
import classes from './RateStar.css';

const RateStar = (props) => {
  const { onClick } = props;

  return (
    <div className={classes.rateStar}>
      <input
        name="rate"
        className={classes.rateStar__input}
        type="radio"
        id="5"
      />
      <label
        htmlFor="5"
        className={classes.rateStar__label}
        onClick={onClick}
      >
        <Star />
      </label>
      <input
        name="rate"
        className={classes.rateStar__input}
        type="radio"
        id="4"
      />
      <label
        htmlFor="4"
        className={classes.rateStar__label}
        onClick={onClick}
      >
        <Star />
      </label>
      <input
        name="rate"
        className={classes.rateStar__input}
        type="radio"
        id="3"
      />
      <label
        htmlFor="3"
        className={classes.rateStar__label}
        onClick={onClick}
      >
        <Star />
      </label>
      <input
        name="rate"
        className={classes.rateStar__input}
        type="radio"
        id="2"
      />
      <label
        htmlFor="2"
        className={classes.rateStar__label}
        onClick={onClick}
      >
        <Star />
      </label>
      <input
        name="rate"
        className={classes.rateStar__input}
        type="radio"
        id="1"
      />
      <label
        htmlFor="1"
        className={classes.rateStar__label}
        onClick={onClick}
      >
        <Star />
      </label>
    </div>
  );
};

RateStar.propTypes = {
  onClick: PropTypes.func.isRequired,
};

export default RateStar;
<file_sep>import React, { PureComponent } from 'react';
import Intro from './Intro/Intro';
import ChartRow from './ChartRow/ChartRow';
import classes from './Home.css';

class Charts extends PureComponent {
  state = {
    list1,
    list2,
    list3,
  }

  render() {
    const { list1, list2, list3 } = this.state;
    return (
      <div className={classes.home}>
        <Intro />
        <ChartRow
          list={list1}
          chartName="Latest Album"
        />
        <ChartRow
          list={list2}
          chartName="New Best Album"
        />
        <ChartRow
          list={list3}
          chartName="New Best Singles"
        />
      </div>
    );
  }
}

export default Charts;

const list1 = [
  {
    id: '1',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 5,
    year: 2011,
    genres: 'folk/rock',
    rating: '9.0',
  },
  {
    id: '2',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b1963f60a9e325d3f0287/1:1/w_160/lemon%20twigs_go%20to%20school.jpg',
    ranking: '01',
    albumName: 'Go to School',
    musician: '<NAME>',
    userRate: 4,
    year: 2005,
    genres: 'rap',
    rating: '7.4',
  },
  {
    id: '3',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ecd008a8eb536b9b12888/1:1/w_320/maymind.jpg',
    ranking: '01',
    albumName: 'Cheap Storage',
    musician: 'Maymind',
    userRate: 4,
    year: 1988,
    genres: 'country',
    rating: '8.3',
  },
  {
    id: '4',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b254b8a8eb536b9b126be/1:1/w_320/Punishment%20in%20Flesh_Innumerable%20Forms.jpg',
    ranking: '01',
    albumName: 'Punishment in Flesh',
    musician: 'Innumerable Forms',
    userRate: 2,
    year: 2002,
    genres: 'rock/pop',
    rating: '2.9',
  },
  {
    id: '5',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7735baf60a9e325d3f01d5/1:1/w_320/blood%20orange_negro%20swan.jpg',
    ranking: '01',
    albumName: '<NAME>',
    musician: 'Blood Orange',
    userRate: 3,
    year: 1967,
    genres: 'R&B',
    rating: '4.5',
  },
  {
    id: '6',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7737b6f60a9e325d3f01d7/1:1/w_320/Anna%20Meredith_Anno.jpg',
    ranking: '01',
    albumName: 'Anno',
    musician: '<NAME>',
    userRate: 4,
    year: 1988,
    genres: 'soul',
    rating: '9.1',
  },
];

const list2 = [
  {
    id: '7',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b731d5e61613f18abb1b3c3/1:1/w_320/Donchristian_Where%20there\'s%20smoke.jpg',
    ranking: '01',
    albumName: 'Where There’s Smoke',
    musician: 'DonChristian',
    userRate: 3,
    year: 2017,
    genres: 'rap',
    rating: '5.7',
  },
  {
    id: '8',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ecea9f66e723ab75eacf9/1:1/w_320/skinless.jpg',
    ranking: '01',
    albumName: 'Marauder',
    musician: 'Interpol',
    userRate: 4,
    year: 2018,
    genres: 'post rock',
    rating: '8.2',
  },
  {
    id: '9',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ecea9f66e723ab75eacf9/1:1/w_320/skinless.jpg',
    ranking: '01',
    albumName: 'Skinless X-1',
    musician: 'Fire-Toolz',
    userRate: 1,
    year: 2018,
    genres: 'folk',
    rating: '7.5',
  },
  {
    id: '10',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7ec49ba78458227bd780cd/1:1/w_320/parts.jpg',
    ranking: '01',
    albumName: 'Parts',
    musician: 'Ohmme',
    userRate: 3,
    year: 2016,
    genres: 'jazz',
    rating: '8.2',
  },
  {
    id: '11',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b247cbec1b01e6732b3a9/1:1/w_320/VA_Kompakt%20Total%2018.jpg',
    ranking: '01',
    albumName: 'Total 18',
    musician: 'Various Artists',
    userRate: 4,
    year: 2003,
    genres: 'pop',
    rating: '8.7',
  },
  {
    id: '12',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7af96a8a8eb536b9b12686/1:1/w_320/The%20Hermit%20And%20The%20Recluse_Orpheus%20Vs%20The%20Sirens.jpg',
    ranking: '01',
    albumName: 'Orpheus vs. the Sirens',
    musician: 'Hermit and the Recluse',
    userRate: 4,
    year: 2004,
    genres: 'art pop',
    rating: '4.4',
  },
];

const list3 = [
  {
    id: '13',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b1adfb1f53320b62b998a/1:1/w_320/gabriel%20kahane_book%20of%20travelers.jpg',
    ranking: '01',
    albumName: 'Book of Travelers',
    musician: '<NAME>',
    userRate: 2,
    year: 1988,
    genres: 'dream pop',
    rating: '6.7',
  },
  {
    id: '14',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b1c58a78458227bd77ee1/1:1/w_320/Tra%CC%88den_st.jpg',
    ranking: '01',
    albumName: 'Träden',
    musician: 'Träden',
    userRate: 1,
    year: 2011,
    genres: 'alternative',
    rating: '2.2',
  },
  {
    id: '15',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7732f167a8ff3026124467/1:1/w_320/djrum_portrait%20with%20firewood.jpg',
    ranking: '01',
    albumName: 'Portrait With Firewood',
    musician: 'Djrum',
    userRate: 5,
    year: 2000,
    genres: 'asian tranditional',
    rating: '9.5',
  },
  {
    id: '16',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b7b17a3494ed0265fa9d947/1:1/w_320/lori%20scacco_desire%20loop.jpg',
    ranking: '01',
    albumName: 'Desire Loop',
    musician: '<NAME>',
    userRate: 2,
    year: 2016,
    genres: 'country',
    rating: '3.3',
  },
  {
    id: '17',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b77198cb1f53320b62b980a/1:1/w_320/ariana%20grande_Sweetener.jpg',
    ranking: '01',
    albumName: 'Sweetener',
    musician: '<NAME>',
    userRate: 4,
    year: 2003,
    genres: 'acid jazz',
    rating: '4.7',
  },
  {
    id: '18',
    albumCoverSrc: 'https://media.pitchfork.com/photos/5b771c3ea78458227bd77dbb/1:1/w_320/Amine%CC%81_ONEPOINTFIVE.jpg',
    ranking: '01',
    albumName: 'ONEPOINTFIVE',
    musician: 'Aminé',
    userRate: 4,
    year: 2001,
    genres: 'pop',
    rating: '8.5',
  },
];
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import Input from '../Input/Input';
import Button from '../Button/Button';
import NoBorderButton from '../NoBorderButton/NoBorderButton';
import classes from './SignInBox.css';

const SignInBox = (props) => {
  const {
    email,
    emailChangeHandler,
    isEmailValid,
    password,
    passwordChangeHandler,
    isPasswordValid,
    submitTrigger,
    submitDisabled,
    onClick,
  } = props;

  let emailValidationClass = classes.signInBox__input;
  let passwordValidationClass = classes.signInBox__input;

  if (isEmailValid === false) {
    emailValidationClass = classes.signInBox__emailNotValid;
  }

  if (isPasswordValid === false) {
    passwordValidationClass = classes.signInBox__passwordNotValid;
  }

  return (
    <div className={classes.signInBox}>
      <div className={emailValidationClass}>
        <p>
          email:
        </p>
        <Input
          maxLength="30"
          value={email}
          placeholder="..."
          onChange={emailChangeHandler}
        />
      </div>
      <div className={passwordValidationClass}>
        <p>
          password:
        </p>
        <Input
          maxLength="30"
          type="password"
          value={password}
          placeholder="..."
          onChange={passwordChangeHandler}
        />
      </div>
      <div className={classes.signInBox__button}>
        <Button
          disabled={submitDisabled}
          onClick={onClick}
        >
          Sign In
        </Button>
        <div className={classes.signInBox__button_forgetPassword}>
          <NoBorderButton onClick={submitTrigger}>
            forget password
          </NoBorderButton>
        </div>
      </div>
    </div>
  );
};

SignInBox.propTypes = {
  email: PropTypes.string.isRequired,
  isEmailValid: PropTypes.bool.isRequired,
  emailChangeHandler: PropTypes.func.isRequired,
  password: PropTypes.string.isRequired,
  isPasswordValid: PropTypes.bool.isRequired,
  passwordChangeHandler: PropTypes.func.isRequired,
  submitTrigger: PropTypes.func.isRequired,
  submitDisabled: PropTypes.string.isRequired,
  onClick: PropTypes.func.isRequired,
};

export default SignInBox;
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import ToolBar from '../ToolBar/ToolBar';
import Footer from '../Footer/Footer';
import classes from './Layouts.css';

const Layouts = (props) => {
  const { children } = props;

  return (
    <div className={classes.layouts}>
      <ToolBar />
      {children}
      <Footer />
    </div>
  );
};

Layouts.propTypes = {
  children: PropTypes.node.isRequired,
};

export default Layouts;
<file_sep>import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import UserLabels from './UserLabels/UserLabels';
import UserRates from './UserRates/UserRates';
import NoBorderButton from '../../components/NoBorderButton/NoBorderButton';
import classes from './UserDetails.css';

class UserDetails extends PureComponent {
  state = {
    name: 'eve',
    email: '<EMAIL>',
    labels: [],
    albums,
  }

  componentWillMount() {
    const {
      user,
    } = this.props;

    this.setState({
      name: user.name,
      email: user.email,
      labels: user.labels,
      albums: user.albums,
    });
  }

  render() {
    const {
      name,
      email,
      labels,
      albums,
    } = this.state;

    return (
      <div className={classes.userDetails}>
        <div className={classes.userDetails__title}>
          <p className={classes.userDetails__title_name}>
            {name}
          </p>
          <p className={classes.userDetails__title_email}>
            {email}
          </p>
          <NoBorderButton>
            change password
          </NoBorderButton>
        </div>
        <UserLabels labels={labels} />
        <UserRates albums={albums} />
      </div>
    );
  }
}

const mapStateToProps = state => ({
  user: state.user,
  comments: state.comments,
});

export default connect(mapStateToProps)(UserDetails);

const user = {
  name: '',
  email: '',
  labels: [],
  albums: [],
};

UserDetails.propTypes = {
  user: PropTypes.instanceOf(user).isRequired,
};

const albums = [
  {
    id: '1',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: 'Leonard Cohen',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '2',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '3',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '4',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '5',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
  {
    id: '6',
    albumCoverSrc: 'https://www.leonardcohenfiles.com/tns-cover.jpg',
    ranking: '01',
    albumName: 'Ten New Songs',
    musician: '<NAME>',
    userRate: 3,
    rating: '9.0',
  },
];
<file_sep>import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import * as actions from '../../store/actions/index';
import SignInBox from '../../components/SignInBox/SignInBox';
import SignUpBox from '../../components/SignUpBox/SignUpBox';
import classes from './UserSign.css';
import Button from '../../components/Button/Button';

class UserSign extends PureComponent {
  state = {
    signInEmail: '',
    isSignInEmailValid: true,
    signInPassword: '',
    isSignInPasswordValid: true,
    signUpEmail: '',
    isSignUpEmailValid: true,
    signUpPassword: '',
    isSignUpPasswordValid: true,
    signUpUsername: '',
    isSignUpUsernameValid: true,
    signUpRepeatPassword: '',
    isSignUpRepeatPasswordValid: true,
    signInButtonStatus: classes.button_active,
    signUpButtonStatus: classes.button_notActive,
    showSignIn: null,
    showSignUp: classes.notShow,
    signInSubmitDisabled: 'disabled',
    signUpSubmitDisabled: 'disabled',
  };

  signInEmailChangeHandler = (event) => {
    const { value } = event.target;
    const pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/g;
    if (!value.match(pattern)) {
      this.setState({
        signInEmail: value,
        isSignInEmailValid: false,
      });
    }

    if (value.match(pattern)) {
      this.setState({
        signInEmail: value,
        isSignInEmailValid: true,
      });
    }
  }

  signInPasswordChangeHandler = (event) => {
    const { value } = event.target;
    const pattern = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm;
    if (!value.match(pattern)) {
      this.setState({
        signInPassword: value,
        isSignInPasswordValid: false,
      });
    }

    if (value.match(pattern)) {
      this.setState({
        signInPassword: value,
        isSignInPasswordValid: true,
      });
    }
  }

  signUpEmailChangeHandler = (event) => {
    const { value } = event.target;
    const pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/g;
    if (!value.match(pattern)) {
      this.setState({
        signUpEmail: value,
        isSignUpEmailValid: false,
      });
    }

    if (value.match(pattern)) {
      this.setState({
        signUpEmail: value,
        isSignUpEmailValid: true,
      });
    }
  }

  signUpPasswordChangeHandler = (event) => {
    const { value } = event.target;
    const pattern = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm;
    if (!value.match(pattern)) {
      this.setState({
        signUpPassword: value,
        isSignUpPasswordValid: false,
      });
    }

    if (value.match(pattern)) {
      this.setState({
        signUpPassword: value,
        isSignUpPasswordValid: true,
      });
    }
  }

  signUpRepeatPasswordChangeHandler = (event) => {
    const { value } = event.target;
    const pattern = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm;
    if (!value.match(pattern)) {
      this.setState({
        signUpRepeatPassword: value,
        isSignUpRepeatPasswordValid: false,
      });
    }

    if (value.match(pattern)) {
      this.setState({
        signUpRepeatPassword: value,
        isSignUpRepeatPasswordValid: true,
      });
    }
  }

  signUpUsernameChangeHandler = (event) => {
    const { value } = event.target;
    const pattern = /^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{2,29}$/igm;
    if (!value.match(pattern)) {
      this.setState({
        signUpUsername: value,
        isSignUpUsernameValid: false,
      });
    }

    if (value.match(pattern)) {
      this.setState({
        signUpUsername: value,
        isSignUpUsernameValid: true,
      });
    }
  }

  showSignInHandler = () => {
    this.setState({
      signInButtonStatus: classes.button_active,
      signUpButtonStatus: classes.button_notActive,
      showSignIn: null,
      showSignUp: classes.notShow,
    });
  }

  showSignUpHandler = () => {
    this.setState({
      signInButtonStatus: classes.button_notActive,
      signUpButtonStatus: classes.button_active,
      showSignIn: classes.notShow,
      showSignUp: null,
    });
  }

  signinSubmit = () => {
    const {
      signInEmail,
      signInPassword,
    } = this.state;
    const userInfo = {
      signInEmail,
      signInPassword,
    };
    const { login } = this.props;
    login(userInfo);
  }

  render() {
    const {
      signInEmail,
      isSignInEmailValid,
      signInPassword,
      isSignInPasswordValid,
      signUpEmail,
      isSignUpEmailValid,
      signUpPassword,
      isSignUpPasswordValid,
      signUpUsername,
      isSignUpUsernameValid,
      signUpRepeatPassword,
      isSignUpRepeatPasswordValid,
      signInButtonStatus,
      signUpButtonStatus,
      showSignIn,
      showSignUp,
      signInSubmitDisabled,
      signUpSubmitDisabled,
    } = this.state;

    const {
      signInEmailChangeHandler,
      signInPasswordChangeHandler,
      signUpEmailChangeHandler,
      signUpPasswordChangeHandler,
      signUpUsernameChangeHandler,
      signUpRepeatPasswordChangeHandler,
      showSignInHandler,
      showSignUpHandler,
      signInSubmit,
    } = this;

    return (
      <div className={classes.userSign}>
        <div className={classes.box}>
          <div className={classes.box__title}>
            <div className={signUpButtonStatus}>
              <Button onClick={showSignUpHandler}>
                Sign Up
              </Button>
            </div>
            <div className={signInButtonStatus}>
              <Button onClick={showSignInHandler}>
                Sign In
              </Button>
            </div>
          </div>
          <div className={showSignIn}>
            <SignInBox
              email={signInEmail}
              isEmailValid={isSignInEmailValid}
              emailChangeHandler={event => signInEmailChangeHandler(event)}
              password={<PASSWORD>}
              isPasswordValid={isSignInPasswordValid}
              passwordChangeHandler={event => signInPasswordChangeHandler(event)}
              submitDisabled={signInSubmitDisabled}
              onClick={signInSubmit}
            />
          </div>
          <div className={showSignUp}>
            <SignUpBox
              email={signUpEmail}
              isEmailValid={isSignUpEmailValid}
              emailChangeHandler={event => signUpEmailChangeHandler(event)}
              username={signUpUsername}
              isUsernameValid={isSignUpUsernameValid}
              usernameChangeHandler={event => signUpUsernameChangeHandler(event)}
              password={<PASSWORD>}
              isPasswordValid={<PASSWORD>}
              passwordChangeHandler={event => signUpPasswordChangeHandler(event)}
              repeatPassword={<PASSWORD>Up<PASSWORD>}
              isRepeatPasswordValid={isSignUpRepeatPasswordValid}
              repeatPasswordChangeHandler={event => signUpRepeatPasswordChangeHandler(event)}
              submitDisabled={signUpSubmitDisabled}
            />
          </div>
        </div>
      </div>
    );
  }
}

UserSign.propTypes = {
  login: PropTypes.func.isRequired,
};

const mapActionToProps = dispatch => ({
  login: userInfo => dispatch(actions.LOG_IN(userInfo)),
});

export default connect(null, mapActionToProps)(UserSign);
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import Search from '../../assets/icon/search';
import classes from './SearchBox.css';

const SearchBox = (props) => {
  const {
    onChange,
    onClick,
    placeholder,
    showSearchBox,
    value,
  } = props;

  return (
    <div className={classes.searchBox}>
      <input
        className={
          showSearchBox
            ? classes.searchBox__input
            : classes.searchBox__input_hidden
        }
        type="text"
        placeholder={placeholder}
        value={value}
        onChange={onChange}
      />
      <button
        className={
          showSearchBox
            ? classes.searchBox__button_left
            : classes.searchBox__button_right
        }
        type="button"
        onClick={onClick}
      >
        <Search />
      </button>
    </div>
  );
};

SearchBox.propTypes = {
  onChange: PropTypes.func.isRequired,
  onClick: PropTypes.func.isRequired,
  placeholder: PropTypes.string.isRequired,
  showSearchBox: PropTypes.bool.isRequired,
  value: PropTypes.string.isRequired,
};

export default SearchBox;
<file_sep>export {
  LOG_IN,
  LOG_OUT,
} from './user';

export {
  POST_COMMENT,
  PUT_COMMENT,
  GET_COMMENT,
  DELETE_COMMENT,
} from './comments';
<file_sep>import React from 'react';
import PropTypes from 'prop-types';
import SingleItem from '../../../components/SingleItem/SingleItem';
import classes from './ChartRow.css';

const ChartRow = (props) => {
  const {
    list,
    chartName,
  } = props;

  const itemList = list.map(item => (
    <SingleItem
      key={item.id}
      albumCoverSrc={item.albumCoverSrc}
      albumName={item.albumName}
      musician={item.musician}
      year={item.year}
      genres={item.genres}
      rating={item.rating}
    />
  ));

  return (
    <div className={classes.chartRow}>
      <div className={classes.chartRow__header}>
        <p>
          {chartName}
        </p>
      </div>
      <div className={classes.chartRow__items}>
        {itemList}
      </div>
    </div>
  );
};

ChartRow.propTypes = {
  list: PropTypes.arrayOf(PropTypes.object).isRequired,
  chartName: PropTypes.string.isRequired,
};

export default ChartRow;
