├── .gitignore ├── advanced-array-methods ├── filter │ ├── filter-exercises.js │ ├── index.html │ └── spec │ │ └── filter.spec.js ├── forEach │ ├── forEach-exercises.js │ ├── index.html │ └── spec │ │ └── forEach.spec.js ├── map │ ├── index.html │ ├── map-exercises.js │ └── spec │ │ └── map.spec.js ├── reduce │ ├── index.html │ ├── reduce-exercises.js │ └── spec │ │ └── reduce.spec.js └── some-every │ ├── index.html │ ├── some-every-exercises.js │ └── spec │ └── some-every.spec.js ├── closures-and-keyword-this ├── call-apply-bind │ ├── call-apply-bind-exercises.js │ ├── index.html │ └── spec │ │ └── call-apply-bind.spec.js └── closures │ ├── closures-exercises.js │ ├── index.html │ └── spec │ └── closures.spec.js ├── css-project ├── 01-starter-code │ ├── assets │ │ ├── css │ │ │ └── styles.css │ │ └── img │ │ │ ├── main.jpg │ │ │ ├── mountain1.jpg │ │ │ ├── mountain2.jpg │ │ │ ├── mountain3.jpg │ │ │ └── mountain4.jpg │ └── index.html ├── 02-nav-and-header │ ├── assets │ │ ├── css │ │ │ └── styles.css │ │ └── img │ │ │ ├── main.jpg │ │ │ ├── mountain1.jpg │ │ │ ├── mountain2.jpg │ │ │ ├── mountain3.jpg │ │ │ └── mountain4.jpg │ └── index.html ├── 03-destinations-and-features │ ├── assets │ │ ├── css │ │ │ └── styles.css │ │ └── img │ │ │ ├── main.jpg │ │ │ ├── mountain1.jpg │ │ │ ├── mountain2.jpg │ │ │ ├── mountain3.jpg │ │ │ └── mountain4.jpg │ └── index.html ├── 04-testimonials-contact-footer │ ├── assets │ │ ├── css │ │ │ └── styles.css │ │ └── img │ │ │ ├── main.jpg │ │ │ ├── mountain1.jpg │ │ │ ├── mountain2.jpg │ │ │ ├── mountain3.jpg │ │ │ └── mountain4.jpg │ └── index.html └── 05-responsive-design │ ├── assets │ ├── css │ │ └── styles.css │ └── img │ │ ├── main.jpg │ │ ├── mountain1.jpg │ │ ├── mountain2.jpg │ │ ├── mountain3.jpg │ │ └── mountain4.jpg │ └── index.html ├── es2015-16-17-part-1 ├── arrow-functions │ ├── arrow-functions-exercises.js │ ├── index.html │ └── spec │ │ └── es2015-part1-spec.js ├── destructuring │ ├── destructuring-exercises.js │ ├── index.html │ └── spec │ │ └── es2015-part1-spec.js └── rest-spread │ ├── index.html │ ├── rest-spread-exercises.js │ └── spec │ └── es2015-part1-spec.js ├── es2015-16-17-part-2 ├── class-keyword │ ├── class-keyword-exercises.js │ ├── index.html │ └── spec │ │ └── es2015-part-2.spec.js ├── es2015-inheritance │ ├── es2015-inheritance-exercises.js │ ├── index.html │ └── spec │ │ └── es2015-part-2.spec.js ├── es2015-methods │ ├── es2015-methods-exercises.js │ ├── index.html │ └── spec │ │ └── es2015-part-2.spec.js ├── maps-sets │ ├── index.html │ ├── maps-sets-exercises.js │ └── spec │ │ └── es2015-part-2.spec.js └── promises │ ├── index.html │ ├── promises-exercises.js │ └── spec │ └── es2015-part-2.spec.js ├── es2016-and-2017 └── async-functions │ ├── async-functions-exercises.js │ ├── index.html │ └── spec │ └── es2015-part-2.spec.js ├── object-oriented-programming ├── constructors │ ├── constructors-exercises.js │ ├── index.html │ └── spec │ │ └── oop.spec.js ├── inheritance │ ├── index.html │ ├── inheritance-exercises.js │ └── spec │ │ └── oop.spec.js └── prototypes │ ├── index.html │ ├── prototypes-exercises.js │ └── spec │ └── oop.spec.js ├── react ├── flags │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── CountryGame.js │ │ ├── FlagAnswer.css │ │ ├── FlagAnswer.js │ │ ├── FlagChoices.css │ │ ├── FlagChoices.js │ │ ├── FlagQuestion.css │ │ ├── FlagQuestion.js │ │ ├── StyledButton.js │ │ ├── index.css │ │ ├── index.js │ │ ├── registerServiceWorker.js │ │ └── world.jpg ├── hacker-news │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ └── registerServiceWorker.js ├── helloworld │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── HobbyList.js │ │ ├── Pet.css │ │ ├── Pet.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js ├── memory-game │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ └── src │ │ ├── Card.css │ │ ├── Card.js │ │ ├── MemoryGame.js │ │ ├── Navbar.css │ │ ├── Navbar.js │ │ ├── index.css │ │ └── index.js ├── pass-state-to-props-demo │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js ├── random-boxes-solution │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ └── registerServiceWorker.js ├── random-boxes-starter │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ └── registerServiceWorker.js ├── react-router-senators │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── Main.js │ │ ├── Navbar.css │ │ ├── Navbar.js │ │ ├── SenatorDetails.js │ │ ├── SenatorList.js │ │ ├── index.css │ │ ├── index.js │ │ ├── registerServiceWorker.js │ │ └── senators.js ├── recipe-props-solution │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── avocado_toast.jpg │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── manifest.json │ │ ├── milkshake.jpg │ │ └── spaghetti.jpg │ └── src │ │ ├── App.test.js │ │ ├── Navbar.css │ │ ├── Navbar.js │ │ ├── Recipe.css │ │ ├── Recipe.js │ │ ├── RecipeApp.css │ │ ├── RecipeApp.js │ │ ├── RecipeList.css │ │ ├── RecipeList.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js ├── recipe-props-starter │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── manifest.json │ │ └── spaghetti.jpg │ └── src │ │ ├── App.test.js │ │ ├── Recipe.css │ │ ├── Recipe.js │ │ ├── RecipeApp.css │ │ ├── RecipeApp.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js ├── recipe-redux-single-folder │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── avocado_toast.jpg │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── manifest.json │ │ ├── milkshake.jpg │ │ └── spaghetti.jpg │ └── src │ │ ├── Navbar.css │ │ ├── Navbar.js │ │ ├── Recipe.css │ │ ├── Recipe.js │ │ ├── RecipeApp.css │ │ ├── RecipeApp.js │ │ ├── RecipeInput.css │ │ ├── RecipeInput.js │ │ ├── RecipeList.css │ │ ├── RecipeList.js │ │ ├── images │ │ └── spaghetti.jpg │ │ ├── index.css │ │ ├── index.js │ │ ├── reducers.js │ │ └── registerServiceWorker.js ├── recipe-with-state │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── avocado_toast.jpg │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── manifest.json │ │ ├── milkshake.jpg │ │ └── spaghetti.jpg │ └── src │ │ ├── App.test.js │ │ ├── Navbar.css │ │ ├── Navbar.js │ │ ├── Recipe.css │ │ ├── Recipe.js │ │ ├── RecipeApp.css │ │ ├── RecipeApp.js │ │ ├── RecipeInput.css │ │ ├── RecipeInput.js │ │ ├── RecipeList.css │ │ ├── RecipeList.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js ├── redux-async │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── index.html │ └── src │ │ ├── actions │ │ └── index.js │ │ ├── components │ │ ├── Picker.js │ │ └── Posts.js │ │ ├── containers │ │ └── App.js │ │ ├── index.js │ │ └── reducers │ │ └── index.js ├── redux-todos │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── index.html │ └── src │ │ ├── actions │ │ ├── index.js │ │ └── index.spec.js │ │ ├── components │ │ ├── App.js │ │ ├── Footer.js │ │ ├── Link.js │ │ ├── Todo.js │ │ └── TodoList.js │ │ ├── containers │ │ ├── AddTodo.js │ │ ├── FilterLink.js │ │ └── VisibleTodoList.js │ │ ├── index.js │ │ └── reducers │ │ ├── index.js │ │ ├── todos.js │ │ ├── todos.spec.js │ │ └── visibilityFilter.js ├── routing-demo │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── SwitchDemo.js │ │ ├── index.css │ │ ├── index.js │ │ └── registerServiceWorker.js ├── simple-todo │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ └── registerServiceWorker.js ├── update-complex-state-solution │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js ├── update-complex-state │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js ├── warbler-solution │ ├── .gitignore │ ├── warbler-client │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ └── manifest.json │ │ └── src │ │ │ ├── actions │ │ │ └── index.js │ │ │ ├── components │ │ │ ├── AuthForm.css │ │ │ ├── AuthForm.js │ │ │ ├── Homepage.js │ │ │ ├── MessageForm.js │ │ │ ├── MessageItem.css │ │ │ ├── MessageItem.js │ │ │ ├── MessageList.js │ │ │ ├── MessageTimeline.js │ │ │ ├── Navbar.css │ │ │ ├── Navbar.js │ │ │ ├── PrivateRoute.js │ │ │ ├── UserAside.css │ │ │ └── UserAside.js │ │ │ ├── containers │ │ │ ├── App.js │ │ │ ├── Main.js │ │ │ └── Warbler.js │ │ │ ├── images │ │ │ ├── default-profile-image.jpg │ │ │ ├── warbler-hero.jpg │ │ │ └── warbler-logo.png │ │ │ ├── index.css │ │ │ ├── index.js │ │ │ ├── reducers │ │ │ ├── currentUser.js │ │ │ ├── index.js │ │ │ └── messages.js │ │ │ └── registerServiceWorker.js │ └── warbler-server │ │ ├── .env │ │ ├── README.md │ │ ├── helpers │ │ ├── auth.js │ │ └── messages.js │ │ ├── index.js │ │ ├── loadData.js │ │ ├── middleware │ │ └── auth.js │ │ ├── models │ │ ├── index.js │ │ ├── message.js │ │ └── user.js │ │ ├── package-lock.json │ │ ├── package.json │ │ └── routes │ │ ├── auth.js │ │ └── messages.js ├── warbler-starter-server │ ├── .env │ ├── README.md │ ├── helpers │ │ ├── auth.js │ │ └── messages.js │ ├── index.js │ ├── loadData.js │ ├── middleware │ │ └── auth.js │ ├── models │ │ ├── index.js │ │ ├── message.js │ │ └── user.js │ ├── package-lock.json │ ├── package.json │ └── routes │ │ ├── auth.js │ │ └── messages.js └── warbler │ ├── warbler-client │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js │ └── warbler-server │ ├── .env │ ├── README.md │ ├── helpers │ ├── auth.js │ └── messages.js │ ├── index.js │ ├── loadData.js │ ├── middleware │ └── auth.js │ ├── models │ ├── index.js │ ├── message.js │ └── user.js │ ├── package-lock.json │ ├── package.json │ └── routes │ ├── auth.js │ └── messages.js ├── readme.md └── todos_api ├── helpers └── todos.js ├── index.js ├── models ├── index.js └── todo.js ├── package-lock.json ├── package.json ├── public ├── app.css └── app.js ├── routes └── todos.js └── views └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /advanced-array-methods/filter/filter-exercises.js: -------------------------------------------------------------------------------- 1 | // filter 2 | 3 | function filterByValue(arr,key){ 4 | return arr.filter(function(val){ 5 | return val[key] !== undefined; 6 | }); 7 | } 8 | 9 | function find(arr, searchValue){ 10 | return arr.filter(function(val){ 11 | return val === searchValue 12 | })[0]; 13 | } 14 | 15 | function findInObj(arr, key, searchValue){ 16 | return arr.filter(function(val){ 17 | return val[key] === searchValue; 18 | })[0]; 19 | } 20 | 21 | function removeVowels(str){ 22 | var vowels = "aeiou" 23 | return str.toLowerCase().split("").filter(function(val){ 24 | return vowels.indexOf(val) === -1; 25 | }).join('') 26 | } 27 | 28 | function doubleOddNumbers(arr){ 29 | return arr.filter(function(val){ 30 | return val % 2 !== 0; 31 | }).map(function(val){ 32 | return val *2; 33 | }) 34 | } -------------------------------------------------------------------------------- /advanced-array-methods/filter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /advanced-array-methods/forEach/forEach-exercises.js: -------------------------------------------------------------------------------- 1 | // forEach 2 | 3 | function doubleValues(arr){ 4 | var newArr = []; 5 | arr.forEach(function(val){ 6 | newArr.push(val * 2) 7 | }) 8 | return newArr; 9 | } 10 | 11 | function onlyEvenValues(arr){ 12 | var newArr = []; 13 | arr.forEach(function(val){ 14 | if(val % 2 === 0){ 15 | newArr.push(val) 16 | } 17 | }) 18 | return newArr; 19 | } 20 | 21 | function showFirstAndLast(arr){ 22 | var newArr = []; 23 | arr.forEach(function(val){ 24 | newArr.push(val[0] + val[val.length-1]) 25 | }); 26 | return newArr; 27 | } 28 | 29 | function addKeyAndValue(arr,key,value){ 30 | arr.forEach(function(val){ 31 | val[key] = value; 32 | }); 33 | return arr; 34 | } 35 | 36 | function vowelCount(str){ 37 | var splitArr = str.toLowerCase().split(""); 38 | var obj = {}; 39 | var vowels = "aeiou"; 40 | 41 | splitArr.forEach(function(letter){ 42 | if(vowels.indexOf(letter) !== -1){ 43 | if(obj[letter]){ 44 | obj[letter]++; 45 | } else{ 46 | obj[letter] = 1; 47 | } 48 | } 49 | }); 50 | return obj; 51 | } 52 | -------------------------------------------------------------------------------- /advanced-array-methods/forEach/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /advanced-array-methods/map/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /advanced-array-methods/map/map-exercises.js: -------------------------------------------------------------------------------- 1 | function doubleValues(arr){ 2 | return arr.map(function(val){ 3 | return val * 2 4 | }); 5 | } 6 | 7 | function valTimesIndex(arr){ 8 | return arr.map(function(val,idx){ 9 | return val*idx; 10 | }) 11 | } 12 | 13 | function extractValue(arr,key){ 14 | return arr.map(function(val){ 15 | return val[key]; 16 | }); 17 | } 18 | 19 | function extractFullName(arr){ 20 | return arr.map(function(val){ 21 | return val.first + " " + val.last; 22 | }); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /advanced-array-methods/map/spec/map.spec.js: -------------------------------------------------------------------------------- 1 | // map Exercises 2 | 3 | describe("#doubleValues", function(){ 4 | it("doubles values in an array", function(){ 5 | expect(doubleValues([1,2,3])).toEqual([2,4,6]) 6 | }); 7 | it("works for negative numbers", function(){ 8 | expect(doubleValues([1,-2,-3])).toEqual([2,-4,-6]) 9 | }); 10 | }); 11 | 12 | describe("#valTimesIndex", function(){ 13 | it("returns a new array with each value multiplied by the index", function(){ 14 | expect(valTimesIndex([1,2,3])).toEqual([0,2,6]) 15 | }); 16 | it("works for negative numbers", function(){ 17 | expect(valTimesIndex([1,-2,-3])).toEqual([0,-2,-6]) 18 | }); 19 | }); 20 | 21 | describe("#extractValue", function(){ 22 | it("returns a new array with the value of each key in an array objects", function(){ 23 | var arr = [{name: 'Elie'}, {name: 'Tim'}, {name: 'Matt'}, {name: 'Colt'}] 24 | expect(extractValue(arr,'name')).toEqual(['Elie', 'Tim', 'Matt', 'Colt']) 25 | }); 26 | }); 27 | 28 | describe("#extractFulName", function(){ 29 | var arr = [{first: 'Elie', last:"Schoppik"}, {first: 'Tim', last:"Garcia"}, {first: 'Matt', last:"Lane"}, {first: 'Colt', last:"Steele"}] 30 | it("returns a new array with the value of each key in an array objects", function(){ 31 | expect(extractFullName(arr,'name')).toEqual(['Elie Schoppik', 'Tim Garcia', 'Matt Lane', 'Colt Steele']) 32 | }); 33 | }); -------------------------------------------------------------------------------- /advanced-array-methods/reduce/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /advanced-array-methods/reduce/reduce-exercises.js: -------------------------------------------------------------------------------- 1 | function extractValue(arr, key){ 2 | return arr.reduce(function(acc,next){ 3 | acc.push(next[key]); 4 | return acc; 5 | },[]); 6 | } 7 | 8 | function vowelCount(str){ 9 | var vowels = "aeiou"; 10 | return str.toLowerCase().split('').reduce(function(acc,next){ 11 | if(vowels.indexOf(next) !== -1){ 12 | if(acc[next]){ 13 | acc[next]++; 14 | } else { 15 | acc[next] = 1; 16 | } 17 | } 18 | return acc; 19 | }, {}); 20 | } 21 | 22 | function addKeyAndValue(arr, key, value){ 23 | return arr.reduce(function(acc,next,idx){ 24 | acc[idx][key] = value; 25 | return acc; 26 | },arr); 27 | } 28 | 29 | function partition(arr, callback){ 30 | return arr.reduce(function(acc,next){ 31 | if(callback(next)){ 32 | acc[0].push(next); 33 | } else { 34 | acc[1].push(next); 35 | } 36 | return acc; 37 | }, [[],[]]); 38 | } -------------------------------------------------------------------------------- /advanced-array-methods/some-every/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /advanced-array-methods/some-every/some-every-exercises.js: -------------------------------------------------------------------------------- 1 | function hasOddNumber(arr){ 2 | return arr.some(function(val){ 3 | return val % 2 !== 0; 4 | }) 5 | } 6 | 7 | function hasAZero(num){ 8 | return num.toString().split('').some(function(val){ 9 | return val === '0'; 10 | }) 11 | } 12 | 13 | function hasOnlyOddNumbers(arr){ 14 | return arr.every(function(val){ 15 | return val % 2 !== 0; 16 | }) 17 | } 18 | 19 | function hasNoDuplicates(arr){ 20 | return arr.every(function(val){ 21 | return arr.indexOf(val) === arr.lastIndexOf(val) 22 | }) 23 | } 24 | 25 | function hasCertainKey(arr, key){ 26 | return arr.every(function(val){ 27 | return key in val 28 | }) 29 | } 30 | 31 | function hasCertainValue(arr, key, searchValue){ 32 | return arr.every(function(val){ 33 | return val[key] === searchValue; 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /closures-and-keyword-this/call-apply-bind/call-apply-bind-exercises.js: -------------------------------------------------------------------------------- 1 | // https://github.com/rithmschool/intermediate_javascript_exercises/blob/master/call_apply_bind_exercise/callApplyBindSpec.js 2 | 3 | function arrayFrom(arrayLikeObject) {} 4 | 5 | function sumEvenArguments() {} 6 | 7 | // Write a function called sumEvenArguments which takes all of the arguments passed to a function and returns the sum of the even ones. 8 | 9 | // sumEvenArguments(1,2,3,4) // 6 10 | // sumEvenArguments(1,2,6) // 8 11 | // sumEvenArguments(1,2) // 2 12 | 13 | // // Write a function called invokeMax which accepts a function and a maximum amount. invokeMax should return a function that when called increments a counter. If the counter is greater than the maximum amount, the inner function should return "Maxed Out" 14 | 15 | // var addOnlyThreeTimes = invokeMax(add,3); 16 | // addOnlyThreeTimes(1,2) // 3 17 | // addOnlyThreeTimes(2,2) // 4 18 | // addOnlyThreeTimes(1,2) // 3 19 | // addOnlyThreeTimes(1,2) // "Maxed Out!" 20 | 21 | function add(a, b) { 22 | return a + b; 23 | } 24 | 25 | function invokeMax(fn, num) {} 26 | 27 | function once(fn, thisArg) {} 28 | 29 | function bind(fn, thisArg) {} 30 | 31 | // BONUS! 32 | function flip(fn, thisArg) {} 33 | -------------------------------------------------------------------------------- /closures-and-keyword-this/call-apply-bind/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /closures-and-keyword-this/closures/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /closures-and-keyword-this/closures/spec/closures.spec.js: -------------------------------------------------------------------------------- 1 | // closures 2 | 3 | describe("#specialMultiply", function(){ 4 | it("returns a function if only one parameter is passed", function(){ 5 | expect(specialMultiply(1)).toEqual(jasmine.any(Function)) 6 | }); 7 | it("returns a function if only one parameter is passed that can be invoked with a second parameter", function(){ 8 | var m = specialMultiply(1) 9 | expect(specialMultiply(1)).toEqual(jasmine.any(Function)) 10 | expect(m(3)).toEqual(3) 11 | }); 12 | it("returns a the product of two numbers if two parameters are passed", function(){ 13 | expect(specialMultiply(1)(3)).toEqual(3) 14 | }); 15 | }); 16 | 17 | describe("#guessingGame", function(){ 18 | it("returns a function", function(){ 19 | expect(guessingGame(1)).toEqual(jasmine.any(Function)) 20 | }); 21 | it("stops you from guessing once you have gotten the answer", function(){ 22 | var g = guessingGame(10) 23 | g(0), g(1), g(2), g(3), g(4), g(5), g(6), g(7), g(8), g(9), g(10) 24 | expect(g(10)).toEqual("All done playing!") 25 | }); 26 | }); -------------------------------------------------------------------------------- /css-project/01-starter-code/assets/css/styles.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/01-starter-code/assets/css/styles.css -------------------------------------------------------------------------------- /css-project/01-starter-code/assets/img/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/01-starter-code/assets/img/main.jpg -------------------------------------------------------------------------------- /css-project/01-starter-code/assets/img/mountain1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/01-starter-code/assets/img/mountain1.jpg -------------------------------------------------------------------------------- /css-project/01-starter-code/assets/img/mountain2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/01-starter-code/assets/img/mountain2.jpg -------------------------------------------------------------------------------- /css-project/01-starter-code/assets/img/mountain3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/01-starter-code/assets/img/mountain3.jpg -------------------------------------------------------------------------------- /css-project/01-starter-code/assets/img/mountain4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/01-starter-code/assets/img/mountain4.jpg -------------------------------------------------------------------------------- /css-project/01-starter-code/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mountain Travel 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /css-project/02-nav-and-header/assets/img/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/02-nav-and-header/assets/img/main.jpg -------------------------------------------------------------------------------- /css-project/02-nav-and-header/assets/img/mountain1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/02-nav-and-header/assets/img/mountain1.jpg -------------------------------------------------------------------------------- /css-project/02-nav-and-header/assets/img/mountain2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/02-nav-and-header/assets/img/mountain2.jpg -------------------------------------------------------------------------------- /css-project/02-nav-and-header/assets/img/mountain3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/02-nav-and-header/assets/img/mountain3.jpg -------------------------------------------------------------------------------- /css-project/02-nav-and-header/assets/img/mountain4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/02-nav-and-header/assets/img/mountain4.jpg -------------------------------------------------------------------------------- /css-project/02-nav-and-header/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mountain Travel 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

