diff --git a/package.json b/package.json index cc21e4e..962aaa1 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "react": "16.3.1", "react-dom": "16", "react-native": "~0.55.2", + "react-native-elements": "^0.19.1", "react-navigation": "^2.0.1" } } diff --git a/src/stores/book/__tests__/index.js b/src/stores/book/__tests__/index.js index 4ce1420..fe02464 100644 --- a/src/stores/book/__tests__/index.js +++ b/src/stores/book/__tests__/index.js @@ -1,8 +1,34 @@ import { BookStore } from '../index' import api from '../mock-api/api' -it('bookstore fetches data', async () => { - const store = BookStore.create({ books: [] }, { api }) +let store = null + +beforeEach(async () => { + store = BookStore.create({ books: [] }, { api }) await store.loadBooks() +}) + +it('Bookstore fetches data', () => { expect(store.books.length).toBe(10) }) + +it(`Bookstore filter is set when setGenre() is called with a valid filter value`, async () => { + store.setGenre('Nonfiction') + expect(store.filter).toBe('Nonfiction') +}) + +it(`Bookstore filter is NOT set when setGenre() is called with an invalid filter value`, async () => { + expect(() => store.setGenre('Adventure')).toThrow() +}) + +it(`Books are sorted by title`, async () => { + const books = store.sortedBooks + expect(books[0].title).toBe('By The Book') + expect(books[1].title).toBe('Jane Eyre') +}) + +it(`Books are sorted by title`, async () => { + store.setGenre('Nonfiction') + const books = store.sortedBooks + expect(books.length).toBe(7) +}) diff --git a/src/stores/book/index.js b/src/stores/book/index.js index 789a939..8b3aa71 100644 --- a/src/stores/book/index.js +++ b/src/stores/book/index.js @@ -6,20 +6,32 @@ let store = null const Book = t.model('Book', { id: t.identifier(), title: t.string, + genre: t.string, pageCount: t.number, authors: t.array(t.string), image: t.maybe(t.string), inStock: t.optional(t.boolean, true), }) +const sortFn = (a, b) => (a.title > b.title ? 1 : a.title === b.title ? 0 : -1) + export const BookStore = t .model('BookStore', { books: t.array(Book), + filter: t.optional( + t.enumeration('FilterEnum', ['All', 'Fiction', 'Nonfiction']), + 'All' + ), }) .views(self => ({ get api() { return getEnv(self).api }, + get sortedBooks() { + return self.filter === 'All' + ? self.books.sort(sortFn) + : self.books.filter(bk => bk.genre === self.filter).sort(sortFn) + }, })) .actions(self => { function updateBooks(books) { @@ -27,6 +39,7 @@ export const BookStore = t self.books.push({ id: book.id, title: book.volumeInfo.title, + genre: book.volumeInfo.categories[0], pageCount: book.volumeInfo.pageCount, authors: book.volumeInfo.authors, publisher: book.volumeInfo.publisher, @@ -44,8 +57,13 @@ export const BookStore = t } }) + const setGenre = genre => { + self.filter = genre + } + return { loadBooks, + setGenre, } }) diff --git a/src/stores/book/mock-api/api.js b/src/stores/book/mock-api/api.js index c2b071f..f6bb050 100644 --- a/src/stores/book/mock-api/api.js +++ b/src/stores/book/mock-api/api.js @@ -3,7 +3,7 @@ const books = require('./books') const delayedPromise = (data, delaySecs = 2) => new Promise(resolve => setTimeout(() => resolve(data), delaySecs * 1000)) -const fetchBooks = () => delayedPromise(books) +const fetchBooks = () => delayedPromise(books, 0.3) export default { fetchBooks, diff --git a/src/views/author/index.js b/src/views/author/index.js index b9b6b8c..02425dd 100644 --- a/src/views/author/index.js +++ b/src/views/author/index.js @@ -1,11 +1,54 @@ import React from 'react' import { View, Button } from 'react-native' +import { ListItem } from 'react-native-elements' import Title from '../../components/Title' +const list = [ + { + name: 'Amy Farha', + avatar_url: + 'https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg', + subtitle: 'Vice President', + }, + { + name: 'Chris Jackson', + avatar_url: + 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg', + subtitle: 'Vice Chairman', + }, + { + name: 'Amanda Martin', + avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/brynn/128.jpg', + subtitle: 'CEO', + }, + { + name: 'Christy Thomas', + avatar_url: + 'https://s3.amazonaws.com/uifaces/faces/twitter/kfriedson/128.jpg', + subtitle: 'Lead Developer', + }, + { + name: 'Melissa Jones', + avatar_url: + 'https://s3.amazonaws.com/uifaces/faces/twitter/nuraika/128.jpg', + subtitle: 'CTO', + }, +] + export default ({ navigation }) => ( + <View> + {list.map((l, i) => ( + <ListItem + key={i} + leftAvatar={{ source: { uri: l.avatar_url } }} + title={l.name} + subtitle={l.subtitle} + /> + ))} + </View> <Button onPress={() => navigation.openDrawer()} title="Open Drawer" /> <Button onPress={() => navigation.navigate('Books')} title="Go to Books" /> </View>