Random Quote Machine Loads Locally But Not to Web Server

Hello again,

I have created a very sleek quote generator with React. When I upload it locally (npm run start) it works perfectly. But when I add it to a repository on Github (all files show up in my repository on Github.com) the version that is uploaded to the Github web server only shows the background image and “loading…” suggesting that my API is not sending back data. The key to remember here is that I can upload other apps (although they are a bit simple) that use APIs and they upload just fine. Thanks in advance for all your help. You guys keep saving me.

The Github link is: https://gabehaus.github.io/ReactQuotes3/

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link
      href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-
awesome.min.css"
      rel="stylesheet"
      integrity="sha384-
wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
      crossorigin="anonymous"
    />
    <script src="https://use.fontawesome.com/3bd7769ce1.js"></script>
    <link
      href="https://fonts.googleapis.com/css?family=Shadows+Into+Light&display=swap"
      rel="stylesheet"
    />

    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
  <script>
    window.twttr = (function(d, s, id) {
      var js,
        fjs = d.getElementsByTagName(s)[0],
        t = window.twttr || {};
      if (d.getElementById(id)) return t;
      js = d.createElement(s);
      js.id = id;
      js.src = "https://platform.twitter.com/widgets.js";
      fjs.parentNode.insertBefore(js, fjs);

      t._e = [];
      t.ready = function(f) {
        t._e.push(f);
      };

      return t;
    })(document, "script", "twitter-wjs");
  </script>
</html>

App.js

import React, { useEffect, useState, componentDidMount } from "react";
import logo from "./logo.svg";
import "./App.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTwitter } from "@fortawesome/free-brands-svg-icons";
import { faRedo } from "@fortawesome/free-solid-svg-icons";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: true,
      quoteData: "",
      backgroundImages: [
        "https://freecodecampassets.s3.us-east-2.amazonaws.com/piotr-chrobot-6oUsyeYXgTg-unsplash.jpg",
        "https://freecodecampassets.s3.us-east-2.amazonaws.com/jj-jordan-S3-kHziSt00-unsplash.jpg",
        "https://freecodecampassets.s3.us-east-2.amazonaws.com/federico-beccari-ahi73ZN5P0Y-unsplash.jpg",
        "https://freecodecampassets.s3.us-east-2.amazonaws.com/joey-kyber-vXtX07KVcE8-unsplash.jpg"
      ],
      index: 0,
      quoteBoxStyles: [
        // red and gray
        {
          position: "relative",
          marginLeft: "auto",
          marginRight: "auto",
          marginTop: "15%",
          width: "50%",

          backgroundColor: "rgba(28, 26, 24, 0.9)",
          borderRadius: "20%",
          borderStyle: "solid",
          borderColor: "#d10000",

          padding: "3%"
        },
        //blue and orange
        {
          position: "relative",
          marginLeft: "auto",
          marginRight: "auto",
          marginTop: "15%",
          width: "50%",

          backgroundColor: "rgba(36, 26, 70, 0.9)",
          borderRadius: "20%",
          borderStyle: "solid",
          borderColor: "#ff2f05",

          padding: "3%"
        },
        //black and purple
        {
          position: "relative",
          marginLeft: "auto",
          marginRight: "auto",
          marginTop: "15%",
          width: "50%",

          backgroundColor: "rgba(28, 26, 24, 0.9)",
          borderRadius: "20%",
          borderStyle: "solid",
          borderColor: "#9f21ff",

          padding: "3%"
        },
        //silver and turquoise
        {
          position: "relative",
          marginLeft: "auto",
          marginRight: "auto",
          marginTop: "15%",
          width: "50%",

          backgroundColor: "rgba(28, 26, 24, 0.9)",
          borderRadius: "20%",
          borderStyle: "solid",
          borderColor: "#fffef5",

          padding: "3%"
        }
      ]
    };

    this.componentDidMount = this.componentDidMount.bind(this);
    this.getData = this.getData.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }

  //initial call of API upon mounting
  async componentDidMount() {
    this.getData();
  }

  //function sets the index when id="new-quote" is clicked
  handleClick() {
    let i = this.state.index < 3 ? (this.state.index += 1) : 0;
    this.setState({ index: i });
  }

  // function setting the background image of the body in ReactDOM dynamically - also sets the styling of id="quote-box"
  setBackground() {
    document.body.style.backgroundImage =
      "url(" + this.state.backgroundImages[this.state.index] + ")";

    this.handleClick();
  }

  // function that is called and assigns a new quote to the global state when "new-quote" is clicked
  async getData() {
    const url = "http://quotes.stormconsultancy.co.uk/random.json";
    const response = await fetch(url);
    var newData = await response.json();
    console.log(newData);
    this.setState({ loading: false, quoteData: newData });
    this.newQuote = this.state.quoteData.quote;
    this.setBackground();
  }

  render() {
    //style block in which font size changes depending on the length of a quote
    let inputStyle = {
      position: "relative",
      marginLeft: "auto",
      marginRight: "auto",
      marginTop: "0%",

      color: "white",
      fontFamily: "Shadows Into Light, cursive",
      fontStyle: "normal",
      fontWeight: 300,
      fontSize: 27
    };

    let quoteForLengthTest = this.state.quoteData.quote;

    if (!this.state.loading) {
      if (quoteForLengthTest.length > 230) {
        inputStyle = {
          position: "relative",
          marginLeft: "auto",
          marginRight: "auto",
          marginTop: "0%",
          color: "white",
          fontFamily: "Shadows Into Light, cursive",

          fontStyle: "normal",
          fontWeight: 300,
          fontSize: 23
        };
      }
    }

    //dynamic style block that changes each time API is called

    // conditions handling the API call
    if (this.state.loading) {
      return <div>"loading..."</div>;
    } else {
      return (
        <div
          id="quote-box"
          className="App"
          style={this.state.quoteBoxStyles[this.state.index]}
        >
          <div id="text" style={inputStyle}>
            "{this.state.quoteData.quote}"
          </div>
          <div id="author">- {this.state.quoteData.author}</div>
          <br></br>
          <div id="loadCheck">{this.state.loading}</div>

          {/* button which appears as refresh icon that calls the API for a new quote */}
          <button id="new-quote" className="buttonClass" onClick={this.getData}>
            <FontAwesomeIcon icon={faRedo} size="3x"></FontAwesomeIcon>
          </button>

          {/* anchor tag that is rendered as a Tweet icon which loads quote into Twitter tweet box*/}
          <a
            class="tweet-quote"
            href={`https://twitter.com/intent/tweet?text=${this.state.quoteData.quote}`}
            data-size="large"
          >
            <FontAwesomeIcon
              icon={faTwitter}
              size="2x"
              color="white"
              style={{
                backgroundColor: "none",
                width: "10%",
                marginLeft: "-35%"
              }}
            ></FontAwesomeIcon>
          </a>
        </div>
      );
    }
  }
}

