Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,812 changes: 2,406 additions & 2,406 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ class App extends Component {
<h1 className="header__h1"><span className="header__text">Inspiration Board</span></h1>
</header>
<Board
url="https://inspiration-board.herokuapp.com/boards/"
boardName={`Ada-Lovelace`}
url="https://inspiration-board.herokuapp.com/"
boardName={`Chantelletubbie/`}
/>
</section>
);
Expand Down
103 changes: 89 additions & 14 deletions src/components/Board.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,108 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import axios from 'axios';

import './Board.css';
import Card from './Card';
import NewCardForm from './NewCardForm';
import CARD_DATA from '../data/card-data.json';
// import CARD_DATA from '../data/card-data.json';

class Board extends Component {
constructor() {
super();
constructor(props) {
super(props);

this.state = {
cards: [],
url: this.props.url,
boardName: this.props.boardName,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should only include things in state if they're going to change as your application runs. As far as I can tell url and boardName don't change, which means it would be clearer to leave them in props

error: undefined
};
}
componentDidMount( ) {
const allCardsURL = this.state.url + 'boards/' + this.state.boardName + 'cards/';

render() {
return (
<div>
Board
</div>
)
axios.get(allCardsURL)
.then((response) => {

this.setState({
cards: response.data
})
})
.catch((error)=> {
const errorStr = `Got an error with status ${error.response.status} and message ${error.response.statusText}`

this.setState({
error: errorStr
})
});
}

deleteCard = (id) => {

const deleteURL = `${this.state.url}cards/${id}`
axios.delete(deleteURL)
.then((response) => {
const card = response.data.card;
alert(`Successfully deleted card with id ${card.id} and message ${card.text}.`)

const updatedCards = this.state.cards.filter((card) => {
return card.card.id !== id
})

this.setState({
cards: updatedCards
})
})
.catch((error) => {
const errorStr = `Got an error with status ${error.response.status} and message ${error.response.statusText}`
this.setState({
error: errorStr
})
})
}

}
addCard = (cardObj) => {

Board.propTypes = {
let URL = `${this.state.url}boards/${this.state.boardName}cards`;

axios.post(URL, cardObj)
.then((response) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you've kept all the API interaction logic in one place - the callbacks are a little more complex, but I would say it makes the app as a whole much easier to comprehend. Whether or not you intended it, this is a great example of the container component pattern well-applied.

const updatedCards = this.state.cards;
updatedCards.push({card: response.data.card});
console.log(updatedCards, "response", response.data)
this.setState({
cards: updatedCards
})
})
.catch((error) => {
const errorStr = `Got an error with status ${error.response.status} and message ${error.response.statusText}`
this.setState({
error: errorStr
})
})
}

render() {

const cards = this.state.cards.map((card) => {
return (<Card key={`${card.card.id}${card.card.text}${card.card.emoji}`}
text={card.card.text} emoji={card.card.emoji} id={card.card.id} deleteCardCallback={this.deleteCard}/>)
})

const display = (this.state.cards.length !== 0) ? (<section>{cards}</section>)
: (<p>{this.state.error}</p>) ;

return (
<div>
<NewCardForm addCardCallback={this.addCard}/>
{display}
</div>
)
}
}

};
Board.propTypes = {
url: PropTypes.string.isRequired,
boardName: PropTypes.string.isRequired
};

export default Board;
export default Board;
32 changes: 23 additions & 9 deletions src/components/Card.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
import React, { Component } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import emoji from 'emoji-dictionary';

import './Card.css';

class Card extends Component {
render() {
return (
<div className="card">
Card
</div>
)

const Card = (props) => {

const { text, emoji, id, deleteCardCallback} = props;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you converted this to a functional component!

const onDelete = () => {
deleteCardCallback(id);
}

return (
<div className="card">
<ul>
<li> {text} </li>
<li> {emoji} </li>
<li><button onClick={onDelete}>Uninspired...</button></li>
</ul>
</div>
)
}

Card.propTypes = {

text: PropTypes.string.isRequired,
emoji: PropTypes.string,
id: PropTypes.number,
deleteCardCallback: PropTypes.func
};


export default Card;
68 changes: 68 additions & 0 deletions src/components/NewCardForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,71 @@ import emoji from 'emoji-dictionary';
import './NewCardForm.css';

const EMOJI_LIST = ["", "heart_eyes", "beer", "clap", "sparkling_heart", "heart_eyes_cat", "dog"]

//text/quote, emoji

class NewCardForm extends Component {

constructor(props) {
super(props)
this.state = {
text: "",
emoji: ""
}
}

onSubmit = (event) => {
event.preventDefault();
this.props.addCardCallback(this.state);

this.setState({
text: "",
emoji: ""
})
}

onFormChange = (event) => {

const field = event.target.name;
const value = event.target.value;

const updatedState = {};
updatedState[field] = value;
this.setState(updatedState);
}

emojiSelect = () => {
const emojis = EMOJI_LIST.map((emoji, index) => {
return <option key={index} value={emoji}>{emoji}</option>
});
return emojis;
};

render() {

return(
<div className="form">
<form onSubmit={this.onSubmit}>
<div>
<label className="" htmlFor="Quote">Quote</label>
<input name="text" placeholder="quote" onChange={this.onFormChange} value={this.state.text} />
</div>
<div>
<label className="" htmlFor="Emoji">Emoji</label>
<select name="emoji" value={this.state.emoji}
onChange={this.onFormChange}>
{this.emojiSelect()}
</select>
</div>
<input type="submit" name="submit" value="Add a Card" />
</form>
</div>
)
}
}

NewCardForm.propTypes = {
addCardCallback: PropTypes.func
};

export default NewCardForm;
18 changes: 18 additions & 0 deletions src/components/test/Card.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import Card from '../Card';
import { shallow } from 'enzyme';

describe('Card', () => {
test('that it matches an existing snapshot', () => {
// First Mount the Component in the testing DOM
// Arrange
const wrapper = shallow( <
Card text="text"
emoji="emoji"
id={0}
deleteCardCallback={() => {} }/>);

// Assert that it looks like the last snapshot
expect(wrapper).toMatchSnapshot();
});
});
16 changes: 16 additions & 0 deletions src/components/test/NewCardForm.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import NewCardForm from '../NewCardForm';
import { shallow } from 'enzyme';

describe('NewCardForm', () => {
test('that it matches an existing snapshot', () => {
// First Mount the Component in the testing DOM
// Arrange
const wrapper = shallow(
<NewCardForm addCardCallback={() => {} } />
);

// Assert that it looks like the last snapshot
expect(wrapper).toMatchSnapshot();
});
});
Loading