Final Fetch


by Jeremy Caudle
code

Oh boy, I had to make today's code tinkering rather troublesome. I think it turned out decent though. I wanted to work with Fetch API and use it to load data from my Treehouse profile into a page. I decided to display it as if I was a character in the Famicom/NES game, Final Fantasy. Click the update info button to load information from my profile into the page.

Name

Job

Level ?

Experience Points

  • Skill ??
  • Skill ??
  • Skill ??
  • Skill ??
  • Skill ??
  • Badge
  • Badge
  • Badge
  • Badge
  • Badge

View the code:

HTML and JS
<section class="code-block">
            <h1 id="name">Name</h1>
            <h2 id="job"><img src="" id="img" alt="" width="16" height="16"/>Job</h2>
            <h2 id="level">Level ?</h2>
            <p id="exp"><span>Experience Points</span> <span id="expPoints"></span></p>
        <div id="gridWrapper">
            <div id="pointsWrapper">
                <ul id="points">
                    <li>Skill <span>??</span></li>
                    <li>Skill <span>??</span></li>
                    <li>Skill <span>??</span></li>
                    <li>Skill <span>??</span></li>
                    <li>Skill <span>??</span></li>
                </ul>
            </div>
            <div id="badgesWrapper">
                <ul id="badges">
                    <li>Badge</li>
                    <li>Badge</li>
                    <li>Badge</li>
                    <li>Badge</li>
                    <li>Badge</li>
                </ul>
            </div>
        </div>
            <button id="importInfo">Update Info</button>
        </section>
        <script>

    // ---------        
    // Variables
    // ---------
    const name = document.getElementById('name');
    const job = document.getElementById('job');
    const photo = document.getElementById('img');
    const exp = document.getElementById('exp');
    const expPoints = document.getElementById('expPoints');
    const pointsWrap = document.getElementById('pointsWrapper');
    const badgesWrap = document.getElementById('badgesWrapper');
    const points = document.getElementById('points');
    const badges = document.getElementById('badges');
    const button = document.getElementById('importInfo');

    // ---------
    // Fetch Functions
    // ---------

    button.addEventListener('click', () => {
        fetch('https://teamtreehouse.com/jeremycaudle85.json')
        .then(response => response.json())
        .then(data => updateInfo(data))
        .catch(error => alert('Looks like there was a problem. Maybe the info the server comes from is having a problem. Try again another time. :)', error))
        button.textContent = "Info Received";
        button.toggleAttribute('disabled');
    })
    
    
    // ---------        
    // Helper Functions
    // ---------

    function updateInfo(data) {
        console.log(data);
        name.innerHTML = `<a href="${data.profile_url}">${data.name}</a>`;
        name.setAttribute('class', 'updated');
        job.innerHTML = `<img src="${data.gravatar_url}" id="img" alt="Photo of ${data.name}" width="16" height="16"/> Web Designer / Developer`;
        job.setAttribute('class', 'updated');
        level.textContent = 'Level 35';
        level.setAttribute('class', 'updated');
        expPoints.textContent = data.points.total;
        exp.setAttribute('class', 'updated');

        // Skills list
        const pointsTreehouseSkills = Object.keys(data.points);
        console.log(pointsTreehouseSkills);
        const pointsTreehouseValues = Object.values(data.points);
        console.log(pointsTreehouseValues);
        let treeSkills = '';
        for(let i = 0; i < pointsTreehouseSkills.length; i++) {
            console.log('start loop');
            let skillName = pointsTreehouseSkills[i];
            let skillValue = pointsTreehouseValues[i];
            treeSkills += `<li>${skillName} <span>${skillValue}</span></li>`;
        };
        points.innerHTML = treeSkills;

        // Badges list
        const badgesList = Object.values(data.badges);
        console.log(badgesList);
        let treeBadges = '';
        for(let i = 0; i < badgesList.length; i++) {
            console.log('start loop');
            let badgeValue = badgesList[i].name;
            console.log(badgeValue);
            treeBadges += `<li><span>${badgeValue}</span></li>`;
        };
        badges.innerHTML = treeBadges;
        
        pointsWrap.setAttribute('class', 'updated');
        badgesWrap.setAttribute('class', 'updated');

    }


        </script>
