diff --git a/index.html b/index.html
index 508ebb3d..16820611 100644
--- a/index.html
+++ b/index.html
@@ -101,19 +101,16 @@
* ...
* ]
*/
- function getPersonList() {
- return new Promise((resolve, reject) => {
- fetch('https://willowtreeapps.com/api/v1.0/profiles')
- .then(response => {
- if (response.status !== 200) {
- reject(new Error("Error!"));
- }
+ async function getPersonList() {
+ let response = await fetch('https://willowtreeapps.com/api/v1.0/profiles');
- response.json().then(imageList => {
- resolve(imageList);
- });
- });
- });
+ if(response.status !== 200) {
+ throw new Error("Error!");
+ }
+
+ let data = await response.json();
+
+ return data;
}
@@ -125,16 +122,21 @@
function getLastName(person) {
- return person.lastName;
+ return person.lastName.trim();
}
const getFirstName = (person) => {
- return person.firstName;
+ return person.firstName.trim();
};
// headshot URLs are scheme relative //
// prepend http: to prevent invalid schemes like file:// or uri://
+ // instead return null if the person does not have a headshot url defined
const getImageUrl = (person) => {
+ if(person.headshot.url === undefined) {
+ return null;
+ }
+
return `http:${person.headshot.url}`;
};
@@ -143,15 +145,15 @@
*/
function shuffleList(list) {
// Make a copy & don't mutate the passed in list
- let result = list.slice(1);
+ let result = list.slice();
- let tmp, j, i = list.length - 1
+ let tmp, j, i = result.length - 1
for (; i > 0; i -= 1) {
j = Math.floor(Math.random() * (i + 1));
- tmp = list[i];
- list[i] = list[j];
- list[j] = tmp;
+ tmp = result[i];
+ result[i] = result[j];
+ result[j] = tmp;
}
return result;
@@ -159,15 +161,55 @@
/**
- * Remove any people that do not have the name we are
- * searching for.
+ * Get all the words from a phrase string.
+ */
+ function getWords(phrase) {
+ let words = [];
+ let cleanedPhrase = phrase.replace(/[\s]+/g, ' ').trim();
+
+ if(phrase.length === 0 || cleanedPhrase === '') {
+ return words;
+ }
+
+ words = cleanedPhrase.split(' ');
+ return words;
+ }
+
+ /**
+ * Remove any people that do not have a name that
+ * contains one or more words from our search string.
*/
function filterByName(searchForName, personList) {
+ // Get each word from the search query.
+ const searchTerms = getWords(searchForName);
+
+ // Filter our list of people...
return personList.filter((person) => {
- return person.firstName === searchForName || person.lastName === searchForName;
+ // If there are no search terms, return everyone in our list.
+ if(searchTerms.length === 0) {
+ return true;
+ }
+
+ // Make sure that one or more search term is found inside
+ return searchTerms.some((searchTerm) => {
+ // Transform our search term into lowercase.
+ searchTerm = searchTerm.trim().toLowerCase();
+
+ // Check if the first name or last name contains our search term.
+ return getFirstName(person).toLowerCase().indexOf(searchTerm) !== -1 ||
+ getLastName(person).toLowerCase().indexOf(searchTerm) !== -1;
+ });
});
}
+ /**
+ * Toggle the value passed in using the following rules:
+ * 1. If the current value is null, switch the value to true.
+ * 2. Otherwise, switch the value to !value.
+ */
+ function toggleBool(currentBool) {
+ return currentBool === null ? true : !currentBool;
+ }
/**
* Takes in a property of an object list, e.g. "name" below
@@ -177,29 +219,38 @@
* And returns a function that will sort that list, e.g.
*
* const sortPeopleByName = sortObjListByProp('name');
- * const sortedPeople = sortPeopleByName(people);
+ * const sortedPeople = sortPeopleByName(people, true);
*
* We now have:
*
* console.log(sortedPeople)
* > [{ name: 'Jon' }, { name: 'Kevin' }, { name: 'Sam' }]
*
+ * You may also sort the list backwards, e.g.
+ *
+ * const sortPeopleByName = sortObjListByProp('name');
+ * const sortedPeopleBackwards = sortPeopleByName(people, false);
+ *
+ * We now have:
+ *
+ * console.log(sortedPeopleBackwards)
+ * > [{ name: 'Sam' }, { name: 'Kevin' }, { name: 'Jon' }]
*/
function sortObjListByProp(prop) {
- return function(objList) {
+ return function(objList, forward) {
// Make a copy & don't mutate the passed in list
- let result = objList.slice(1);
+ let result = objList.slice();
result.sort((a, b) => {
if (a[prop] < b[prop]) {
- return -1;
+ return forward ? -1 : 1;
}
if (a[prop] > b[prop]) {
- return 1;
+ return forward ? 1 : -1;
}
- return 1;
+ return 0;
});
return result;
@@ -208,7 +259,7 @@
const sortByFirstName = sortObjListByProp('firstName');
- const sortByLastName = (personList) => sortByFirstName(personList).reverse();
+ const sortByLastName = sortObjListByProp('lastName');
/*==================================================
@@ -227,11 +278,21 @@
src: props.src
});
- const ListRow = (props) => React.DOM.tr({ key: `${props.person.firstName} ${props.person.lastName}` }, [
- React.DOM.td({ key: 'thumb' }, React.createElement(Thumbnail, { src: getImageUrl(props.person) })),
- React.DOM.td({ key: 'first' }, null, getFirstName(props.person)),
- React.DOM.td({ key: 'last' }, null, getLastName(props.person)),
- ]);
+ const NotPictured = (props) => React.DOM.span({
+ className: 'not-pictured',
+ children: 'Not Pictured'
+ });
+
+ const ListRow = (props) => {
+ const imageUrl = getImageUrl(props.person);
+ const imageElement = imageUrl === null ? NotPictured : Thumbnail;
+
+ return React.DOM.tr({ key: `${props.person.firstName} ${props.person.lastName}` }, [
+ React.DOM.td({ key: 'thumb' }, React.createElement(imageElement, { src: imageUrl })),
+ React.DOM.td({ key: 'first' }, null, getFirstName(props.person)),
+ React.DOM.td({ key: 'last' }, null, getLastName(props.person)),
+ ]);
+ };
const ListContainer = (props) => React.DOM.table({ className: 'list-container' }, [
React.DOM.thead({ key: 'thead' }, React.DOM.tr({}, [
@@ -247,7 +308,10 @@
getInitialState() {
return {
personList: [],
- visiblePersonList: []
+ visiblePersonList: [],
+ sortFirstForward: null,
+ sortLastForward: null,
+ searchQuery: ''
};
},
@@ -260,38 +324,51 @@
},
_shuffleList() {
+ const searchResults = filterByName(this.state.searchQuery, this.state.personList);
+
this.setState({
- visiblePersonList: shuffleList(this.state.personList)
+ visiblePersonList: shuffleList(searchResults)
});
},
_sortByFirst() {
+ const searchResults = filterByName(this.state.searchQuery, this.state.personList);
+
+ const newSortFirstForward = toggleBool(this.state.sortFirstForward);
+
this.setState({
- visiblePersonList: sortByFirstName(this.state.personList)
+ sortFirstForward: newSortFirstForward,
+ sortLastForward: null,
+ visiblePersonList: sortByFirstName(searchResults, newSortFirstForward)
});
},
_sortByLast() {
+ const searchResults = filterByName(this.state.searchQuery, this.state.personList);
+
+ const newSortLastForward = toggleBool(this.state.sortLastForward);
+
this.setState({
- visiblePersonList: sortByLastName(this.state.personList)
+ sortFirstForward: null,
+ sortLastForward: newSortLastForward,
+ visiblePersonList: sortByLastName(searchResults, newSortLastForward)
});
},
_onSearch(e) {
this.setState({
+ searchQuery: e.target.value,
visiblePersonList: filterByName(e.target.value, this.state.personList)
});
},
render() {
- const { visiblePersonList } = this.state;
-
return React.DOM.div({ className: 'app-container' }, [
React.createElement(Search, { key: 'search', onChange: this._onSearch }),
React.DOM.button({ key: 'shuffle', onClick: this._shuffleList }, null, 'Shuffle'),
React.DOM.button({ key: 'sort-first', onClick: this._sortByFirst }, null, 'Sort (First Name)'),
React.DOM.button({ key: 'sort-last', onClick: this._sortByLast }, null, 'Sort (Last Name)'),
- React.createElement(ListContainer, { key: 'list', personList: visiblePersonList })
+ React.createElement(ListContainer, { key: 'list', personList: this.state.visiblePersonList })
]);
}
});