diff --git a/package-lock.json b/package-lock.json index 0d789ea1..dbb0a44c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@types/node": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.0.tgz", - "integrity": "sha512-hWzNviaVFIr1TqcRA8ou49JaSHp+Rfabmnqg2kNvusKqLhPU0rIsGPUj5WJJ7ld4Bb7qdgLmIhLfCD1qS08IVA==", + "version": "10.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.3.tgz", + "integrity": "sha512-/gwCgiI2e9RzzZTKbl+am3vgNqOt7a9fJ/uxv4SqYKxenoEDNVU3KZEadlpusWhQI0A0dOrZ0T68JYKVjzmgdQ==", "dev": true }, "abab": { @@ -2961,7 +2961,7 @@ "object.values": "1.0.4", "prop-types": "15.6.1", "react-reconciler": "0.7.0", - "react-test-renderer": "16.4.0" + "react-test-renderer": "16.4.1" } }, "enzyme-adapter-utils": { @@ -2975,6 +2975,15 @@ "prop-types": "15.6.1" } }, + "enzyme-to-json": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.3.4.tgz", + "integrity": "sha1-Z8YEDpMRgvGDQYry659DIyWKp38=", + "dev": true, + "requires": { + "lodash": "4.17.10" + } + }, "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", @@ -7399,7 +7408,7 @@ "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", "dev": true, "requires": { - "@types/node": "10.3.0" + "@types/node": "10.3.3" } }, "parseurl": { @@ -9005,9 +9014,9 @@ "integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw==" }, "react-is": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.0.tgz", - "integrity": "sha512-8ADZg/mBw+t2Fbr5Hm1K64v8q8Q6E+DprV5wQ5A8PSLW6XP0XJFMdUskVEW8efQ5oUgWHn8EYdHEPAMF0Co6hA==", + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.1.tgz", + "integrity": "sha512-xpb0PpALlFWNw/q13A+1aHeyJyLYCg0/cCHPUA43zYluZuIPHaHL3k8OBsTgQtxqW0FhyDEMvi8fZ/+7+r4OSQ==", "dev": true }, "react-reconciler": { @@ -9208,15 +9217,15 @@ } }, "react-test-renderer": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.4.0.tgz", - "integrity": "sha512-Seh1t9xFY6TKiV/hRlPzUkqX1xHOiKIMsctfU0cggo1ajsLjoIJFL520LlrxV+4/VIj+clrCeH6s/aVv/vTStg==", + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.4.1.tgz", + "integrity": "sha512-wyyiPxRZOTpKnNIgUBOB6xPLTpIzwcQMIURhZvzUqZzezvHjaGNsDPBhMac5fIY3Jf5NuKxoGvV64zDSOECPPQ==", "dev": true, "requires": { "fbjs": "0.8.16", "object-assign": "4.1.1", "prop-types": "15.6.1", - "react-is": "16.4.0" + "react-is": "16.4.1" } }, "read-pkg": { diff --git a/package.json b/package.json index ba61363d..8c570fd7 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,11 @@ "devDependencies": { "enzyme": "^3.3.0", "enzyme-adapter-react-16": "^1.1.1", + "enzyme-to-json": "^3.3.4", "gh-pages": "^1.2.0" }, + "jest": { + "snapshotSerializers": ["enzyme-to-json/serializer"] + }, "homepage": "http://adagold.github.io/inspiration-board" } diff --git a/src/App.js b/src/App.js index c4854e15..00a7ab52 100644 --- a/src/App.js +++ b/src/App.js @@ -1,17 +1,44 @@ import React, { Component } from 'react'; import './App.css'; import Board from './components/Board'; +import Status from './components/Status'; class App extends Component { + constructor() { + super(); + + this.state= { + status: { + message: 'Loaded the page', + type: 'success' + } + } + } + + updateStatus = (message, type) => { + this.setState({ + status: { + message: message, + type: type + } + }) + } + render() { return (
+ +

Inspiration Board

