Part Detail (From Design to Database with Firestore)

This supports a software dev. class for businesspeople that you can find here: https://www.alexandercowan.com/making-html-manageable And a case you can find here: https://www.alexandercowan.com/making-html-manageable

by Alex Cowan

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.6.0/jasmine.min.js"></script>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.2.5/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/8.2.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.2.5/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.2.5/firebase-analytics.js"></script>

<script>
  // Your web app's Firebase configuration
  // For Firebase JS SDK v7.20.0 and later, measurementId is optional
  var firebaseConfig = {
    apiKey: "AIzaSyCOPgDQ4PAwNtOxZQtkkRpy0LV37VVEzJg",
    authDomain: "hinh-78995.firebaseapp.com",
    projectId: "hinh-78995",
    storageBucket: "hinh-78995.appspot.com",
    messagingSenderId: "389014950808",
    appId: "1:389014950808:web:5599635662f42697b091ed",
    measurementId: "G-XL6BSRZLQE",
  }
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig)
  firebase.analytics()
</script>
<link
  rel="stylesheet"
  href="//netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css"
/>
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<div class="top-bar">
  <ul class="nav-list">
    <li><a href="#">Home</a></li>
    <li><a href="#">Parts</a></li>
    <li><a href="#">Search</a></li>
    <li><a href="#">Help</a></li>
  </ul>
  <div id="search-box">
    <input
      type="text"
      name="parts-search"
      placeholder="Mfg., Model, or Part Number"
      size="30"
    />
  </div>
</div>

<div id="part-info">
  <img id="part-img" alt="PCB board" style="width: 300px" />
  <h2 id="part-title"></h2>
  <button type="button" id="order-btn">Add to Cart</button
  ><button type="button"...

CSS

.top-bar,
  #search-box,
  .nav-list li,
  .nav-list a {
    background-color: #002d45;
    font-family: "Proxima Nova", "helvetica neue", helvetica, sans-serif;
    font-weight: bold;
    font-size: 110%;
    color: #ffffff;
  }

  .top-bar {
    height: 40px;
    margin: 0;
    padding: 10px;
    display: flex;
    align-items: center;
  }

  .nav-list {
    list-style-type: none;
    padding: 0;
    display: inline;
  }

  .nav-list li {
    float: left;
  }

  .nav-list a {
    display: inline;
    padding: 8px;
    text-decoration: none;
  }

  #search-box {
    margin-left: auto;
    margin-right: 0;
    padding: 10px;
  }

  p {
    font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
    overflow: scroll;
    margin: 0;
  }

  #part-info {
    margin: 15px;
    padding: 0 5px;
    width: 100%;
  }

  #part-info img {
    float: left;
    padding: 5px;
  }

  #part-info h2 {
    display: inline;
  }

  button {
    display: inline;
    font-size: 20px;
    margin: 0 5px 5px 0;
  }

  #review-signifier {
    direction: rtl;
    unicode-bidi: bidi-override;
    float: left;
  }

  #part-info h3 {
    margin: 0;
  }

  input.star {
    display: none;
  }

  label.star {
    padding: 0;
    font-size: 15px;
    color: #444;
  }

  input.star:checked ~ label.star:before {
    content: "\f005";
    color: #000;
    transition: all 0.25s;
  }

  label.star:before {
    content: "\f006";
    font-family: FontAwesome;
  }

  .fa-star {
    opacity: 0.5;
  }

  .checked {
    color: black;
    opacity: 1;
  }

  #user-reviews {
    clear: both;
  }

  #mod-link {
    display: none;
  }

JavaScript

// Creates an instance of the DB using the Firebase SDK
var db = firebase.firestore();

// Get just the part number that the user clickied on in the parts search page. Splits on '#' and takes the second element.
var partnum = localStorage.getItem("part-index").split("#", 2)[1];
console.log("incoming with part number " + partnum);

// Define the file path for where the part data lives
var part_file_path = "parts/" + partnum;

// Go get the part data from the applicable document in Firestore
db.doc(part_file_path)
  .get()
  .then(function (docSnapshot) {
    var part = docSnapshot.data();
    var id = docSnapshot.id;

    // Render the specific part information on the page
    document.getElementById("partnum").textContent = "Part #: " + id;
    document.getElementById("availability").textContent =
      "Availability: " + part.Availability;
    document.getElementById("orders").textContent =
      "Orders (90 day): " + part.Orders;
    document.getElementById("price").textContent =
      "Price: $" + parseFloat(part.Price).toFixed(2);
    document.getElementById("part-title").textContent =
      part.Manufacturer + " " + part.Model + " " + part.Type;
    document
      .getElementById("part-img")
      .setAttribute("src", "https://" + part.imageURL);

    // Initialize the stars and number of ratings
    var review_file_path = "parts/" + partnum + "/reviews";
    
    postReviews(review_file_path);
  });

function postReviews(reviewFilePath) {
  let totalRating = 0;
  let numReviews = 0;

  return db
    .collection(reviewFilePath)
    .get()
    .then((querySnapshot) => {
      querySnapshot.forEach((doc) => {
        totalRating += doc.data().rating;
        numReviews++;
      });
      return { totalRating, numReviews };
    })
    .then(({ totalRating, numReviews }) => {
      const avgRating = totalRating / numReviews;
      const roundedRating = Math.floor(avgRating);
      displayStars(roundedRating, "star-rating");
     ...