Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 37 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
# 📊 Project: Complex API 2

### Goal: Use data returned from one api to make a request to another api and display the data returned

### How to submit your code for review:

- Fork and clone this repo
- Create a new branch called answer
- Checkout answer branch
- Push to your fork
- Issue a pull request
- Your pull request description should contain the following:
- (1 to 5 no 3) I completed the challenge
- (1 to 5 no 3) I feel good about my code
- Anything specific on which you want feedback!

Example:
```
I completed the challenge: 5
I feel good about my code: 4
I'm not sure if my constructors are setup cleanly...
```
# Have You Seen This Bird? (Compex-API2)

_A website to search for different birds in your area using the eBird and Nuthatch APIs_

<hr>

<img src="./Screenshot 2025-11-10 at 5.42.51 PM.png">

<hr>

## Tech Used

| Category | Tools |
| --------- | ----------------------------------- |
| Frontend | HTML, CSS, JavaScript |

Also, the Nuthatch, eBird, and GeoCodio APIs

<hr>

## Live Demo

https://godwinkamau.github.io/complex-api2/

<hr>

## Features

- Type in a city and find the birds recently spotted in that area.

<hr>

## Lessons Learned

- Tranferring data from one API to another to mix and match information.
- Creating elements in the DOM after fetching data.
- A lot about birdwatching.
Binary file added Screenshot 2025-11-10 at 5.42.51 PM.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
168 changes: 168 additions & 0 deletions css/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
:root{
--dred:#8d311e;
--red:#F55536;
--dorange:#FF773D;
--sandy:#F19143;
--lorange:#FFB238;
--gold:#FABC3C;
}

/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

* {
box-sizing: border-box;
}

body {
background: var(--dorange);
height:100vh;
background-repeat: no-repeat;
}

.intro {
background: var(--dred);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
height:150px;
}

h1{
color: var(--gold);
font-family: 'Condiment',Arial, Helvetica, sans-serif;
font-size: 3rem;
}

p {
font-family: 'Poiret One',sans-serif;
font-size: 1.5rem;
color:var(--sandy)
}

.birdListContainer{
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap:13px;
border:1px double var(--gold);
height:150px;
background-color: var(--red);
margin-bottom: 10px;
}

fieldset{
display: flex;
align-items: center;
justify-content:center;
border:1px double var(--gold);
background: var(--dorange);
width:300px;
padding:15px;
}

legend{
font-weight:bold;
}

#birdList {
display: flex;
/* flex-direction: column; */
flex-wrap: wrap;
align-items: center;
justify-content: space-around;
gap:13px;
}

.row {
display: flex;
align-items: center;
justify-content: space-evenly;
gap:20px;
background: linear-gradient(90deg,var(--dred),var(--red));
width:48%;
height:500px;
border:2px inset var(--dred)

}

.row:nth-of-type(even){
background: linear-gradient(90deg,var(--red),var(--dred));
}

.row img{
object-fit: cover;
overflow: hidden;
max-width:300px;
}
.words{
line-height: 2rem;
}

button {
padding:15px;
background: var(--dorange);
color: var(--lorange);
transition:transform .3s;
}

button:hover{
transform: scale(1.2);
}

h2{
font-family: 'Condiment',Arial, Helvetica, sans-serif;;
font-size: 2rem;
}

i{
font-style: italic;
}
28 changes: 28 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bird Watcher</title>
<meta name="description" content="I'm watching you, birds">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Condiment&family=Poiret+One&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<section class="intro">
<h1>Have You Seen This Bird?</h1>
<p class="desc">Give me a city/state, and I'll give you a picture and list of the most recently sited birds in your area.</p>
</section>
<section class="birdListContainer">
<fieldset><legend>Name a city in the United States </legend><input type="text" id="city" name="city"></fieldset>
<fieldset><legend>Name the state, as well </legend><input type="text" id="state" name="state"></fieldset>
<button>Find Birds!</button>
</section>
<div id="birdList">

</div>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
103 changes: 103 additions & 0 deletions js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const eBirdAPI = 'rql0ki1be3du'
const nuthachAPI = '246b0567-e4c7-4587-8322-3f44fbd7ed20'
const geoCodioAPI = '8689098626efb2b48be0470499fa2b84e48477f'
document.querySelector('button').addEventListener('click',birdWhere)
const eBirdRequest = new Headers()
eBirdRequest.append('X-eBirdApiToken',eBirdAPI)
let requestOptions = {
method:'GET',
headers:eBirdRequest,
redirect:'follow'
}

const images = document.querySelectorAll('img')
const imageArray = []
let imageCounter = 0

function birdWhere() {
if (document.querySelector('.row')) {
let deleteRows = document.querySelectorAll('.row')
deleteRows.forEach(row => {row.remove()})
}
const location = document.querySelector('#city').value
const forURL = location.split(' ').join('+')
const state = document.querySelector('#state').value
const stateURL = state.split(' ').join('+')
fetch(`https://api.geocod.io/v1.9/geocode?q=${forURL}+${stateURL}&country=USA&api_key=${geoCodioAPI}`)
.then(res => res.json())
.then(data => {
const lat = data.results[0].location.lat
const long = data.results[0].location.lng
birdSightings(lat,long)
})
.catch(err => console.log(err))

}

function birdSightings(lat, long) {
fetch(`https://api.ebird.org/v2/data/obs/geo/recent?lat=${lat}&lng=${long}&maxResults=10`, requestOptions)
.then(res => res.json())
.then(data => {
console.log(data.forEach(bird => {
const sciName = bird.sciName.split(' ').join('%20')
getBirdPic(sciName)
})
)
})
.catch(err => console.log(err))
}

function getBirdPic(sciName) {

fetch(`https://nuthatch.lastelm.software/v2/birds?sciName=${sciName}&hasImg=true`,{
headers: {'api-key': nuthachAPI}
})
.then(res => res.json())
.then(data => {

if (data.entities[0].images.length === 0) {
return
}
console.log(data.entities[0])
const imgSrc =data.entities[0].images[0]

imageArray.push(imgSrc)

//taken directly from Nuthatch API site: https://nuthatch.lastelm.software/
let birdGallery = document.getElementById("birdList");
for(let i=0; i<5; i++) {
let bird = data["entities"][i];
//Row
let birdRow = document.createElement("div");
birdRow.className = "row";
let birdDiv = document.createElement("div");
birdDiv.className = "words";
birdDiv.innerHTML = `<h2>${bird["name"]}</h2><ul>
<li>Scientific name: <i>${bird["sciName"]}</i></li>
<li>Conservation Status: ${bird["status"]}</li>
<li>Max Wingspan: ${bird["wingspanMax"]} cm</li>
</ul>`;
//Image
let imgDiv = document.createElement("div");
imgDiv.className = "birdImg";
let image = document.createElement("img");
image.setAttribute("src", bird["images"].length ? bird["images"][0] : "noBird.png");
// image.setAttribute("width", "500");
imgDiv.appendChild(image);
birdRow.appendChild(birdDiv);
birdRow.appendChild(imgDiv);
birdGallery.appendChild(birdRow);
}
// let image = document.createElement("img");
// image.setAttribute("src", imgSrc);
// image.setAttribute("width", "500")
// birdListContainer.appendChild(image)
})
.catch(err => console.log(err))
}

if(imageArray.length === 5) {
images.forEach((image,idx) => {
image.src = imageArray[idx]
})
}