Mountain Travel

15 | 20 |
21 | 22 |
23 |
24 |
25 |

Mountain Travel

26 |

Unmissable Adventure Tours Around The World

27 | Contact Us Now 28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /css-project/03-destinations-and-features/assets/img/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/03-destinations-and-features/assets/img/main.jpg -------------------------------------------------------------------------------- /css-project/03-destinations-and-features/assets/img/mountain1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/03-destinations-and-features/assets/img/mountain1.jpg -------------------------------------------------------------------------------- /css-project/03-destinations-and-features/assets/img/mountain2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/03-destinations-and-features/assets/img/mountain2.jpg -------------------------------------------------------------------------------- /css-project/03-destinations-and-features/assets/img/mountain3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/03-destinations-and-features/assets/img/mountain3.jpg -------------------------------------------------------------------------------- /css-project/03-destinations-and-features/assets/img/mountain4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/03-destinations-and-features/assets/img/mountain4.jpg -------------------------------------------------------------------------------- /css-project/04-testimonials-contact-footer/assets/img/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/04-testimonials-contact-footer/assets/img/main.jpg -------------------------------------------------------------------------------- /css-project/04-testimonials-contact-footer/assets/img/mountain1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/04-testimonials-contact-footer/assets/img/mountain1.jpg -------------------------------------------------------------------------------- /css-project/04-testimonials-contact-footer/assets/img/mountain2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/04-testimonials-contact-footer/assets/img/mountain2.jpg -------------------------------------------------------------------------------- /css-project/04-testimonials-contact-footer/assets/img/mountain3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/04-testimonials-contact-footer/assets/img/mountain3.jpg -------------------------------------------------------------------------------- /css-project/04-testimonials-contact-footer/assets/img/mountain4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/04-testimonials-contact-footer/assets/img/mountain4.jpg -------------------------------------------------------------------------------- /css-project/05-responsive-design/assets/img/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/05-responsive-design/assets/img/main.jpg -------------------------------------------------------------------------------- /css-project/05-responsive-design/assets/img/mountain1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/05-responsive-design/assets/img/mountain1.jpg -------------------------------------------------------------------------------- /css-project/05-responsive-design/assets/img/mountain2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/05-responsive-design/assets/img/mountain2.jpg -------------------------------------------------------------------------------- /css-project/05-responsive-design/assets/img/mountain3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/05-responsive-design/assets/img/mountain3.jpg -------------------------------------------------------------------------------- /css-project/05-responsive-design/assets/img/mountain4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/css-project/05-responsive-design/assets/img/mountain4.jpg -------------------------------------------------------------------------------- /es2015-16-17-part-1/arrow-functions/arrow-functions-exercises.js: -------------------------------------------------------------------------------- 1 | // function tripleAndFilter(arr){ 2 | // return arr.map(function(value){ 3 | // return value * 3; 4 | // }).filter(function(value){ 5 | // return value % 5; 6 | // }) 7 | // } 8 | 9 | // 1 10 | 11 | // function doubleOddNumbers(arr){ 12 | // return arr.filter(function(val){ 13 | // return val % 2 !== 0; 14 | // }).map(function(val){ 15 | // return val *2; 16 | // }) 17 | // } 18 | 19 | // 2 20 | 21 | // function mapFilterAndReduce(arr){ 22 | // return arr.map(function(val){ 23 | // return val.firstName 24 | // }).filter(function(val){ 25 | // return val.length < 5; 26 | // }).reduce(function(acc,next){ 27 | // acc[next] = next.length 28 | // return acc; 29 | // }, {}) 30 | // } 31 | 32 | // 3 33 | 34 | // 4 35 | 36 | // 5 37 | var instructor = { 38 | firstName: "Colt", 39 | sayHi: function() { 40 | setTimeout(function() { 41 | console.log("Hello " + this.firstName); 42 | }, 1000); 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /es2015-16-17-part-1/arrow-functions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /es2015-16-17-part-1/arrow-functions/spec/es2015-part1-spec.js: -------------------------------------------------------------------------------- 1 | // arrow functions 2 | describe("#tripleAndFilter", function(){ 3 | it("triples an array of numbers and returns an array of all those numbers divisible by 5", function(){ 4 | expect(tripleAndFilter([1,2,3,4,5])).toEqual([15]) 5 | }); 6 | }); 7 | 8 | describe("#doubleOddNumbers", function(){ 9 | it("returns a new array of all odd numbers doubled", function(){ 10 | expect(doubleOddNumbers([1,2,3,4,5])).toEqual([2,6,10]) 11 | }); 12 | }); 13 | 14 | describe("#mapFilterAndReduce", function(){ 15 | it("maps over an array and filters for a length less than 5 and reduces into an object with the key as the name and value as the length", function(){ 16 | var arr = mapFilterAndReduce([{firstName: 'Elie'}, {firstName: 'Rusty'}, {firstName: 'Matthew'}, {firstName: 'Tim'}]) 17 | expect(arr).toEqual({Elie: 4, Tim: 3}) 18 | }); 19 | }); 20 | 21 | describe("#createStudent", function(){ 22 | it("returns an object with the keys and values of firstName and lastName", function(){ 23 | expect(createStudentObj('Elie', 'Schoppik')).toEqual({firstName: 'Elie', lastName: 'Schoppik'}) 24 | }); 25 | }); -------------------------------------------------------------------------------- /es2015-16-17-part-1/destructuring/destructuring-exercises.js: -------------------------------------------------------------------------------- 1 | function displayStudentInfo(obj) {} 2 | 3 | function printFullName({ first, last }) {} 4 | 5 | function createStudent({ likesJavaScript = true, likesES2015 = true } = {}) {} 6 | 7 | function reverseArray(arr) {} 8 | -------------------------------------------------------------------------------- /es2015-16-17-part-1/destructuring/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /es2015-16-17-part-1/rest-spread/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /es2015-16-17-part-1/rest-spread/rest-spread-exercises.js: -------------------------------------------------------------------------------- 1 | // spread 2 | function smallestValue(...args) {} 3 | 4 | // placeInMiddle([1,2,6,7],[3,4,5]) 5 | function placeInMiddle(arr, vals) {} 6 | 7 | // rest 8 | function joinArrays(...args) {} 9 | 10 | // rest 11 | function sumEvenArgs(...args) {} 12 | 13 | // rest 14 | function flip(fn, thisArg, ...outerArgs) {} 15 | 16 | // rest + spread 17 | function bind(fn, thisArg, ...outerArgs) {} 18 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/class-keyword/class-keyword-exercises.js: -------------------------------------------------------------------------------- 1 | // Write a method called multiplyFavoriteNumber that takes in a number and returns the product of the number and the Person's favorite number 2 | 3 | // function Person(firstName, lastName, favoriteColor, favoriteNumber){ 4 | // this.firstName = firstName; 5 | // this.lastName = lastName; 6 | // this.favoriteColor = favoriteColor; 7 | // this.favoriteNumber = favoriteNumber; 8 | // this.multiplyFavoriteNumber = function(num){ 9 | // return num * this.favoriteNumber; 10 | // } 11 | // } 12 | 13 | class Person {} 14 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/class-keyword/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/es2015-inheritance/es2015-inheritance-exercises.js: -------------------------------------------------------------------------------- 1 | class Vehicle {} 2 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/es2015-inheritance/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/es2015-methods/es2015-methods-exercises.js: -------------------------------------------------------------------------------- 1 | // Array.from 2 | // Object.assign 3 | // Number.isFinite 4 | 5 | function copyObject(obj) {} 6 | 7 | function checkIfFinite(num) {} 8 | 9 | function areAllNumbersFinite(arr) {} 10 | 11 | function convertArrayLikeObject(obj) {} 12 | 13 | function displayEvenArguments() {} 14 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/es2015-methods/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/maps-sets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/maps-sets/maps-sets-exercises.js: -------------------------------------------------------------------------------- 1 | // maps 2 | 3 | class MessageBoard {} 4 | 5 | // sets 6 | function uniqueValues(arr) {} 7 | 8 | function hasDuplicates(arr) {} 9 | 10 | function countPairs(arr, num) {} 11 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/promises/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/promises/promises-exercises.js: -------------------------------------------------------------------------------- 1 | function getMostFollowers(...usernames) {} 2 | function starWarsString(id) {} 3 | -------------------------------------------------------------------------------- /es2015-16-17-part-2/promises/spec/es2015-part-2.spec.js: -------------------------------------------------------------------------------- 1 | describe("#getMostFollowers", function(){ 2 | it("returns a string with the most followers", function(done){ 3 | getMostFollowers('elie','tim','defunkt').then(function(result){ 4 | expect(result).toEqual('Chris Wanstrath has the most followers with 16213') 5 | done(); 6 | }) 7 | }); 8 | }); 9 | 10 | describe("#starWarsString", function(){ 11 | it("returns a string with the most followers", function(done){ 12 | starWarsString(1).then(function(result){ 13 | expect(result).toEqual('Luke Skywalker is featured in The Empire Strikes Back, directed by Irvin Kershner and it takes place on Hoth') 14 | done(); 15 | }) 16 | starWarsString(5).then(function(result){ 17 | expect(result).toEqual('Leia Organa is featured in The Empire Strikes Back, directed by Irvin Kershner and it takes place on Hoth') 18 | done(); 19 | }) 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /es2016-and-2017/async-functions/async-functions-exercises.js: -------------------------------------------------------------------------------- 1 | function getMostFollowers(...usernames) {} 2 | 3 | function starWarsString(id) {} 4 | -------------------------------------------------------------------------------- /es2016-and-2017/async-functions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /es2016-and-2017/async-functions/spec/es2015-part-2.spec.js: -------------------------------------------------------------------------------- 1 | // Async Spec 2 | 3 | describe("#getMostFollowers", function(){ 4 | it("returns a string with the most followers", function(done){ 5 | getMostFollowers('elie','tim','defunkt').then(function(result){ 6 | expect(result).toEqual('Chris Wanstrath has the most followers') 7 | done(); 8 | }) 9 | }); 10 | }); 11 | 12 | describe("#starWarsString", function(){ 13 | it("returns a string with the most followers", function(done){ 14 | starWarsString(1).then(function(result){ 15 | expect(result).toEqual('Luke Skywalker is featured in The Empire Strikes Back, directed by Irvin Kershner and it takes place on Hoth') 16 | done(); 17 | }) 18 | starWarsString(5).then(function(result){ 19 | expect(result).toEqual('Leia Organa is featured in The Empire Strikes Back, directed by Irvin Kershner and it takes place on Hoth') 20 | done(); 21 | }) 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /object-oriented-programming/constructors/constructors-exercises.js: -------------------------------------------------------------------------------- 1 | // Create a constructor function for a Person, each person should have a firstName, lastName, favoriteColor and favoriteNumber. 2 | 3 | // Write a method called multiplyFavoriteNumber that takes in a number and returns the product of the number and the Person's favorite number 4 | 5 | // refactor 6 | -------------------------------------------------------------------------------- /object-oriented-programming/constructors/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /object-oriented-programming/constructors/spec/oop.spec.js: -------------------------------------------------------------------------------- 1 | // constructors 2 | 3 | describe("Person", function(){ 4 | var person = new Person("Elie", "Schoppik", "purple", 34) 5 | it("has a firstName", function(){ 6 | expect(person.hasOwnProperty('firstName')).toEqual(true); 7 | }); 8 | it("has a lastName", function(){ 9 | expect(person.hasOwnProperty('lastName')).toEqual(true); 10 | }); 11 | it("has a favoriteColor", function(){ 12 | expect(person.hasOwnProperty('favoriteColor')).toEqual(true); 13 | }); 14 | it("has a favoriteNumber", function(){ 15 | expect(person.hasOwnProperty('favoriteNumber')).toEqual(true); 16 | }); 17 | }); 18 | 19 | describe("#multiplyFavoriteNumber", function(){ 20 | var person = new Person("Elie", "Schoppik", "purple", 34) 21 | it("takes in a number and returns the product of the number and the Person's favorite number", function(){ 22 | expect(person.multiplyFavoriteNumber(10)).toEqual(340) 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /object-oriented-programming/inheritance/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /object-oriented-programming/inheritance/inheritance-exercises.js: -------------------------------------------------------------------------------- 1 | // inherit 1 thing from another 2 | 3 | function Vehicle(make, model, year) {} 4 | -------------------------------------------------------------------------------- /object-oriented-programming/prototypes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | > 14 | 15 | 16 | -------------------------------------------------------------------------------- /object-oriented-programming/prototypes/prototypes-exercises.js: -------------------------------------------------------------------------------- 1 | // Create a constructor function for a Person. Each person should have a firstName, lastName, favoriteColor, favoriteNumber) 2 | 3 | // Add a function on the Person.prototype called fullName that returns the firstName and lastName property of an object created by the Person constructor concatenated together. 4 | 5 | // Add a property on the Person object called family which is an empty array. 6 | 7 | // Add a function on the Person.prototype called addToFamily which adds an object constructed from the Person constructor to the family array. To make sure that the object you are adding is an object construced from the Person constructor - take a look at the instanceofoperator. Make sure that your family array does not include duplicates! This method should the length of the family array. 8 | 9 | function Person(firstName, lastName, favoriteColor, favoriteNumber) {} 10 | 11 | Person.prototype.fullName = function() {}; 12 | 13 | Person.prototype.addToFamily = function(person) {}; 14 | 15 | // Part II: 16 | 17 | // Make the tests pass for the following tasks: 18 | 19 | // Implement your own version of Array.prototype.map 20 | 21 | Array.prototype.map = function(callback) {}; 22 | 23 | // Implement a function that reverses a string and place it on the String.prototype 24 | 25 | String.prototype.reverse = function() {}; 26 | -------------------------------------------------------------------------------- /react/flags/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/flags/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flags", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.0.0-rc.2", 7 | "react-dom": "^16.0.0-rc.2", 8 | "react-scripts": "1.0.13", 9 | "shuffle-array": "^1.0.1" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react/flags/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/flags/public/favicon.ico -------------------------------------------------------------------------------- /react/flags/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/flags/src/App.css: -------------------------------------------------------------------------------- 1 | .flag-app { 2 | text-align: center; 3 | } 4 | 5 | .title-header { 6 | display: flex; 7 | height: 20vh; 8 | background-size: cover; 9 | background-repeat: no-repeat; 10 | justify-content: center; 11 | align-items: flex-end; 12 | background-color: "#6b93d6"; 13 | } 14 | 15 | .title-text { 16 | font-size: 3.5em; 17 | color: #e9eff9; 18 | text-shadow: 3px 3px 4px black; 19 | } 20 | 21 | @media (max-width: 450px) { 22 | .title-header { 23 | height: 14vh; 24 | } 25 | 26 | .title-text { 27 | font-size: 2.1em; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /react/flags/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import CountryGame from './CountryGame'; 3 | import worldImg from './world.jpg'; 4 | import './App.css'; 5 | 6 | 7 | class App extends Component { 8 | render() { 9 | return ( 10 |
11 |
14 |

