React

by Turi S

HTML

<div id="app"></div>

<!-- https://itunes.apple.com/us/rss/topalbums/limit=25/json -->

<!--
Album title
Artist Name
Price
Release date
 -->

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
  line-height: 1.6;
}

h1 {
  text-align: center;
  font-size: 200%;
  font-weight: bold;
  margin-bottom: 1em;
  position: relative;
  z-index: 10;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
  text-align: center;
}

.AlbumList {
  display: inline-block;
  min-height: 100vh;
}

.Album {
  display: flex;
  margin-bottom: 1em;
  text-align: left;
  align-items: center;
  
  border-radius: 3px;
  box-shadow: 0 1px 6px -3px black;
}

.Album__body {
  margin-left: 2em;
}

.Album h2 {
  font-weight: bold;
  font-size: 110%;
}

.Album__artist {
  font-style: italic;
}

.Album__price {
  font-weight: bold;
}

.Album__release {
  color: rgb(171,193,208);
  font-size: 90%;
}

.Album img { display: block; }

@media (max-width: 500px) {
  .Album {
    flex-direction: column;
    align-items: stretch;
    border-bottom: 1px solid lightgray;
    margin-bottom: 2em;
  }
  
  .Album__body {
    margin-left: 0;
    margin: 1em;
  }
  
  .Album__image-wrap {
    background: #000000;
  }
  
  .Album img {
    margin: 0 auto;
  }
 
  
}

.Loading {
  position: fixed;
  top: 0; left: 0;
  width: 100vw; height: 100vh;
  background: rgba(255,255,255,.9);
  display: flex;
  align-items: center;
  justify-content: center;
}

React

class AlbumApp extends React.Component {
  constructor(props) {
    super(props)
    this.state = {albums: null, isLoading: true, limit: 25};
  }
  
  componentDidMount() {
  	this.getAlbumData(this.state.limit, true);
  }
  
  getAlbumData(limit, skipInitialState = false) {
  	if (!skipInitialState) {
      this.setState({isLoading: true, limit});
    }
    
    const curFetchProm = this.fetchProm = fetch(`https://itunes.apple.com/us/rss/topalbums/limit=${limit}/json`);
    
    curFetchProm
    	.then(res => res.json())
      .then(res => delay(res, 3000))
      .then(json => {
      	if (curFetchProm !== this.fetchProm) return;
      	console.log('fetch finished');
        
      	this.setState({
        	albums: json.feed.entry,
          isLoading: false
        })
      })
  }

 
  render() {
  	const {albums, isLoading, limit} = this.state;
    
    return (
      <div className="AlbumList">
        <h1>
          Top{' '}
          <select value={limit} onChange={
          	e => this.getAlbumData(e.target.value)
           }>
            <option value="2">2</option>
            <option value="10">10</option>
            <option value="25">25</option>
            <option value="50">50</option>
          </select>{' '}
          iTunes Albums
        </h1>
       
        {albums && albums.map((album, i) => 
       	  <Album 
            key={album.id.attributes['im:id']}
            data={album}
            rank={i+1}
           />
         )}
         
         {isLoading && <Loading />}
      </div>
    )
  }

}

ReactDOM.render(<AlbumApp />, document.querySelector("#app"))

function Album({rank, data}) {
	return (
  	<article className="Album">
      <div className="Album__image-wrap">
        <img className="Album__artwork" src={data['im:image'][2].label} alt="Album artwork" />

      </div>
      
      <div className="Album__body">
        <h2>{rank}. {data['im:name'].label}</h2>
        <div...