diff --git a/package-lock.json b/package-lock.json index cd16608..68921b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,11 @@ "integrity": "sha512-LAQ1d4OPfSJ/BMbI2DuizmYrrkD9JMaTdi2hQTlI53lQ4kRQPyZQRS4CYQ7O66bnBBnP/oYdRxbk++X0xuFU6A==", "dev": true }, + "@types/node": { + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.4.tgz", + "integrity": "sha512-8TqvB0ReZWwtcd3LXq3YSrBoLyXFgBX/sBZfGye9+YS8zH7/g+i6QRIuiDmwBoTzcQ/pk89nZYTYU4c5akKkzw==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -4925,6 +4930,14 @@ "json-parse-better-errors": "1.0.2" } }, + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "requires": { + "@types/node": "10.5.4" + } + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -5853,6 +5866,11 @@ "prop-types": "15.6.2" } }, + "react-attr-converter": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/react-attr-converter/-/react-attr-converter-0.3.1.tgz", + "integrity": "sha512-dSxo2Mn6Zx4HajeCeQNLefwEO4kNtV/0E682R1+ZTyFRPqxDa5zYb5qM/ocqw9Bxr/kFQO0IUiqdV7wdHw+Cdg==" + }, "react-dom": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz", @@ -5864,6 +5882,15 @@ "prop-types": "15.6.2" } }, + "react-render-html": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-render-html/-/react-render-html-0.6.0.tgz", + "integrity": "sha512-F9Xn8Iy2oJvepMdDrN+XUPOwqv3ni856ikuvu/dyJ2guozN01vF0C55Ja+CQfnziQNlLevSVXzuQKYa/mhyjAQ==", + "requires": { + "parse5": "3.0.3", + "react-attr-converter": "0.3.1" + } + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", diff --git a/package.json b/package.json index e975d47..3903f39 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "axios": "^0.18.0", "react": "^16.4.1", "react-dom": "^16.4.1", + "react-render-html": "^0.6.0", "vex-js": "^4.1.0" }, "devDependencies": { diff --git a/src/app/PawnedListItem.css b/src/app/PawnedListItem.css new file mode 100644 index 0000000..fdcaaf3 --- /dev/null +++ b/src/app/PawnedListItem.css @@ -0,0 +1,18 @@ + +.breach-name { + font-size: 19px; + color: red; + font-weight: bold; +} + + +.breach-description a{ + color: #565656; + font-weight: bold; +} + + + +.breach { + padding-bottom: 10px; +} diff --git a/src/app/PawnedListItem.js b/src/app/PawnedListItem.js index cf275e1..da537fd 100644 --- a/src/app/PawnedListItem.js +++ b/src/app/PawnedListItem.js @@ -1,16 +1,23 @@ -import React,{Component} from 'react'; +import React, { Component } from 'react'; +import renderHTML from 'react-render-html'; +import './PawnedListItem.css'; +export default class PawnedListItem extends Component { -export default class PawnedListItem extends Component{ - - constructor(props){ + constructor(props) { super(props); } - render(){ - return( -
- {this.props.breach.Description} -
+ render() { + return ( +
+
+ {this.props.breach.Domain} +
+
+ {renderHTML(this.props.breach.Description)} +
+ +
) } } \ No newline at end of file diff --git a/src/app/SearchField.css b/src/app/SearchField.css new file mode 100644 index 0000000..72cf5aa --- /dev/null +++ b/src/app/SearchField.css @@ -0,0 +1,75 @@ +.searchWrapper{ + display: flex; + width: 500px; + justify-content: center; + align-items: center; + flex-direction: column +} + +.search{ + +} + +.title{ + font-size: 45px; +} + +.check-button{ + height: 52px; + padding-bottom: 7px; + margin-left: 11px; +} + +.display-message{ + padding-top: 13px; +} + +.safe-message{ + color: green; +} + +.not-safe-message{ + color: #ff4a4a; +} + +.searchResults { + padding-top: 21px; + max-height: 400px; + overflow: auto; + margin: 0 .4rem; +} + +.searchResults div{margin: 5px 0} + +.search .email-field{ + border: 1px solid #000; + height: 46px; + width: 375px; + font-family: RMTyperighter; + font-size: 18px; + padding: 3px; +} + +.hover-field { + text-decoration: none +} +.hover-field:hover { + position: relative +} +.hover-field span { + display: none; + font-size: 12px; + color: #000; +} +.hover-field:hover span { + border: #8f8e8e 1px solid; + padding: 5px 20px 5px 5px; + display: block; + z-index: 100; + left: -6px; + margin: 10px; + width: 250px; + position: absolute; + top: -46px; + text-decoration: none; +} \ No newline at end of file diff --git a/src/app/SearchField.js b/src/app/SearchField.js index 2a43cd3..9fb5a01 100644 --- a/src/app/SearchField.js +++ b/src/app/SearchField.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import axios from 'axios'; import PawnedListItem from './PawnedListItem'; +import './SearchField.css'; export default class SearchField extends Component { @@ -8,34 +9,48 @@ export default class SearchField extends Component { super(props); this.state = { isPawnedEmail: '', - pawnedList: [] + pawnedList: [], + intiated: false, + displayMessage: '', + displayMessageStyle: '' }; this.onFocus = this.onFocus.bind(this); this.onBlur = this.onBlur.bind(this); this.checkIsPawned = this.checkIsPawned.bind(this); - this.videoItems = []; + this.breachItems = []; + this.displayMessage; } render() { if (this.state.pawnedList.length > 0) { - this.videoItems = this.state.pawnedList.map((breach) => { + this.breachItems = this.state.pawnedList.map((breach) => { return }); + } else { + this.breachItems = []; } return (
- +
- this.setState({ isPawnedEmail: event.target.value })} required onFocus={this.onFocus} onBlur={this.onBlur} /> - + { if (event.key == 'Enter') this.checkIsPawned.call() }} onChange={(event) => this.setState({ isPawnedEmail: event.target.value })} required onFocus={this.onFocus} onBlur={this.onBlur} /> + +
+
+ {this.state.displayMessage}
- {this.videoItems} + {this.breachItems}
); @@ -55,17 +70,29 @@ export default class SearchField extends Component { checkIsPawned() { // axios.get() + this.setState({ + intiated: true + }); console.log(this.state.isPawnedEmail) axios({ method: 'get', url: `https://haveibeenpwned.com/api/v2/breachedaccount/${this.state.isPawnedEmail}` }).then((response) => { - console.log(response); + const breachList = response.data; this.setState({ - pawnedList: response.data - }) + pawnedList: response.data, + displayMessage: `Your email address is Pawned on ${breachList.length} websites`, + displayMessageStyle: 'not-safe-message' + }); }).catch((error) => { console.log('Error ', error); + if (error.response.status === 404) { + this.setState({ + displayMessage: `You are safe now.`, + displayMessageStyle: 'safe-message', + pawnedList: [] + }); + } }) } } \ No newline at end of file diff --git a/src/css/style.css b/src/css/style.css index 1c549f4..4edbd94 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -48,38 +48,3 @@ footer,header { padding: .75em 2em; cursor: pointer; } -.searchWrapper{ - display: flex; - width: 500px; - justify-content: center; - align-items: center; - flex-direction: column -} -.search{ - -} -.searchResults { - padding-top: 21px; - max-height: 400px; - overflow: auto; - margin: 0 .4rem; -} -.searchResults div{margin: 5px 0} -.search .email-field{ - border: 1px solid #000; - height: 46px; - width: 375px; - font-family: RMTyperighter; - font-size: 18px; - padding: 3px; -} - -.check-button{ - height: 52px; - padding-bottom: 7px; - margin-left: 11px; -} - -.title{ - font-size: 45px; -} \ No newline at end of file