<file_sep>import React, { Component } from 'react'
import {View, TextInput,ListView, Text, StyleSheet, Platform, TouchableOpacity } from 'react-native'
import { white } from '../utils/colors'
import TextButton from './TextButton'
import * as flashCardApi  from '../utils/api'
import {getQuestionsInOneDeck} from "../utils/api";
import {clearLocalNotification, setLocalNotification} from "../utils/notification"

class CardDetail extends Component{
    state ={
        type:'question',
        currentQuestId:0,
        score:0,
        questions:[],
        finish: false
    }
    correct =() =>{
        let score = this.state.score + 100/this.state.questions.length
        let currentQuestId = (this.state.currentQuestId < this.state.questions.length) && this.state.currentQuestId + 1
        let finish = (currentQuestId === this.state.questions.length) ? true : false
        this.setState({score,currentQuestId,finish,type:'question'})
        finish === true && clearLocalNotification().then(setLocalNotification())
    }

    incorrect =() =>{
        let currentQuestId = (this.state.currentQuestId< this.state.questions.length) && this.state.currentQuestId + 1
        let finish = (currentQuestId === this.state.questions.length) ? true: false
        this.setState({currentQuestId,finish,type:'question'})
        finish === true && clearLocalNotification().then(setLocalNotification())

    }
    flipCard = (type) =>{
        this.setState(()=>({
            type:(type==='question')?'answer':'question'
        }))
    }
    startOver = () => {
        this.setState({
            type:'question',
            currentQuestId:0,
            score:0,
            finish: false
        })
    }

    componentDidMount() {
        const params = this.props.navigation.state.params
        const name =  params ? params.name : ''
        getQuestionsInOneDeck(name).then(
            (arrReturn) => {
                this.setState({questions:arrReturn})
            }
        )
    }

    render(){
        const {type,
            currentQuestId,
            score,
            questions} = this.state
        const {goBack} = this.props.navigation;

        return(
            <View>
                {!this.state.finish && this.state.questions.length > 0
                    &&
                <View>
                    <Text style={styles.progress}>
                        {currentQuestId+1}/{questions.length}
                    </Text>
                    <Text style={styles.deckName}>
                        {(questions.length > 0) && questions[currentQuestId][type]}
                        </Text>
                    <TextButton style={{margin: 20}} onPress={() => this.flipCard(type)}>
                        {(type==='question')?'Answer':'Question'}
                    </TextButton>
                    <TextButton style={{margin: 20}} onPress={this.correct}>
                        Correct
                    </TextButton>
                    <TextButton style={{margin: 20}} onPress={this.incorrect}>
                        Incorrect
                    </TextButton>
                </View>}
                {this.state.finish && this.state.questions.length > 0
                    &&<View>
                        <Text style={styles.deckName}>Finish</Text>
                        <Text style={styles.score}>Your score is {Math.round(this.state.score,0)}</Text>
                        <TextButton style={{margin: 20}} onPress={this.startOver}>
                            Restart Quiz
                        </TextButton>
                        <TextButton style={{margin: 20}} onPress={()=> goBack()}>
                            Back to Deck
                        </TextButton>
                    </View>
                }
                {this.state.questions.length == 0
                && <View>
                    <Text style={styles.deckName}> Please Add Card first</Text>
                </View>
                }
            </View>
        )
    }
}

const styles = StyleSheet.create({
    progress: {
        fontSize: 20,
        paddingTop: 20,
        marginLeft: 10,
        marginRight: 10,
    },
    deckName: {
        fontSize: 50,
        paddingTop: 50,
        justifyContent: 'center',
        alignItems: 'center',
        marginLeft: 10,
        marginRight: 10,
        textAlign: 'center'
    },
    score: {
        fontSize: 20,
        paddingTop: 20,
        justifyContent: 'center',
        alignItems: 'center',
        marginLeft: 10,
        marginRight: 10,
        textAlign: 'center'
    },
    deckCardNumber:{
        fontSize: 20,
        paddingTop: 20,
        justifyContent: 'center',
        alignItems: 'center',
        marginLeft: 10,
        marginRight: 10,
        textAlign: 'center'
    }
})


export default CardDetail<file_sep>#Mobile Flashcard

## Description

This is a mobile application (Android or iOS - or both) that allows users to study collections of flashcards. The app will allow users to create different categories of flashcards called "decks", add flashcards to those decks, then take quizzes on those decks.


