Skip to content

Commit

Permalink
feat: book shelves
Browse files Browse the repository at this point in the history
  • Loading branch information
isdenmois committed Mar 21, 2021
1 parent d17a2b4 commit f8ed93e
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 101 deletions.
7 changes: 4 additions & 3 deletions src/components/button.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import { TouchableOpacity, View, ViewStyle, TextStyle, Platform } from 'react-native';
import { TouchableOpacity, View, ViewStyle, TextStyle } from 'react-native';
import { DynamicStyleSheet, useDynamicValue } from 'react-native-dynamic';
import classnames from 'rn-classnames';
import { dynamicColor, boldText } from 'types/colors';
import { TextM } from 'components/text';
import { theme } from './theme';

interface Props {
label: string;
Expand Down Expand Up @@ -53,8 +54,8 @@ const ds = new DynamicStyleSheet({
marginLeft: 6,
} as ViewStyle,
thin: {
paddingHorizontal: 10,
paddingVertical: 5,
paddingVertical: theme.spacing[1],
paddingHorizontal: theme.spacing[3],
borderRadius: 15,
} as ViewStyle,
disabled: {
Expand Down
2 changes: 1 addition & 1 deletion src/navigation/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type MainParamList = {
paper?: boolean;
};
[MainRoutes.ReadList]: { filters?; sort?; readonly?: boolean; listId?: string; listName?: string };
[MainRoutes.WishList]: null;
[MainRoutes.WishList]: { listId?: string; listName?: string };
[MainRoutes.Details]: { bookId: string; extra?: Partial<BookData>; fantlabId?: string; initialTab?: string };
[MainRoutes.Editions]: { editionIds: number[]; translators: EditionTranslators };
[MainRoutes.BookSelect]: null;
Expand Down
3 changes: 1 addition & 2 deletions src/screens/book-list/read-list.screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { getColor, dynamicColor } from 'types/colors';
import { BookSort, BookFilters } from 'types/book-filters';
import { BOOK_STATUSES } from 'types/book-statuses.enum';
import { withScroll } from 'utils/scroll-to-top';
import { getCurrentYear } from 'utils/date';
import { Button, ScreenHeader, Screen } from 'components';
import { BookList } from './components/book-list';
import { createQueryState } from './book-list.service';
Expand All @@ -34,7 +33,7 @@ export class ReadList extends React.Component<Props, State> {
state: State = createQueryState(
{
status: BOOK_STATUSES.READ,
...(this.props.route.params?.filters || { year: getCurrentYear() }),
...(this.props.route.params?.filters || {}),
},
this.props.route.params?.sort || { field: 'date', desc: true },
);
Expand Down
2 changes: 1 addition & 1 deletion src/screens/home/components/current-books.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { EmptyBook } from './empty-book';
import { Dimensions } from 'react-native';
import { useObservable } from 'utils/use-observable';

const PADDINGS = 48;
const PADDINGS = 32;

function getCurrentBooks() {
return currentBooksQuery().observeWithColumns(['thumbnail']);
Expand Down
18 changes: 13 additions & 5 deletions src/screens/home/components/empty-book.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from 'react';
import { useObservable } from 'utils/use-observable';
import Icon from 'react-native-vector-icons/FontAwesome5';

import { openModal, t } from 'services';
import { getNavigation, openModal, t } from 'services';
import { Button } from 'components';
import { ModalRoutes } from 'navigation/routes';
import { MainRoutes, ModalRoutes } from 'navigation/routes';
import { Box, Text, useTheme } from 'components/theme';
import { wishBooksQuery } from '../home.queries';

Expand All @@ -13,10 +13,11 @@ const getWishBooksCount = () => wishBooksQuery().observeCount();
export const EmptyBook = () => {
const wishBooksCount = useObservable(getWishBooksCount, 1, []);
const openBookSelect = () => openModal(ModalRoutes.BookSelect);
const openBookPicker = () => getNavigation().push(MainRoutes.BookSelect);
const { colors } = useTheme();

return (
<Box height={400} alignItems='center' justifyContent='center'>
<Box height={390} alignItems='center' justifyContent='center'>
<Icon name='bookmark' size={36} color={colors.Empty} />

{!wishBooksCount && (
Expand All @@ -29,9 +30,16 @@ export const EmptyBook = () => {
{t('home.empty.choose')}
</Text>
)}

{!!wishBooksCount && (
<Box mt={2}>
<Button testID='bookPickButton' onPress={openBookPicker} label={t('nav.pick')} thin />
</Box>
)}

{!!wishBooksCount && (
<Box mt={3}>
<Button testID='bookSelectButton' onPress={openBookSelect} label={t('modal.select-book')} />
<Box mt={2}>
<Button testID='bookSelectButton' onPress={openBookSelect} label={t('modal.select-book')} thin />
</Box>
)}
</Box>
Expand Down
60 changes: 0 additions & 60 deletions src/screens/home/components/navigation-links.tsx

This file was deleted.

17 changes: 7 additions & 10 deletions src/screens/home/components/now-reading-book.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BOOK_STATUSES } from 'types/book-statuses.enum';
import { Button, Thumbnail } from 'components';
import { MainRoutes, ModalRoutes } from 'navigation/routes';
import { getNavigation, openModal, t } from 'services';
import { Box, Text, theme } from 'components/theme';
import { Box, Text } from 'components/theme';

interface Props {
book: Book;
Expand All @@ -19,7 +19,7 @@ export function NowReadingBook({ book }: Props) {
const openBook = useCallback(() => getNavigation().push(MainRoutes.Details, { bookId: book.id }), []);

return (
<Box alignItems='center' maxWidth='100%' pt={3}>
<Box alignItems='center' py={1}>
<TouchableOpacity style={s.thumbnail} onPress={openBook} testID='currentThumbnail'>
<Thumbnail cache style={s.image} width={200} height={300} title={book.title} url={book.thumbnail} />
</TouchableOpacity>
Expand All @@ -30,21 +30,18 @@ export function NowReadingBook({ book }: Props) {
</Text>
</TouchableOpacity>

<Button label={t('button.ive-finished')} thin onPress={openChangeStatus} style={s.button} />
<Box mt={1}>
<Button label={t('button.ive-finished')} thin onPress={openChangeStatus} />
</Box>
</Box>
);
}

const s = StyleSheet.create({
thumbnail: {
marginRight: 15,
borderRadius: 5,
borderRadius: 20,
} as ImageStyle,
image: {
borderRadius: 5,
borderRadius: 20,
} as ImageStyle,
button: {
marginTop: theme.spacing[1],
paddingHorizontal: theme.spacing[3],
},
});
27 changes: 25 additions & 2 deletions src/screens/home/home.queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ import { BOOK_STATUSES } from 'types/book-statuses.enum';
import { dayOfYear, getStartOfYear, daysAmount } from 'utils/date';
import { database } from 'store';
import Book from 'store/book';
import List from 'store/list';
import { settings } from 'services';
import _ from 'lodash';

const INITIAL_SORT = { field: 'title', desc: false };
const getDefaultSort = () => {
const sort = settings.defaultSort || INITIAL_SORT;
const field = _.snakeCase(sort.field);

console.log('sort', sort, field);

return Q.experimentalSortBy(field, sort.desc ? Q.desc : Q.asc);
};

export function booksReadForecast(read: number, total: number): number {
const yearProgress = dayOfYear() / daysAmount();
Expand All @@ -19,7 +32,7 @@ export function currentBooksQuery() {
}

export function wishBooksQuery() {
return database.collections.get('books').query(Q.where('status', BOOK_STATUSES.WISH));
return database.collections.get<Book>('books').query(Q.where('status', BOOK_STATUSES.WISH), getDefaultSort());
}

export function readBooksThisYearQuery() {
Expand All @@ -28,7 +41,9 @@ export function readBooksThisYearQuery() {
}

export function readBooksQuery() {
return database.collections.get<Book>('books').query(Q.where('status', BOOK_STATUSES.READ));
return database.collections
.get<Book>('books')
.query(Q.where('status', BOOK_STATUSES.READ), Q.experimentalSortBy('date', Q.desc));
}

export function lastReadDateObserver() {
Expand All @@ -38,3 +53,11 @@ export function lastReadDateObserver() {
.observeWithColumns(['date'])
.pipe(map(rows => rows[0]?.date));
}

export function allListsObserver() {
return database.collections.get<List>('lists').query().observeWithColumns(['name']);
}

export function listBooksQuery(listId: string) {
return database.collections.get<Book>('books').query(Q.on('list_books', 'list_id', listId), getDefaultSort());
}
87 changes: 85 additions & 2 deletions src/screens/home/screens/bookshelves.screen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,89 @@
import React, { FC } from 'react';
import { Text } from 'react-native';
import { Q, Query } from '@nozbe/watermelondb';

import { Box, Text } from 'components/theme';
import { RecyclerList } from 'components/recycler-list';
import { ScrollView, TouchableOpacity } from 'react-native';
import { Thumbnail } from 'components';
import { getNavigation } from 'services';
import { MainRoutes } from 'navigation/routes';
import Book from 'store/book';
import { useObservable } from 'utils/use-observable';
import { allListsObserver, listBooksQuery, readBooksQuery, wishBooksQuery } from '../home.queries';
import List from 'store/list';

const LIMIT = 10;

const openReadList = () => getNavigation().push(MainRoutes.ReadList);
const openWishList = () => getNavigation().push(MainRoutes.WishList);
const openList = (list: List) => () =>
getNavigation().push(MainRoutes.WishList, { listId: list.id, listName: list.name });

export const BookshelvesScreen: FC = () => {
return <Text>BookshelvesScreen</Text>;
const lists = useObservable(allListsObserver, [], []);

return (
<ScrollView contentContainerStyle={{ padding: 16 }}>
<BookList title='Read books' query={readBooksQuery} onViewAllPress={openReadList} />
<BookList mt={4} title='Want to read' query={wishBooksQuery} onViewAllPress={openWishList} />

{lists.map(list => (
<BookList
key={list.id}
mt={4}
title={list.name}
query={() => listBooksQuery(list.id)}
onViewAllPress={openList(list)}
/>
))}
</ScrollView>
);
};

type ListProps = { mt?: number; query(): Query<Book>; title?: string; onViewAllPress?() };
function BookList({ mt, title, query, onViewAllPress }: ListProps) {
const books = useObservable(() => query().extend(Q.experimentalTake(LIMIT)).observe(), [], []);
const totalCount = useObservable(() => query().observeCount(), 0, []);

return (
<Box mt={mt}>
{!!title && (
<Box flexDirection='row' justifyContent='space-between'>
<Text variant='body'>{title}</Text>

<TouchableOpacity onPress={onViewAllPress}>
<Text variant='body'>
{'View all'}
{totalCount > 0 ? ` (${totalCount})` : ''}
</Text>
</TouchableOpacity>
</Box>
)}

<Box mt={1} height={144}>
<RecyclerList
data={books}
itemHeight={144}
itemWidth={96}
rowRenderer={renderBook}
isHorizontal
showsHorizontalScrollIndicator={false}
/>
</Box>
</Box>
);
}

function renderBook(type, book: Book) {
return (
<TouchableOpacity onPress={() => getNavigation().push(MainRoutes.Details, { bookId: book.id })}>
<Thumbnail cache style={{ borderRadius: 10 }} width={80} height={120} title={book.title} url={book.thumbnail} />

<Box mr={2} mt={1} alignItems='center'>
<Text variant='small' numberOfLines={1}>
{book.title}
</Text>
</Box>
</TouchableOpacity>
);
}
13 changes: 5 additions & 8 deletions src/screens/home/screens/main.screen.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import React, { FC } from 'react';
import { ScrollView, StyleSheet, ViewStyle } from 'react-native';
import { Screen } from 'components';

import { CurrentBook } from '../components/current-books';
import { BookChallenge } from '../components/book-challenge';
import { ReadBooks } from '../components/read-books';

export const MainScreen: FC = () => {
return (
<Screen>
<ScrollView testID='homeScreen' contentContainerStyle={s.container}>
<CurrentBook />
<ScrollView testID='homeScreen' contentContainerStyle={s.container}>
<CurrentBook />

<BookChallenge />
<BookChallenge />

<ReadBooks />
</ScrollView>
</Screen>
<ReadBooks />
</ScrollView>
);
};

Expand Down
Loading

0 comments on commit f8ed93e

Please sign in to comment.