Guess The Flag

15 |
16 | 17 |
18 | ); 19 | } 20 | } 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /react/flags/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/flags/src/FlagAnswer.css: -------------------------------------------------------------------------------- 1 | .flag-answer { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | font-size: 1.3em; 6 | } 7 | 8 | .flag-answer button { 9 | margin-left: 25px; 10 | } 11 | -------------------------------------------------------------------------------- /react/flags/src/FlagAnswer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import StyledButton from './StyledButton'; 3 | import './FlagAnswer.css'; 4 | 5 | const FlagAnswer = ({correct, answer, onNext}) => ( 6 |
7 | {correct ? 8 | `Correct!: ${answer}` : 9 | `Incorrect! Correct Answer: ${answer}`} 10 | 11 |
12 | ); 13 | 14 | export default FlagAnswer; 15 | -------------------------------------------------------------------------------- /react/flags/src/FlagChoices.css: -------------------------------------------------------------------------------- 1 | .flag-form { 2 | display: flex; 3 | max-width: 1000px; 4 | margin: 0 auto; 5 | justify-content: space-around; 6 | font-size: 1.3em; 7 | } 8 | -------------------------------------------------------------------------------- /react/flags/src/FlagChoices.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import StyledButton from './StyledButton'; 3 | import './FlagChoices.css'; 4 | 5 | const FlagChoices = props => { 6 | let options = props.options || [] 7 | const {handleChange, handleSubmit} = props; 8 | let inputs = options.map(opt => ( 9 | 17 | )); 18 | 19 | return ( 20 |
21 | {inputs} 22 | 23 | 24 | ); 25 | } 26 | 27 | export default FlagChoices; 28 | -------------------------------------------------------------------------------- /react/flags/src/FlagQuestion.css: -------------------------------------------------------------------------------- 1 | .flag-img { 2 | max-height: 65vh; 3 | max-width: 90%; 4 | border: 1px solid black; 5 | margin: 15px; 6 | } 7 | -------------------------------------------------------------------------------- /react/flags/src/StyledButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const StyledButton = ({text, onClick, type}) => ( 4 | 20 | ); 21 | 22 | export default StyledButton; 23 | -------------------------------------------------------------------------------- /react/flags/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | background-color: #e9eff9; 6 | } 7 | -------------------------------------------------------------------------------- /react/flags/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/flags/src/world.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/flags/src/world.jpg -------------------------------------------------------------------------------- /react/hacker-news/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/hacker-news/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-todo", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.0.0-rc.3", 7 | "react-dom": "^16.0.0-rc.3", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /react/hacker-news/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/hacker-news/public/favicon.ico -------------------------------------------------------------------------------- /react/hacker-news/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/hacker-news/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | } 7 | 8 | .App ol li { 9 | font-size: 1.2em; 10 | margin: 10px; 11 | } 12 | 13 | .todo-input { 14 | padding: 2px; 15 | min-width: 250px; 16 | min-height: 25px; 17 | font-size: 1.2em; 18 | margin: 10px; 19 | } 20 | 21 | .save-button { 22 | font-size: 1.2em; 23 | } 24 | 25 | .todo-content { 26 | width: 50%; 27 | } 28 | 29 | @media (max-width: 700px) { 30 | .todo-content { 31 | width: 95%; 32 | } 33 | } -------------------------------------------------------------------------------- /react/hacker-news/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './App.css'; 3 | 4 | class App extends Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | stories: [] 9 | }; 10 | } 11 | 12 | componentDidMount() { 13 | const topStories = 'https://hacker-news.firebaseio.com/v0/topstories.json'; 14 | const storyUrlBase = 'https://hacker-news.firebaseio.com/v0/item/'; 15 | 16 | fetch(topStories) 17 | .then(data => data.json()) 18 | .then(data => data.map(id => { 19 | const url = `${storyUrlBase}${id}.json`; 20 | return fetch(url).then(d => d.json()); 21 | })) 22 | .then(promises => Promise.all(promises)) 23 | .then(stories => this.setState({stories})); 24 | } 25 | 26 | render() { 27 | let views =
Loading...
; 28 | const {stories} = this.state; 29 | if (stories && stories.length > 0) { 30 | views = stories.map(s=> ( 31 |

32 | {s.title} from {s.by} 33 |

34 | )); 35 | } 36 | 37 | return ( 38 |
39 |

Hacker News Top Stories

40 | {views} 41 |
42 | ); 43 | } 44 | } 45 | 46 | export default App; 47 | -------------------------------------------------------------------------------- /react/hacker-news/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/hacker-news/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/hacker-news/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/helloworld/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/helloworld/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helloworld", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^15.6.1", 7 | "react-dom": "^15.6.1", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } -------------------------------------------------------------------------------- /react/helloworld/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/helloworld/public/favicon.ico -------------------------------------------------------------------------------- /react/helloworld/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/helloworld/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /react/helloworld/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | class App extends Component { 6 | render() { 7 | return ( 8 |
9 |
10 | logo 11 |

HELLO WORLD!!

12 |
13 |

14 | To get started, edit src/App.js and save to reload. 15 |

16 |
17 | ); 18 | } 19 | } 20 | 21 | export { App }; 22 | -------------------------------------------------------------------------------- /react/helloworld/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/helloworld/src/HobbyList.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | class HobbyList extends Component { 4 | render() { 5 | const hobbies = ["Sleeping", "Eating", "Cuddling"]; 6 | const style = {fontSize: '1.5em'}; 7 | return ( 8 |
    9 | {hobbies.map((h, i) => { 10 | return
  • {h}
  • 11 | })} 12 |
13 | ); 14 | } 15 | } 16 | 17 | export default HobbyList; -------------------------------------------------------------------------------- /react/helloworld/src/Pet.css: -------------------------------------------------------------------------------- 1 | .name { 2 | font-size: 3em; 3 | margin: .25em; 4 | } 5 | .card { 6 | font-family: Helvetica, Arial, sans-serif; 7 | background-color: #c1bcb6; 8 | margin: 10px; 9 | padding: 10px; 10 | border-radius: 10px; 11 | border: 4px solid #005365; 12 | color: #005365; 13 | display: flex; 14 | flex-direction: column; 15 | justify-content: center; 16 | align-items: center; 17 | } 18 | .card img { 19 | width: 300px; 20 | padding: 4px 20px 10px 20px; 21 | } -------------------------------------------------------------------------------- /react/helloworld/src/Pet.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import HobbyList from './HobbyList'; 3 | import './Pet.css'; 4 | 5 | class Pet extends Component { 6 | render() { 7 | return (
8 |

Moxie

9 | Moxie 12 |
Hobbies:
13 | 14 |
); 15 | } 16 | } 17 | 18 | export default Pet; -------------------------------------------------------------------------------- /react/helloworld/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | 7 | #root { 8 | display: flex; 9 | flex-direction: row; 10 | justify-content: center; 11 | } -------------------------------------------------------------------------------- /react/helloworld/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import Pet from './Pet'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/memory-game/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | -------------------------------------------------------------------------------- /react/memory-game/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "memory-game", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^16.0.0-rc.3", 8 | "react-dom": "^16.0.0-rc.3", 9 | "shuffle-array": "^1.0.1" 10 | }, 11 | "devDependencies": { 12 | "react-scripts": "0.9.5" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /react/memory-game/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/memory-game/public/favicon.ico -------------------------------------------------------------------------------- /react/memory-game/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | Memory Game 17 | 18 | 19 |
20 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /react/memory-game/src/Card.css: -------------------------------------------------------------------------------- 1 | .card-container { 2 | margin: 10px; 3 | height: 150px; 4 | min-width: 100px; 5 | width: 10%; 6 | background-color: grey; 7 | border: 6px solid grey; 8 | border-radius: 25px; 9 | display: inline-block; 10 | } 11 | -------------------------------------------------------------------------------- /react/memory-game/src/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import './Card.css' 4 | 5 | const Card = (props) => { 6 | let style = {}; 7 | if (props.showing) { 8 | style.backgroundColor = props.backgroundColor; 9 | } 10 | return ( 11 |
16 | ); 17 | }; 18 | 19 | Card.propTypes = { 20 | showing: PropTypes.bool.isRequired, 21 | backgroundColor: PropTypes.string.isRequired, 22 | onClick: PropTypes.func.isRequired 23 | }; 24 | 25 | export default Card; 26 | -------------------------------------------------------------------------------- /react/memory-game/src/Navbar.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #2c3e50; 3 | display: flex; 4 | justify-content: space-between; 5 | align-items: center; 6 | color: white; 7 | padding: 0 15px; 8 | } 9 | 10 | header h1 { 11 | text-align: center; 12 | } 13 | 14 | header li { 15 | list-style: none; 16 | } 17 | 18 | header a { 19 | text-decoration: none; 20 | color: inherit; 21 | cursor: pointer; 22 | opacity: 0.9; 23 | } 24 | 25 | header a:hover { 26 | opacity: 1; 27 | } 28 | 29 | header nav { 30 | display: flex; 31 | } 32 | 33 | header nav li { 34 | margin: 0 15px; 35 | } 36 | 37 | header nav li:first-child { 38 | margin-left: 0; 39 | } 40 | 41 | header nav li:last-child { 42 | margin-right: 0; 43 | } 44 | 45 | @media (max-width: 1000px) { 46 | header{ 47 | padding: 20px 50px; 48 | } 49 | } 50 | 51 | 52 | @media (max-width: 700px) { 53 | header{ 54 | flex-direction: column; 55 | } 56 | 57 | header h2{ 58 | margin-bottom: 15px; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /react/memory-game/src/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import './Navbar.css'; 4 | 5 | const Navbar = ({onNewGame}) => ( 6 |
7 |

Memory Game

8 | 11 |
12 | ); 13 | 14 | Navbar.propTypes = { 15 | onNewGame: PropTypes.func.isRequired 16 | }; 17 | 18 | export default Navbar; 19 | -------------------------------------------------------------------------------- /react/memory-game/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/memory-game/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import MemoryGame from './MemoryGame'; 4 | import './index.css'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root') 9 | ); 10 | -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "update-complex-state", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1", 9 | "react-scripts": "1.0.13" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/pass-state-to-props-demo/public/favicon.ico -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 20px; 3 | text-align: center; 4 | } 5 | 6 | .App ul { 7 | padding: 0; 8 | display: flex; 9 | justify-content: space-between; 10 | } 11 | 12 | .App li { 13 | list-style: none; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | background: #ecf0f1; 6 | } 7 | -------------------------------------------------------------------------------- /react/pass-state-to-props-demo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/random-boxes-solution/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/random-boxes-solution/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "random-boxes-starter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^16.0.0-rc.3", 8 | "react-dom": "^16.0.0-rc.3", 9 | "react-scripts": "1.0.13" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react/random-boxes-solution/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/random-boxes-solution/public/favicon.ico -------------------------------------------------------------------------------- /react/random-boxes-solution/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/random-boxes-solution/src/App.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /react/random-boxes-solution/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/random-boxes-solution/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/random-boxes-solution/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/random-boxes-starter/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/random-boxes-starter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "random-boxes-starter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^16.0.0-rc.3", 8 | "react-dom": "^16.0.0-rc.3", 9 | "react-scripts": "1.0.13" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react/random-boxes-starter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/random-boxes-starter/public/favicon.ico -------------------------------------------------------------------------------- /react/random-boxes-starter/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/random-boxes-starter/src/App.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /react/random-boxes-starter/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/random-boxes-starter/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/random-boxes-starter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/react-router-senators/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/react-router-senators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-router-senators", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.0.0-rc.3", 7 | "react-dom": "^16.0.0-rc.3", 8 | "react-router-dom": "^4.2.2", 9 | "react-scripts": "1.0.13" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react/react-router-senators/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/react-router-senators/public/favicon.ico -------------------------------------------------------------------------------- /react/react-router-senators/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/react-router-senators/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | -------------------------------------------------------------------------------- /react/react-router-senators/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Main from './Main'; 3 | import Navbar from './Navbar'; 4 | import './App.css'; 5 | 6 | const App = ({senators}) => ( 7 |
8 | 9 |
10 |
11 |
12 |
13 | ); 14 | 15 | export default App; 16 | -------------------------------------------------------------------------------- /react/react-router-senators/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/react-router-senators/src/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Switch, Route} from 'react-router-dom'; 3 | import SenatorList from './SenatorList'; 4 | import SenatorDetails from './SenatorDetails'; 5 | 6 | const Main = ({senators}) => ( 7 | 8 | ( 9 | 10 | )}/> 11 | ( 12 | 13 | )}/> 14 | 15 | ); 16 | 17 | export default Main; 18 | -------------------------------------------------------------------------------- /react/react-router-senators/src/Navbar.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #2c3e50; 3 | display: flex; 4 | justify-content: space-between; 5 | align-items: center; 6 | color: white; 7 | padding: 0 15px; 8 | } 9 | 10 | header h2 { 11 | margin: 0 15px; 12 | } 13 | 14 | header li { 15 | list-style: none; 16 | } 17 | 18 | header a { 19 | text-decoration: none; 20 | color: inherit; 21 | cursor: pointer; 22 | opacity: 0.9; 23 | } 24 | 25 | header a:hover { 26 | opacity: 1; 27 | } 28 | 29 | @media (max-width: 1000px) { 30 | header{ 31 | padding: 20px 50px; 32 | } 33 | } 34 | 35 | 36 | @media (max-width: 700px) { 37 | header{ 38 | flex-direction: column; 39 | } 40 | 41 | header h2{ 42 | margin-bottom: 15px; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /react/react-router-senators/src/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {NavLink} from 'react-router-dom'; 3 | import './Navbar.css'; 4 | 5 | const activeStyle={display: 'none'}; 6 | 7 | const Navbar = () => ( 8 |
9 |