CSS
/* Variables */
            :root {
                --bg-color: #111;
                --bg-secondary: white;
                --text-color: #232323;
                --radius-main: 1rem;
            }

        @font-face {
        font-family: "ThaleahFat";
        src: url("https://jeremycaudle.com/retro-japanese-games/fonts/ThaleahFat.ttf") format("truetype");
        /* Font Thaleah Fat by Tiny Worlds - Available at https://tinyworlds.itch.io/free-pixel-font-thaleah */
        }
            
            html { box-sizing: border-box; z-index: 0; }
            html * { box-sizing: inherit; }
            section.code-block {
                background: var(--bg-color, #111);
                max-width: 512px;
                margin: 2rem auto;
                padding: 1rem;
                max-height: 480px;
            }

            section.code-block * {
                font-family: "ThaleahFat", "Helvetica", "Arial", sans-serif;
                font-weight: normal;
                color: white;
            }

            section.code-block h1, section.code-block h2, section.code-block p, section.code-block div, section.code-block button {
                font-size: 1.5rem;
                background-color: rgb(48, 48, 48);
                border: solid 2px white;
                box-shadow: 0 0 0 2px gray, inset 0 0 0 2px gray;
                border-radius: .25rem;
                padding: .5rem;
                margin: 0 0 .5rem 0;
                transition: background-color .25s ease-out;
            }

            section.code-block ul {
                list-style-type: none;
                padding: 0;
                margin: .5rem 0;
            }   

            section.code-block ul li {
                
            }

            section.code-block ul li span {
                text-align: right;
            }

            section.code-block button {
                font-size: 1rem;
                background-color: orange;
                color:black;
                cursor: pointer;
                transition: all .125s ease-out;
                margin: auto;
                display: block;
            }

            section.code-block button:hover, section.code-block button:focus {
                background-color: rgb(255, 175, 25);
                border-color: black;
            }

            section.code-block .updated {
                background-color: blue;
            }

            section.code-block button:disabled {
                background-color: black;
                border: gray;
                box-shadow: none;
                cursor: default;
                color: white;
            }

            #points, #badges {
                max-height: 135px;
                overflow: auto;
                scrollbar-color: transparent;
            }

            /* Float-based layout for older browsers */

            #name, #job {
                float: left;
                margin-right:2%;
             }

             #level {
                 float:right;
             }

             #job {
                 width: 52%;
             }

             #name, #level {
                 width: 22%;
             }

            #exp {
                float: none;
                clear: both;
                width: 80%;
                margin: .5rem auto;
            }

            #exp span {text-align: left;}
            #exp #expPoints {float: right;}
            #expPoints::after {
                content: "";
                display: none;
                height: 1px;
                width: 1px;
                float: none;
                clear: both;
            }

            #pointsWrapper {
                float:left;
                width: 49%;
                margin-right:2%
            }

            #badgesWrapper {
                width: 49%;
                float:right;    
            }

            #importInfo {
                float:none;
                clear: both;
            }

            /* Support and media queries */

            @supports (display:grid) {
                #name, #job, #level, #exp, #exp #expPoints, #pointsWrapper, #badgesWrapper {
                    float:none;
                    width: auto;
                }
                section.code-block { 
                    display: grid;
                    grid-template-columns: 1fr 2fr 1fr;
                    grid-template-rows: repeat(3, min-content);
                }

                #name { 
                    grid-column: 1 / 2;
                    grid-row: 1 / 2;
                }

                #job {
                    grid-column: 2 / 3;
                    grid-row: 1 / 2;
                }

                #exp {
                    grid-column: 1 / 4;
                    grid-row: 2 / 3;
                    width: 80%;
                }

                #importInfo {
                    grid-column: 2 / 3;
                    grid-row: 4 / 5;
                }

                section.code-block div#gridWrapper {
                    background: none;
                    border: none;
                    box-shadow: none;
                    margin: 0;
                    display: grid;
                    grid-template-columns: 1fr 1fr;
                    grid-column: 1 / 4;
                    grid-row: 3 / 4;
                }
            }