diff --git a/README.md b/README.md index 76d6d581..2ad52f0a 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ This repository is for the Integrating With HubSpot I: Foundations course. This To read the full directions, please go to the [practicum instructions](https://app.hubspot.com/academy/l/tracks/1092124/1093824/5493?language=en). -**Put your HubSpot developer test account custom objects URL link here:** https://app.hubspot.com/contacts/l/objects/${custom-obj-number}/views/all/list - +https://app.hubspot.com/contacts/49699460/objects/2-43819039/views/all/list ___ ## Tips: - Commit to your repository often. Even if you make small tweaks to your code, it’s best to be committing to your repository frequently. diff --git a/index.js b/index.js index f337a32d..28845fa7 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ +require('dotenv').config(); const express = require('express'); const axios = require('axios'); const app = express(); @@ -8,20 +9,84 @@ app.use(express.urlencoded({ extended: true })); app.use(express.json()); // * Please DO NOT INCLUDE the private app access token in your repo. Don't do this practicum in your normal account. -const PRIVATE_APP_ACCESS = ''; +const PRIVATE_APP_ACCESS = process.env.TOKEN; // TODO: ROUTE 1 - Create a new app.get route for the homepage to call your custom object data. Pass this data along to the front-end and create a new pug template in the views folder. // * Code for Route 1 goes here +app.get('/', async (req, res) => { + + const objects = 'https://api.hubspot.com/crm/v3/objects/cards?limit=10&properties=name&properties=card_name&properties=cmc&properties=spell_type&archived=false'; + const headers = { + Authorization: `Bearer ${PRIVATE_APP_ACCESS}`, + 'Content-Type': 'application/json' + } + + try { + const resp = await axios.get(objects, { headers }); + const data = resp.data.results; + + res.render('homepage', { title: 'MTG Cards | Integrating With HubSpot I Practicum', data }); + } catch (error) { + console.error(error); + } + +}); + // TODO: ROUTE 2 - Create a new app.get route for the form to create or update new custom object data. Send this data along in the next route. // * Code for Route 2 goes here +app.get('/update-cobj', async (req, res) => { + + const objects = 'https://api.hubspot.com/crm/v3/objects/cards'; + const headers = { + Authorization: `Bearer ${PRIVATE_APP_ACCESS}`, + 'Content-Type': 'application/json' + } + + try { + const resp = await axios.get(objects, { headers }); + const data = resp.data.results; + + res.render('updates', { title: 'Update Custom Object Form | Integrating With HubSpot I Practicum', data }); + } catch (error) { + console.error(error); + } + +}); + // TODO: ROUTE 3 - Create a new app.post route for the custom objects form to create or update your custom object data. Once executed, redirect the user to the homepage. // * Code for Route 3 goes here +app.post('/update-cobj', async (req, res) => { + const update = { + properties: { + "card_name": req.body.card_name, + "name": req.body.name, + "cmc": req.body.cmc, + "spell_type": req.body.spell_type + } + } + + const addCard = `https://api.hubapi.com/crm/v3/objects/cards/`; + const headers = { + Authorization: `Bearer ${PRIVATE_APP_ACCESS}`, + 'Content-Type': 'application/json' + }; + + try { + await axios.post(addCard, update, { headers } ); + res.redirect('back'); + + } catch(err) { + console.error(err); + } + +}); + /** * * This is sample code to give you a reference for how you should structure your calls. @@ -68,4 +133,4 @@ app.post('/update', async (req, res) => { // * Localhost -app.listen(3000, () => console.log('Listening on http://localhost:3000')); \ No newline at end of file +app.listen(3000, () => console.log('Listening on http://localhost:3000')); diff --git a/package.json b/package.json index 62db37aa..4eda7957 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "axios": "^1.3.5", + "dotenv": "^16.5.0", "express": "^4.18.2", "pug": "^3.0.2" } diff --git a/public/css/style.css b/public/css/style.css index 85587bb4..bff112f6 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -9,6 +9,10 @@ body, * { h1 { margin: 1rem; } +a { + text-align: center; + display: block; +} .cards { display: flex; @@ -55,4 +59,61 @@ input[type="submit"] { border: none; padding: .375rem 1rem; margin-top: 10px; +} + +/* Center tables for demo */ +table { + margin: 0 auto; +} + +/* Default Table Style */ +table { + color: #333; + background: white; + border: 1px solid grey; + font-size: 12pt; + border-collapse: collapse; +} +table thead th, +table tfoot th { + color: #777; + background: rgba(0,0,0,.1); +} +table caption { + padding:.5em; +} +table th, +table td { + padding: .5em; + border: 1px solid lightgrey; +} +/* Zebra Table Style */ +[data-table-theme*=zebra] tbody tr:nth-of-type(odd) { + background: rgba(0,0,0,.05); +} +[data-table-theme*=zebra][data-table-theme*=dark] tbody tr:nth-of-type(odd) { + background: rgba(255,255,255,.05); +} +/* Dark Style */ +[data-table-theme*=dark] { + color: #ddd; + background: #333; + font-size: 12pt; + border-collapse: collapse; +} +[data-table-theme*=dark] thead th, +[data-table-theme*=dark] tfoot th { + color: #aaa; + background: rgba(0255,255,255,.15); +} +[data-table-theme*=dark] caption { + padding:.5em; +} +[data-table-theme*=dark] th, +[data-table-theme*=dark] td { + padding: .5em; + border: 1px solid grey; +} +h1 { + text-align: center; } \ No newline at end of file diff --git a/views/homepage.pug b/views/homepage.pug new file mode 100644 index 00000000..8fb9c6b3 --- /dev/null +++ b/views/homepage.pug @@ -0,0 +1,22 @@ +doctype html +html + head + title= `${title}` + meta(name="viewport" content="width=device-width, initial-scale=1") + link(rel="stylesheet", href="/css/style.css") + body + h1 MTG Cards with alternate names + table + tbody + tr + th Real Name + th Display Name + th Type + th CMC + each card in data + tr + td #{card.properties.card_name} + td #{card.properties.name} + td #{card.properties.spell_type} + td #{card.properties.cmc} + a(href="/update-cobj") Add to this table diff --git a/views/updates.pug b/views/updates.pug new file mode 100644 index 00000000..d1b74305 --- /dev/null +++ b/views/updates.pug @@ -0,0 +1,23 @@ +doctype html +html + head + title= `${title}` + meta(name="viewport" content="width=device-width, initial-scale=1") + link(rel="stylesheet", href="/css/style.css") + body + a(href="/") Return to the homepage + .form-wrapper + form(method="POST") + label(for="card_name") Card Name + input(type="text" name="card_name" required) + label(for="name") Display Name + input(type="text" name="name" required) + label(for="spell_type") Spell Type + select(name="spell_type" required) + option(value=creature) creature + option(value=sorcery) sorcery + option(value=instant) instant + option(value=enchantment) enchantment + label(for="cmc") CMC + input(type="number" name="cmc" required) + input(type="submit" value="Submit")