Beginning React+Redux "Music Store" sample

This commit is contained in:
SteveSandersonMS
2016-02-05 23:28:13 +00:00
parent 35e620ae48
commit 5811c98230
69 changed files with 7508 additions and 6 deletions

View File

@@ -0,0 +1,60 @@
import * as React from 'react';
import { Link } from 'react-router';
import { provide } from '../../TypedRedux';
import { ApplicationState } from '../../store';
import * as AlbumDetailsState from '../../store/AlbumDetails';
interface RouteParams {
albumId: number;
}
class AlbumDetails extends React.Component<AlbumDetailsProps, void> {
componentWillMount() {
this.props.requestAlbumDetails(this.props.params.albumId);
}
componentWillReceiveProps(nextProps: AlbumDetailsProps) {
if (nextProps.params.albumId !== this.props.params.albumId) {
nextProps.requestAlbumDetails(nextProps.params.albumId);
}
}
public render() {
if (this.props.isLoaded) {
const albumData = this.props.album;
return <div>
<h2>{ albumData.Title }</h2>
<p><img alt={ albumData.Title } src={ albumData.AlbumArtUrl } /></p>
<div id="album-details">
<p>
<em>Genre:</em>
{ albumData.Genre.Name }
</p>
<p>
<em>Artist:</em>
{ albumData.Artist.Name }
</p>
<p>
<em>Price:</em>
${ albumData.Price.toFixed(2) }
</p>
<p className="button">
Add to cart
</p>
</div>
</div>;
} else {
return <p>Loading...</p>;
}
}
}
// Selects which part of global state maps to this component, and defines a type for the resulting props
const provider = provide(
(state: ApplicationState) => state.albumDetails,
AlbumDetailsState.actionCreators
).withExternalProps<{ params: RouteParams }>();
type AlbumDetailsProps = typeof provider.allProps;
export default provider.connect(AlbumDetails);

View File

@@ -0,0 +1,17 @@
import * as React from 'react';
import { Link } from 'react-router';
import { Album } from '../../store/FeaturedAlbums';
export class AlbumTile extends React.Component<{ album: Album, key?: any }, void> {
public render() {
const { album } = this.props;
return (
<li className="col-lg-2 col-md-2 col-sm-2 col-xs-4 container">
<Link to={ '/album/' + album.AlbumId }>
<img alt={ album.Title } src={ album.AlbumArtUrl } />
<h4>{ album.Title }</h4>
</Link>
</li>
);
}
}

View File

@@ -0,0 +1,48 @@
import * as React from 'react';
import { Link } from 'react-router';
import { provide } from '../../TypedRedux';
import { ApplicationState } from '../../store';
import * as GenreDetailsStore from '../../store/GenreDetails';
import { AlbumTile } from './AlbumTile';
interface RouteParams {
genreId: number
}
class GenreDetails extends React.Component<GenreDetailsProps, void> {
componentWillMount() {
this.props.requestGenreDetails(this.props.params.genreId);
}
componentWillReceiveProps(nextProps: GenreDetailsProps) {
if (nextProps.params.genreId !== this.props.params.genreId) {
nextProps.requestGenreDetails(nextProps.params.genreId);
}
}
public render() {
if (this.props.isLoaded) {
let albums = this.props.albums;
return <div>
<h3>Albums</h3>
<ul className="list-unstyled">
{albums.map(album =>
<AlbumTile key={ album.AlbumId } album={ album } />
)}
</ul>
</div>;
} else {
return <p>Loading...</p>;
}
}
}
// Selects which part of global state maps to this component, and defines a type for the resulting props
const provider = provide(
(state: ApplicationState) => state.genreDetails,
GenreDetailsStore.actionCreators
).withExternalProps<{ params: RouteParams }>();
type GenreDetailsProps = typeof provider.allProps;
export default provider.connect(GenreDetails);

View File

@@ -0,0 +1,41 @@
import * as React from 'react';
import { Link } from 'react-router';
import { provide } from '../../TypedRedux';
import { ApplicationState } from '../../store';
import * as GenreList from '../../store/GenreList';
class Genres extends React.Component<GenresProps, void> {
componentWillMount() {
if (!this.props.genres.length) {
this.props.requestGenresList();
}
}
public render() {
let { genres } = this.props;
return <div>
<h3>Browse Genres</h3>
<p>Select from { genres.length || '...' } genres:</p>
<ul className="list-group">
{genres.map(genre =>
<li key={ genre.GenreId } className="list-group-item">
<Link to={ '/genre/' + genre.GenreId }>
{ genre.Name }
</Link>
</li>
)}
</ul>
</div>;
}
}
// Selects which part of global state maps to this component, and defines a type for the resulting props
const provider = provide(
(state: ApplicationState) => state.genreList,
GenreList.actionCreators
);
type GenresProps = typeof provider.allProps;
export default provider.connect(Genres);

View File

@@ -0,0 +1,37 @@
import * as React from 'react';
import { Link } from 'react-router';
import { provide } from '../../TypedRedux';
import { ApplicationState } from '../../store';
import { actionCreators } from '../../store/FeaturedAlbums';
import { AlbumTile } from './AlbumTile';
class Home extends React.Component<HomeProps, void> {
componentWillMount() {
if (!this.props.albums.length) {
this.props.requestFeaturedAlbums();
}
}
public render() {
let { albums } = this.props;
return <div>
<div className="jumbotron">
<h1>MVC Music Store</h1>
<img src="/Images/home-showcase.png" />
</div>
<ul className="row list-unstyled" id="album-list">
{albums.map(album =>
<AlbumTile key={ album.AlbumId } album={ album } />
)}
</ul>
</div>;
}
}
// Selects which part of global state maps to this component, and defines a type for the resulting props
const provider = provide(
(state: ApplicationState) => state.featuredAlbums,
actionCreators
);
type HomeProps = typeof provider.allProps;
export default provider.connect(Home);