diff --git a/actions/index.js b/actions/index.js index 33428bb..823c73a 100644 --- a/actions/index.js +++ b/actions/index.js @@ -1,6 +1,8 @@ export const LOAD_DECKS = "LOAD_DECKS"; export const NEW_DECK = "NEW_DECK"; +export const ADD_CARD = "ADD_CARD"; + export function loadDecks(decks){ return { type: LOAD_DECKS, @@ -13,4 +15,12 @@ export function newDeck(deck){ type: NEW_DECK, deck } +} + +export function addCard(deckKey, card){ + return { + type: ADD_CARD, + deckKey, + card + } } \ No newline at end of file diff --git a/components/flashcards/AddCard.js b/components/flashcards/AddCard.js index 4bac0b5..52397b4 100644 --- a/components/flashcards/AddCard.js +++ b/components/flashcards/AddCard.js @@ -1,15 +1,128 @@ import React, { Component } from 'react'; -import { Text, View } from 'react-native'; +import { StyleSheet, Text, View, TextInput, TouchableOpacity, Alert } from 'react-native'; +import { connect } from 'react-redux'; +import { NavigationActions } from 'react-navigation'; +import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -export default class AddCard extends Component { +import { addCard } from '../../actions'; +import { addCardToDeck, getDeck } from '../../services'; + +import { COLOR_WHITE, COLOR_B_5 } from '../../utils/colors'; + +class AddCard extends Component { + + state = { + card: { + question: '', + answer: '' + } + } + + reset() { + this.setState({ + deck: { + question: '', + answer: '' + } + }); + } + + async addCard() { + const { deckKey, refresher } = this.props.navigation.state.params; + + try { + if (this.state.card.question.trim() === '' || this.state.card.answer.trim() === '') { + Alert.alert( + 'Required', + "Type a valid question/answer.", + [{ text: 'Ok', onPress: () => { } }], + { cancelable: false }); + return; + } + + + await addCardToDeck(deckKey, this.state.card); + this.props.dispatch(addCard(deckKey, this.state.card)); + refresher(); + this.props.navigation.goBack(); + + } catch (e) { + Alert.alert( + 'Error', + `Error adding a new card to deck '${deckKey}'.`, + [ + { text: 'Ok', onPress: () => { } } + ]); + console.error(e); + } + + this.reset(); + } render() { + const { deckKey } = this.props.navigation.state.params; return ( - - AddCard + + Question + { + this.setState((prev) => { + const prevCard = prev.card; + return { + card: { + ...prevCard, + question + } + } + }) + }} /> + + Answer + { + this.setState((prev) => { + const prevCard = prev.card; + return { + card: { + ...prevCard, + answer + } + } + }) + }} /> + + + + + + ); } -} \ No newline at end of file +} + +const styles = StyleSheet.create({ + container: { + alignItems: 'center', + flex: 1 + }, + rowContainer: { + flexDirection: 'row', + justifyContent: 'space-between' + }, + text: { + fontSize: 20 + }, + saveBtn: { + backgroundColor: COLOR_B_5, + borderRadius: 2, + margin: 5, + padding: 10 + } +}) + +export default connect()(AddCard); \ No newline at end of file diff --git a/components/flashcards/DeckDetails.js b/components/flashcards/DeckDetails.js index 8bd4554..acd064f 100644 --- a/components/flashcards/DeckDetails.js +++ b/components/flashcards/DeckDetails.js @@ -17,6 +17,14 @@ class DeckDetails extends Component { } } + /** + * Child navigate.goBack() does not re-render state. + * https://github.com/react-navigation/react-navigation/issues/922 + */ + refresher(){ + this.setState({}); + } + render() { const { deck } = this.props; if (typeof deck === 'undefined') { @@ -42,7 +50,7 @@ class DeckDetails extends Component { {deck.cards.length} Card(s) - + this.props.navigation.navigate('AddCard', { deckKey: deck.name, refresher: this.refresher.bind(this) })}> Add Card diff --git a/reducers/index.js b/reducers/index.js index eb12deb..480cff4 100644 --- a/reducers/index.js +++ b/reducers/index.js @@ -1,6 +1,7 @@ import { LOAD_DECKS, - NEW_DECK + NEW_DECK, + ADD_CARD } from '../actions'; function decks(state = { decks: {} }, action) { @@ -26,6 +27,21 @@ function decks(state = { decks: {} }, action) { decks } } + case ADD_CARD: { + const { card, deckKey } = action; + const freshDeck = decks[deckKey]; + + freshDeck.cards.push(card); + + const freshDecks = { + ...decks, + [deckKey]: freshDeck + } + return { + decks: freshDecks + } + + } default: { return state; } diff --git a/services/index.js b/services/index.js index 12835c4..f67180f 100644 --- a/services/index.js +++ b/services/index.js @@ -11,4 +11,22 @@ export async function persistDeck(deck){ export async function loadDecks() { const decks = JSON.parse(await AsyncStorage.getItem(FLASHCARDS_STORAGE_KEY)); return decks !== null ? decks : []; +} + +export async function getDeck(deckKey){ + const decks = await loadDecks(); + const deck = decks[deckKey]; + return deck; +} + +export async function addCardToDeck(deckKey, card){ + const deck = await getDeck(deckKey); + + if(typeof deck === 'undefined'){ + console.warn(`Trying to fetch invalid deck: ${deckKey}`); + return; + } + + deck.cards.push(card) + await persistDeck(deck); } \ No newline at end of file