From Design to Data Model with Firestore
by Alex Cowan
HTML
<!-- 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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<!-- Top Bar: Navigation, Search Box, and Authentication Controls -->
<div class="top-bar">
<ul class="nav-list">
<li><a href="#">Home</a></li>
<li><a href="#">Help</a></li>
</ul>
<div id="search-box">
</div>
<div id="auth-control">
<img
src="https://www.alexandercowan.com/wp-content/uploads/2018/04/login-icon.png"
alt="auth"
style="width: 30px; float: left"
/>
<ul class="nav-list">
<li id="login-trigger"><a href="#" id="auth-text">Log In</a></li>
</ul>
<div id="login-content">
<!-- Login Form (CHANGED: Updated form ID to "loginForm") -->
<form id="loginForm" onsubmit="return false">
<input type="text" placeholder="Email" id="login_email" required />
<input...
CSS
body {
display: block;
margin: 8px;
}
.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 {
color: #FFFFFF;
height: 40px;
margin: 0px;
padding: 10px;
display: flex;
align-items: center;
}
#Header {
font-family: Proxima Nova,helvetica neue,helvetica,sans-serif;
font-weight: bold;
font-size: 200%;
color: rgb(0, 0, 0);
}
.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;
}
#login-content {
display: none;
position: absolute;
margin-right: 10px;
top: 60px;
right: 0;
left: 1000;
z-index: 999;
background: #ffffff;
padding: 15px;
border: 1px solid #CCC;
width: 200px;
}
/* Keeps this in sync w/ the login-content div */
#login-form {
display: none;
}
#login-content input {
margin-bottom: 3px;
padding: 10px;
width: 90%;
border: 1px solid #CCC;
}
#login-content label {
cursor: pointer;
font-family: Proxima Nova,helvetica neue,helvetica,sans-serif;
color: #002D45;
}
#login-content #register-form {
display: none;
}
#login-content #forgotten-form {
display: none;
}
#login-content, #after-reset, #if-error, #if-reg-error {
display: none;
}
#login-content .auth-link {
cursor: pointer;
font-family: Proxima Nova,helvetica neue,helvetica, sans-serif;
color: #002D45;
}
#forgotten-link, #reset-response, #after-reset, #login-link-modal, #if-error, #if-reg-error {
cursor: pointer;
font-family: Proxima Nova,helvetica neue,helvetica,sans-serif;
color: #002D45;
font-size: 80%;
}
#login-link-modal {
font-size: 120%;
}
#go-btn {
margin: 5px;
}
#search-controls {
background-color: #ffffff;
font-family: Proxima Nova,helvetica...
JavaScript
// -----------------------------
// CODE THAT LOADS THE HVAC PARTS (FROM FIRESTORE)
// -----------------------------
var db = firebase.firestore();
db.collection("parts")
.limit(10)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const data = doc.data();
const partArray = [
doc.id,
data.imageURL,
data.Manufacturer,
data.Model,
data.Type,
data.Price,
data.Availability,
data.Orders,
];
drawDiv(partArray);
});
});
function drawDiv(divData) {
if (divData == null) return null;
let partNum = divData[0].trim();
let imgURL = divData[1].trim();
let mfr = divData[2].trim();
let model = divData[3].trim();
let type = divData[4].trim();
let price = "$" + Number(divData[5]).toFixed(2);
let avail = divData[6].trim();
let orders = String(divData[7]).trim();
var newPartsDiv = document.createElement("div");
newPartsDiv.className = "catalog-part";
newPartsDiv.setAttribute("mfr", mfr);
newPartsDiv.setAttribute("model", model);
var partImg = document.createElement("img");
partImg.setAttribute("src", "https://" + imgURL);
newPartsDiv.appendChild(partImg);
var newOverlayDiv = document.createElement("div");
newOverlayDiv.className = "overlay";
var link = document.createElement("a");
link.className = "part-ref";
link.setAttribute("href", "#");
link.textContent = mfr + " #" + partNum;
var newOverlayDivP = document.createElement("p");
newOverlayDivP.appendChild(link);
newOverlayDivP.appendChild(document.createElement("br"));
newOverlayDivP.appendChild(document.createTextNode(orders + " Orders"));
newOverlayDivP.appendChild(document.createElement("br"));
newOverlayDivP.appendChild(document.createTextNode(price + " " + avail));
var reviewContainer = document.createElement("span");
reviewContainer.id = "review-" +...