This project was bootstrapped with [Create React Native App](https://github.com/react-community/create-react-native-app).


## Installation

### `npm install`

You shall install all Dependency by running `npm install`. All dependency in `package.json` shall be installed.

### `npm start`

Runs your app in development mode.

Open it in the [Expo app](https://expo.io) on your phone to view it. It will reload if you save edits to your files, and you will see build errors and logs in the terminal.

Sometimes you may need to reset or clear the React Native packager's cache. To do so, you can pass the `--reset-cache` flag to the start script:

```
npm start --reset-cache
# or
yarn start --reset-cache
```

### Testing environment.
This App is test with IOS simulator, and an android phone.<file_sep>import { AsyncStorage } from 'react-native'

const DECK_NAME = 'MobileFlashcard:deckname'

export function fetchDeckResults () {
    return AsyncStorage.getItem(DECK_NAME)
}

export function getQuestionsInOneDeck (key) {
    return AsyncStorage.getItem(DECK_NAME).then((results)=>{
        const data = JSON.parse(results)
        return data[key]['questions']
    })
}

export function submitDeck (key) {
    return AsyncStorage.mergeItem(DECK_NAME, JSON.stringify({
        [key]: {title:key, questions:[]}
    })).then(() => AsyncStorage.getItem(DECK_NAME))

}

export function submitCard ( entry, key ) {
    return AsyncStorage.getItem(DECK_NAME)
        .then((results) => {
            const data = JSON.parse(results)
            data[key]['questions'].push(entry)
            AsyncStorage.setItem(DECK_NAME, JSON.stringify(data))
        }).then(() => AsyncStorage.getItem(DECK_NAME))
}

<file_sep>import { FETCH_DECK } from '../actions'

function deckList (state = {}, action) {
    let arrReturn = {...state};
    switch (action.type) {
        case FETCH_DECK :
            var {deckList} = action
            return {
                deckList
            }
        default :
            return state
    }
}

export default deckList<file_sep>import React, { Component } from 'react'
import {View,ListView, Text, StyleSheet, Platform, TouchableOpacity } from 'react-native'
import { white } from '../utils/colors'
import { StackNavigator } from 'react-navigation';
import DeckEntry from "./DeckEntry";
import { fetchDeckResults } from '../utils/api'
import { connect } from 'react-redux'
import {fetchDeck} from "../actions";


class DeckList extends Component {
    componentDidMount (){
        fetchDeckResults().then((items)=>{
            items = JSON.parse(items)
            let deckList = []
            Object.entries(items).map(
                (item) => {
                    (1 in item ) && ('title' in item[1])&&(deckList.push({name:item[1].title, cardsNumbers:item[1].questions.length}))
                }
            )
            this.props.fetchDeck(deckList)
        })
    }
    renderDeck = ({name, cardsNumbers}) =>(
        <TouchableOpacity onPress={() =>
            this.props.navigation.navigate(
            'DeckEntry',
            {name}
        )} style ={styles.item}>
            <Text style={styles.deckName}>
                {name}
            </Text>
            <Text style={styles.deckCardNumber}>
                cards number: {cardsNumbers}
            </Text>
        </TouchableOpacity>
    )
    render (){
        const {deckList} = this.props
        const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        return (
            <View>
            {deckList ? <ListView
                dataSource={ds.cloneWithRows(deckList)}
                renderRow={(rowData) => this.renderDeck(rowData)}
            />
            :<Text style ={styles.deckName}> Please a new deck to start</Text>
            }
            </View>
        )
    }
}

const styles = StyleSheet.create({
    item: {
        backgroundColor: white,
        borderRadius: Platform.OS === 'ios' ? 16 : 2,
        padding: 20,
        marginLeft: 10,
        marginRight: 10,
        marginTop: 17,
        justifyContent: 'center',
        shadowRadius: 3,
        shadowOpacity: 0.8,
        shadowColor: 'rgba(0, 0, 0, 0.24)',
        shadowOffset: {
            width: 0,
            height: 3
        },
        alignItems: 'center',
    },
    deckName: {
        fontSize: 25,
        paddingTop: 20,
        paddingBottom: 20,
    },
    deckCardNumber:{
        fontSize: 15,
    }
})


function mapStateToProps({deckList}){
    return {'deckList': deckList}
}

function mapDispatchToProps (dispatch) {
    return {
        fetchDeck: (deckList) => dispatch(fetchDeck(deckList)),
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(DeckList)
<file_sep>import React, { Component } from 'react'
import {View, TextInput,ListView, Text, StyleSheet, Platform, TouchableOpacity } from 'react-native'
import { white } from '../utils/colors'
import TextButton from './TextButton'
import * as flashCardApi  from '../utils/api'
import {fetchDeck} from "../actions";
import {connect} from "react-redux";


class DeckEntry extends Component{
    addCard =(name) =>{
        this.props.navigation.navigate(
            'NewCard',
            {name}
        )
    }
    startQuiz =(name) =>{
        this.props.navigation.navigate(
            'CardDetail',
            {name}
        )
    }
    render(){
        const params = this.props.navigation.state.params
        const name =  params ? params.name : ''
        const {deckList} = this.props
        console.log(deckList);
        console.log(deckList.filter((deck) => deck.name === name));
        const cardsNumbers = (deckList.length > 0 && deckList.filter((deck) => deck.name === name).length > 0)
            ? deckList.filter((deck) => deck.name === name)[0].cardsNumbers
            : 0

        return(
            <View>
                <Text style={styles.deckName}>
                    {name}
                </Text>
                <Text style={styles.deckCardNumber}>
                    cards number: {cardsNumbers}
                </Text>
                <TextButton style={{margin: 20}} onPress={() => this.addCard(name)}>
                    Add Card
                </TextButton>
                <TextButton style={{margin: 20}} onPress={() => this.startQuiz(name)}>
                    Start Quiz
                </TextButton>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    deckName: {
        fontSize: 50,
        paddingTop: 50,
        justifyContent: 'center',
        alignItems: 'center',
        marginLeft: 10,
        marginRight: 10,
        textAlign: 'center'
    },
    deckCardNumber:{
        fontSize: 20,
        paddingTop: 20,
        justifyContent: 'center',
        alignItems: 'center',
        marginLeft: 10,
        marginRight: 10,
        textAlign: 'center'
    }
})

function mapStateToProps({deckList}){
    return {'deckList': deckList}
}

function mapDispatchToProps (dispatch) {
    return {
        fetchDeck: (deckList) => dispatch(fetchDeck(deckList)),
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(DeckEntry)<file_sep>import React, { Component } from 'react'
import {View, TextInput,ListView, Text, StyleSheet, Platform, TouchableOpacity,KeyboardAvoidingView } from 'react-native'
import { white } from '../utils/colors'
import TextButton from './TextButton'
import {submitDeck}  from '../utils/api'
import DeckEntry from "./DeckEntry";
import { connect } from 'react-redux'
import {fetchDeck} from "../actions";

class NewDeck extends Component{

    submit =(name) =>{
        (name) && submitDeck(name).then((items)=>{items = JSON.parse(items)
            let deckList = []
            Object.entries(items).map(
                (item) => {
                    (1 in item ) && ('title' in item[1])&&(deckList.push({name:item[1].title, cardsNumbers:item[1].questions.length}))
                }
            )
            this.props.fetchDeck(deckList)}).then(this.props.navigation.navigate(
            'DeckEntry',
            {name}
        ))
    }
    render(){
        let deckNameProps = '';
        return(
            <KeyboardAvoidingView behavior="padding">
                <Text style={styles.title}>What is the title of your new deck?</Text>
                <TextInput
                    style={styles.content}
                    onChangeText={(deckName) => {deckNameProps = deckName}}
                    placeholder='Deck title'
                />
                <TextButton style={{margin: 20}} onPress={() =>this.submit(deckNameProps)}>
                    Submit
                </TextButton>
            </KeyboardAvoidingView>
        )
    }
}

const styles = StyleSheet.create({
    container:{
        flex:1,
        alignItems: 'center',
        justifyContent:'center',
        paddingTop:30,
    },
    title: {
        fontSize: 50,
        paddingBottom: 25,
        justifyContent: 'center',
        alignItems: 'center',
        marginLeft: 10,
        marginRight: 10,
        textAlign: 'center'
    },
    content:{
        height: 30,
        borderColor: 'gray',
        borderWidth: 1,
        marginLeft: 10,
        marginRight: 10,
    }
})

function mapStateToProps({deckList}){
    return {'deckList': deckList}
}

function mapDispatchToProps (dispatch) {
    return {
        fetchDeck: (deckList) => dispatch(fetchDeck(deckList)),
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(NewDeck)
<file_sep>import React from 'react';
import { StyleSheet, Text, View, Platform , StatusBar} from 'react-native';
import DeckList from './components/DeckList'
import { TabNavigator, StackNavigator } from 'react-navigation'
import NewDeck from './components/NewDeck'
import { white, purple } from './utils/colors'
import { FontAwesome, Ionicons } from '@expo/vector-icons'
import { Constants } from 'expo'
import CardDetail from './components/CardDetail'
import DeckEntry from "./components/DeckEntry";
import NewCard from "./components/NewCard";
import reducer from './reducers'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import {setLocalNotification} from "./utils/notification";

function UdaciStatusBar ({backgroundColor, ...props}) {
    return (
        <View style={{ backgroundColor, height: Constants.statusBarHeight }}>
            <StatusBar translucent backgroundColor={backgroundColor} {...props} />
        </View>
    )
}
const Tabs = TabNavigator({
    DeckList: {
        screen: DeckList,
        navigationOptions: {
            tabBarLabel: 'Decks',
        },
    },
    NewDeck: {
        screen: NewDeck,
        navigationOptions: {
            tabBarLabel: 'NEW DECK',
        },
    },
}, {
    navigationOptions: {
        header: null
    },
    tabBarOptions: {
        activeTintColor: Platform.OS === 'ios' ? purple : white,
        style: {
            height: 56,
            backgroundColor: Platform.OS === 'ios' ? white : purple,
            shadowColor: 'rgba(0, 0, 0, 0.24)',
            shadowOffset: {
                width: 0,
                height: 3
            },
            shadowRadius: 6,
            shadowOpacity: 1
        }
    }
})

const MainNavigator = StackNavigator({
    Home: {
        screen: Tabs,
        navigationOptions: {
            title: "Deck List",
            headerTintColor: white,
            headerStyle: {
                backgroundColor: purple,
            }
        }
    },
    CardDetail: {
        path: "Card Detail",
        screen: CardDetail,
        navigationOptions: {
            title: "Start Quiz",
            headerTintColor: white,
            headerStyle: {
                backgroundColor: purple,
            }
        }
    },
    DeckEntry: {
        screen: DeckEntry,
        navigationOptions: {
            title: "Deck",
            headerTintColor: white,
            headerStyle: {
                backgroundColor: purple,
            }
        }
    },
    NewCard: {
        screen: NewCard,
        navigationOptions: {
            title: "New Card",
            headerTintColor: white,
            headerStyle: {
                backgroundColor: purple,
            }
        }
    }
})

export default class App extends React.Component {
    componentDidMount(){
        setLocalNotification()
    }
  render() {
    return (
        <Provider store={createStore(reducer)}>
          <View style={{flex: 1}}>
              <UdaciStatusBar backgroundColor={purple} barStyle="light-content" />
              <MainNavigator />
          </View>
        </Provider>
    );
  }
}
<file_sep>import React, { Component } from 'react'
import {View,ListView, Text, StyleSheet, Platform, TouchableOpacity,TextInput } from 'react-native'
import { white } from '../utils/colors'
import TextButton from './TextButton'
import * as flashCardApi  from '../utils/api'
import {fetchDeck} from "../actions";
import {connect} from "react-redux";

class NewCard extends Component{
    state ={
        question:'',
        answer:''
    }
    submit =(name,question,answer) =>{
        const {goBack} = this.props.navigation;
        (question && answer) &&
        flashCardApi.submitCard({question: question, answer: answer},name).then((items)=>{items = JSON.parse(items)
            let deckList = []
            Object.entries(items).map(
                (item) => {
                    (1 in item ) && ('title' in item[1])&&(deckList.push({name:item[1].title, cardsNumbers:item[1].questions.length}))
                }
            )
            this.props.fetchDeck(deckList)}).then(()=>{goBack()})
    }
    render(){
        const params = this.props.navigation.state.params
        const name =  params ? params.name : ''
        const cardsNumbers =  params ? params.cardsNumbers : ''
        let thisAnswer = ''
        let thisQuestion = ''
        return(
            <View>
                <TextInput
                    style={styles.input}
                    onChangeText={(question) => thisQuestion = question }
                    placeholder='Enter Question here'
                />
                <TextInput
                    style={styles.input}
                    onChangeText={(answer) => thisAnswer = answer}
                    placeholder='Enter Answer here'
                />
                <TextButton style={{margin: 20}} onPress={() => this.submit(name,thisQuestion,thisAnswer)}>
                    Submit
                </TextButton>
            </View>
        )
    }
}
const styles = StyleSheet.create({
    input: {height: 40, borderColor: 'gray', borderWidth: 1,
        justifyContent: 'center',
        alignItems: 'center',
        marginLeft: 10,
        marginRight: 10,}
})

function mapStateToProps({deckList}){
    return {'deckList': deckList}
}

function mapDispatchToProps (dispatch) {
    return {
        fetchDeck: (deckList) => dispatch(fetchDeck(deckList)),
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(NewCard)