-
); diff --git a/src/components/Board.css b/src/components/Board.css index ba21589d..6a1e81bb 100644 --- a/src/components/Board.css +++ b/src/components/Board.css @@ -1,6 +1,7 @@ .board { display: flex; flex-wrap: wrap; + justify-content: center; } .validation-errors-display { diff --git a/src/components/Board.js b/src/components/Board.js index 9222fd88..4eaf5f87 100644 --- a/src/components/Board.js +++ b/src/components/Board.js @@ -7,6 +7,12 @@ import Card from './Card'; import NewCardForm from './NewCardForm'; import CARD_DATA from '../data/card-data.json'; +const BOARDS_URL = 'https://inspiration-board.herokuapp.com/boards/Emilce/cards'; + +const DELETE_URL = 'https://inspiration-board.herokuapp.com/boards/Emilce/cards/'; + +const CARD_URL = 'https://inspiration-board.herokuapp.com/boards/Emilce/cards'; + class Board extends Component { constructor() { super(); @@ -16,18 +22,97 @@ class Board extends Component { }; } + deleteCard = (cardId) => { + console.log( "This is card:"+ cardId); + console.log(`${DELETE_URL}${cardId}`); + axios.delete(`${DELETE_URL}${cardId}`) + .then((response) => { + console.log(response); + for (let i = 0; i < this.state.cards.length; i++) { + if (this.state.cards[i].card.id === cardId) { + this.state.cards.splice(i, 1); + this.setState({cards: this.state.cards}); + + console.log(`deleting card ${this.state.cards[i].card.id}`); + break; + } + } + + }) + .catch((error) => { + this.setState({ error: error.message }) + }) + } + + addCard = (card) => { + console.log("adding card"); + axios.post(CARD_URL, card) + .then((response) => { + console.log("THIS IS RESPONSE",response); + + let updatedCards = this.state.cards; + updatedCards.push(response.data); + + this.setState({ cards: updatedCards }); + }) + } + + componentDidMount() { + this.props.updateStatusCallback('Loading cards...', 'success'); + + axios.get(BOARDS_URL) + .then((response)=> { + console.log("getting board data"); + console.log(response); + + this.props.updateStatusCallback('Successfully loaded cards!', 'success'); + + const data = response.data.slice(0,100); + this.setState({cards: data}) + }) + .catch((error) => { + console.log(error); + // this.setState({ error: error.message}) + this.props.updateStatusCallback(error.message, 'error'); + }) + } + + render() { + const attrCards = this.state.cards + console.log("attr cards: ", attrCards); + + const cards = attrCards.map((cardInfo, index) => { + console.log("inside card mapping"); + return + }); + return ( + +
+
- Board + +
+ +
+ + { cards }
+ +
) } } Board.propTypes = { - + deleteCard: PropTypes.func.isRequired, + updateStatusCallback: PropTypes.func.isRequired }; export default Board; diff --git a/src/components/Board.test.js b/src/components/Board.test.js index e69de29b..dfd269bc 100644 --- a/src/components/Board.test.js +++ b/src/components/Board.test.js @@ -0,0 +1,35 @@ +import React from 'react'; +import Board from './Board'; +import { mount, shallow } from 'enzyme'; + +import NewCardForm from './NewCardForm'; + +describe('Board', () => { + test('shallow mount', () => { + const board = shallow( + {}} /> + ); + + expect(board).toMatchSnapshot(); + + board.unmount(); + }); + + test('render a new card form', () =>{ + const form = shallow( + + ); + expect(form).toMatchSnapshot(); + }); + + test('render a new card form', () =>{ + const form = shallow( + {}} /> + ); + + expect(form).toMatchSnapshot(); + + form.unmount(); + }); + +}); diff --git a/src/components/Card.js b/src/components/Card.js index 6788cc03..1d464d15 100644 --- a/src/components/Card.js +++ b/src/components/Card.js @@ -5,17 +5,35 @@ import emoji from 'emoji-dictionary'; import './Card.css'; class Card extends Component { + + deleteOnSubmit = (event) => { + // console.log(this.props.id); + this.props.onDeleteCard(this.props.id); + } + render() { + const emojis = this.props.emoji + return (
- Card + Card + + {this.props.id} + {this.props.text} + {emoji.getUnicode(`${emojis}`)} + + +
) } } Card.propTypes = { - + text: PropTypes.string.isRequired, + emoji: PropTypes.string }; export default Card; diff --git a/src/components/Card.test.js b/src/components/Card.test.js new file mode 100644 index 00000000..de8c69f2 --- /dev/null +++ b/src/components/Card.test.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Card from './Card'; +import { mount, shallow } from 'enzyme'; + +describe('Card', () => { + test('onClick handler working', () => { + // const textValue = 'Encouraging message'; + const onClick = jest.fn(); + const wrapper = shallow( + + ); + + expect(wrapper).toMatchSnapshot(); + + wrapper.find('button').simulate('click'); + }) +}) diff --git a/src/components/NewCardForm.css b/src/components/NewCardForm.css index d11b9ad4..d277b5e5 100644 --- a/src/components/NewCardForm.css +++ b/src/components/NewCardForm.css @@ -4,6 +4,7 @@ width: 50%; margin: auto; padding-bottom: 4rem; + background-color: lightblue; } .new-card-form__header { diff --git a/src/components/NewCardForm.js b/src/components/NewCardForm.js index 47331423..f34f6890 100644 --- a/src/components/NewCardForm.js +++ b/src/components/NewCardForm.js @@ -4,3 +4,86 @@ import emoji from 'emoji-dictionary'; import './NewCardForm.css'; const EMOJI_LIST = ["", "heart_eyes", "beer", "clap", "sparkling_heart", "heart_eyes_cat", "dog"] + +class NewCardForm extends Component { + static propTypes = { + addCardCallback: PropTypes.func.isRequired + }; + + constructor() { + super(); + + this.state = { + text: '', + emoji: '' + } + } + + onInputChange = (event) => { + // this doesn't work for multiple keys + // this.setState({ + // text: event.target.value, + // emoji: event.target.value}); + const key = event.target.name; + let value = event.target.value; + + const updatedInput= {}; + updatedInput[key] = value; + this.setState(updatedInput); + } + + onFormSubmit = (event) => { + event.preventDefault(); + console.log("on form submit"); + + this.props.addCardCallback(this.state); + + console.log(this.state); + this.setState({ + text: '', + emoji: '' + }); + console.log(this.state); + } + + render() { + const emojiList = EMOJI_LIST.map((emojiWord, index) => { + return }) + + return ( +
+ +
Add a card +
+ +
+ + +
+ +
+ + +
+ +
+
+
+ ); + } +} + +export default NewCardForm; diff --git a/src/components/NewCardForm.test.js b/src/components/NewCardForm.test.js index e69de29b..9a38a6b0 100644 --- a/src/components/NewCardForm.test.js +++ b/src/components/NewCardForm.test.js @@ -0,0 +1,15 @@ +import React from 'react'; +import NewCardForm from './NewCardForm'; +import { mount } from 'enzyme'; + +describe('NewCardForm', () => { + test('that it matches an existing snapshot', () => { + // Arrange: First Mount the Component in the testing DOM + const wrapper = mount( {} } />); + + // Asserts that looks like last snapshot + expect(wrapper).toMatchSnapshot(); + + wrapper.unmount(); + }); +}); diff --git a/src/components/Status.js b/src/components/Status.js new file mode 100644 index 00000000..cc8a0afe --- /dev/null +++ b/src/components/Status.js @@ -0,0 +1,23 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +class Status extends React.Component { + static propTypes = { + message: PropTypes.string, + type: PropTypes.string + } + render() { + let prefix = ''; + if (this.props.type === 'error') { + prefix = "There was a problem: "; + } + return ( +
+ {prefix} + {this.props.message} +
+ ); + } +} + +export default Status; diff --git a/src/components/__snapshots__/Board.test.js.snap b/src/components/__snapshots__/Board.test.js.snap new file mode 100644 index 00000000..eb5a2ace --- /dev/null +++ b/src/components/__snapshots__/Board.test.js.snap @@ -0,0 +1,192 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Board render a new card form 1`] = ` +
+
+ Add a card +
+
+ + +
+
+ + +
+
+ +
+
+`; + +exports[`Board render a new card form 2`] = ` +
+
+ Add a card +
+
+ + +
+
+ + +
+
+ +
+
+`; + +exports[`Board shallow mount 1`] = ` +
+
+ +
+
+
+`; diff --git a/src/components/__snapshots__/Card.test.js.snap b/src/components/__snapshots__/Card.test.js.snap new file mode 100644 index 00000000..ed74262c --- /dev/null +++ b/src/components/__snapshots__/Card.test.js.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Card onClick handler working 1`] = ` +