Skip to content

Commit

Permalink
FEATURE: Inserting decks
Browse files Browse the repository at this point in the history
Inserting decks to AsyncStorage + reducer/action.
  • Loading branch information
diogosilverio committed Jan 21, 2018
1 parent 1c6147c commit 789f6e6
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 44 deletions.
3 changes: 2 additions & 1 deletion App.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { StackNavigator, TabNavigator } from 'react-navigation';
import FlashStatusBar from './components/ui/FlashStatusBar';
import FlashStackNavigator from './components/navigators/FlashStackNavigator';

import reducers from './reducers';

export default class App extends Component {

render() {

const store = createStore(() => { });
const store = createStore(reducers);

return (
<Provider store={store}>
Expand Down
10 changes: 9 additions & 1 deletion actions/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
export const LOAD_DECKS = "LOAD_DECKS";
export const NEW_DECK = "NEW_DECK";

export function loadDecks(decks){
return {
action: LOAD_DECKS,
type: LOAD_DECKS,
decks
}
}

export function newDeck(deck){
return {
type: NEW_DECK,
deck
}
}
58 changes: 46 additions & 12 deletions components/flashcards/DeckList.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import {
TouchableOpacity,
View
} from 'react-native';
import { NavigationActions } from 'react-navigation';
import { Entypo } from '@expo/vector-icons';

import DeckItem from '../ui/DeckItem';

import { loadDecks } from '../../services';
import * as services from '../../services';
import * as actions from '../../actions'

import { COLOR_B_4 } from '../../utils/colors';

Expand All @@ -21,30 +24,47 @@ class DeckList extends Component {
tabBarLabel: 'Decks'
}

state = {
decks: null
async componentDidMount() {
const decks = await services.loadDecks();
this.props.dispatch(actions.loadDecks(decks));

}

componentDidMount() {
const decks = loadDecks();
this.setState({
decks
})
navigateToNewDeck() {
const routeName = "New";

const navigation = NavigationActions.navigate({
routeName
});

console.log(navigation);

this.props.navigation.dispatch(navigation);
}

render() {

if (this.state.decks === null) {
if (this.props.decks === null) {
return (
<View style={{ flex: 1, alignContent: 'center', justifyContent: 'center' }}>
<ActivityIndicator size={50} />
</View>
);
} else if (this.props.decks.length === 0) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Entypo size={75} name="emoji-sad" />
<Text>You have no registered decks.</Text>
<TouchableOpacity style={styles.btnAdd} onPress={this.navigateToNewDeck.bind(this)}>
<Text>Add a new deck!</Text>
</TouchableOpacity>
</View>
);
} else {
return (
<ScrollView style={styles.container}>
{this.state.decks.map((deck) => (
<TouchableOpacity key={deck.id}>
{this.props.decks.map((deck) => (
<TouchableOpacity key={deck.name}>
<DeckItem deck={deck} />
</TouchableOpacity>
))}
Expand All @@ -58,7 +78,21 @@ class DeckList extends Component {
const styles = StyleSheet.create({
container: {
flex: 1
},
btnAdd: {
backgroundColor: COLOR_B_4,
borderRadius: 2,
padding: 4,
margin: 10
}
})

export default connect()(DeckList);
function mapStateToProps({ decks }) {
const deckArray = Object.keys(decks).map((key) => decks[key]);

return {
decks: deckArray
}
}

export default connect(mapStateToProps)(DeckList);
73 changes: 59 additions & 14 deletions components/flashcards/NewDeck.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,85 @@
import React, { Component } from 'react';
import { container, connect } from 'react-redux';
import {
Alert,
Slider,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View
} from 'react-native';
import { NavigationActions } from 'react-navigation';

import { MaterialIcons, MaterialCommunityIcons } from '@expo/vector-icons';

import DifficultyMeter from '../ui/DifficultyMeter';

import { newDeck } from '../../actions';
import { persistDeck } from '../../services';

import { COLOR_B_4, COLOR_B_5, COLOR_WHITE } from '../../utils/colors';

export default class NewDeck extends Component {
class NewDeck extends Component {

state = {
deck: {
name: '',
description: '',
difficulty: 0
difficulty: 0,
cards: [],
won: 0,
lost: 0
}
}

reset() {
this.setState({
deck: {
name: '',
description: '',
difficulty: 0
}
});
}

async createNewDeck() {
try {
if (this.state.deck.name.trim() === '') {
Alert.alert(
'Required',
"Deck's name is required",
[{ text: 'Ok', onPress: () => { } }],
{ cancelable: false });
return;
}

persistDeck(this.state.deck);
this.props.dispatch(newDeck(this.state.deck));

const routeName = "Index";
const navigation = NavigationActions.navigate({ routeName });

this.props.navigation.dispatch(navigation);

} catch (e) {
Alert.alert(
'Error',
'Error adding a new deck to your device.',
[
{ text: 'Ok', onPress: () => { } }
]);
console.error(e);
}
this.reset();
}

render() {
return (
<View style={styles.container}>
<Text style={styles.text}>Name</Text>
<TextInput style={{ borderWidth: 0, width: '75%' }} maxLength={30} placeholder="Javascript II" value={this.state.deck.name}
<TextInput style={{ borderWidth: 0, width: '75%' }} maxLength={30} placeholder="Javascript II"
value={this.state.deck.name}
onChangeText={(name) => {
this.setState((prev) => {
const prevDeck = prev.deck;
Expand Down Expand Up @@ -75,18 +126,10 @@ export default class NewDeck extends Component {
</View>

<View style={styles.rowContainer}>
<TouchableOpacity style={styles.cancelBtn} onPress={() => {
this.setState({
deck: {
name: '',
description: '',
difficulty: 0
}
});
}}>
<TouchableOpacity style={styles.cancelBtn} onPress={this.reset.bind(this)}>
<MaterialIcons name="cancel" size={40} color={COLOR_WHITE} />
</TouchableOpacity>
<TouchableOpacity style={styles.saveBtn}>
<TouchableOpacity style={styles.saveBtn} onPress={this.createNewDeck.bind(this)}>
<MaterialIcons name="done" size={40} color={COLOR_WHITE} />
</TouchableOpacity>
</View>
Expand Down Expand Up @@ -121,4 +164,6 @@ const styles = StyleSheet.create({
margin: 5,
padding: 10
}
})
})

export default connect()(NewDeck);
25 changes: 20 additions & 5 deletions reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import { LOAD_DECKS } from '../actions';
import {
LOAD_DECKS,
NEW_DECK
} from '../actions';

function decks(state, action) {
function decks(state = { decks: {} }, action) {
const { type } = action;
const { decks } = state;

switch(type){
case LOAD_DECKS:{
switch (type) {
case LOAD_DECKS: {
const decks = action.decks;

return {
decks
};
}
default:{
case NEW_DECK: {
const deck = action.deck;
const freshDecks = {
...decks,
[deck.name]: deck
}

return {
decks
}
}
default: {
return state;
}
}
Expand Down
24 changes: 13 additions & 11 deletions services/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export function loadDecks() {
return [
{ id: 1, name: 'Javascript 101', description: 'Basic questions about loops, data types and functions', cards: [], difficulty: 18, won: 10, lost: 3 },
{ id: 2, name: 'Cryptocurrency', description: 'Main algorithms, PoS, PoW, Bitcoin...', cards: [], difficulty: 58, won: 9, lost: 7 },
{ id: 3, name: 'Java threads', description: 'Concurrency framework, locks and APIs', cards: [], difficulty: 80, won: 18, lost: 12 },
{ id: 4, name: 'Unity 5 basics', description: 'Basic components and actions', cards: [], difficulty: 1, won: 6, lost: 1 },
{ id: 5, name: 'Pro React Native', description: 'Advanced and custom components', cards: [], difficulty: 70, won: 10, lost: 5 },
{ id: 6, name: 'RESTful', description: 'Verbs, scenarios and status codes', cards: [], difficulty: 60, won: 18, lost: 12 },
{ id: 7, name: 'Elixir', description: 'Basic structure, loops, running scripts', cards: [], difficulty: 1, won: 6, lost: 1 },
{ id: 8, name: 'Python 3', description: 'Concepts, changes and new apis', cards: [], difficulty: 22, won: 10, lost: 5 },
];
import { AsyncStorage } from 'react-native';

const FLASHCARDS_STORAGE_KEY = "Flashcards:decks"

export async function persistDeck(deck){
await AsyncStorage.mergeItem(FLASHCARDS_STORAGE_KEY, JSON.stringify({
[deck.name]: deck
}))
}

export async function loadDecks() {
const decks = JSON.parse(await AsyncStorage.getItem(FLASHCARDS_STORAGE_KEY));
return decks !== null ? decks : [];
}

0 comments on commit 789f6e6

Please sign in to comment.