Home

10 |
11 | ); 12 | 13 | export default Navbar; 14 | -------------------------------------------------------------------------------- /react/react-router-senators/src/SenatorDetails.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SenatorDetails = ({senators, match, ...rest}) => { 4 | const senator = senators.find(s => s.person.cspanid === +match.params.cspanid); 5 | if (!senator) { 6 | return ( 7 |
Sorry, no senator found
8 | ); 9 | } 10 | 11 | return ( 12 |
13 |

{senator.person.name}

14 |

{senator.description} - {senator.party}

15 |

{senator.website}

16 |
17 | ); 18 | }; 19 | 20 | export default SenatorDetails; 21 | -------------------------------------------------------------------------------- /react/react-router-senators/src/SenatorList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Link} from 'react-router-dom'; 3 | 4 | const SenatorList = (props) => { 5 | const senators = props.senators.map(s => ( 6 |
  • 7 | {s.person.name} 8 |
  • 9 | )); 10 | return ( 11 |
    12 |

    Senators

    13 |
      14 | {senators} 15 |
    16 |
    17 | ); 18 | } 19 | 20 | export default SenatorList; 21 | -------------------------------------------------------------------------------- /react/react-router-senators/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/react-router-senators/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import {BrowserRouter as Router} from 'react-router-dom'; 4 | import senators from './senators'; 5 | import './index.css'; 6 | import App from './App'; 7 | import registerServiceWorker from './registerServiceWorker'; 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | registerServiceWorker(); 16 | -------------------------------------------------------------------------------- /react/recipe-props-solution/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/recipe-props-solution/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recipe-props-starter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.0.0-rc.3", 7 | "react-dom": "^16.0.0-rc.3", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /react/recipe-props-solution/public/avocado_toast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-solution/public/avocado_toast.jpg -------------------------------------------------------------------------------- /react/recipe-props-solution/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-solution/public/favicon.ico -------------------------------------------------------------------------------- /react/recipe-props-solution/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/recipe-props-solution/public/milkshake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-solution/public/milkshake.jpg -------------------------------------------------------------------------------- /react/recipe-props-solution/public/spaghetti.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-solution/public/spaghetti.jpg -------------------------------------------------------------------------------- /react/recipe-props-solution/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/recipe-props-solution/src/Navbar.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #2c3e50; 3 | display: flex; 4 | justify-content: space-between; 5 | align-items: center; 6 | color: white; 7 | padding: 0 15px; 8 | } 9 | 10 | header h1 { 11 | text-align: center; 12 | } 13 | 14 | header li { 15 | list-style: none; 16 | } 17 | 18 | header a { 19 | text-decoration: none; 20 | color: inherit; 21 | cursor: pointer; 22 | opacity: 0.9; 23 | } 24 | 25 | header a:hover { 26 | opacity: 1; 27 | } 28 | 29 | header nav { 30 | display: flex; 31 | } 32 | 33 | header nav li { 34 | margin: 0 15px; 35 | } 36 | 37 | header nav li:first-child { 38 | margin-left: 0; 39 | } 40 | 41 | header nav li:last-child { 42 | margin-right: 0; 43 | } 44 | 45 | @media (max-width: 1000px) { 46 | header{ 47 | padding: 20px 50px; 48 | } 49 | } 50 | 51 | 52 | @media (max-width: 700px) { 53 | header{ 54 | flex-direction: column; 55 | } 56 | 57 | header h2{ 58 | margin-bottom: 15px; 59 | } 60 | } -------------------------------------------------------------------------------- /react/recipe-props-solution/src/Navbar.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import './Navbar.css'; 3 | 4 | class Navbar extends Component { 5 | render() { 6 | return ( 7 |
    8 |

    Recipe App

    9 | 15 |
    16 | ); 17 | } 18 | } 19 | 20 | export default Navbar; -------------------------------------------------------------------------------- /react/recipe-props-solution/src/Recipe.css: -------------------------------------------------------------------------------- 1 | .recipe-card { 2 | width: 31%; 3 | min-width: 240px; 4 | margin: 1%; 5 | border: 1px solid rgba(160,160,160,0.2); 6 | background: white; 7 | border-radius: 0 0 2px 2px; 8 | box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2); 9 | } 10 | 11 | 12 | .recipe-card-content { 13 | padding: 16px; 14 | } 15 | 16 | 17 | .recipe-card-image { 18 | overflow: hidden; 19 | height: 50%; 20 | } 21 | 22 | .recipe-card img { 23 | width: 100%; 24 | max-height: 250px; 25 | } 26 | 27 | .recipe-title { 28 | margin: 0; 29 | } -------------------------------------------------------------------------------- /react/recipe-props-solution/src/Recipe.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import './Recipe.css'; 4 | 5 | class Recipe extends Component { 6 | static propTypes = { 7 | title: PropTypes.string.isRequired, 8 | ingredients: PropTypes.arrayOf(PropTypes.string).isRequired, 9 | instructions: PropTypes.string.isRequired, 10 | img: PropTypes.string.isRequired, 11 | } 12 | 13 | render() { 14 | const {title, img, instructions} = this.props; 15 | const ingredients = this.props.ingredients.map((ing, index) => ( 16 |
  • {ing}
  • 17 | )); 18 | return ( 19 |
    20 |
    21 | {title} 22 |
    23 |
    24 |

    {title}

    25 |

    Ingredients:

    26 |
      27 | {ingredients} 28 |
    29 |

    Instructions:

    30 |

    {instructions}

    31 |
    32 | 33 |
    34 | ); 35 | } 36 | } 37 | 38 | export default Recipe; -------------------------------------------------------------------------------- /react/recipe-props-solution/src/RecipeApp.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-solution/src/RecipeApp.css -------------------------------------------------------------------------------- /react/recipe-props-solution/src/RecipeApp.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Navbar from './Navbar'; 3 | import RecipeList from './RecipeList'; 4 | import './RecipeApp.css'; 5 | 6 | class RecipeApp extends Component { 7 | render() { 8 | return ( 9 |
    10 | 11 | 12 |
    13 | ); 14 | } 15 | } 16 | 17 | export default RecipeApp; 18 | -------------------------------------------------------------------------------- /react/recipe-props-solution/src/RecipeList.css: -------------------------------------------------------------------------------- 1 | .recipe-list { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | } 6 | 7 | @media (max-width: 580px) { 8 | .recipe-list { 9 | display: block; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /react/recipe-props-solution/src/RecipeList.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import Recipe from './Recipe'; 3 | import PropTypes from 'prop-types'; 4 | import './RecipeList.css'; 5 | 6 | class RecipeList extends Component { 7 | static defaultProps = { 8 | recipes: [ 9 | { 10 | title: "Spaghetti", 11 | instructions: "Open jar of Spaghetti sauce. Bring to simmer. Boil water. Cook pasta until done. Combine pasta and sauce", 12 | ingredients: ["pasta", "8 cups water", "1 box spaghetti"], 13 | img: "spaghetti.jpg" 14 | }, 15 | { 16 | title: "Milkshake", 17 | instructions: "Combine ice cream and milk. Blend until creamy", 18 | ingredients: ["2 Scoops Ice cream", "8 ounces milk"], 19 | img: "milkshake.jpg" 20 | }, 21 | { 22 | title: "Avocado Toast", 23 | instructions: "Toast bread. Slice avocado and spread on bread. Add salt, oil, and pepper to taste.", 24 | ingredients: ["2 slices of bread", "1 avocado", "1 tablespoon olive oil", "1 pinch of salt", "pepper"], 25 | img: "avocado_toast.jpg" 26 | } 27 | ] 28 | } 29 | 30 | static propTypes = { 31 | recipes: PropTypes.arrayOf(PropTypes.object).isRequired 32 | } 33 | 34 | render() { 35 | const recipes = this.props.recipes.map((r,index) => ( 36 | 37 | )); 38 | 39 | return ( 40 |
    41 | {recipes} 42 |
    43 | ) 44 | 45 | } 46 | } 47 | 48 | export default RecipeList; -------------------------------------------------------------------------------- /react/recipe-props-solution/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: roboto; 5 | background: #ecf0f1; 6 | } 7 | -------------------------------------------------------------------------------- /react/recipe-props-solution/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import RecipeApp from './RecipeApp'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/recipe-props-starter/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/recipe-props-starter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recipe-props-starter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.0.0-rc.3", 7 | "react-dom": "^16.0.0-rc.3", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /react/recipe-props-starter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-starter/public/favicon.ico -------------------------------------------------------------------------------- /react/recipe-props-starter/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/recipe-props-starter/public/spaghetti.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-starter/public/spaghetti.jpg -------------------------------------------------------------------------------- /react/recipe-props-starter/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/recipe-props-starter/src/Recipe.css: -------------------------------------------------------------------------------- 1 | .recipe-card { 2 | width: 31%; 3 | min-width: 240px; 4 | margin: 1%; 5 | border: 1px solid rgba(160,160,160,0.2); 6 | background: white; 7 | border-radius: 0 0 2px 2px; 8 | box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2); 9 | } 10 | 11 | 12 | .recipe-card-content { 13 | padding: 16px; 14 | } 15 | 16 | 17 | .recipe-card-image { 18 | overflow: hidden; 19 | height: 50%; 20 | } 21 | 22 | .recipe-card img { 23 | width: 100%; 24 | max-height: 250px; 25 | } 26 | 27 | .recipe-title { 28 | margin: 0; 29 | } -------------------------------------------------------------------------------- /react/recipe-props-starter/src/Recipe.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import './Recipe.css'; 3 | 4 | class Recipe extends Component { 5 | render() { 6 | const {title, img, instructions} = this.props; 7 | const ingredients = this.props.ingredients.map((ing, index) => ( 8 |
  • {ing}
  • 9 | )); 10 | return ( 11 |
    12 |
    13 | {title} 14 |
    15 |
    16 |

    {title}

    17 |

    Ingredients:

    18 |
      19 | {ingredients} 20 |
    21 |

    Instructions:

    22 |

    {instructions}

    23 |
    24 | 25 |
    26 | ); 27 | } 28 | } 29 | 30 | export default Recipe; -------------------------------------------------------------------------------- /react/recipe-props-starter/src/RecipeApp.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-props-starter/src/RecipeApp.css -------------------------------------------------------------------------------- /react/recipe-props-starter/src/RecipeApp.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Recipe from './Recipe'; 3 | import './RecipeApp.css'; 4 | 5 | class RecipeApp extends Component { 6 | render() { 7 | return ( 8 |
    9 | 15 |
    16 | ); 17 | } 18 | } 19 | 20 | export default RecipeApp; 21 | -------------------------------------------------------------------------------- /react/recipe-props-starter/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: roboto; 5 | background: #ecf0f1; 6 | } 7 | -------------------------------------------------------------------------------- /react/recipe-props-starter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import RecipeApp from './RecipeApp'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recipe-exercise", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^16.0.0-rc.3", 8 | "react-dom": "^16.0.0-rc.3", 9 | "react-redux": "^5.0.6", 10 | "react-scripts": "1.0.13", 11 | "redux": "^3.7.2" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/public/avocado_toast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-redux-single-folder/public/avocado_toast.jpg -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-redux-single-folder/public/favicon.ico -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/public/milkshake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-redux-single-folder/public/milkshake.jpg -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/public/spaghetti.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-redux-single-folder/public/spaghetti.jpg -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/Navbar.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #2c3e50; 3 | display: flex; 4 | justify-content: space-between; 5 | align-items: center; 6 | color: white; 7 | padding: 0 15px; 8 | } 9 | 10 | header h1 { 11 | text-align: center; 12 | } 13 | 14 | header li { 15 | list-style: none; 16 | } 17 | 18 | header a { 19 | text-decoration: none; 20 | color: inherit; 21 | cursor: pointer; 22 | opacity: 0.9; 23 | } 24 | 25 | header a:hover { 26 | opacity: 1; 27 | } 28 | 29 | header nav { 30 | display: flex; 31 | } 32 | 33 | header nav li { 34 | margin: 0 15px; 35 | } 36 | 37 | header nav li:first-child { 38 | margin-left: 0; 39 | } 40 | 41 | header nav li:last-child { 42 | margin-right: 0; 43 | } 44 | 45 | @media (max-width: 1000px) { 46 | header{ 47 | padding: 20px 50px; 48 | } 49 | } 50 | 51 | 52 | @media (max-width: 700px) { 53 | header{ 54 | flex-direction: column; 55 | } 56 | 57 | header h2{ 58 | margin-bottom: 15px; 59 | } 60 | } -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/Navbar.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import './Navbar.css'; 4 | 5 | class Navbar extends Component { 6 | static defaultProps = { 7 | onNewRecipe() {} 8 | } 9 | 10 | static propTypes = { 11 | onNewRecipe: PropTypes.func 12 | } 13 | 14 | render() { 15 | return ( 16 |
    17 |

    Recipe App

    18 | 24 |
    25 | ); 26 | } 27 | } 28 | 29 | export default Navbar; -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/Recipe.css: -------------------------------------------------------------------------------- 1 | .recipe-card { 2 | width: 31%; 3 | min-width: 240px; 4 | margin: 1%; 5 | border: 1px solid rgba(160,160,160,0.2); 6 | background: white; 7 | border-radius: 0 0 2px 2px; 8 | box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2); 9 | } 10 | 11 | 12 | .recipe-card-content { 13 | padding: 16px; 14 | } 15 | 16 | 17 | .recipe-card-image { 18 | overflow: hidden; 19 | height: 50%; 20 | } 21 | 22 | .recipe-card img { 23 | width: 100%; 24 | max-height: 250px; 25 | } 26 | 27 | .recipe-title { 28 | margin: 0; 29 | } -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/Recipe.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import './Recipe.css'; 4 | 5 | class Recipe extends Component { 6 | static propTypes = { 7 | title: PropTypes.string.isRequired, 8 | ingredients: PropTypes.arrayOf(PropTypes.string).isRequired, 9 | instructions: PropTypes.string.isRequired, 10 | img: PropTypes.string.isRequired, 11 | id: PropTypes.number.isRequired, 12 | onDelete: PropTypes.func.isRequired 13 | } 14 | 15 | render() { 16 | const {title, img, instructions, id, onDelete} = this.props; 17 | const ingredients = this.props.ingredients.map((ing, index) => ( 18 |
  • {ing}
  • 19 | )); 20 | return ( 21 |
    22 |
    23 | {title} 24 |
    25 |
    26 |

    {title}

    27 |

    Ingredients:

    28 |
      29 | {ingredients} 30 |
    31 |

    Instructions:

    32 |

    {instructions}

    33 | 34 |
    35 |
    36 | ); 37 | } 38 | } 39 | 40 | export default Recipe; -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/RecipeApp.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-redux-single-folder/src/RecipeApp.css -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/RecipeApp.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import {connect} from 'react-redux'; 3 | import Navbar from './Navbar'; 4 | import RecipeInput from './RecipeInput'; 5 | import RecipeList from './RecipeList'; 6 | import './RecipeApp.css'; 7 | 8 | const RecipeApp = ({ 9 | shouldShowForm, 10 | recipes, 11 | saveRecipe, 12 | deleteRecipe, 13 | showForm, 14 | hideForm 15 | }) => ( 16 |
    17 | 18 | { shouldShowForm ? 19 | : 23 | null } 24 | 25 |
    26 | ); 27 | 28 | const mapStateToProps = state => ({ 29 | recipes: state.recipes, 30 | shouldShowForm: state.shouldShowForm 31 | }); 32 | 33 | const mapDispatchToProps = dispatch => ({ 34 | saveRecipe(recipe) { 35 | dispatch({ 36 | type: "SAVE_RECIPE", 37 | recipe 38 | }) 39 | }, 40 | deleteRecipe(recipeId) { 41 | dispatch({ 42 | type: "DELETE_RECIPE", 43 | recipeId 44 | }) 45 | }, 46 | showForm() { 47 | dispatch({ 48 | type: "SHOW_FORM" 49 | }) 50 | }, 51 | hideForm() { 52 | dispatch({ 53 | type: "HIDE_FORM" 54 | }) 55 | } 56 | }); 57 | 58 | export default connect(mapStateToProps, mapDispatchToProps)(RecipeApp); 59 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/RecipeInput.css: -------------------------------------------------------------------------------- 1 | .recipe-form { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: flex-start; 5 | justify-content: center; 6 | margin: 10px; 7 | padding: 15px; 8 | border-radius: 10px; 9 | border: 7px solid #2c3e50; 10 | } 11 | 12 | .recipe-form input[type=text] { 13 | padding: 5px 8px; 14 | box-sizing: border-box; 15 | } 16 | 17 | .recipe-form-line { 18 | display: flex; 19 | flex-direction: row; 20 | align-items: center; 21 | justify-content: flex-start; 22 | margin-top: 5px; 23 | } 24 | 25 | .recipe-form-line input { 26 | margin-left: 15px; 27 | } 28 | 29 | .buttons { 30 | color: white; 31 | background-color: #2c3e50; 32 | border-radius: 6px; 33 | padding: 0 10px 1px 10px; 34 | margin: 8px 0; 35 | align-self: flex-end; 36 | font-size: 1.1em; 37 | } 38 | 39 | .close-button { 40 | background-color: transparent; 41 | background-repeat: no-repeat; 42 | border: none; 43 | cursor: pointer; 44 | overflow: hidden; 45 | font-size: 0.9em; 46 | color: #777; 47 | text-shadow: 0 1px 0 #fff; 48 | align-self: flex-end; 49 | } 50 | 51 | .recipe-form-container { 52 | display: flex; 53 | align-items: center; 54 | justify-content: center; 55 | } 56 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/RecipeList.css: -------------------------------------------------------------------------------- 1 | .recipe-list { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | } 6 | 7 | @media (max-width: 580px) { 8 | .recipe-list { 9 | display: block; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/RecipeList.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import Recipe from './Recipe'; 3 | import PropTypes from 'prop-types'; 4 | import './RecipeList.css'; 5 | 6 | class RecipeList extends Component { 7 | static propTypes = { 8 | recipes: PropTypes.arrayOf(PropTypes.object).isRequired, 9 | onDelete: PropTypes.func.isRequired 10 | } 11 | 12 | render() { 13 | const {onDelete} = this.props; 14 | const recipes = this.props.recipes.map((r,index) => ( 15 | 16 | )); 17 | 18 | return ( 19 |
    20 | {recipes} 21 |
    22 | ) 23 | 24 | } 25 | } 26 | 27 | export default RecipeList; -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/images/spaghetti.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-redux-single-folder/src/images/spaghetti.jpg -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: roboto; 5 | background: #ecf0f1; 6 | } 7 | -------------------------------------------------------------------------------- /react/recipe-redux-single-folder/src/reducers.js: -------------------------------------------------------------------------------- 1 | export default (state={}, action) => { 2 | switch(action.type) { 3 | case "SAVE_RECIPE": 4 | const newRecipe = {id: state.nextRecipeId, ...action.recipe}; 5 | return { 6 | ...state, 7 | nextRecipeId: state.nextRecipeId + 1, 8 | shouldShowForm: false, 9 | recipes: [...state.recipes, newRecipe] 10 | }; 11 | case "DELETE_RECIPE": 12 | const recipes = state.recipes.filter(r => r.id !== action.recipeId); 13 | return {...state, recipes}; 14 | case "SHOW_FORM": 15 | return {...state, shouldShowForm: true}; 16 | case "HIDE_FORM": 17 | return {...state, shouldShowForm: false}; 18 | default: 19 | return state; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /react/recipe-with-state/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/recipe-with-state/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recipe-props-starter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^16.0.0-rc.3", 8 | "react-dom": "^16.0.0-rc.3", 9 | "react-scripts": "1.0.13" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react/recipe-with-state/public/avocado_toast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-with-state/public/avocado_toast.jpg -------------------------------------------------------------------------------- /react/recipe-with-state/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-with-state/public/favicon.ico -------------------------------------------------------------------------------- /react/recipe-with-state/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/recipe-with-state/public/milkshake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-with-state/public/milkshake.jpg -------------------------------------------------------------------------------- /react/recipe-with-state/public/spaghetti.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-with-state/public/spaghetti.jpg -------------------------------------------------------------------------------- /react/recipe-with-state/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/recipe-with-state/src/Navbar.css: -------------------------------------------------------------------------------- 1 | header { 2 | background-color: #2c3e50; 3 | display: flex; 4 | justify-content: space-between; 5 | align-items: center; 6 | color: white; 7 | padding: 0 15px; 8 | } 9 | 10 | header h1 { 11 | text-align: center; 12 | } 13 | 14 | header li { 15 | list-style: none; 16 | } 17 | 18 | header a { 19 | text-decoration: none; 20 | color: inherit; 21 | cursor: pointer; 22 | opacity: 0.9; 23 | } 24 | 25 | header a:hover { 26 | opacity: 1; 27 | } 28 | 29 | header nav { 30 | display: flex; 31 | } 32 | 33 | header nav li { 34 | margin: 0 15px; 35 | } 36 | 37 | header nav li:first-child { 38 | margin-left: 0; 39 | } 40 | 41 | header nav li:last-child { 42 | margin-right: 0; 43 | } 44 | 45 | @media (max-width: 1000px) { 46 | header{ 47 | padding: 20px 50px; 48 | } 49 | } 50 | 51 | 52 | @media (max-width: 700px) { 53 | header{ 54 | flex-direction: column; 55 | } 56 | 57 | header h2{ 58 | margin-bottom: 15px; 59 | } 60 | } -------------------------------------------------------------------------------- /react/recipe-with-state/src/Navbar.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import './Navbar.css'; 4 | 5 | class Navbar extends Component { 6 | static defaultProps = { 7 | onNewRecipe() {} 8 | } 9 | 10 | static propTypes = { 11 | onNewRecipe: PropTypes.func 12 | } 13 | 14 | render() { 15 | return ( 16 |
    17 |

    Recipe App

    18 | 24 |
    25 | ); 26 | } 27 | } 28 | 29 | export default Navbar; -------------------------------------------------------------------------------- /react/recipe-with-state/src/Recipe.css: -------------------------------------------------------------------------------- 1 | .recipe-card { 2 | width: 31%; 3 | min-width: 240px; 4 | margin: 1%; 5 | border: 1px solid rgba(160,160,160,0.2); 6 | background: white; 7 | border-radius: 0 0 2px 2px; 8 | box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2); 9 | } 10 | 11 | 12 | .recipe-card-content { 13 | padding: 16px; 14 | } 15 | 16 | 17 | .recipe-card-image { 18 | overflow: hidden; 19 | height: 50%; 20 | } 21 | 22 | .recipe-card img { 23 | width: 100%; 24 | max-height: 250px; 25 | } 26 | 27 | .recipe-title { 28 | margin: 0; 29 | } -------------------------------------------------------------------------------- /react/recipe-with-state/src/Recipe.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import './Recipe.css'; 4 | 5 | class Recipe extends Component { 6 | static propTypes = { 7 | title: PropTypes.string.isRequired, 8 | ingredients: PropTypes.arrayOf(PropTypes.string).isRequired, 9 | instructions: PropTypes.string.isRequired, 10 | img: PropTypes.string.isRequired, 11 | id: PropTypes.number.isRequired, 12 | onDelete: PropTypes.func.isRequired 13 | } 14 | 15 | render() { 16 | const {title, img, instructions, id, onDelete} = this.props; 17 | const ingredients = this.props.ingredients.map((ing, index) => ( 18 |
  • {ing}
  • 19 | )); 20 | return ( 21 |
    22 |
    23 | {title} 24 |
    25 |
    26 |

    {title}

    27 |

    Ingredients:

    28 |
      29 | {ingredients} 30 |
    31 |

    Instructions:

    32 |

    {instructions}

    33 | 34 |
    35 |
    36 | ); 37 | } 38 | } 39 | 40 | export default Recipe; -------------------------------------------------------------------------------- /react/recipe-with-state/src/RecipeApp.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/recipe-with-state/src/RecipeApp.css -------------------------------------------------------------------------------- /react/recipe-with-state/src/RecipeInput.css: -------------------------------------------------------------------------------- 1 | .recipe-form { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: flex-start; 5 | justify-content: center; 6 | margin: 10px; 7 | padding: 15px; 8 | border-radius: 10px; 9 | border: 7px solid #2c3e50; 10 | } 11 | 12 | .recipe-form input[type=text] { 13 | padding: 5px 8px; 14 | box-sizing: border-box; 15 | } 16 | 17 | .recipe-form-line { 18 | display: flex; 19 | flex-direction: row; 20 | align-items: center; 21 | justify-content: flex-start; 22 | margin-top: 5px; 23 | } 24 | 25 | .recipe-form-line input { 26 | margin-left: 15px; 27 | } 28 | 29 | .buttons { 30 | color: white; 31 | background-color: #2c3e50; 32 | border-radius: 6px; 33 | padding: 0 10px 1px 10px; 34 | margin: 8px 0; 35 | align-self: flex-end; 36 | font-size: 1.1em; 37 | } 38 | 39 | .close-button { 40 | background-color: transparent; 41 | background-repeat: no-repeat; 42 | border: none; 43 | cursor: pointer; 44 | overflow: hidden; 45 | font-size: 0.9em; 46 | color: #777; 47 | text-shadow: 0 1px 0 #fff; 48 | align-self: flex-end; 49 | } 50 | 51 | .recipe-form-container { 52 | display: flex; 53 | align-items: center; 54 | justify-content: center; 55 | } 56 | -------------------------------------------------------------------------------- /react/recipe-with-state/src/RecipeList.css: -------------------------------------------------------------------------------- 1 | .recipe-list { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | } 6 | 7 | @media (max-width: 580px) { 8 | .recipe-list { 9 | display: block; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /react/recipe-with-state/src/RecipeList.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import Recipe from './Recipe'; 3 | import PropTypes from 'prop-types'; 4 | import './RecipeList.css'; 5 | 6 | class RecipeList extends Component { 7 | static propTypes = { 8 | recipes: PropTypes.arrayOf(PropTypes.object).isRequired, 9 | onDelete: PropTypes.func.isRequired 10 | } 11 | 12 | render() { 13 | const {onDelete} = this.props; 14 | const recipes = this.props.recipes.map((r,index) => ( 15 | 16 | )); 17 | 18 | return ( 19 |
    20 | {recipes} 21 |
    22 | ) 23 | 24 | } 25 | } 26 | 27 | export default RecipeList; -------------------------------------------------------------------------------- /react/recipe-with-state/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: roboto; 5 | background: #ecf0f1; 6 | } 7 | -------------------------------------------------------------------------------- /react/recipe-with-state/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import RecipeApp from './RecipeApp'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/redux-async/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # production 7 | build 8 | 9 | # misc 10 | .DS_Store 11 | npm-debug.log 12 | -------------------------------------------------------------------------------- /react/redux-async/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "async", 3 | "version": "0.0.1", 4 | "private": true, 5 | "devDependencies": { 6 | "react-scripts": "^1.0.2", 7 | "redux-logger": "^3.0.6" 8 | }, 9 | "dependencies": { 10 | "prop-types": "^15.5.10", 11 | "react": "^15.5.0", 12 | "react-dom": "^15.5.0", 13 | "react-redux": "^5.0.5", 14 | "redux": "^3.5.2", 15 | "redux-thunk": "^2.1.0" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "eject": "react-scripts eject", 21 | "test": "react-scripts test" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /react/redux-async/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Redux Async Example 7 | 8 | 9 |
    10 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /react/redux-async/src/actions/index.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_POSTS = 'REQUEST_POSTS' 2 | export const RECEIVE_POSTS = 'RECEIVE_POSTS' 3 | export const SELECT_REDDIT = 'SELECT_REDDIT' 4 | export const INVALIDATE_REDDIT = 'INVALIDATE_REDDIT' 5 | 6 | export const selectReddit = reddit => ({ 7 | type: SELECT_REDDIT, 8 | reddit 9 | }) 10 | 11 | export const invalidateReddit = reddit => ({ 12 | type: INVALIDATE_REDDIT, 13 | reddit 14 | }) 15 | 16 | export const requestPosts = reddit => ({ 17 | type: REQUEST_POSTS, 18 | reddit 19 | }) 20 | 21 | export const receivePosts = (reddit, json) => ({ 22 | type: RECEIVE_POSTS, 23 | reddit, 24 | posts: json.data.children.map(child => child.data), 25 | receivedAt: Date.now() 26 | }) 27 | 28 | const fetchPosts = reddit => dispatch => { 29 | dispatch(requestPosts(reddit)) 30 | return fetch(`https://www.reddit.com/r/${reddit}.json`) 31 | .then(response => response.json()) 32 | .then(json => dispatch(receivePosts(reddit, json))) 33 | } 34 | 35 | const shouldFetchPosts = (state, reddit) => { 36 | const posts = state.postsByReddit[reddit] 37 | if (!posts) { 38 | return true 39 | } 40 | if (posts.isFetching) { 41 | return false 42 | } 43 | return posts.didInvalidate 44 | } 45 | 46 | export const fetchPostsIfNeeded = reddit => (dispatch, getState) => { 47 | if (shouldFetchPosts(getState(), reddit)) { 48 | return dispatch(fetchPosts(reddit)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /react/redux-async/src/components/Picker.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Picker = ({ value, onChange, options }) => ( 5 | 6 |

    {value}

    7 | 15 |
    16 | ) 17 | 18 | Picker.propTypes = { 19 | options: PropTypes.arrayOf( 20 | PropTypes.string.isRequired 21 | ).isRequired, 22 | value: PropTypes.string.isRequired, 23 | onChange: PropTypes.func.isRequired 24 | } 25 | 26 | export default Picker 27 | -------------------------------------------------------------------------------- /react/redux-async/src/components/Posts.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Posts = ({posts}) => ( 5 |
      6 | {posts.map((post, i) => 7 |
    • {post.title}
    • 8 | )} 9 |
    10 | ) 11 | 12 | Posts.propTypes = { 13 | posts: PropTypes.array.isRequired 14 | } 15 | 16 | export default Posts 17 | -------------------------------------------------------------------------------- /react/redux-async/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createStore, applyMiddleware } from 'redux' 4 | import { Provider } from 'react-redux' 5 | import thunk from 'redux-thunk' 6 | import { createLogger } from 'redux-logger' 7 | import reducer from './reducers' 8 | import App from './containers/App' 9 | 10 | const middleware = [ thunk ] 11 | if (process.env.NODE_ENV !== 'production') { 12 | middleware.push(createLogger()) 13 | } 14 | 15 | const store = createStore( 16 | reducer, 17 | applyMiddleware(...middleware) 18 | ) 19 | 20 | render( 21 | 22 | 23 | , 24 | document.getElementById('root') 25 | ) 26 | -------------------------------------------------------------------------------- /react/redux-todos/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # production 7 | build 8 | 9 | # misc 10 | .DS_Store 11 | npm-debug.log 12 | -------------------------------------------------------------------------------- /react/redux-todos/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todos", 3 | "version": "0.0.1", 4 | "private": true, 5 | "devDependencies": { 6 | "enzyme": "^2.8.2", 7 | "react-addons-test-utils": "^15.5.1", 8 | "react-scripts": "^1.0.2" 9 | }, 10 | "dependencies": { 11 | "prop-types": "^15.5.10", 12 | "react": "^15.5.0", 13 | "react-dom": "^15.5.0", 14 | "react-redux": "^5.0.5", 15 | "redux": "^3.5.2" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "eject": "react-scripts eject", 21 | "test": "react-scripts test" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /react/redux-todos/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Redux Todos Example 7 | 8 | 9 |
    10 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /react/redux-todos/src/actions/index.js: -------------------------------------------------------------------------------- 1 | let nextTodoId = 0 2 | export const addTodo = (text) => ({ 3 | type: 'ADD_TODO', 4 | id: nextTodoId++, 5 | text 6 | }) 7 | 8 | export const setVisibilityFilter = (filter) => ({ 9 | type: 'SET_VISIBILITY_FILTER', 10 | filter 11 | }) 12 | 13 | export const toggleTodo = (id) => ({ 14 | type: 'TOGGLE_TODO', 15 | id 16 | }) 17 | -------------------------------------------------------------------------------- /react/redux-todos/src/actions/index.spec.js: -------------------------------------------------------------------------------- 1 | import * as actions from './index' 2 | 3 | describe('todo actions', () => { 4 | it('addTodo should create ADD_TODO action', () => { 5 | expect(actions.addTodo('Use Redux')).toEqual({ 6 | type: 'ADD_TODO', 7 | id: 0, 8 | text: 'Use Redux' 9 | }) 10 | }) 11 | 12 | it('setVisibilityFilter should create SET_VISIBILITY_FILTER action', () => { 13 | expect(actions.setVisibilityFilter('active')).toEqual({ 14 | type: 'SET_VISIBILITY_FILTER', 15 | filter: 'active' 16 | }) 17 | }) 18 | 19 | it('toggleTodo should create TOGGLE_TODO action', () => { 20 | expect(actions.toggleTodo(1)).toEqual({ 21 | type: 'TOGGLE_TODO', 22 | id: 1 23 | }) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /react/redux-todos/src/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Footer from './Footer' 3 | import AddTodo from '../containers/AddTodo' 4 | import VisibleTodoList from '../containers/VisibleTodoList' 5 | 6 | const App = () => ( 7 |
    8 | 9 | 10 |
    11 |
    12 | ) 13 | 14 | export default App 15 | -------------------------------------------------------------------------------- /react/redux-todos/src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import FilterLink from '../containers/FilterLink' 3 | 4 | const Footer = () => ( 5 |

    6 | Show: 7 | {" "} 8 | 9 | All 10 | 11 | {", "} 12 | 13 | Active 14 | 15 | {", "} 16 | 17 | Completed 18 | 19 |

    20 | ) 21 | 22 | export default Footer 23 | -------------------------------------------------------------------------------- /react/redux-todos/src/components/Link.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Link = ({ active, children, onClick }) => { 5 | if (active) { 6 | return {children} 7 | } 8 | 9 | return ( 10 | // eslint-disable-next-line 11 | { 13 | e.preventDefault() 14 | onClick() 15 | }} 16 | > 17 | {children} 18 | 19 | ) 20 | } 21 | 22 | Link.propTypes = { 23 | active: PropTypes.bool.isRequired, 24 | children: PropTypes.node.isRequired, 25 | onClick: PropTypes.func.isRequired 26 | } 27 | 28 | export default Link 29 | -------------------------------------------------------------------------------- /react/redux-todos/src/components/Todo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Todo = ({ onClick, completed, text }) => ( 5 |
  • 11 | {text} 12 |
  • 13 | ) 14 | 15 | Todo.propTypes = { 16 | onClick: PropTypes.func.isRequired, 17 | completed: PropTypes.bool.isRequired, 18 | text: PropTypes.string.isRequired 19 | } 20 | 21 | export default Todo 22 | -------------------------------------------------------------------------------- /react/redux-todos/src/components/TodoList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Todo from './Todo' 4 | 5 | const TodoList = ({ todos, onTodoClick }) => ( 6 |
      7 | {todos.map(todo => 8 | onTodoClick(todo.id)} 12 | /> 13 | )} 14 |
    15 | ) 16 | 17 | TodoList.propTypes = { 18 | todos: PropTypes.arrayOf(PropTypes.shape({ 19 | id: PropTypes.number.isRequired, 20 | completed: PropTypes.bool.isRequired, 21 | text: PropTypes.string.isRequired 22 | }).isRequired).isRequired, 23 | onTodoClick: PropTypes.func.isRequired 24 | } 25 | 26 | export default TodoList 27 | -------------------------------------------------------------------------------- /react/redux-todos/src/containers/AddTodo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { addTodo } from '../actions' 4 | 5 | let AddTodo = ({ dispatch }) => { 6 | let input 7 | 8 | return ( 9 |
    10 |
    { 11 | e.preventDefault() 12 | if (!input.value.trim()) { 13 | return 14 | } 15 | dispatch(addTodo(input.value)) 16 | input.value = '' 17 | }}> 18 | { 19 | input = node 20 | }} /> 21 | 24 |
    25 |
    26 | ) 27 | } 28 | AddTodo = connect()(AddTodo) 29 | 30 | export default AddTodo 31 | -------------------------------------------------------------------------------- /react/redux-todos/src/containers/FilterLink.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { setVisibilityFilter } from '../actions' 3 | import Link from '../components/Link' 4 | 5 | const mapStateToProps = (state, ownProps) => ({ 6 | active: ownProps.filter === state.visibilityFilter 7 | }) 8 | 9 | const mapDispatchToProps = (dispatch, ownProps) => ({ 10 | onClick: () => { 11 | dispatch(setVisibilityFilter(ownProps.filter)) 12 | } 13 | }) 14 | 15 | const FilterLink = connect( 16 | mapStateToProps, 17 | mapDispatchToProps 18 | )(Link) 19 | 20 | export default FilterLink 21 | -------------------------------------------------------------------------------- /react/redux-todos/src/containers/VisibleTodoList.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { toggleTodo } from '../actions' 3 | import TodoList from '../components/TodoList' 4 | 5 | const getVisibleTodos = (todos, filter) => { 6 | switch (filter) { 7 | case 'SHOW_ALL': 8 | return todos 9 | case 'SHOW_COMPLETED': 10 | return todos.filter(t => t.completed) 11 | case 'SHOW_ACTIVE': 12 | return todos.filter(t => !t.completed) 13 | default: 14 | throw new Error('Unknown filter: ' + filter) 15 | } 16 | } 17 | 18 | const mapStateToProps = (state) => ({ 19 | todos: getVisibleTodos(state.todos, state.visibilityFilter) 20 | }) 21 | 22 | const mapDispatchToProps = { 23 | onTodoClick: toggleTodo 24 | } 25 | 26 | const VisibleTodoList = connect( 27 | mapStateToProps, 28 | mapDispatchToProps 29 | )(TodoList) 30 | 31 | export default VisibleTodoList 32 | -------------------------------------------------------------------------------- /react/redux-todos/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createStore } from 'redux' 4 | import { Provider } from 'react-redux' 5 | import App from './components/App' 6 | import reducer from './reducers' 7 | 8 | const store = createStore(reducer) 9 | 10 | render( 11 | 12 | 13 | , 14 | document.getElementById('root') 15 | ) 16 | -------------------------------------------------------------------------------- /react/redux-todos/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import todos from './todos' 3 | import visibilityFilter from './visibilityFilter' 4 | 5 | const todoApp = combineReducers({ 6 | todos, 7 | visibilityFilter 8 | }) 9 | 10 | export default todoApp 11 | -------------------------------------------------------------------------------- /react/redux-todos/src/reducers/todos.js: -------------------------------------------------------------------------------- 1 | const todos = (state = [], action) => { 2 | switch (action.type) { 3 | case 'ADD_TODO': 4 | return [ 5 | ...state, 6 | { 7 | id: action.id, 8 | text: action.text, 9 | completed: false 10 | } 11 | ] 12 | case 'TOGGLE_TODO': 13 | return state.map(todo => 14 | (todo.id === action.id) 15 | ? {...todo, completed: !todo.completed} 16 | : todo 17 | ) 18 | default: 19 | return state 20 | } 21 | } 22 | 23 | export default todos 24 | -------------------------------------------------------------------------------- /react/redux-todos/src/reducers/visibilityFilter.js: -------------------------------------------------------------------------------- 1 | const visibilityFilter = (state = 'SHOW_ALL', action) => { 2 | switch (action.type) { 3 | case 'SET_VISIBILITY_FILTER': 4 | return action.filter 5 | default: 6 | return state 7 | } 8 | } 9 | 10 | export default visibilityFilter 11 | -------------------------------------------------------------------------------- /react/routing-demo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/routing-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "routing-demo", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.0.0-rc.3", 7 | "react-dom": "^16.0.0-rc.3", 8 | "react-router-dom": "^4.2.2", 9 | "react-scripts": "1.0.13" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react/routing-demo/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/routing-demo/public/favicon.ico -------------------------------------------------------------------------------- /react/routing-demo/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/routing-demo/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /react/routing-demo/src/App.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {NavLink} from 'react-router-dom'; 3 | import './App.css'; 4 | import SwitchDemo from './SwitchDemo'; 5 | 6 | class App extends Component { 7 | render() { 8 | const active = {textDecoration: 'none', cursor: 'default', color: 'grey'}; 9 | const defaultStyle = { 10 | margin: '5px' 11 | } 12 | return ( 13 |
    14 | 15 | HOME 16 | 17 | 18 | ABOUT 19 | 20 |
    21 | 22 |
    23 |
    24 | ); 25 | } 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /react/routing-demo/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/routing-demo/src/SwitchDemo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Switch, Route} from 'react-router-dom'; 3 | 4 | const Homepage = () => ( 5 |
    HOMEPAGE
    6 | ); 7 | const About = () => ( 8 |
    ABOUT
    9 | ); 10 | 11 | const SwitchDemo = () => ( 12 | 13 | 14 | 15 | 16 | ); 17 | 18 | export default SwitchDemo; 19 | -------------------------------------------------------------------------------- /react/routing-demo/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/routing-demo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import {BrowserRouter as Router} from 'react-router-dom'; 4 | import './index.css'; 5 | import App from './App'; 6 | import registerServiceWorker from './registerServiceWorker'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById('root') 13 | ); 14 | registerServiceWorker(); 15 | -------------------------------------------------------------------------------- /react/simple-todo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/simple-todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-todo", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^15.6.1", 7 | "react-dom": "^15.6.1", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } -------------------------------------------------------------------------------- /react/simple-todo/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/simple-todo/public/favicon.ico -------------------------------------------------------------------------------- /react/simple-todo/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/simple-todo/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | } 7 | 8 | .App ol li { 9 | font-size: 1.2em; 10 | margin: 10px; 11 | } 12 | 13 | .todo-input { 14 | padding: 2px; 15 | min-width: 250px; 16 | min-height: 25px; 17 | font-size: 1.2em; 18 | margin: 10px; 19 | } 20 | 21 | .save-button { 22 | font-size: 1.2em; 23 | } 24 | 25 | .todo-content { 26 | width: 50%; 27 | } 28 | 29 | @media (max-width: 700px) { 30 | .todo-content { 31 | width: 95%; 32 | } 33 | } -------------------------------------------------------------------------------- /react/simple-todo/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './App.css'; 3 | 4 | const TodoItem = ({text}) => ( 5 |
  • {text}
  • 6 | ); 7 | 8 | class App extends Component { 9 | constructor(props) { 10 | super(props); 11 | this.state = { 12 | todos: [], 13 | newTodo: '' 14 | }; 15 | this.handleSubmit = this.handleSubmit.bind(this); 16 | } 17 | handleSubmit(e) { 18 | e.preventDefault(); 19 | const todos = [...this.state.todos, this.state.newTodo]; 20 | this.setState({todos, newTodo: ''}); 21 | } 22 | render() { 23 | const {newTodo} = this.state; 24 | const todos = this.state.todos.map((t, i) => ( 25 | 26 | )); 27 | return ( 28 |
    29 |

    Simple Todo App

    30 |
    31 | this.setState({[e.target.name]: e.target.value })} 39 | /> 40 | 46 |
    47 |
    48 |
      49 | {todos} 50 |
    51 |
    52 |
    53 | ); 54 | } 55 | } 56 | 57 | export default App; 58 | -------------------------------------------------------------------------------- /react/simple-todo/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/simple-todo/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/simple-todo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/update-complex-state-solution/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/update-complex-state-solution/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "update-complex-state", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^15.6.1", 7 | "react-dom": "^15.6.1", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } -------------------------------------------------------------------------------- /react/update-complex-state-solution/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/update-complex-state-solution/public/favicon.ico -------------------------------------------------------------------------------- /react/update-complex-state-solution/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/update-complex-state-solution/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 20px; 3 | text-align: center; 4 | } 5 | 6 | .App ul { 7 | display: flex; 8 | justify-content: space-between; 9 | } 10 | 11 | .App li { 12 | list-style: none; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /react/update-complex-state-solution/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/update-complex-state-solution/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | background: #ecf0f1; 6 | } 7 | -------------------------------------------------------------------------------- /react/update-complex-state-solution/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/update-complex-state/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/update-complex-state/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "update-complex-state", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^15.6.1", 7 | "react-dom": "^15.6.1", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } -------------------------------------------------------------------------------- /react/update-complex-state/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/update-complex-state/public/favicon.ico -------------------------------------------------------------------------------- /react/update-complex-state/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/update-complex-state/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 20px; 3 | text-align: center; 4 | } 5 | 6 | .App ul { 7 | display: flex; 8 | justify-content: space-between; 9 | } 10 | 11 | .App li { 12 | list-style: none; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /react/update-complex-state/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './App.css'; 3 | 4 | class App extends Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | instructors: [ 9 | { 10 | name: 'Tim', 11 | hobbies: ['sailing', 'react'] 12 | }, { 13 | name: 'Matt', 14 | hobbies: ['math', 'd3'] 15 | }, { 16 | name: 'Colt', 17 | hobbies: ['css', 'hiking'] 18 | }, { 19 | name: 'Elie', 20 | hobbies: ['music', 'es2015'] 21 | } 22 | ] 23 | }; 24 | } 25 | render() { 26 | const instructors = this.state.instructors.map((instructor, index) => ( 27 |
  • 28 |

    {instructor.name}

    29 |

    Hobbies: {instructor.hobbies.join(", ")}

    30 |
  • 31 | )); 32 | return ( 33 |
    34 |
      35 | {instructors} 36 |
    37 |
    38 | ); 39 | } 40 | } 41 | 42 | export default App; 43 | -------------------------------------------------------------------------------- /react/update-complex-state/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/update-complex-state/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | background: #ecf0f1; 6 | } 7 | -------------------------------------------------------------------------------- /react/update-complex-state/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/warbler-solution/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "warbler-client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "moment": "^2.18.1", 7 | "react": "^16.0.0-rc.3", 8 | "react-dom": "^16.0.0-rc.3", 9 | "react-moment": "^0.6.5", 10 | "react-redux": "^5.0.6", 11 | "react-router-dom": "^4.2.2", 12 | "react-scripts": "1.0.13", 13 | "redux": "^3.7.2", 14 | "redux-logger": "^3.0.6", 15 | "redux-thunk": "^2.2.0" 16 | }, 17 | "proxy": "http://localhost:8081", 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test --env=jsdom", 22 | "eject": "react-scripts eject" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/warbler-solution/warbler-client/public/favicon.ico -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/AuthForm.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/warbler-solution/warbler-client/src/components/AuthForm.css -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/Homepage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import MessageTimeline from '../components/MessageTimeline'; 3 | 4 | const Homepage = ({currentUser, messages}) => { 5 | if (!currentUser) { 6 | return
    Please login
    ; 7 | } 8 | return ( 9 | 14 | ); 15 | } 16 | 17 | export default Homepage; 18 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/MessageForm.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | class MessageForm extends Component { 4 | static defaultProps = { 5 | onSubmit() {} 6 | } 7 | 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | message: '' 12 | } 13 | } 14 | 15 | render() { 16 | const {message} = this.state; 17 | const {onSubmit, errorMessage} = this.props; 18 | return ( 19 |
    { 20 | e.preventDefault(); 21 | onSubmit(message); 22 | this.setState({message: ''}); 23 | }}> 24 | {errorMessage ? 25 |
    {errorMessage}
    : 26 | undefined} 27 | 34 | 41 |
    42 | ); 43 | } 44 | } 45 | 46 | export default MessageForm; 47 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/MessageItem.css: -------------------------------------------------------------------------------- 1 | .timeline-image { 2 | border-radius: 5px; 3 | height: 48px; 4 | width: 48px; 5 | margin-top: 2px; 6 | flex: 1 7 | } 8 | 9 | .message-area, 10 | .timeline-image { 11 | display: inline-block; 12 | } 13 | 14 | .message-area { 15 | margin-left: 5px; 16 | flex: 1; 17 | } 18 | 19 | .message-area a { 20 | margin-right: 3px; 21 | } 22 | 23 | .message-container { 24 | text-align: left; 25 | display: flex; 26 | flex-direction: row; 27 | } 28 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/MessageItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Link} from 'react-router-dom'; 3 | import Moment from 'react-moment'; 4 | import './MessageItem.css'; 5 | import DefaultProfileImg from '../images/default-profile-image.jpg'; 6 | 7 | const MessageItem = (props) => { 8 | const {profileImageUrl, username, text, date} = props; 9 | return ( 10 |
  • 11 | 12 | {`${username} 17 | 18 |
    19 | @{username} 20 | {date} 21 |

    {text}

    22 |
    23 |
  • 24 | ); 25 | } 26 | 27 | export default MessageItem; 28 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/MessageList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import MessageItem from './MessageItem'; 3 | 4 | const MessageList = ({messages}) => { 5 | let messageList = messages.map(m => ( 6 | 13 | )); 14 | return ( 15 |
    16 |
      17 | {messageList} 18 |
    19 |
    20 | ); 21 | } 22 | 23 | MessageList.defaultProps = { 24 | messages: [] 25 | } 26 | 27 | export default MessageList; 28 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/MessageTimeline.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import MessageList from './MessageList'; 3 | import UserAside from './UserAside'; 4 | 5 | const MessageTimeline = ({profileImageUrl, username, messages}) => ( 6 |
    7 | 11 | 12 |
    13 | ); 14 | 15 | export default MessageTimeline; 16 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/Navbar.css: -------------------------------------------------------------------------------- 1 | .navbar-brand > img { 2 | display: inline-block; 3 | margin-bottom: 2px; 4 | width: 20px; 5 | border-radius: 2px; 6 | } 7 | 8 | .nav > li > a > img { 9 | margin: -20px 0 -15px; 10 | width: 40px; 11 | border-radius: 3px; 12 | } 13 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Link} from 'react-router-dom'; 3 | import Logo from '../images/warbler-logo.png'; 4 | import './Navbar.css'; 5 | 6 | const Navbar = props => { 7 | const {currentUser, onLogout, profileImageUrl} = props; 8 | return ( 9 | 30 | ); 31 | } 32 | 33 | export default Navbar; 34 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/PrivateRoute.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Redirect, Route} from 'react-router-dom'; 3 | 4 | const PrivateRoute = ({component: Component, componentProps, currentUser, ...rest}) => ( 5 | ( 6 | currentUser ? 7 | : 8 | 12 | )}/> 13 | ); 14 | 15 | export default PrivateRoute; 16 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/UserAside.css: -------------------------------------------------------------------------------- 1 | #profile-image, 2 | #profile-avatar { 3 | border-radius: 5px; 4 | display: block; 5 | margin-left: -15px; 6 | } 7 | 8 | #profile-image { 9 | margin: 0 auto 15px; 10 | width: 100%; 11 | } 12 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/components/UserAside.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './UserAside.css'; 3 | 4 | const UserAside = ({ 5 | profileImageUrl, 6 | username, 7 | messageCount 8 | }) => ( 9 | 18 | ); 19 | 20 | export default UserAside; 21 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/containers/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {withRouter} from 'react-router-dom'; 4 | import * as actions from '../actions'; 5 | import Main from './Main'; 6 | import Navbar from '../components/Navbar'; 7 | 8 | const App = ({ 9 | currentUser, 10 | authErrorMessage, 11 | onLogout 12 | }) => ( 13 |
    14 | 22 |
    23 |
    24 | ); 25 | 26 | 27 | const mapStateToProps = state => ({ 28 | currentUser: state.currentUser 29 | }); 30 | 31 | const mapDispatchToProps = dispatch => ({ 32 | onLogout() { dispatch(actions.userLogout()) }, 33 | }); 34 | 35 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App)); 36 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/containers/Warbler.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Provider} from 'react-redux'; 3 | import {createStore, applyMiddleware} from 'redux'; 4 | import thunk from 'redux-thunk'; 5 | import {createLogger} from 'redux-logger'; 6 | import {BrowserRouter as Router} from 'react-router-dom'; 7 | import rootReducer, {getCurrentUser} from '../reducers'; 8 | import {authenticateUser} from '../actions'; 9 | import App from './App'; 10 | 11 | const middleware = [thunk]; 12 | if (process.env.NODE_ENV !== 'production') { 13 | middleware.push(createLogger()) 14 | } 15 | 16 | const store = createStore( 17 | rootReducer, 18 | applyMiddleware(...middleware) 19 | ); 20 | 21 | let user = getCurrentUser(); 22 | 23 | if (user) { 24 | store.dispatch(authenticateUser(user)); 25 | } 26 | 27 | 28 | const Warbler = () => ( 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | 36 | export default Warbler; 37 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/images/default-profile-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/warbler-solution/warbler-client/src/images/default-profile-image.jpg -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/images/warbler-hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/warbler-solution/warbler-client/src/images/warbler-hero.jpg -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/images/warbler-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/warbler-solution/warbler-client/src/images/warbler-logo.png -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import Warbler from './containers/Warbler'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render( 8 | , 9 | document.getElementById('root') 10 | ); 11 | registerServiceWorker(); 12 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/reducers/currentUser.js: -------------------------------------------------------------------------------- 1 | const LOCAL_STORAGE_USER_KEY = 'warbler-user-auth-info'; 2 | 3 | const setCurrentUser = (currentUser) => { 4 | localStorage.setItem(LOCAL_STORAGE_USER_KEY, JSON.stringify(currentUser)); 5 | }; 6 | 7 | const clearCurrentUser = () => { 8 | localStorage.removeItem(LOCAL_STORAGE_USER_KEY); 9 | }; 10 | 11 | export const getCurrentUser = () => { 12 | try { 13 | return JSON.parse(localStorage.getItem(LOCAL_STORAGE_USER_KEY)); 14 | } catch(e) { 15 | return undefined; 16 | } 17 | }; 18 | 19 | 20 | const currentUser = (state=null, action) => { 21 | switch(action.type) { 22 | case "USER_LOGOUT": 23 | clearCurrentUser(); 24 | return null; 25 | case "AUTHENTICATE_USER": 26 | setCurrentUser(action.currentUser); 27 | return {...action.currentUser}; 28 | default: 29 | return state; 30 | } 31 | }; 32 | 33 | export default currentUser; 34 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import {combineReducers} from 'redux'; 2 | import currentUser, {getCurrentUser} from './currentUser'; 3 | import messages from './messages'; 4 | 5 | export {getCurrentUser}; 6 | 7 | const rootReducer = combineReducers({ 8 | currentUser, 9 | messages, 10 | }); 11 | 12 | export default rootReducer; 13 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-client/src/reducers/messages.js: -------------------------------------------------------------------------------- 1 | const messages = (state=[], action) => { 2 | switch(action.type) { 3 | case "LOAD_MESSAGES": 4 | return [...action.messages]; 5 | case "ADD_MESSAGE": 6 | return [action.message, ...state]; 7 | default: 8 | return state; 9 | } 10 | }; 11 | 12 | export default messages; 13 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/.env: -------------------------------------------------------------------------------- 1 | SECRET_KEY=b9a4566aaa7a098e97a0a3d94036cfbd81538b4418199796 2 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/README.md: -------------------------------------------------------------------------------- 1 | # Warbler Server Starter 2 | 3 | The sever does token based authentication for signup and sign in 4 | 5 | ## Setup 6 | 7 | The server is a NodeJS application that uses express and mongoDB. To get setup: 8 | 9 | * run: `npm install` 10 | * Create a `.env` file. In the file, add 11 | 12 | ```js 13 | SECRET_KEY=longRandomStringOfCharacters 14 | ``` 15 | __DO NOT CHECK IN THIS FILE__ 16 | 17 | * npm start 18 | 19 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/helpers/auth.js: -------------------------------------------------------------------------------- 1 | var db = require('../models'); 2 | var jwt = require('jsonwebtoken'); 3 | 4 | exports.signin = function(req,res){ 5 | db.User.findOne({email: req.body.email}).then(function(user){ 6 | user.comparePassword(req.body.password, function(err, isMatch){ 7 | if(isMatch){ 8 | var token = jwt.sign({userId: user.id}, process.env.SECRET_KEY); 9 | res.status(200).json({userId: user.id, 10 | username: user.username, 11 | profileImageUrl: user.profileImageUrl, 12 | token 13 | }); 14 | } else { 15 | res.status(400).json({message: 'Invalid Email/Password.'}) 16 | } 17 | }) 18 | }).catch(function(err){ 19 | res.status(400).json({message: 'Invalid Email/Password'}) 20 | }) 21 | }; 22 | 23 | exports.signup = function(req, res, next){ 24 | db.User.create(req.body).then(function(user){ 25 | var token = jwt.sign({ userId: user.id}, process.env.SECRET_KEY); 26 | res.status(200).json({userId: user.id, 27 | username: user.username, 28 | profileImageUrl: user.profileImageUrl, 29 | token 30 | }); 31 | }).catch(function(err) { 32 | res.status(400).json(err); 33 | }); 34 | }; 35 | 36 | module.exports = exports; 37 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/helpers/messages.js: -------------------------------------------------------------------------------- 1 | var db = require('../models'); 2 | 3 | exports.createMessage = function(req,res,next){ 4 | const newMessage = { 5 | text: req.body.text, 6 | userId: req.params.id 7 | }; 8 | 9 | db.Message.create(newMessage).then(function(message){ 10 | db.User.findById(req.params.id).then(function(user){ 11 | user.messages.push(message.id) 12 | user.save().then(function(user) { 13 | return db.Message.findById(message._id) 14 | .populate("userId", {username: true, profileImageUrl: true}) 15 | }).then(function(m) { 16 | return res.status(200).json(m); 17 | }).catch(next); 18 | }).catch(next); 19 | }).catch(next); 20 | }; 21 | 22 | module.exports = exports; -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config() 2 | var express = require("express"); 3 | var app = express(); 4 | var cors = require('cors'); 5 | var bodyParser = require("body-parser"); 6 | var authRoutes = require("./routes/auth"); 7 | var messagesRoutes = require("./routes/messages"); 8 | var auth = require('./middleware/auth'); 9 | var db = require("./models"); 10 | 11 | app.use(cors()); 12 | app.use(bodyParser.json()); 13 | app.use(bodyParser.urlencoded({extended:true})); 14 | 15 | app.get("/", function(req,res){ 16 | res.json({message: "Make a POST requst to /api/auth/signup to signup"}); 17 | }); 18 | 19 | app.use('/api/users/:id/messages', 20 | auth.loginRequired, auth.ensureCorrectUser, 21 | messagesRoutes); 22 | app.use('/api/auth', authRoutes); 23 | app.get('/api/messages', function(req, res, next) { 24 | db.Message.find().sort({createAt: 'desc'}) 25 | .populate("userId", {username: true, profileImageUrl: true}) 26 | .then(function(messages) { 27 | res.json(messages); 28 | }).catch(function(err) { 29 | res.status(500).json(err); 30 | }) 31 | }); 32 | 33 | const PORT = 8081 34 | 35 | app.listen(PORT, function(){ 36 | console.log(`Server is listening on port ${PORT}`); 37 | }); 38 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/models/index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | mongoose.set('debug', true); 3 | mongoose.Promise = global.Promise; 4 | mongoose.connect('mongodb://localhost/warbler', { 5 | keepAlive: true, 6 | reconnectTries: Number.MAX_VALUE, 7 | useMongoClient: true 8 | }); 9 | 10 | module.exports.User = require("./user"); 11 | module.exports.Message = require("./message"); 12 | 13 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/models/message.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | var User = require("./user"); 3 | 4 | 5 | var messageSchema = new mongoose.Schema({ 6 | text: { 7 | type: String, 8 | required: true, 9 | maxLength: 160 10 | }, 11 | userId: { 12 | type: mongoose.Schema.Types.ObjectId, 13 | ref: "User", 14 | required: true 15 | } 16 | }, { 17 | timestamps: true 18 | }); 19 | 20 | messageSchema.pre('remove', function(next){ 21 | User.findById(this.userId).then(user => { 22 | user.messages.remove(this.id); 23 | user.save().then(function(e){ 24 | next(); 25 | }); 26 | }).catch(function(err) { 27 | next(err); 28 | }); 29 | }); 30 | 31 | var Message = mongoose.model('Message', messageSchema); 32 | module.exports = Message; 33 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/models/user.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | var bcrypt = require("bcryptjs"); 3 | 4 | var userSchema = new mongoose.Schema({ 5 | email: { 6 | type: String, 7 | required: true, 8 | unique: true 9 | }, 10 | username: { 11 | type: String, 12 | required: true, 13 | unique: true 14 | }, 15 | password: { 16 | type: String, 17 | required: true 18 | }, 19 | profileImageUrl: { 20 | type:String, 21 | }, 22 | messages: [{ 23 | type: mongoose.Schema.Types.ObjectId, 24 | ref: 'Message' 25 | }] 26 | }); 27 | 28 | userSchema.pre('save', function(next){ 29 | var user = this; 30 | if (!user.isModified('password')) return next(); 31 | bcrypt.hash(user.password, 10).then(function(hashedPassword) { 32 | user.password = hashedPassword 33 | next(); 34 | }, function(err){ 35 | return next(err) 36 | }); 37 | }); 38 | 39 | userSchema.methods.comparePassword = function(candidatePassword, next) { 40 | bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { 41 | if(err) return next(err); 42 | next(null, isMatch); 43 | }); 44 | }; 45 | 46 | var User = mongoose.model('User', userSchema); 47 | module.exports = User; 48 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "warbler-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node ./node_modules/nodemon/bin/nodemon.js index.js", 9 | "debug": "node --inspect-brk app.js" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "bcryptjs": "^2.4.3", 16 | "body-parser": "^1.16.1", 17 | "cors": "^2.8.3", 18 | "dotenv": "^4.0.0", 19 | "express": "^4.14.1", 20 | "faker": "^4.1.0", 21 | "jsonwebtoken": "^7.3.0", 22 | "mongoose": "^4.8.4" 23 | }, 24 | "devDependencies": { 25 | "locus": "^2.0.1", 26 | "nodemon": "^1.11.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/routes/auth.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | var db = require("../models"); 4 | var jwt = require('jsonwebtoken'); 5 | var helpers = require('../helpers/auth'); 6 | 7 | router.post('/signin', helpers.signin); 8 | router.post('/signup', helpers.signup); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /react/warbler-solution/warbler-server/routes/messages.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router({mergeParams: true}); 3 | var db = require("../models"); 4 | var helpers = require('../helpers/messages'); 5 | 6 | router.post('/', helpers.createMessage); 7 | 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /react/warbler-starter-server/.env: -------------------------------------------------------------------------------- 1 | SECRET_KEY=b9a4566aaa7a098e97a0a3d94036cfbd81538b4418199796 2 | -------------------------------------------------------------------------------- /react/warbler-starter-server/README.md: -------------------------------------------------------------------------------- 1 | # Warbler Server Starter 2 | 3 | The sever does token based authentication for signup and sign in 4 | 5 | ## Setup 6 | 7 | The server is a NodeJS application that uses express and mongoDB. To get setup: 8 | 9 | * run: `npm install` 10 | * Create a `.env` file. In the file, add 11 | 12 | ```js 13 | SECRET_KEY=longRandomStringOfCharacters 14 | ``` 15 | __DO NOT CHECK IN THIS FILE__ 16 | 17 | * npm start 18 | 19 | -------------------------------------------------------------------------------- /react/warbler-starter-server/helpers/auth.js: -------------------------------------------------------------------------------- 1 | var db = require('../models'); 2 | var jwt = require('jsonwebtoken'); 3 | 4 | exports.signin = function(req,res){ 5 | db.User.findOne({email: req.body.email}).then(function(user){ 6 | user.comparePassword(req.body.password, function(err, isMatch){ 7 | if(isMatch){ 8 | var token = jwt.sign({userId: user.id}, process.env.SECRET_KEY); 9 | res.status(200).json({userId: user.id, 10 | username: user.username, 11 | profileImageUrl: user.profileImageUrl, 12 | token 13 | }); 14 | } else { 15 | res.status(400).json({message: 'Invalid Email/Password.'}) 16 | } 17 | }) 18 | }).catch(function(err){ 19 | res.status(400).json({message: 'Invalid Email/Password'}) 20 | }) 21 | }; 22 | 23 | exports.signup = function(req, res, next){ 24 | db.User.create(req.body).then(function(user){ 25 | var token = jwt.sign({ userId: user.id}, process.env.SECRET_KEY); 26 | res.status(200).json({userId: user.id, 27 | username: user.username, 28 | profileImageUrl: user.profileImageUrl, 29 | token 30 | }); 31 | }).catch(function(err) { 32 | res.status(400).json(err); 33 | }); 34 | }; 35 | 36 | module.exports = exports; 37 | -------------------------------------------------------------------------------- /react/warbler-starter-server/helpers/messages.js: -------------------------------------------------------------------------------- 1 | var db = require('../models'); 2 | 3 | exports.createMessage = function(req,res,next){ 4 | const newMessage = { 5 | text: req.body.text, 6 | userId: req.params.id 7 | }; 8 | 9 | db.Message.create(newMessage).then(function(message){ 10 | db.User.findById(req.params.id).then(function(user){ 11 | user.messages.push(message.id) 12 | user.save().then(function(user) { 13 | return db.Message.findById(message._id) 14 | .populate("userId", {username: true, profileImageUrl: true}) 15 | }).then(function(m) { 16 | return res.status(200).json(m); 17 | }).catch(next); 18 | }).catch(next); 19 | }).catch(next); 20 | }; 21 | 22 | module.exports = exports; -------------------------------------------------------------------------------- /react/warbler-starter-server/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config() 2 | var express = require("express"); 3 | var app = express(); 4 | var cors = require('cors'); 5 | var bodyParser = require("body-parser"); 6 | var authRoutes = require("./routes/auth"); 7 | var messagesRoutes = require("./routes/messages"); 8 | var auth = require('./middleware/auth'); 9 | var db = require("./models"); 10 | 11 | app.use(cors()); 12 | app.use(bodyParser.json()); 13 | app.use(bodyParser.urlencoded({extended:true})); 14 | 15 | app.get("/", function(req,res){ 16 | res.json({message: "Make a POST requst to /api/auth/signup to signup"}); 17 | }); 18 | 19 | app.use('/api/users/:id/messages', 20 | auth.loginRequired, auth.ensureCorrectUser, 21 | messagesRoutes); 22 | app.use('/api/auth', authRoutes); 23 | app.get('/api/messages', function(req, res, next) { 24 | db.Message.find().sort({createAt: 'desc'}) 25 | .populate("userId", {username: true, profileImageUrl: true}) 26 | .then(function(messages) { 27 | res.json(messages); 28 | }).catch(function(err) { 29 | res.status(500).json(err); 30 | }) 31 | }); 32 | 33 | const PORT = 8081 34 | 35 | app.listen(PORT, function(){ 36 | console.log(`Server is listening on port ${PORT}`); 37 | }); 38 | -------------------------------------------------------------------------------- /react/warbler-starter-server/models/index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | mongoose.set('debug', true); 3 | mongoose.Promise = global.Promise; 4 | mongoose.connect('mongodb://localhost/warbler', { 5 | keepAlive: true, 6 | reconnectTries: Number.MAX_VALUE, 7 | useMongoClient: true 8 | }); 9 | 10 | module.exports.User = require("./user"); 11 | module.exports.Message = require("./message"); 12 | 13 | -------------------------------------------------------------------------------- /react/warbler-starter-server/models/message.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | var User = require("./user"); 3 | 4 | 5 | var messageSchema = new mongoose.Schema({ 6 | text: { 7 | type: String, 8 | required: true, 9 | maxLength: 160 10 | }, 11 | userId: { 12 | type: mongoose.Schema.Types.ObjectId, 13 | ref: "User", 14 | required: true 15 | } 16 | }, { 17 | timestamps: true 18 | }); 19 | 20 | messageSchema.pre('remove', function(next){ 21 | User.findById(this.userId).then(user => { 22 | user.messages.remove(this.id); 23 | user.save().then(function(e){ 24 | next(); 25 | }); 26 | }).catch(function(err) { 27 | next(err); 28 | }); 29 | }); 30 | 31 | var Message = mongoose.model('Message', messageSchema); 32 | module.exports = Message; 33 | -------------------------------------------------------------------------------- /react/warbler-starter-server/models/user.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | var bcrypt = require("bcryptjs"); 3 | 4 | var userSchema = new mongoose.Schema({ 5 | email: { 6 | type: String, 7 | required: true, 8 | unique: true 9 | }, 10 | username: { 11 | type: String, 12 | required: true, 13 | unique: true 14 | }, 15 | password: { 16 | type: String, 17 | required: true 18 | }, 19 | profileImageUrl: { 20 | type:String, 21 | }, 22 | messages: [{ 23 | type: mongoose.Schema.Types.ObjectId, 24 | ref: 'Message' 25 | }] 26 | }); 27 | 28 | userSchema.pre('save', function(next){ 29 | var user = this; 30 | if (!user.isModified('password')) return next(); 31 | bcrypt.hash(user.password, 10).then(function(hashedPassword) { 32 | user.password = hashedPassword 33 | next(); 34 | }, function(err){ 35 | return next(err) 36 | }); 37 | }); 38 | 39 | userSchema.methods.comparePassword = function(candidatePassword, next) { 40 | bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { 41 | if(err) return next(err); 42 | next(null, isMatch); 43 | }); 44 | }; 45 | 46 | var User = mongoose.model('User', userSchema); 47 | module.exports = User; 48 | -------------------------------------------------------------------------------- /react/warbler-starter-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "warbler-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node ./node_modules/nodemon/bin/nodemon.js index.js", 9 | "debug": "node --inspect-brk app.js" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "bcryptjs": "^2.4.3", 16 | "body-parser": "^1.16.1", 17 | "cors": "^2.8.3", 18 | "dotenv": "^4.0.0", 19 | "express": "^4.14.1", 20 | "faker": "^4.1.0", 21 | "jsonwebtoken": "^7.3.0", 22 | "mongoose": "^4.8.4" 23 | }, 24 | "devDependencies": { 25 | "locus": "^2.0.1", 26 | "nodemon": "^1.11.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /react/warbler-starter-server/routes/auth.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | var db = require("../models"); 4 | var jwt = require('jsonwebtoken'); 5 | var helpers = require('../helpers/auth'); 6 | 7 | router.post('/signin', helpers.signin); 8 | router.post('/signup', helpers.signup); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /react/warbler-starter-server/routes/messages.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router({mergeParams: true}); 3 | var db = require("../models"); 4 | var helpers = require('../helpers/messages'); 5 | 6 | router.post('/', helpers.createMessage); 7 | 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /react/warbler/warbler-client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /react/warbler/warbler-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "warbler-client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.0.0-rc.3", 7 | "react-dom": "^16.0.0-rc.3", 8 | "react-scripts": "1.0.13" 9 | }, 10 | "proxy": "http://localhost:8081", 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } -------------------------------------------------------------------------------- /react/warbler/warbler-client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rithmschool/udemy_course_exercises/ab8246fa47b5c1158f9467eee37eec78475df559/react/warbler/warbler-client/public/favicon.ico -------------------------------------------------------------------------------- /react/warbler/warbler-client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /react/warbler/warbler-client/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /react/warbler/warbler-client/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | class App extends Component { 6 | render() { 7 | return ( 8 |
    9 |
    10 | logo 11 |

    Welcome to React

    12 |
    13 |

    14 | To get started, edit src/App.js and save to reload. 15 |

    16 |
    17 | ); 18 | } 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /react/warbler/warbler-client/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /react/warbler/warbler-client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /react/warbler/warbler-client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/.env: -------------------------------------------------------------------------------- 1 | SECRET_KEY=b9a4566aaa7a098e97a0a3d94036cfbd81538b4418199796 2 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/README.md: -------------------------------------------------------------------------------- 1 | # Warbler Server Starter 2 | 3 | The sever does token based authentication for signup and sign in 4 | 5 | ## Setup 6 | 7 | The server is a NodeJS application that uses express and mongoDB. To get setup: 8 | 9 | * run: `npm install` 10 | * Create a `.env` file. In the file, add 11 | 12 | ```js 13 | SECRET_KEY=longRandomStringOfCharacters 14 | ``` 15 | __DO NOT CHECK IN THIS FILE__ 16 | 17 | * npm start 18 | 19 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/helpers/auth.js: -------------------------------------------------------------------------------- 1 | var db = require('../models'); 2 | var jwt = require('jsonwebtoken'); 3 | 4 | exports.signin = function(req,res){ 5 | db.User.findOne({email: req.body.email}).then(function(user){ 6 | user.comparePassword(req.body.password, function(err, isMatch){ 7 | if(isMatch){ 8 | var token = jwt.sign({userId: user.id}, process.env.SECRET_KEY); 9 | res.status(200).json({userId: user.id, 10 | username: user.username, 11 | profileImageUrl: user.profileImageUrl, 12 | token 13 | }); 14 | } else { 15 | res.status(400).json({message: 'Invalid Email/Password.'}) 16 | } 17 | }) 18 | }).catch(function(err){ 19 | res.status(400).json({message: 'Invalid Email/Password'}) 20 | }) 21 | }; 22 | 23 | exports.signup = function(req, res, next){ 24 | db.User.create(req.body).then(function(user){ 25 | var token = jwt.sign({ userId: user.id}, process.env.SECRET_KEY); 26 | res.status(200).json({userId: user.id, 27 | username: user.username, 28 | profileImageUrl: user.profileImageUrl, 29 | token 30 | }); 31 | }).catch(function(err) { 32 | res.status(400).json(err); 33 | }); 34 | }; 35 | 36 | module.exports = exports; 37 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/helpers/messages.js: -------------------------------------------------------------------------------- 1 | var db = require('../models'); 2 | 3 | exports.createMessage = function(req,res,next){ 4 | const newMessage = { 5 | text: req.body.text, 6 | userId: req.params.id 7 | }; 8 | 9 | db.Message.create(newMessage).then(function(message){ 10 | db.User.findById(req.params.id).then(function(user){ 11 | user.messages.push(message.id) 12 | user.save().then(function(user) { 13 | return db.Message.findById(message._id) 14 | .populate("userId", {username: true, profileImageUrl: true}) 15 | }).then(function(m) { 16 | return res.status(200).json(m); 17 | }).catch(next); 18 | }).catch(next); 19 | }).catch(next); 20 | }; 21 | 22 | module.exports = exports; -------------------------------------------------------------------------------- /react/warbler/warbler-server/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config() 2 | var express = require("express"); 3 | var app = express(); 4 | var cors = require('cors'); 5 | var bodyParser = require("body-parser"); 6 | var authRoutes = require("./routes/auth"); 7 | var messagesRoutes = require("./routes/messages"); 8 | var auth = require('./middleware/auth'); 9 | var db = require("./models"); 10 | 11 | app.use(cors()); 12 | app.use(bodyParser.json()); 13 | app.use(bodyParser.urlencoded({extended:true})); 14 | 15 | app.get("/", function(req,res){ 16 | res.json({message: "Make a POST requst to /api/auth/signup to signup"}); 17 | }); 18 | 19 | app.use('/api/users/:id/messages', 20 | auth.loginRequired, auth.ensureCorrectUser, 21 | messagesRoutes); 22 | app.use('/api/auth', authRoutes); 23 | app.get('/api/messages', function(req, res, next) { 24 | db.Message.find().sort({createAt: 'desc'}) 25 | .populate("userId", {username: true, profileImageUrl: true}) 26 | .then(function(messages) { 27 | res.json(messages); 28 | }).catch(function(err) { 29 | res.status(500).json(err); 30 | }) 31 | }); 32 | 33 | const PORT = 8081 34 | 35 | app.listen(PORT, function(){ 36 | console.log(`Server is listening on port ${PORT}`); 37 | }); 38 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/models/index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | mongoose.set('debug', true); 3 | mongoose.Promise = global.Promise; 4 | mongoose.connect('mongodb://localhost/warbler', { 5 | keepAlive: true, 6 | reconnectTries: Number.MAX_VALUE, 7 | useMongoClient: true 8 | }); 9 | 10 | module.exports.User = require("./user"); 11 | module.exports.Message = require("./message"); 12 | 13 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/models/message.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | var User = require("./user"); 3 | 4 | 5 | var messageSchema = new mongoose.Schema({ 6 | text: { 7 | type: String, 8 | required: true, 9 | maxLength: 160 10 | }, 11 | userId: { 12 | type: mongoose.Schema.Types.ObjectId, 13 | ref: "User", 14 | required: true 15 | } 16 | }, { 17 | timestamps: true 18 | }); 19 | 20 | messageSchema.pre('remove', function(next){ 21 | User.findById(this.userId).then(user => { 22 | user.messages.remove(this.id); 23 | user.save().then(function(e){ 24 | next(); 25 | }); 26 | }).catch(function(err) { 27 | next(err); 28 | }); 29 | }); 30 | 31 | var Message = mongoose.model('Message', messageSchema); 32 | module.exports = Message; 33 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/models/user.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | var bcrypt = require("bcryptjs"); 3 | 4 | var userSchema = new mongoose.Schema({ 5 | email: { 6 | type: String, 7 | required: true, 8 | unique: true 9 | }, 10 | username: { 11 | type: String, 12 | required: true, 13 | unique: true 14 | }, 15 | password: { 16 | type: String, 17 | required: true 18 | }, 19 | profileImageUrl: { 20 | type:String, 21 | }, 22 | messages: [{ 23 | type: mongoose.Schema.Types.ObjectId, 24 | ref: 'Message' 25 | }] 26 | }); 27 | 28 | userSchema.pre('save', function(next){ 29 | var user = this; 30 | if (!user.isModified('password')) return next(); 31 | bcrypt.hash(user.password, 10).then(function(hashedPassword) { 32 | user.password = hashedPassword 33 | next(); 34 | }, function(err){ 35 | return next(err) 36 | }); 37 | }); 38 | 39 | userSchema.methods.comparePassword = function(candidatePassword, next) { 40 | bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { 41 | if(err) return next(err); 42 | next(null, isMatch); 43 | }); 44 | }; 45 | 46 | var User = mongoose.model('User', userSchema); 47 | module.exports = User; 48 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "warbler-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node ./node_modules/nodemon/bin/nodemon.js index.js", 9 | "debug": "node --inspect-brk app.js" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "bcryptjs": "^2.4.3", 16 | "body-parser": "^1.16.1", 17 | "cors": "^2.8.3", 18 | "dotenv": "^4.0.0", 19 | "express": "^4.14.1", 20 | "faker": "^4.1.0", 21 | "jsonwebtoken": "^7.3.0", 22 | "mongoose": "^4.8.4" 23 | }, 24 | "devDependencies": { 25 | "locus": "^2.0.1", 26 | "nodemon": "^1.11.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/routes/auth.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | var db = require("../models"); 4 | var jwt = require('jsonwebtoken'); 5 | var helpers = require('../helpers/auth'); 6 | 7 | router.post('/signin', helpers.signin); 8 | router.post('/signup', helpers.signup); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /react/warbler/warbler-server/routes/messages.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router({mergeParams: true}); 3 | var db = require("../models"); 4 | var helpers = require('../helpers/messages'); 5 | 6 | router.post('/', helpers.createMessage); 7 | 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /todos_api/helpers/todos.js: -------------------------------------------------------------------------------- 1 | var db = require('../models'); 2 | 3 | exports.getTodos = function(req, res){ 4 | db.Todo.find() 5 | .then(function(todos){ 6 | res.json(todos); 7 | }) 8 | .catch(function(err){ 9 | res.send(err); 10 | }) 11 | } 12 | 13 | exports.createTodo = function(req, res){ 14 | db.Todo.create(req.body) 15 | .then(function(newTodo){ 16 | res.status(201).json(newTodo); 17 | }) 18 | .catch(function(err){ 19 | res.send(err); 20 | }) 21 | } 22 | 23 | exports.getTodo = function(req, res){ 24 | db.Todo.findById(req.params.todoId) 25 | .then(function(foundTodo){ 26 | res.json(foundTodo); 27 | }) 28 | .catch(function(err){ 29 | res.send(err); 30 | }) 31 | } 32 | 33 | exports.updateTodo = function(req, res){ 34 | db.Todo.findOneAndUpdate({_id: req.params.todoId}, req.body, {new: true}) 35 | .then(function(todo){ 36 | res.json(todo); 37 | }) 38 | .catch(function(err){ 39 | res.send(err); 40 | }) 41 | } 42 | 43 | exports.deleteTodo = function(req, res){ 44 | db.Todo.remove({_id: req.params.todoId}) 45 | .then(function(){ 46 | res.json({message: 'We deleted it!'}); 47 | }) 48 | .catch(function(err){ 49 | res.send(err); 50 | }) 51 | } 52 | 53 | module.exports = exports; -------------------------------------------------------------------------------- /todos_api/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | app = express(), 3 | port = process.env.PORT || 3000, 4 | bodyParser = require('body-parser'); 5 | 6 | var todoRoutes = require("./routes/todos"); 7 | 8 | app.use(bodyParser.json()); 9 | app.use(bodyParser.urlencoded({extended: true})); 10 | app.use(express.static(__dirname +'/public')); 11 | app.use(express.static(__dirname + '/views')); 12 | 13 | app.get('/', function(req, res){ 14 | res.sendFile("index.html"); 15 | }); 16 | 17 | app.use('/api/todos', todoRoutes); 18 | 19 | app.listen(port, function(){ 20 | console.log("APP IS RUNNING ON PORT " + process.env.PORT); 21 | }) 22 | 23 | -------------------------------------------------------------------------------- /todos_api/models/index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | mongoose.set('debug', true); 3 | mongoose.connect('mongodb://localhost/todo-api'); 4 | 5 | mongoose.Promise = Promise; 6 | 7 | module.exports.Todo = require("./todo"); -------------------------------------------------------------------------------- /todos_api/models/todo.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | 3 | var todoSchema = new mongoose.Schema({ 4 | name: { 5 | type: String, 6 | required: 'Name cannot be blank!' 7 | }, 8 | completed: { 9 | type: Boolean, 10 | default: false 11 | }, 12 | created_date: { 13 | type: Date, 14 | default: Date.now 15 | } 16 | }); 17 | 18 | var Todo = mongoose.model('Todo', todoSchema); 19 | 20 | module.exports = Todo; -------------------------------------------------------------------------------- /todos_api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todos_api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.17.2", 13 | "express": "^4.15.4", 14 | "mongoose": "^4.11.9" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /todos_api/routes/todos.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var db = require("../models"); 4 | var helpers = require("../helpers/todos"); 5 | 6 | router.route('/') 7 | .get(helpers.getTodos) 8 | .post(helpers.createTodo) 9 | 10 | router.route('/:todoId') 11 | .get(helpers.getTodo) 12 | .put(helpers.updateTodo) 13 | .delete(helpers.deleteTodo) 14 | 15 | module.exports = router; -------------------------------------------------------------------------------- /todos_api/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 |
    11 |

    todolist

    12 |

    A simple todo list app built with node

    13 |
    14 | 15 |
    16 | 17 |
    18 | 19 |
      20 |
    21 | 22 | 23 | --------------------------------------------------------------------------------