diff --git a/.gitignore b/.gitignore index db4412b..619e844 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ npm-debug.log .cache _build +.vscode diff --git a/index.html b/index.html index 0855a46..592dfcc 100644 --- a/index.html +++ b/index.html @@ -9,5 +9,5 @@
- + diff --git a/package-lock.json b/package-lock.json index 0e01ab9..e28cb5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8758,6 +8758,12 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "dev": true + }, "typescript-compare": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", diff --git a/package.json b/package.json index 9b83a72..6072546 100644 --- a/package.json +++ b/package.json @@ -1,36 +1,37 @@ { - "scripts": { - "start": "cross-env NODE_ENV=development parcel index.html --public-url / --out-dir _build", - "build": "cross-env NODE_ENV=production parcel build index.html --public-url /urban-enigma/ --out-dir docs --no-source-maps --no-content-hash", - "lint": "cross-env NODE_ENV=development prettier --check src/**/* assets/*.css" - }, - "devDependencies": { - "@babel/core": "^7.4.0", - "@babel/plugin-transform-runtime": "^7.4.0", - "@babel/preset-env": "^7.5.5", - "@babel/preset-react": "^7.0.0", - "autoprefixer": "^9.5.0", - "cross-env": "^5.2.0", - "jest": "^24.9.0", - "parcel-bundler": "^1.12.3", - "parcel-plugin-static-files-copy": "^2.3.1", - "prettier": "^1.18.2" - }, - "dependencies": { - "@babel/runtime-corejs2": "^7.4.2", - "react": "^16.8.5", - "react-dom": "^16.8.5", - "react-redux": "^6.0.1", - "redux": "^4.0.1", - "redux-saga": "^1.0.2" - }, - "postcss": { - "modules": false, - "plugins": { - "autoprefixer": {} - } - }, - "browserslist": [ - "defaults" - ] + "scripts": { + "start": "cross-env NODE_ENV=development parcel index.html --public-url / --out-dir _build", + "build": "cross-env NODE_ENV=production parcel build index.html --public-url /urban-enigma/ --out-dir docs --no-source-maps --no-content-hash", + "lint": "cross-env NODE_ENV=development prettier --check src/**/*" + }, + "devDependencies": { + "@babel/core": "^7.4.0", + "@babel/plugin-transform-runtime": "^7.4.0", + "@babel/preset-env": "^7.5.5", + "@babel/preset-react": "^7.0.0", + "autoprefixer": "^9.5.0", + "cross-env": "^5.2.0", + "jest": "^24.9.0", + "parcel-bundler": "^1.12.3", + "parcel-plugin-static-files-copy": "^2.3.1", + "prettier": "^1.18.2", + "typescript": "^3.6.3" + }, + "dependencies": { + "@babel/runtime-corejs2": "^7.4.2", + "react": "^16.8.5", + "react-dom": "^16.8.5", + "react-redux": "^6.0.1", + "redux": "^4.0.1", + "redux-saga": "^1.0.2" + }, + "postcss": { + "modules": false, + "plugins": { + "autoprefixer": {} + } + }, + "browserslist": [ + "defaults" + ] } diff --git a/src/actions/index.js b/src/actions/index.js deleted file mode 100644 index a227aa0..0000000 --- a/src/actions/index.js +++ /dev/null @@ -1,38 +0,0 @@ -export const LOAD_ALBUMS = 'LOAD_ALBUMS'; -export const LOAD_ALBUMS_OK = 'LOAD_ALBUMS_OK'; -export const SELECT_ALBUM = 'SELECT_ALBUM'; -export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'; -export const SET_SORT_KEY = 'SET_SORT_KEY'; -export const UNSELECT_ALBUM = 'UNSELECT_ALBUM'; - -export const setVisibilityFilter = filter => ({ - type: SET_VISIBILITY_FILTER, - payload: { - filter - }, -}); - -export const setSortKey = key => ({ - type: SET_SORT_KEY, - payload: { - key, - }, -}); - -export const albumsLoadedOk = albums => ({ - type: LOAD_ALBUMS_OK, - payload: { - albums, - }, -}) - -export const selectAlbum = album => ({ - type: SELECT_ALBUM, - payload: { - album - }, -}); - -export const unselectAlbum = () => ({ - type: UNSELECT_ALBUM, -}); diff --git a/src/actions/index.ts b/src/actions/index.ts new file mode 100644 index 0000000..40aab46 --- /dev/null +++ b/src/actions/index.ts @@ -0,0 +1,40 @@ +import { Album } from "../interfaces"; + +export const LOAD_ALBUMS = "LOAD_ALBUMS"; +export const LOAD_ALBUMS_OK = "LOAD_ALBUMS_OK"; +export const SELECT_ALBUM = "SELECT_ALBUM"; +export const SET_VISIBILITY_FILTER = "SET_VISIBILITY_FILTER"; +export const SET_SORT_KEY = "SET_SORT_KEY"; +export const UNSELECT_ALBUM = "UNSELECT_ALBUM"; + +export const setVisibilityFilter = (filter: string) => ({ + type: SET_VISIBILITY_FILTER, + payload: { + filter + } +}); + +export const setSortKey = (key: string) => ({ + type: SET_SORT_KEY, + payload: { + key + } +}); + +export const albumsLoadedOk = (albums: Array) => ({ + type: LOAD_ALBUMS_OK, + payload: { + albums + } +}); + +export const selectAlbum = (album: Album) => ({ + type: SELECT_ALBUM, + payload: { + album + } +}); + +export const unselectAlbum = () => ({ + type: UNSELECT_ALBUM +}); diff --git a/src/components/album-list.jsx b/src/components/album-list.jsx deleted file mode 100644 index c286747..0000000 --- a/src/components/album-list.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React, { Component } from 'react'; -import Album from './album'; - -export default class AlbumList extends Component { - render() { - const { - albums, - handleOnClick, - blurred, - } = this.props; - const classNames = blurred ? 'blur' : '' - return ( -
- {albums.map(album => ( - - ))} -
- ); - } -} diff --git a/src/components/album-list.tsx b/src/components/album-list.tsx new file mode 100644 index 0000000..9b9b11c --- /dev/null +++ b/src/components/album-list.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import Album from "./album"; +import * as interfaces from "../interfaces"; + +export default (props: AlbumList) => { + const { albums, handleOnClick, blurred } = props; + const classNames = blurred ? "blur" : ""; + return ( +
+ {albums.map((album: interfaces.Album) => ( + + ))} +
+ ); +}; + +interface AlbumList { + albums: Array; + handleOnClick: Function; + blurred: boolean; +} diff --git a/src/components/album.jsx b/src/components/album.jsx deleted file mode 100644 index 53012ac..0000000 --- a/src/components/album.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { Component } from 'react'; - -export default class Album extends Component { - handleKeyPress(e, callback) { - const SPACE_KEY = 32 - const ENTER_KEY = 13 - if (e.charCode === SPACE_KEY || e.charCode === ENTER_KEY) { - e.preventDefault(); - callback(); - } - } - - render() { - const { album, handleOnClick } = this.props; - const { - id, - artist, - title, - songs, - year, - img, - purchased_on, - } = album; - const imagePath = `./covers/${img}`; - const song = songs.join(', '); - return ( -
handleOnClick(album)}> -
- cover -
- - #{id+1}: {artist} - {song}, från "{title}" ({year})
- ✔️ {purchased_on} -
-
- ); - } -} diff --git a/src/components/album.tsx b/src/components/album.tsx new file mode 100644 index 0000000..8c8614f --- /dev/null +++ b/src/components/album.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import * as interfaces from "../interfaces"; + +export default (props: Album) => { + const handleKeyPress = (e: KeyboardEvent, callback: Function) => { + const SPACE_KEY = 32; + const ENTER_KEY = 13; + if (e.charCode === SPACE_KEY || e.charCode === ENTER_KEY) { + e.preventDefault(); + callback(); + } + }; + + const { album, handleOnClick } = props; + const { id, artist, title, songs, year, img, purchased_on } = album; + const imagePath = `./covers/${img}`; + const song = songs.join(", "); + return ( +
handleOnClick(album)} + > +
+ cover +
+ + #{id + 1}: {artist} - {song}, från "{title}" ({year})
+ ✔️ {purchased_on} +
+
+ ); +}; + +interface Album { + album: interfaces.Album; + handleOnClick: Function; +} diff --git a/src/components/app.jsx b/src/components/app.jsx deleted file mode 100644 index 22fdba5..0000000 --- a/src/components/app.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { Component } from 'react'; -import AlbumList from '../containers/album-list'; -import FilterInput from '../containers/filter-input'; -import Modal from '../containers/modal'; - -export default class App extends Component { - render() { - return ( - -
-

Brütal Legend

- -
- - -
- ); - } -} diff --git a/src/components/app.tsx b/src/components/app.tsx new file mode 100644 index 0000000..5f5c4d7 --- /dev/null +++ b/src/components/app.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import AlbumList from "../containers/album-list"; +import FilterInput from "../containers/filter-input"; +import Modal from "../containers/modal"; + +export default () => ( + +
+

Brütal Legend

+ +
+ + +
+); diff --git a/src/components/filter-input.jsx b/src/components/filter-input.jsx deleted file mode 100644 index 5789453..0000000 --- a/src/components/filter-input.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { Component } from 'react'; - -export default class FilterInput extends Component { - render() { - const { - value, - handleOnChange, - } = this.props; - return ( -
- handleOnChange(evt.target.value)} - placeholder='Filtrera på år, artist, låt, skivtitel ...' - /> -
- ); - } -} \ No newline at end of file diff --git a/src/components/filter-input.tsx b/src/components/filter-input.tsx new file mode 100644 index 0000000..701bcdd --- /dev/null +++ b/src/components/filter-input.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +export default (props: FilterInput) => { + const { value, handleOnChange } = props; + return ( +
+ handleOnChange(evt.target.value)} + placeholder="Filtrera på år, artist, låt, skivtitel ..." + /> +
+ ); +}; + +interface FilterInput { + value: string; + handleOnChange: Function; +} diff --git a/src/components/modal.jsx b/src/components/modal.jsx deleted file mode 100644 index ec51921..0000000 --- a/src/components/modal.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import React, { Component } from 'react'; - -export default class Modal extends Component { - handleKeyPress(e, callback) { - alert("sdsdsd") - console.log(e.charCode) - callback(); - } - - render() { - const { - id, - artist, - title, - songs, - year, - img, - description, - handleOnClick, - } = this.props; - if (id === undefined) { - return ''; - } - const imagePath = `assets/covers/${img}`; - const song = songs.join(', '); - return ( -
this.handleKeyPress(e, handleOnClick)}> -
- - #{id+1}: {artist} - {song}, från "{title}" ({year})
-
-
- {description.split('\n\n').map(text => ( -

- {text} -

- ))} -
-
-
- ); - } -} diff --git a/src/components/modal.tsx b/src/components/modal.tsx new file mode 100644 index 0000000..fd103a9 --- /dev/null +++ b/src/components/modal.tsx @@ -0,0 +1,42 @@ +import React from "react"; +import { Album } from "../interfaces"; + +interface Modal { + album: Album; + handleOnClick: Function; +} + +export default (props: Modal) => { + const handleKeyPress = (e: KeyboardEvent, callback: Function) => { + console.log(e.charCode); + callback(); + }; + + const { album, handleOnClick } = props; + const { id, artist, title, songs, year, img, description } = album; + if (id === undefined) { + return ""; + } + // const imagePath = `assets/covers/${img}`; + const song = songs.join(", "); + return ( +
handleOnClick()} + onKeyPress={e => handleKeyPress(e, handleOnClick)} + > +
+ + #{id + 1}: {artist} - {song}, från "{title}" ({year}) +
+
+
+ {description.split("\n\n").map(text => ( +

{text}

+ ))} +
+
+
+ ); +}; diff --git a/src/components/sort-select.jsx b/src/components/sort-select.jsx deleted file mode 100644 index a9a44e3..0000000 --- a/src/components/sort-select.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { Component } from 'react'; - -export default class SortSelect extends Component { - render() { - const { value, handleOnChange } = this.props; - return ( - - ); - } -} \ No newline at end of file diff --git a/src/components/sort-select.tsx b/src/components/sort-select.tsx new file mode 100644 index 0000000..a3b9814 --- /dev/null +++ b/src/components/sort-select.tsx @@ -0,0 +1,24 @@ +import React from "react"; + +export default (props: SortSelect) => { + const { value, handleOnChange } = props; + return ( + + ); +}; + +interface SortSelect { + value: string; + handleOnChange: Function; +} diff --git a/src/containers/album-list.js b/src/containers/album-list.js deleted file mode 100644 index e751903..0000000 --- a/src/containers/album-list.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import AlbumList from '../components/album-list'; -import { selectAlbum } from '../actions' - -const getAlbums = (albums, filter) => { - const atos = o => [o.artist, o.title, o.songs.join(' '), o.year].join(' ').toLowerCase(); - if (filter) { - const term = filter.toLowerCase(); - return albums.filter(album => atos(album).match(term)); - } - return albums; -}; - -const mapStateToProps = state => ({ - albums: getAlbums(state.albums, state.visibilityFilter), - blurred: "id" in state.selectedAlbum, -}); - -const mapDispatchToProps = dispatch => ({ - handleOnClick: album => dispatch(selectAlbum(album)), -}); - -export default connect(mapStateToProps, mapDispatchToProps)(AlbumList); diff --git a/src/containers/album-list.ts b/src/containers/album-list.ts new file mode 100644 index 0000000..2850a02 --- /dev/null +++ b/src/containers/album-list.ts @@ -0,0 +1,26 @@ +import { connect } from "react-redux"; +import AlbumList from "../components/album-list"; +import { selectAlbum } from "../actions"; +import { Album, State } from "../interfaces"; + +const atos = (o: Album) => + [o.artist, o.title, o.songs.join(" "), o.year].join(" ").toLowerCase(); + +const getAlbums = (albums: Array, filter: string) => { + if (filter) { + const term = filter.toLowerCase(); + return albums.filter((album: Album) => atos(album).match(term)); + } + return albums; +}; + +const mapStateToProps = (state: State) => ({ + albums: getAlbums(state.albums, state.visibilityFilter), + blurred: "id" in state.selectedAlbum +}); + +const mapDispatchToProps = (dispatch: Function) => ({ + handleOnClick: (album: Album) => dispatch(selectAlbum(album)) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(AlbumList); diff --git a/src/containers/filter-input.js b/src/containers/filter-input.js deleted file mode 100644 index e6a269a..0000000 --- a/src/containers/filter-input.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import FilterInput from '../components/filter-input'; -import { setVisibilityFilter } from '../actions'; - -const mapStateToProps = state => ({ - value: state.visibilityFilter, -}); - -const mapDispatchToProps = dispatch => ({ - handleOnChange: filter => dispatch(setVisibilityFilter(filter)), -}); - -export default connect(mapStateToProps, mapDispatchToProps)(FilterInput); diff --git a/src/containers/filter-input.ts b/src/containers/filter-input.ts new file mode 100644 index 0000000..c73a92a --- /dev/null +++ b/src/containers/filter-input.ts @@ -0,0 +1,14 @@ +import { connect } from "react-redux"; +import FilterInput from "../components/filter-input"; +import { setVisibilityFilter } from "../actions"; +import { State } from "../interfaces"; + +const mapStateToProps = (state: State) => ({ + value: state.visibilityFilter +}); + +const mapDispatchToProps = (dispatch: Function) => ({ + handleOnChange: (filter: string) => dispatch(setVisibilityFilter(filter)) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(FilterInput); diff --git a/src/containers/modal.js b/src/containers/modal.js deleted file mode 100644 index 647c0a7..0000000 --- a/src/containers/modal.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import Modal from '../components/modal'; -import { unselectAlbum } from '../actions'; - -const mapStateToProps = state => ({ - ...state.selectedAlbum, -}); - -const mapDispatchToProps = dispatch => ({ - handleOnClick: album => dispatch(unselectAlbum(album)), -}); - -export default connect(mapStateToProps, mapDispatchToProps)(Modal); diff --git a/src/containers/modal.ts b/src/containers/modal.ts new file mode 100644 index 0000000..9a23ba7 --- /dev/null +++ b/src/containers/modal.ts @@ -0,0 +1,15 @@ +import React from "react"; +import { connect } from "react-redux"; +import Modal from "../components/modal"; +import { unselectAlbum } from "../actions"; +import { State } from "../interfaces"; + +const mapStateToProps = (state: State) => ({ + album: state.selectedAlbum +}); + +const mapDispatchToProps = (dispatch: Function) => ({ + handleOnClick: () => dispatch(unselectAlbum()) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Modal); diff --git a/src/containers/sort-select.js b/src/containers/sort-select.js deleted file mode 100644 index 7828c63..0000000 --- a/src/containers/sort-select.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import SortSelect from '../components/sort-select'; -import {setSortKey} from "../actions"; - -const mapStateToProps = state => ({ - value: state.sortKey -}); - -const mapDispatchToProps = (dispatch) => ({ - handleOnChange: (key) => dispatch(setSortKey(key)) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(SortSelect); diff --git a/src/containers/sort-select.ts b/src/containers/sort-select.ts new file mode 100644 index 0000000..1dafcaf --- /dev/null +++ b/src/containers/sort-select.ts @@ -0,0 +1,15 @@ +import React from "react"; +import { connect } from "react-redux"; +import SortSelect from "../components/sort-select"; +import { setSortKey } from "../actions"; +import { State } from "../interfaces"; + +const mapStateToProps = (state: State) => ({ + value: state.sortKey +}); + +const mapDispatchToProps = (dispatch: Function) => ({ + handleOnChange: (key: string) => dispatch(setSortKey(key)) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SortSelect); diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 9caa515..0000000 --- a/src/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import '@babel/polyfill'; -import React from 'react'; -import { render } from 'react-dom'; -import { createStore, applyMiddleware, compose } from 'redux'; -import { Provider } from 'react-redux'; -import createSagaMiddleware from 'redux-saga'; -import rootReducer from './reducers'; -import rootSagas from './sagas'; -import App from './components/app'; - -const sagaMiddleware = createSagaMiddleware() - -/* eslint-disable no-underscore-dangle */ -const composeEnhancers = - window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose -/* eslint-enable */ - -const store = createStore( - rootReducer, - composeEnhancers(applyMiddleware(sagaMiddleware)), -) - -sagaMiddleware.run(rootSagas) - -render( - - - , - document.getElementById('brutal') -); - -store.dispatch({ type: 'LOAD_ALBUMS', payload: { source: './albums.json' }}); diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..0b17294 --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { render } from "react-dom"; +import { createStore, applyMiddleware, compose } from "redux"; +import { Provider } from "react-redux"; +import createSagaMiddleware from "redux-saga"; +import rootReducer from "./reducers"; +import rootSagas from "./sagas"; +import App from "./components/app"; +import { LOAD_ALBUMS } from "./actions"; + +const sagaMiddleware = createSagaMiddleware(); + +/* eslint-disable no-underscore-dangle */ +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +/* eslint-enable */ + +const store = createStore( + rootReducer, + composeEnhancers(applyMiddleware(sagaMiddleware)) +); + +sagaMiddleware.run(rootSagas); + +render( + + + , + document.getElementById("brutal") +); + +store.dispatch({ type: LOAD_ALBUMS, payload: { source: "./albums.json" } }); diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts new file mode 100644 index 0000000..1948f53 --- /dev/null +++ b/src/interfaces/index.ts @@ -0,0 +1,17 @@ +export interface Album { + id: number; + artist: string; + title: string; + songs: Array; + year: number; + img: string; + purchased_on: string; + description: string; +} + +export interface State { + albums: Array; + selectedAlbum: Album; + visibilityFilter: string; + sortKey: string; +} diff --git a/src/reducers/albums.js b/src/reducers/albums.js deleted file mode 100644 index 9a82da4..0000000 --- a/src/reducers/albums.js +++ /dev/null @@ -1,11 +0,0 @@ -import { LOAD_ALBUMS_OK } from '../actions'; - -export default (state = [], action) => { - switch (action.type) { - case LOAD_ALBUMS_OK: - const { albums } = action.payload; - return albums; - default: - return state; - } -}; diff --git a/src/reducers/albums.ts b/src/reducers/albums.ts new file mode 100644 index 0000000..051e6e1 --- /dev/null +++ b/src/reducers/albums.ts @@ -0,0 +1,19 @@ +import { LOAD_ALBUMS_OK } from "../actions"; +import { Album } from "../interfaces"; + +interface AlbumsAction { + type: string; + payload: { + albums: Array; + }; +} + +export default (state: Array = [], action: AlbumsAction) => { + switch (action.type) { + case LOAD_ALBUMS_OK: + const { albums } = action.payload; + return albums; + default: + return state; + } +}; diff --git a/src/reducers/index.js b/src/reducers/index.js deleted file mode 100644 index dd3626b..0000000 --- a/src/reducers/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import { combineReducers } from 'redux'; -import albums from './albums'; -import visibilityFilter from './visibility-filter'; -import sortKey from "./sort-key"; -import selectedAlbum from './selected-album'; - -export default combineReducers({ - albums, - visibilityFilter, - sortKey, - selectedAlbum, -}); diff --git a/src/reducers/index.ts b/src/reducers/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/reducers/selected-album.js b/src/reducers/selected-album.js deleted file mode 100644 index a25ec92..0000000 --- a/src/reducers/selected-album.js +++ /dev/null @@ -1,12 +0,0 @@ -import { SELECT_ALBUM, UNSELECT_ALBUM } from '../actions'; - -export default (state = {}, action) => { - switch (action.type) { - case SELECT_ALBUM: - return action.payload.album; - case UNSELECT_ALBUM: - return {}; - default: - return state; - } -}; diff --git a/src/reducers/selected-album.ts b/src/reducers/selected-album.ts new file mode 100644 index 0000000..02c59f0 --- /dev/null +++ b/src/reducers/selected-album.ts @@ -0,0 +1,20 @@ +import { SELECT_ALBUM, UNSELECT_ALBUM } from "../actions"; +import { Album } from "../interfaces"; + +interface AlbumAction { + type: string; + payload: { + album: Album; + }; +} + +export default (state: Object = {}, action: AlbumAction) => { + switch (action.type) { + case SELECT_ALBUM: + return action.payload.album; + case UNSELECT_ALBUM: + return {}; + default: + return state; + } +}; diff --git a/src/reducers/sort-key.js b/src/reducers/sort-key.js deleted file mode 100644 index 887a402..0000000 --- a/src/reducers/sort-key.js +++ /dev/null @@ -1,10 +0,0 @@ -import { SET_SORT_KEY } from '../actions'; - -export default (state = 'id', action) => { - switch (action.type) { - case SET_SORT_KEY: - return action.payload.key; - default: - return state; - } -}; diff --git a/src/reducers/sort-key.ts b/src/reducers/sort-key.ts new file mode 100644 index 0000000..2e7774d --- /dev/null +++ b/src/reducers/sort-key.ts @@ -0,0 +1,17 @@ +import { SET_SORT_KEY } from "../actions"; + +interface SortKeyAction { + type: string; + payload: { + key: string; + }; +} + +export default (state: string = "id", action: SortKeyAction) => { + switch (action.type) { + case SET_SORT_KEY: + return action.payload.key; + default: + return state; + } +}; diff --git a/src/reducers/visibility-filter.js b/src/reducers/visibility-filter.js deleted file mode 100644 index f62b75c..0000000 --- a/src/reducers/visibility-filter.js +++ /dev/null @@ -1,10 +0,0 @@ -import { SET_VISIBILITY_FILTER } from '../actions'; - -export default (state = '', action) => { - switch (action.type) { - case SET_VISIBILITY_FILTER: - return action.payload.filter; - default: - return state; - } -}; diff --git a/src/reducers/visibility-filter.ts b/src/reducers/visibility-filter.ts new file mode 100644 index 0000000..7cd24d4 --- /dev/null +++ b/src/reducers/visibility-filter.ts @@ -0,0 +1,17 @@ +import { SET_VISIBILITY_FILTER } from "../actions"; + +interface VisibilityFilterAction { + type: string; + payload: { + filter: string; + }; +} + +export default (state: string = "", action: VisibilityFilterAction) => { + switch (action.type) { + case SET_VISIBILITY_FILTER: + return action.payload.filter; + default: + return state; + } +}; diff --git a/src/sagas/index.js b/src/sagas/index.js deleted file mode 100644 index 52af7ed..0000000 --- a/src/sagas/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import { put, takeEvery, all, call } from 'redux-saga/effects'; -import { LOAD_ALBUMS, albumsLoadedOk } from '../actions'; - -function* watchLoadAlbumsAsync() { - yield takeEvery(LOAD_ALBUMS, loadAlbumsAsync); -} - -function* loadAlbumsAsync(action) { - try { - const { source } = action.payload; - const data = yield call(() => fetch(source) - .then(response => response.json()) - .then(data => data), {} - ); - yield put(albumsLoadedOk(data)); - } catch (error) { - yield console.error(error); - } -} - -export default function* () { - yield all([ - watchLoadAlbumsAsync(), - ]); -}; diff --git a/src/sagas/index.ts b/src/sagas/index.ts new file mode 100644 index 0000000..dabb1c5 --- /dev/null +++ b/src/sagas/index.ts @@ -0,0 +1,32 @@ +import { put, takeEvery, all, call } from "redux-saga/effects"; +import { LOAD_ALBUMS, albumsLoadedOk } from "../actions"; + +function* watchLoadAlbumsAsync() { + yield takeEvery(LOAD_ALBUMS, loadAlbumsAsync); +} + +function* loadAlbumsAsync(action: LoadAlbumsAction) { + try { + const { source } = action.payload; + const data = yield call( + () => + fetch(source) + .then(response => response.json()) + .then(data => data), + {} + ); + yield put(albumsLoadedOk(data)); + } catch (error) { + yield console.error(error); + } +} + +export default function*() { + yield all([watchLoadAlbumsAsync()]); +} + +interface LoadAlbumsAction { + payload: { + source: string; + }; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..81ba7bd --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "jsx": "react", + "baseUrl": "./src", + "paths": { + "~*": ["./*"] + } + }, + "include": ["src/**/*"] +}