export default App;

Index.css

@import url("https://fonts.googleapis.com/css?family=Raleway");

html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}

*:focus {
  outline: none;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background: url("https://freecodecampassets.s3.us-east-2.amazonaws.com/piotr-chrobot-6oUsyeYXgTg-unsplash.jpg")
    no-repeat center center fixed;
  -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
  z-index: 1;
}

#quote-box {
  position: relative;
  margin-left: auto;
  margin-right: auto;
  margin-top: 15%;
  width: 50%;

  background-color: rgba(36, 26, 70, 0.9);
  border-radius: 20%;
  border-style: solid;
  border-color: #ff2f05;

  padding: 3%;
}

#formBox {
  width: 300;
  position: relative;
}

#enterButton {
  height: 37px;
  border-radius: 5px;

  margin-left: 15px;
}

#author {
  position: relative;
  font-style: italic;
  font-size: 25px;
  font-family: "Shadows Into Light", cursive;
  color: white;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}

#loadCheck {
  color: black;
  background-color: green;
  z-index: 2;
  font-size: 50px;
}

#new-quote {
  font-family: Raleway;
  font-style: normal;
  background: none;
  color: white;
  border: none;
  float: left;
  width: 10%;
  margin-left: 39%;
  cursor: pointer;
}

package.json

{
  "name": "ReactQuotes3",
  "version": "0.1.0",
  "homepage": "http://Gabehaus.github.io/ReactQuotes3",
  "private": true,
  "dependencies": {
    "@fortawesome/fontawesome": "^1.1.8",
    "@fortawesome/fontawesome-free-solid": "^5.0.13",
    "@fortawesome/react-fontawesome": "^0.1.8",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.4.0",
    "@testing-library/user-event": "^7.2.1",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-scripts": "3.3.0",
    "react-tweet-embed": "^1.2.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "gh-pages": "^2.2.0"
  }
}

I just read this via the Chrome developer:

App.js:112 Mixed Content: The page at ‘https://gabehaus.github.io/ReactQuotes3/’ was loaded over HTTPS, but requested an insecure resource ‘http://quotes.stormconsultancy.co.uk/random.json’. This request has been blocked; the content must be served over HTTPS.
(anonymous) @ App.js:112
(index):1 A cookie associated with a cross-site resource at http://twitter.com/ was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.
(index):1 Uncaught (in promise) TypeError: Failed to fetch

OK, I solved the problem. I was calling an http API from Github, which uses https. The solution was to add the following to index.html:

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">