diff --git a/client/index.html b/client/index.html deleted file mode 100644 index 6f4402acf..000000000 --- a/client/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Group Project Base - - - - - - \ No newline at end of file diff --git a/client/script.js b/client/script.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/styles.css b/client/styles.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/css/style.css b/css/style.css new file mode 100644 index 000000000..d23ccd5a5 --- /dev/null +++ b/css/style.css @@ -0,0 +1,374 @@ +/* + New code bonus: pure CSS data loading icon + This comes from loading.io/css - it's nice to show that something is happening! +*/ + +* { + box-sizing: border-box; + } + footer h4 { + text-align: center; + width: auto; + + } + img { + height: 100px; + width: auto; + } + p { + align-self: center; + } + li { + align-self: center; + } + /* + These rules apply to actual HTML elements with no labelling! + So: they style the tags directly + */ + + html { + background-color: #fff; + font-size: 16px; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + + /* these are specific to different browsers */ + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + -webkit-text-size-adjust: 100%; + -moz-text-size-adjust: 100%; + text-size-adjust: 100%; + } + + body { + margin: 0; + padding: 0; + + font-family: ‘Segoe UI’, Candara, ‘Bitstream Vera Sans’, ‘DejaVu Sans’, ‘Bitsream Vera Sans’, ‘Trebuchet MS’, Verdana, ‘Verdana Ref’, sans-serif; + font-weight: 400; + line-height: 1.5; + background-color: rgb(239, 239, 239); + } + + + a { + display: inline-block; + text-decoration: none; + } + + h2 { + margin:0; + padding:0; + padding-bottom:1.5rem; + } + + form { + accent-color: hsla(120, 100%, 50%, 0.482); + } + + /* + - These styles use 'class names' + - You can apply them by using the 'class' attribute on your HTML + - like this:
+ - note that the period vanishes there! + */ + + + .wrapper { + min-height: 100vh; + display: flex; + flex-direction: column; + margin: 0; + flex: 1; +} + +.container { + margin: 0 20px; + display: flex; + justify-content: space-evenly; + align-items: start; + flex:1; +} + +.header { + padding-top: 1rem; + padding-left: 1rem; + padding-right: 1rem; + padding-bottom: 1.5rem; +} + +.box{ + + border: 2px dashed; + border-radius: 4px; + width: fit-content; + height:fit-content; + padding: 1.5rem; + margin: 0 auto; + } + .thickBox { + border: 3px dashed; + border-radius: 4px; + padding: 1.5rem; + margin:0; + } + + .left_section { + /* background-color: rgba(0, 139, 139, 0.8); */ + flex: 0 1 auto; + margin: 1rem; + padding: 1.5rem; + } + + .right_section { + /* background-color: rgba(255, 224, 138, 0.7); */ + flex: 1 2 auto; + margin: 1rem; + align-items: center; + display: flex; + flex-flow: column; + } + .green { + background-color: limegreen; + } + .orange { + background-color: orange; + } + /* + This block is actually dependent on the "container" block having a flex set on it + and the "wrapper" block displaying as a flex column with a "vertical height" (vh) of 100. + That serves to cram the footer to the bottom of the page. + */ + + .footer { + flex-shrink: 0; + padding: 1rem; + font-size: 1.2rem; + font-weight: 600; + } + + .footer a { + color:darkgreen; + text-decoration: underline; + } + + /* + This is an example of a 'pseudoclass' + In this instance, it says what to do if a mouse hovers over a link + This is pretty desktop-specific, since there's no hover function on touchscreens + */ + .footer a:hover { + /* Hue, saturation, luminosity, alpha */ + background-color: hsla(0, 0%, 90%, 0.15); + /* red, green, blue, alpha */ + color: lightgreen; + text-decoration: none; + } + + .subtitle { + color: rgba(0, 0, 0, 0.8); + margin: 0px; + margin-bottom: 5px; + } + + + /* Deploy this with images as direct "children" and the images should pop into shape */ + .grid { + display: flex; + justify-content: space-evenly; + flex-flow: wrap; + width: 350px; + height: 350px; + margin: 0 auto; + } + + .grid img { + width: 150px; + height: 150px; + } + + + /* Carousel */ + div.carousel { + max-width: 300px; + overflow: hidden; + text-align: center; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + margin: 0 auto; + margin-bottom: 1rem; + } + + .carousel .slides { + display: flex; + overflow-x: auto; + scroll-snap-type: x mandatory; + scroll-behavior: smooth; + -webkit-overflow-scrolling: touch; + } + + /* .carousel_item, */ + .hidden { + display: none; + } + + .visible { + display: block; + } + + .carousel_item img { + /* + Setting width, rather than max-width or min-width, + means annoying pop-ins won't happen + but it also means you need to format your images to be compatible + or they will stretch weird + + - try a tall one and see what happens + - change the height on a fixed image size and see what happens + - now make sure that images are _always_ square + - ... there's a reason crop tools are popular in image editors + */ + width: 150px; + height: 100px; + } + + .prev, + .next { + border: none; + margin: 2px; + text-align: center; + border-radius: 5px; + font-weight: bold; + height: 45px; + padding: 10px; + line-height: 0; /* This centers a button's text! */ + border: 2px solid rgb(99,99,99); /* shorthand for how to do a border */ + } + + .prev:focus, + .next:focus { + margin: 0; + /* Pick a good border colour and check out how it works with your buttons */ + } + + .prev:hover, + .next:hover { + background-color: rgb(246, 169, 93); + /* Pick a good background colour for your hover pseudoclass */ + } + + /* MAP STYLES */ + + #map { + display: block; + width: 400px; + height: 300px; + border: 2px dashed rgb(99,99,99); + margin-bottom: 1rem; + } + + /* + Form Styles + */ + + + form input { + /* This is a hack to make sure our boxes line up with one another nicely */ + width: 100%; + width: -moz-available; /* WebKit-based browsers will ignore this. */ + width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */ + width: fill-available; + + /* here we are setting white space correctly */ + margin-bottom: 1rem; + height: 2rem; + border-radius: 4px; + } + + form label { + width: 100%; + width: -moz-available; /* WebKit-based browsers will ignore this. */ + width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */ + width: fill-available; + align-items: flex-start; + + display: block; /* this turns the label text into a box we can set margins on */ + margin-bottom: 0.5rem; + } + .lds-ellipsis { + display: inline-block; + position: relative; + width: 80px; + height: 80px; + } + .lds-ellipsis_hidden { + display: hidden; + } + .lds-ellipsis div { + position: absolute; + top: 33px; + width: 13px; + height: 13px; + border-radius: 50%; + background: #fff; + animation-timing-function: cubic-bezier(0, 1, 1, 0); + } + .lds-ellipsis div:nth-child(1) { + left: 8px; + animation: lds-ellipsis1 0.6s infinite; + } + .lds-ellipsis div:nth-child(2) { + left: 8px; + animation: lds-ellipsis2 0.6s infinite; + } + .lds-ellipsis div:nth-child(3) { + left: 32px; + animation: lds-ellipsis2 0.6s infinite; + } + .lds-ellipsis div:nth-child(4) { + left: 56px; + animation: lds-ellipsis3 0.6s infinite; + } + @keyframes lds-ellipsis1 { + 0% { + transform: scale(0); + } + 100% { + transform: scale(1); + } + } + @keyframes lds-ellipsis3 { + 0% { + transform: scale(1); + } + 100% { + transform: scale(0); + } + } + @keyframes lds-ellipsis2 { + 0% { + transform: translate(0, 0); + } + 100% { + transform: translate(24px, 0); + } + } + + /* How To Write A Media Query For Small Screens */ + + @media only screen and (max-width: 736px){ + /* Rules in here will only apply when a screen is the correct size */ + /* check it out by using your developer tools to shrink your screen-size */ + .container { + background-color: rgba(204, 8, 162, 0.65); + flex-direction: column; + justify-content: center; + align-items: center; + } + } + + diff --git a/images/UMD-logo.jpg b/images/UMD-logo.jpg new file mode 100644 index 000000000..f731ea658 Binary files /dev/null and b/images/UMD-logo.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 000000000..109fa5578 --- /dev/null +++ b/index.html @@ -0,0 +1,33 @@ + + + + + + Failed House Insepctions API + + + + + +
+
+

Find Which House in PG County has Failed it's House Inspection!

+
+

Filter Violation Codes by the Top Six Violation Codes in Maryland

+
  • Violation 1H1
  • +
  • Violation 1H2
  • +
  • Violation 1H4
  • +
  • Violation 1H7
  • +
  • Violation 1H9
  • +
  • Violation OWL
  • +
    +

    This Webpage was designed by Joseph Hartner and Sumeet Singh
    UMD Logo

    +
    +
    + + + \ No newline at end of file diff --git a/js/1h1.js b/js/1h1.js new file mode 100644 index 000000000..92be64e7b --- /dev/null +++ b/js/1h1.js @@ -0,0 +1,122 @@ +/* eslint-disable max-len */ +/* eslint linebreak-style: ["error", "windows"] */ + +// function used to grab random number from the API // + +function getRandomInclusive(min, max) { + const newMin = Math.ceil(min); + const newMax = Math.floor(max); + return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); +} + +// The function that injects the HTML page with information from the API // +function injectHTML(list) { + console.log('fired injectHTML'); + const target = document.querySelector('#house_list'); + target.innerHTML = ''; + + const listEl = document.createElement('ol'); + target.appendChild(listEl); + + list.forEach((item) => { + const el = document.createElement('li'); + el.innerText = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`; + listEl.appendChild(el); + }); +} + +// Function that fliters the list from the API data. // +function filterList(list, filterInputValue) { + return list.filter((item) => { + const lowerCaseName = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`.toLowerCase(); + const lowerCaseQuery = filterInputValue.toLowerCase(); + return lowerCaseName.includes(lowerCaseQuery); + }); +} + +// Function that process the house list into an array of 10 houses per search // +function processHouse(list) { + const range = [...Array(10).keys()]; + const newArray = range.map((item) => { + const index = getRandomInclusive(0, list.length); + return list[index]; + }); + return newArray; +} + +// The function that is incharge of the objects for the map location // +function initMap() { + console.log('initMap'); + const map = L.map('map').setView([38.9897, -76.9378], 13); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: + '© OpenStreetMap' + }).addTo(map); + return map; +} + +// The fucntion that adds a marker placement onto the map // +function markerPlace(array, map) { + console.log('markerPlace', array); + map.eachLayer((layer) => { + if (layer instanceof L.Marker) { + layer.remove(); + } + }); + array.forEach((item, index) => { + const lat = item.location.latitude; + const long = item.location.longitude; + console.log([lat, long]); + L.marker([lat, long]).addTo(map); + if (index === 0) { + map.setView([lat, long], 10); + } + }); +} + +// The async function that retreives the GET request information // +async function violationH1() { + const url = 'https://data.princegeorgescountymd.gov/resource/9hyf-46qb.json?violation_code=1H1&$where=within_circle(location,%2038.83063,%20-76.901726,%20500000)'; + const data = await fetch(url); + const json = await data.json(); + const reply = json.filter((item) => Boolean(item.violation_code)).filter((item) => Boolean(item.location)); + console.log(reply); + return reply; +} + +// The async function that runs all the rpevious functions into our HTML file // +async function mainEvent() { + const form = document.querySelector('.main_form'); + const loadAnimation = document.querySelector('.lds-ellipsis'); + const h1 = document.querySelector('#violationh1'); + + h1.style.display = 'none'; + + const pageMap = initMap(); + const violation1 = await violationH1(); + + if (violation1.length > 0) { + h1.style.display = 'block'; + loadAnimation.classList.remove('lds-ellipsis'); + loadAnimation.classList.add('lds-ellipsis_hidden'); + + let currentList = []; + form.addEventListener('input', (event) => { + console.log(event.target.value); + const newFilterList = filterList(currentList, event.target.value); + injectHTML(newFilterList); + markerPlace(newFilterList, pageMap); + }); + + form.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + + currentList = processHouse(violation1); + + injectHTML(currentList); + markerPlace(currentList, pageMap); + }); + } +} +document.addEventListener('DOMContentLoaded', async () => mainEvent()); \ No newline at end of file diff --git a/js/1h2.js b/js/1h2.js new file mode 100644 index 000000000..2343c38e2 --- /dev/null +++ b/js/1h2.js @@ -0,0 +1,122 @@ +/* eslint-disable max-len */ +/* eslint linebreak-style: ["error", "windows"] */ + +// function used to grab random number from the API // + +function getRandomInclusive(min, max) { + const newMin = Math.ceil(min); + const newMax = Math.floor(max); + return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); +} + +// The function that injects the HTML page with information from the API // +function injectHTML(list) { + console.log('fired injectHTML'); + const target = document.querySelector('#house_list'); + target.innerHTML = ''; + + const listEl = document.createElement('ol'); + target.appendChild(listEl); + + list.forEach((item) => { + const el = document.createElement('li'); + el.innerText = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`; + listEl.appendChild(el); + }); +} + +// Function that fliters the list from the API data. // +function filterList(list, filterInputValue) { + return list.filter((item) => { + const lowerCaseName = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`.toLowerCase(); + const lowerCaseQuery = filterInputValue.toLowerCase(); + return lowerCaseName.includes(lowerCaseQuery); + }); +} + +// Function that process the house list into an array of 10 houses per search // +function processHouse(list) { + const range = [...Array(10).keys()]; + const newArray = range.map((item) => { + const index = getRandomInclusive(0, list.length); + return list[index]; + }); + return newArray; +} + +// The function that is incharge of the objects for the map location // +function initMap() { + console.log('initMap'); + const map = L.map('map').setView([38.9897, -76.9378], 13); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: + '© OpenStreetMap' + }).addTo(map); + return map; +} + +// The fucntion that adds a marker placement onto the map // +function markerPlace(array, map) { + console.log('markerPlace', array); + map.eachLayer((layer) => { + if (layer instanceof L.Marker) { + layer.remove(); + } + }); + array.forEach((item, index) => { + const lat = item.location.latitude; + const long = item.location.longitude; + console.log([lat, long]); + L.marker([lat, long]).addTo(map); + if (index === 0) { + map.setView([lat, long], 10); + } + }); +} + +// The async function that retreives the GET request information // +async function violationH2() { + const url = 'https://data.princegeorgescountymd.gov/resource/9hyf-46qb.json?violation_code=1H2&$where=within_circle(location,%2038.83063,%20-76.901726,%20500000)'; + const data = await fetch(url); + const json = await data.json(); + const reply = json.filter((item) => Boolean(item.violation_code)).filter((item) => Boolean(item.location)); + console.log(reply); + return reply; +} + +// The async function that runs all the rpevious functions into our HTML file // +async function mainEvent() { + const form = document.querySelector('.main_form'); + const loadAnimation = document.querySelector('.lds-ellipsis'); + const h2 = document.querySelector('#violationh2'); + + h2.style.display = 'none'; + + const pageMap = initMap(); + const violation2 = await violationH2(); + + if (violation2.length > 0) { + h2.style.display = 'block'; + loadAnimation.classList.remove('lds-ellipsis'); + loadAnimation.classList.add('lds-ellipsis_hidden'); + + let currentList = []; + form.addEventListener('input', (event) => { + console.log(event.target.value); + const newFilterList = filterList(currentList, event.target.value); + injectHTML(newFilterList); + markerPlace(newFilterList, pageMap); + }); + + form.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + + currentList = processHouse(violation2); + + injectHTML(currentList); + markerPlace(currentList, pageMap); + }); + } +} +document.addEventListener('DOMContentLoaded', async () => mainEvent()); \ No newline at end of file diff --git a/js/1h4.js b/js/1h4.js new file mode 100644 index 000000000..b885a0cf5 --- /dev/null +++ b/js/1h4.js @@ -0,0 +1,122 @@ +/* eslint-disable max-len */ +/* eslint linebreak-style: ["error", "windows"] */ + +// function used to grab random number from the API // + +function getRandomInclusive(min, max) { + const newMin = Math.ceil(min); + const newMax = Math.floor(max); + return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); +} + +// The function that injects the HTML page with information from the API // +function injectHTML(list) { + console.log('fired injectHTML'); + const target = document.querySelector('#house_list'); + target.innerHTML = ''; + + const listEl = document.createElement('ol'); + target.appendChild(listEl); + + list.forEach((item) => { + const el = document.createElement('li'); + el.innerText = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`; + listEl.appendChild(el); + }); +} + +// Function that fliters the list from the API data. // +function filterList(list, filterInputValue) { + return list.filter((item) => { + const lowerCaseName = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`.toLowerCase(); + const lowerCaseQuery = filterInputValue.toLowerCase(); + return lowerCaseName.includes(lowerCaseQuery); + }); +} + +// Function that process the house list into an array of 10 houses per search // +function processHouse(list) { + const range = [...Array(10).keys()]; + const newArray = range.map((item) => { + const index = getRandomInclusive(0, list.length); + return list[index]; + }); + return newArray; +} + +// The function that is incharge of the objects for the map location // +function initMap() { + console.log('initMap'); + const map = L.map('map').setView([38.9897, -76.9378], 13); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: + '© OpenStreetMap' + }).addTo(map); + return map; +} + +// The fucntion that adds a marker placement onto the map // +function markerPlace(array, map) { + console.log('markerPlace', array); + map.eachLayer((layer) => { + if (layer instanceof L.Marker) { + layer.remove(); + } + }); + array.forEach((item, index) => { + const lat = item.location.latitude; + const long = item.location.longitude; + console.log([lat, long]); + L.marker([lat, long]).addTo(map); + if (index === 0) { + map.setView([lat, long], 10); + } + }); +} + +// The async function that retreives the GET request information // +async function violationH4() { + const url = 'https://data.princegeorgescountymd.gov/resource/9hyf-46qb.json?violation_code=1H4&$where=within_circle(location,%2038.83063,%20-76.901726,%20500000)'; + const data = await fetch(url); + const json = await data.json(); + const reply = json.filter((item) => Boolean(item.violation_code)).filter((item) => Boolean(item.location)); + console.log(reply); + return reply; +} + +// The async function that runs all the rpevious functions into our HTML file // +async function mainEvent() { + const form = document.querySelector('.main_form'); + const loadAnimation = document.querySelector('.lds-ellipsis'); + const h4 = document.querySelector('#violationh4'); + + h4.style.display = 'none'; + + const pageMap = initMap(); + const violation4 = await violationH4(); + + if (violation4.length > 0) { + h4.style.display = 'block'; + loadAnimation.classList.remove('lds-ellipsis'); + loadAnimation.classList.add('lds-ellipsis_hidden'); + + let currentList = []; + form.addEventListener('input', (event) => { + console.log(event.target.value); + const newFilterList = filterList(currentList, event.target.value); + injectHTML(newFilterList); + markerPlace(newFilterList, pageMap); + }); + + form.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + + currentList = processHouse(violation4); + + injectHTML(currentList); + markerPlace(currentList, pageMap); + }); + } +} +document.addEventListener('DOMContentLoaded', async () => mainEvent()); \ No newline at end of file diff --git a/js/1h7.js b/js/1h7.js new file mode 100644 index 000000000..b451dcb12 --- /dev/null +++ b/js/1h7.js @@ -0,0 +1,122 @@ +/* eslint-disable max-len */ +/* eslint linebreak-style: ["error", "windows"] */ + +// function used to grab random number from the API // + +function getRandomInclusive(min, max) { + const newMin = Math.ceil(min); + const newMax = Math.floor(max); + return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); +} + +// The function that injects the HTML page with information from the API // +function injectHTML(list) { + console.log('fired injectHTML'); + const target = document.querySelector('#house_list'); + target.innerHTML = ''; + + const listEl = document.createElement('ol'); + target.appendChild(listEl); + + list.forEach((item) => { + const el = document.createElement('li'); + el.innerText = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`; + listEl.appendChild(el); + }); +} + +// Function that fliters the list from the API data. // +function filterList(list, filterInputValue) { + return list.filter((item) => { + const lowerCaseName = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`.toLowerCase(); + const lowerCaseQuery = filterInputValue.toLowerCase(); + return lowerCaseName.includes(lowerCaseQuery); + }); +} + +// Function that process the house list into an array of 10 houses per search // +function processHouse(list) { + const range = [...Array(10).keys()]; + const newArray = range.map((item) => { + const index = getRandomInclusive(0, list.length); + return list[index]; + }); + return newArray; +} + +// The function that is incharge of the objects for the map location // +function initMap() { + console.log('initMap'); + const map = L.map('map').setView([38.9897, -76.9378], 13); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: + '© OpenStreetMap' + }).addTo(map); + return map; +} + +// The fucntion that adds a marker placement onto the map // +function markerPlace(array, map) { + console.log('markerPlace', array); + map.eachLayer((layer) => { + if (layer instanceof L.Marker) { + layer.remove(); + } + }); + array.forEach((item, index) => { + const lat = item.location.latitude; + const long = item.location.longitude; + console.log([lat, long]); + L.marker([lat, long]).addTo(map); + if (index === 0) { + map.setView([lat, long], 10); + } + }); +} + +// The async function that retreives the GET request information // +async function violationH7() { + const url = 'https://data.princegeorgescountymd.gov/resource/9hyf-46qb.json?violation_code=1H7&$where=within_circle(location,%2038.83063,%20-76.901726,%20500000)'; + const data = await fetch(url); + const json = await data.json(); + const reply = json.filter((item) => Boolean(item.violation_code)).filter((item) => Boolean(item.location)); + console.log(reply); + return reply; +} + +// The async function that runs all the rpevious functions into our HTML file // +async function mainEvent() { + const form = document.querySelector('.main_form'); + const loadAnimation = document.querySelector('.lds-ellipsis'); + const h7 = document.querySelector('#violationh7'); + + h7.style.display = 'none'; + + const pageMap = initMap(); + const violation7 = await violationH7(); + + if (violation7.length > 0) { + h7.style.display = 'block'; + loadAnimation.classList.remove('lds-ellipsis'); + loadAnimation.classList.add('lds-ellipsis_hidden'); + + let currentList = []; + form.addEventListener('input', (event) => { + console.log(event.target.value); + const newFilterList = filterList(currentList, event.target.value); + injectHTML(newFilterList); + markerPlace(newFilterList, pageMap); + }); + + form.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + + currentList = processHouse(violation7); + + injectHTML(currentList); + markerPlace(currentList, pageMap); + }); + } +} +document.addEventListener('DOMContentLoaded', async () => mainEvent()); \ No newline at end of file diff --git a/js/1h9.js b/js/1h9.js new file mode 100644 index 000000000..6e0f4b705 --- /dev/null +++ b/js/1h9.js @@ -0,0 +1,122 @@ +/* eslint-disable max-len */ +/* eslint linebreak-style: ["error", "windows"] */ + +// function used to grab random number from the API // + +function getRandomInclusive(min, max) { + const newMin = Math.ceil(min); + const newMax = Math.floor(max); + return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); +} + +// The function that injects the HTML page with information from the API // +function injectHTML(list) { + console.log('fired injectHTML'); + const target = document.querySelector('#house_list'); + target.innerHTML = ''; + + const listEl = document.createElement('ol'); + target.appendChild(listEl); + + list.forEach((item) => { + const el = document.createElement('li'); + el.innerText = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`; + listEl.appendChild(el); + }); +} + +// Function that fliters the list from the API data. // +function filterList(list, filterInputValue) { + return list.filter((item) => { + const lowerCaseName = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`.toLowerCase(); + const lowerCaseQuery = filterInputValue.toLowerCase(); + return lowerCaseName.includes(lowerCaseQuery); + }); +} + +// Function that process the house list into an array of 10 houses per search // +function processHouse(list) { + const range = [...Array(10).keys()]; + const newArray = range.map((item) => { + const index = getRandomInclusive(0, list.length); + return list[index]; + }); + return newArray; +} + +// The function that is incharge of the objects for the map location // +function initMap() { + console.log('initMap'); + const map = L.map('map').setView([38.9897, -76.9378], 13); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: + '© OpenStreetMap' + }).addTo(map); + return map; +} + +// The fucntion that adds a marker placement onto the map // +function markerPlace(array, map) { + console.log('markerPlace', array); + map.eachLayer((layer) => { + if (layer instanceof L.Marker) { + layer.remove(); + } + }); + array.forEach((item, index) => { + const lat = item.location.latitude; + const long = item.location.longitude; + console.log([lat, long]); + L.marker([lat, long]).addTo(map); + if (index === 0) { + map.setView([lat, long], 10); + } + }); +} + +// The async function that retreives the GET request information // +async function violationH9() { + const url = 'https://data.princegeorgescountymd.gov/resource/9hyf-46qb.json?violation_code=1H9&$where=within_circle(location,%2038.83063,%20-76.901726,%20500000)'; + const data = await fetch(url); + const json = await data.json(); + const reply = json.filter((item) => Boolean(item.violation_code)).filter((item) => Boolean(item.location)); + console.log(reply); + return reply; +} + +// The async function that runs all the rpevious functions into our HTML file // +async function mainEvent() { + const form = document.querySelector('.main_form'); + const loadAnimation = document.querySelector('.lds-ellipsis'); + const h9 = document.querySelector('#violationh9'); + + h9.style.display = 'none'; + + const pageMap = initMap(); + const violation9 = await violationH9(); + + if (violation9.length > 0) { + h9.style.display = 'block'; + loadAnimation.classList.remove('lds-ellipsis'); + loadAnimation.classList.add('lds-ellipsis_hidden'); + + let currentList = []; + form.addEventListener('input', (event) => { + console.log(event.target.value); + const newFilterList = filterList(currentList, event.target.value); + injectHTML(newFilterList); + markerPlace(newFilterList, pageMap); + }); + + form.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + + currentList = processHouse(violation9); + + injectHTML(currentList); + markerPlace(currentList, pageMap); + }); + } +} +document.addEventListener('DOMContentLoaded', async () => mainEvent()); \ No newline at end of file diff --git a/js/owl.js b/js/owl.js new file mode 100644 index 000000000..188de63a0 --- /dev/null +++ b/js/owl.js @@ -0,0 +1,122 @@ +/* eslint-disable max-len */ +/* eslint linebreak-style: ["error", "windows"] */ + +// function used to grab random number from the API // + +function getRandomInclusive(min, max) { + const newMin = Math.ceil(min); + const newMax = Math.floor(max); + return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); +} + +// The function that injects the HTML page with information from the API // +function injectHTML(list) { + console.log('fired injectHTML'); + const target = document.querySelector('#house_list'); + target.innerHTML = ''; + + const listEl = document.createElement('ol'); + target.appendChild(listEl); + + list.forEach((item) => { + const el = document.createElement('li'); + el.innerText = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`; + listEl.appendChild(el); + }); +} + +// Function that fliters the list from the API data. // +function filterList(list, filterInputValue) { + return list.filter((item) => { + const lowerCaseName = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`.toLowerCase(); + const lowerCaseQuery = filterInputValue.toLowerCase(); + return lowerCaseName.includes(lowerCaseQuery); + }); +} + +// Function that process the house list into an array of 10 houses per search // +function processHouse(list) { + const range = [...Array(10).keys()]; + const newArray = range.map((item) => { + const index = getRandomInclusive(0, list.length); + return list[index]; + }); + return newArray; +} + +// The function that is incharge of the objects for the map location // +function initMap() { + console.log('initMap'); + const map = L.map('map').setView([38.9897, -76.9378], 13); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: + '© OpenStreetMap' + }).addTo(map); + return map; +} + +// The fucntion that adds a marker placement onto the map // +function markerPlace(array, map) { + console.log('markerPlace', array); + map.eachLayer((layer) => { + if (layer instanceof L.Marker) { + layer.remove(); + } + }); + array.forEach((item, index) => { + const lat = item.location.latitude; + const long = item.location.longitude; + console.log([lat, long]); + L.marker([lat, long]).addTo(map); + if (index === 0) { + map.setView([lat, long], 10); + } + }); +} + +// The async function that retreives the GET request information // +async function violationOwl() { + const url = 'https://data.princegeorgescountymd.gov/resource/9hyf-46qb.json?violation_code=OWL&$where=within_circle(location,%2038.83063,%20-76.901726,%20500000)'; + const data = await fetch(url); + const json = await data.json(); + const reply = json.filter((item) => Boolean(item.violation_code)).filter((item) => Boolean(item.location)); + console.log(reply); + return reply; +} + +// The async function that runs all the rpevious functions into our HTML file // +async function mainEvent() { + const form = document.querySelector('.main_form'); + const loadAnimation = document.querySelector('.lds-ellipsis'); + const owl = document.querySelector('#violationowl'); + + owl.style.display = 'none'; + + const pageMap = initMap(); + const violationO = await violationOwl(); + + if (violationO.length > 0) { + owl.style.display = 'block'; + loadAnimation.classList.remove('lds-ellipsis'); + loadAnimation.classList.add('lds-ellipsis_hidden'); + + let currentList = []; + form.addEventListener('input', (event) => { + console.log(event.target.value); + const newFilterList = filterList(currentList, event.target.value); + injectHTML(newFilterList); + markerPlace(newFilterList, pageMap); + }); + + form.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + + currentList = processHouse(violationO); + + injectHTML(currentList); + markerPlace(currentList, pageMap); + }); + } +} +document.addEventListener('DOMContentLoaded', async () => mainEvent()); \ No newline at end of file diff --git a/js/script.js b/js/script.js new file mode 100644 index 000000000..8dc79bf69 --- /dev/null +++ b/js/script.js @@ -0,0 +1,114 @@ +/* eslint-disable max-len */ +/* eslint linebreak-style: ["error", "windows"] */ + +// function used to grab random number from the API // +function getRandomInclusive(min, max) { + const newMin = Math.ceil(min); + const newMax = Math.floor(max); + return Math.floor(Math.random() * (newMax - newMin + 1) + newMin); +} +// The function that injects the HTML page with information from the API // +function injectHTML(list) { + console.log('fired injectHTML'); + const target = document.querySelector('#house_list'); + target.innerHTML = ''; + + const listEl = document.createElement('ol'); + target.appendChild(listEl); + + list.forEach((item) => { + const el = document.createElement('li'); + el.innerText = `${item.street_number} ${item.street_name} ${item.street_type + } ${item.zip_code}`; + listEl.appendChild(el); + }); +} +// Function that fliters the list from the API data. // +function filterList(list, filterInputValue) { + return list.filter((item) => { + const lowerCaseName = `${item.street_number} ${item.street_name} ${item.street_type} ${item.zip_code}`.toLowerCase(); + const lowerCaseQuery = filterInputValue.toLowerCase(); + return lowerCaseName.includes(lowerCaseQuery); + }); +} +// Function that process the house list into an array of 10 houses per search // +function processHouse(list) { + const range = [...Array(10).keys()]; + const newArray = range.map((item) => { + const index = getRandomInclusive(0, list.length); + return list[index]; + }); + return newArray; +} +// The function that is incharge of the objects for the map location // +function initMap() { + console.log('initMap'); + const map = L.map('map').setView([38.9897, -76.9378], 13); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© OpenStreetMap' + }).addTo(map); + return map; +} +// The fucntion that adds a marker placement onto the map // +function markerPlace(array, map) { + console.log('markerPlace', array); + map.eachLayer((layer) => { + if (layer instanceof L.Marker) { + layer.remove(); + } + }); + array.forEach((item, index) => { + const lat = item.location.latitude; + const long = item.location.longitude; + console.log([lat, long]); + L.marker([lat, long]).addTo(map); + if (index === 0) { + map.setView([lat, long], 10); + } + }); +} +// The async function that retreives the GET request information // +async function getData() { + const url = 'https://data.princegeorgescountymd.gov/resource/9hyf-46qb.json&$where=within_circle(location,%2038.83063,%20-76.901726,%20500000)'; + const data = await fetch(url); + const json = await data.json(); + const reply = json.filter((item) => Boolean(item.location)).filter((item) => Boolean(item.violation_code)); + console.log(reply); + return reply; +} +// The async function that runs all the rpevious functions into our HTML file // +async function mainEvent() { + const form = document.querySelector('.main_form'); + const submit = document.querySelector('#get-house'); + const loadAnimation = document.querySelector('.lds-ellipsis'); + + submit.style.display = 'none'; + + const pageMap = initMap(); + const mapData = await getData(); + + if (violation1.length > 0) { + submit.style.display = 'block'; + loadAnimation.classList.remove('lds-ellipsis'); + loadAnimation.classList.add('lds-ellipsis_hidden'); + + let currentList = []; + form.addEventListener('input', (event) => { + console.log(event.target.value); + const newFilterList = filterList(currentList, event.target.value); + injectHTML(newFilterList); + markerPlace(newFilterList, pageMap); + }); + + form.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + + currentList = processHouse(mapData); + + injectHTML(currentList); + markerPlace(currentList, pageMap); + }); + } +} +document.addEventListener('DOMContentLoaded', async () => mainEvent()); \ No newline at end of file diff --git a/links/1h1.html b/links/1h1.html new file mode 100644 index 000000000..6fb7a93e2 --- /dev/null +++ b/links/1h1.html @@ -0,0 +1,36 @@ + + + + + + 1H1 Violation Code + + + + + + Home +
    +

    This is the violation page for the 1H1 code

    +
    +
    +

    Map Location of Failed House

    +

    1h1: International Property Maintenance Code - Building elements, site conditions, swimming pools, plumbing, mechanical, electrical and fire protection systems in residential & nonresidential structures

    +
    +

    Filtered Failed Homes:

    + +
    + +
    +
    +

    A list of failed homes from the PG County open API

    +
    +
    +
    + + + \ No newline at end of file diff --git a/links/1h2.html b/links/1h2.html new file mode 100644 index 000000000..906a1a032 --- /dev/null +++ b/links/1h2.html @@ -0,0 +1,36 @@ + + + + + + 1H2 Violation Code + + + + + + Home +
    +

    This is the violation page for the 1H2 code

    +
    +
    +

    Map Location of Failed House

    +

    1h2: International Property Maintenance Code - Building elements, site conditions, swimming pools, plumbing, mechanical, electrical and fire protection systems in residential & nonresidential structures

    +
    +

    Filtered Failed Homes:

    + +
    + +
    +
    +

    A list of failed homes from the PG County open API

    +
    +
    +
    + + + \ No newline at end of file diff --git a/links/1h4.html b/links/1h4.html new file mode 100644 index 000000000..4e24f3590 --- /dev/null +++ b/links/1h4.html @@ -0,0 +1,36 @@ + + + + + + 1H4 Violation Code + + + + + + Home +
    +

    This is the violation page for the 1H4 code

    +
    +
    +

    Map Location of Failed House

    +

    1h4: International Property Maintenance Code - Building elements, site conditions, swimming pools, plumbing, mechanical, electrical and fire protection systems in residential & nonresidential structures

    +
    +

    Filtered Failed Homes:

    + +
    + +
    +
    +

    A list of failed homes from the PG County open API

    +
    +
    +
    + + + \ No newline at end of file diff --git a/links/1h7.html b/links/1h7.html new file mode 100644 index 000000000..267e40425 --- /dev/null +++ b/links/1h7.html @@ -0,0 +1,37 @@ + + + + + 1H7 Violation Code + + + + + + Home +
    +

    This is the violation page for the 1H7 code

    +
    +
    +

    Map Location of Failed House

    + +
    +

    Filtered Failed Homes:

    + +
    + +
    +
    +

    A list of failed homes from the PG County open API

    +
    +
    +
    + + + \ No newline at end of file diff --git a/links/1h9.html b/links/1h9.html new file mode 100644 index 000000000..d12e78505 --- /dev/null +++ b/links/1h9.html @@ -0,0 +1,36 @@ + + + + + + 1H9 Violation Code + + + + + + Home +
    +

    This is the violation page for the 1H9 code

    +
    +
    +

    Map Location of Failed House

    +

    1h9: Prince George's

    +
    +

    Filtered Failed Homes:

    + +
    + +
    +
    +

    A list of failed homes from the PG County open API

    +
    +
    +
    + + + \ No newline at end of file diff --git a/links/owl.html b/links/owl.html new file mode 100644 index 000000000..622f6e3b0 --- /dev/null +++ b/links/owl.html @@ -0,0 +1,37 @@ + + + + + + OWL Violation Code + + + + + + + Home +
    +

    This is the violation page for the OWL code

    +
    +
    +

    Map Location of Failed House

    +

    1h9: PG County Code

    +
    +

    Filtered Failed Homes:

    + +
    + +
    +
    +

    A list of failed homes from the PG County open API

    +
    +
    +
    + + + \ No newline at end of file diff --git a/routes/apiRoutes.js b/routes/apiRoutes.js deleted file mode 100644 index 3c599dd0f..000000000 --- a/routes/apiRoutes.js +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable no-console */ -import express from 'express'; -import fetch from 'node-fetch'; - -import foodService from './foodService.js'; - -const router = express.Router(); - -router.get('/', (req, res) => { - res.send('Welcome to the UMD Dining API!'); -}); - -// Generic API inclusion demonstration -// Replace this with the group member's actual route -// This leads to /api/member1 -router.use('/foodService', foodService); - -export default router; diff --git a/routes/foodService.js b/routes/foodService.js deleted file mode 100644 index 574596c69..000000000 --- a/routes/foodService.js +++ /dev/null @@ -1,97 +0,0 @@ -import express from 'express'; -import fetch from 'node-fetch'; - -const router = express.Router(); - -// -// This is a demo of how to structure your final project API -// One route file is expected per student, with appropriate HTTP methods on each endpoint -// - -// ///////////////////////////////// -// Food Inspection Set Demos -// ///////////////////////////////// -router.route('/foodServicesPG') // actually localhost:3000/api/foodServicesPG - .get(async (req, res) => { - try { - const url = 'https://data.princegeorgescountymd.gov/resource/umjn-t2iz.json'; - const data = await fetch(url); - const json = await data.json(); - console.log(json); - - res.json({data: json}); - } catch (error) { - console.log(error); - res.json({error: error}); - } - }) - .put((req, res) => { - try { - res.json({message: 'put FoodServices endpoint'}); - } catch (error) { - console.log(error); - res.json({error: 'Something went wrong on the server'}); - } - }) - .post((req, res) => { - try { - res.json({message: 'post FoodServices endpoint'}); - } catch (error) { - console.log(error); - res.json({error: 'Something went wrong on the server'}); - } - }) - .delete((req, res) => { - try { - res.json({message: 'delete FoodServices endpoint'}); - } catch (error) { - console.log(error); - res.json({error: 'Something went wrong on the server'}); - } - }); - -router.route('/foodServicesPG/:zipCode') // actually localhost:3000/api/foodServicesPG/20782 - .get(async (req, res) => { - try { - const url = 'https://data.princegeorgescountymd.gov/resource/umjn-t2iz.json'; - const request = await fetch(url); - const json = await request.json(); - console.log(json); - - const filteredList = json.filter((item, index) => { - const {zipCode} = req.params; - return item.zip === zipCode; - }); - - res.json({data: filteredList}); - } catch (error) { - console.log(error); - res.json({error: error}); - } - }) - .put((req, res) => { - try { - res.json({message: 'put FoodServices ID endpoint'}); - } catch (error) { - console.log(error); - res.json({error: 'Something went wrong on the server'}); - } - }) - .post((req, res) => { - try { - res.json({message: 'post FoodServices ID endpoint'}); - } catch (error) { - console.log(error); - res.json({error: 'Something went wrong on the server'}); - } - }) - .delete((req, res) => { - try { - res.json({message: 'delete FoodServices ID endpoint'}); - } catch (error) { - console.log(error); - res.json({error: 'Something went wrong on the server'}); - } - }); - -export default router; \ No newline at end of file diff --git a/server.js b/server.js index 0138ab1df..d6cf946e7 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,5 @@ /* eslint-disable no-console */ import express from 'express'; -import apiRoutes from './routes/apiRoutes.js'; const app = express(); @@ -11,7 +10,7 @@ app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(express.static(staticFolder)); -app.use('/api', apiRoutes); + async function bootServer() { try {