diff --git a/homework/src/index.js b/homework/src/index.js index 1cb1638a0..eef602bab 100644 --- a/homework/src/index.js +++ b/homework/src/index.js @@ -1,19 +1,123 @@ 'use strict'; { - function fetchJSON(url, cb) { - const xhr = new XMLHttpRequest(); - xhr.open('GET', url); - xhr.responseType = 'json'; - xhr.onload = () => { - if (xhr.status < 400) { - cb(null, xhr.response); - } else { - cb(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`)); + const root = document.getElementById('root'); + const startupContainer = createAndAppend('div', root, { id: 'startup' }); + const headerStartupContainer = createAndAppend('h1', startupContainer, { html: 'HackYourFuture' }); + const descriptionFirstContainer = createAndAppend('h5', startupContainer, { html: '"Refugee code school in Amsterdam"' }); + const instructionsFirstContainer = createAndAppend('h4', startupContainer, { html: 'Select a repository to display information:' }); + const repositoryContainer = createAndAppend('div', root); + const contributorsContainer = createAndAppend('div', root); + + function fetchJSON(url) { + return new Promise(function (resolve, reject) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.send(); + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + if (xhr.status < 400) { + resolve(xhr.response); + } else { + reject(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`)); + } + } + }; + xhr.onerror = () => reject(new Error('Network request failed')); + }); + } + + function handleErrorStart(error) { + + createAndAppend('div', startupContainer, { html: error.message, class: 'alert-error' }); + } + + function handleErrorRepository(error) { + + const repositoryContainer2 = createAndAppend('div', repositoryContainer, { id: 'information' }); + const headerRepositoryContainer = createAndAppend('h2', repositoryContainer2, { html: 'Repository Description' }); + const innerRepositoryContainer = createAndAppend('div', repositoryContainer2); + createAndAppend('div', innerRepositoryContainer, { html: error.message, class: 'alert-error' }); + } + + function handleErrorContributors(error) { + + const contributorsContainer2 = createAndAppend('div', contributorsContainer, { id: 'contributors' }); + const headerContributorsContainer = createAndAppend('h2', contributorsContainer2, { html: 'Repository contributors' }); + const innerContributorContainer = createAndAppend('div', contributorsContainer2, { id: 'inner-contributors' }); + createAndAppend('div', innerContributorContainer, { html: error.message, class: 'alert-error' }); + } + + function startUpAndBuildSelectList(data) { + + const arrayOfObjects = JSON.parse(data); + const newSelect = createAndAppend('select', startupContainer, { id: 'select-menu' }); + + arrayOfObjects.sort(function (a, b) { + const nameA = a.name.toUpperCase(); + const nameB = b.name.toUpperCase(); + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; } - }; - xhr.onerror = () => cb(new Error('Network request failed')); - xhr.send(); + return 0; + }); + + const optionItem = createAndAppend('option', newSelect, { html: 'Select' }); + + for (let i = 0; i < arrayOfObjects.length; i++) { + const optionItem = createAndAppend('option', newSelect, { html: arrayOfObjects[i].name, value: i }); + } + + newSelect.addEventListener('change', handleNewRepositoryRequest => { + const newUrl = 'https://api.github.com/repos/HackYourFuture/' + arrayOfObjects[event.target.value].name; + repositoryContainer.innerHTML = ''; + contributorsContainer.innerHTML = ''; + + fetchJSON(newUrl).then(buildRepositoryInfoSection, handleErrorRepository).then(buildContributorsSection, handleErrorContributors); + }); + } + + function buildRepositoryInfoSection(data) { + + const repositoryContainer2 = createAndAppend('div', repositoryContainer, { id: 'information' }); + const headerRepositoryContainer = createAndAppend('h2', repositoryContainer2, { html: 'Repository Description' }); + const innerRepositoryContainer = createAndAppend('div', repositoryContainer2); + const repositoryObject = JSON.parse(data); + const table = createAndAppend('table', innerRepositoryContainer); + const tableRow1 = createAndAppend('tr', table); + const tableHeader1 = createAndAppend('th', tableRow1, { html: 'Repository' }); + const tableData1 = createAndAppend('td', tableRow1); + const webpageLink = createAndAppend('a', tableData1, { html: repositoryObject.name, href: repositoryObject.svn_url, target: '_blank' }); + const tableRow2 = createAndAppend('tr', table); + const tableHeader2 = createAndAppend('th', tableRow2, { html: 'Description:' }); + const tableData2 = createAndAppend('td', tableRow2, { html: repositoryObject.description }); + const tableRow3 = createAndAppend('tr', table); + const tableHeader3 = createAndAppend('th', tableRow3, { html: 'Forks:' }); + const tableData3 = createAndAppend('td', tableRow3, { html: repositoryObject.forks }); + const tableRow4 = createAndAppend('tr', table); + const tableHeader4 = createAndAppend('th', tableRow4, { html: 'Updated:' }); + const tableData4 = createAndAppend('td', tableRow4, { html: repositoryObject.updated_at }); + const contributorsUrl = repositoryObject.contributors_url; + + return fetchJSON(contributorsUrl); + } + + function buildContributorsSection(data) { + + const contributorsContainer2 = createAndAppend('div', contributorsContainer, { id: 'contributors' }); + const headerContributorsContainer = createAndAppend('h2', contributorsContainer2, { html: 'Repository contributors' }); + const innerContributorContainer = createAndAppend('div', contributorsContainer2, { id: 'inner-contributors' }); + const arrayOfContributors = JSON.parse(data); + + for (const contributor of arrayOfContributors) { + const singleContributorContainer = createAndAppend('div', innerContributorContainer, { class: 'single-contributor' }); + const contributorName = createAndAppend('h3', singleContributorContainer); + const contributorLink = createAndAppend('a', contributorName, { html: contributor.login, href: contributor.html_url, target: '_blank' }); + const contributorImage = createAndAppend('img', singleContributorContainer, { src: contributor.avatar_url, alt: 'profile picture of ' + contributor.login, class: 'profile-pictures' }); + } } function createAndAppend(name, parent, options = {}) { @@ -29,19 +133,5 @@ }); return elem; } - - function main(url) { - fetchJSON(url, (err, data) => { - const root = document.getElementById('root'); - if (err) { - createAndAppend('div', root, { html: err.message, class: 'alert-error' }); - } else { - createAndAppend('pre', root, { html: JSON.stringify(data, null, 2) }); - } - }); - } - - const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; - - window.onload = () => main(HYF_REPOS_URL); + fetchJSON("https://api.github.com/orgs/HackYourFuture/repos?per_page=100").then(startUpAndBuildSelectList, handleErrorStart); } diff --git a/homework/src/style.css b/homework/src/style.css index a8985a8a5..24e5008ae 100644 --- a/homework/src/style.css +++ b/homework/src/style.css @@ -1,3 +1,239 @@ + +body { + font-family: 'Raleway', sans-serif; + background-color:rgb(237,237,237); + color:rgb(92,83,74); +} + +* {box-sizing: border-box;} + +h1 { + font-size: 2.5vw; + color: rgb(0,118,163); + margin-bottom: 0px; +} + +h3 { + text-align: center; + font-size: 0.9vw; + color: rgb(85,85,85); +} + +h2 { + text-align: center; + padding: 1vw; + font-size: 1.8vw; + color: rgb(0,118,163); +} + +h4 { + font-size: 1vw; + font-weight: normal; + color: rgb(51,51,51); + margin-top: 1.5vw; + margin-bottom: 0.5vw; +} + +h5 { + font-size: 0.8vw; + font-weight: normal; + font-style: italic; + color: rgb(2, 98, 136); + margin-top: 0.8vw; +} + +#select-menu { + font-size: 1vw; + border-radius: 0.8vw; + padding: 0.3vw; +} + +table { + margin: 0 auto; + font-size: 1.2vw; + padding: 1vw; +} + +th {padding: 1vw;} + +td {padding: 1vw;} + +#startup { + position: fixed; + top:14vw; + left: 3.5%; + width: 23%; + padding: 1%; +} + +#information { + position: fixed; + background-color: white; + top:11vw; + left: 30%; + width: 40%; + padding: 1%; + border-radius:2vw; +} + +#contributors { + position: absolute; + top:3vw; + right: 3%; + width: 24%; + padding: 1%; +} + +#inner-contributors { + display: flex; + flex-wrap:wrap; + justify-content:space-around; +} + +.single-contributor { + width: 38%; + border-radius:1.5vw; + height: 9vw; + margin: 6%; +} + +.profile-pictures { + width: 50%; + margin-left: 25%; + border-radius: 1vw; +} + .alert-error { - color: red; + color: red; + background-color: rgb(250, 198, 198); + padding: 1vw; + border-radius:1.3vw; +} + +@media screen and (min-width:416px) and (max-width:1024px) { + + h1 {font-size: 3vw;} + + h3 {font-size: 1.6vw;} + + h2 {font-size: 2.5vw;} + + h4 {font-size: 1.3vw;} + + h5 {font-size: 1.2vw;} + + #select-menu { + font-size: 1.3vw; + border-radius:1vw; + } + + table { + font-size: 1.7vw; + } + + #startup { + position: absolute; + top: 8.5vw; + left: 3%; + width: 28%; + } + + #information { + position: absolute; + background-color: white; + top:4vw; + left: 37%; + width: 60%; + border-radius:3vw; + } + + #contributors { + position: relative; + top:37vw; + right: 0vw; + width: 100%; + } + + #inner-contributors { + display: flex; + flex-wrap:wrap; + justify-content:space-around; + } + + .single-contributor { + width: 15%; + border-radius:3vw; + height: 16vw; + margin: 2%; + } + + .profile-pictures { + width: 50%; + border-radius:2vw; + } + .alert-error {border-radius:1.5vw;} + +} + +@media screen and (max-width:415px) { + + h1 {font-size: 6vw;} + + h3 {font-size: 3.2vw;} + + h2 {font-size: 4.5vw;} + + h4 {font-size: 2.5vw;} + + h5 {font-size: 2vw;} + + #select-menu { + font-size: 2.5vw; + border-radius:1.5vw; + } + + table {font-size: 3vw;} + + #startup { + position: absolute; + top: 6vw; + left: 6.5%; + width: 92%; + } + + #information { + position: absolute; + background-color: white; + top:45vw; + left: 6.5%; + width: 86%; + padding: 3%; + border-radius:5vw; + } + + #contributors { + position: relative; + top:95vw; + right: 0vw; + width: 100%; + } + + #inner-contributors { + display: flex; + flex-wrap:wrap; + justify-content:space-around; + } + + .single-contributor { + width: 26%; + border-radius:3vw; + height: 28vw; + margin: 3%; + } + .single-contributor h3 {padding: 3%;} + .profile-pictures { + width: 50%; + border-radius:3.5vw; + } + .alert-error {border-radius:2.5vw;} } \ No newline at end of file