api to handle creating ideas and saving to database

This commit is contained in:
JasonFraser 2024-08-28 21:33:45 -04:00
parent 84a080ca73
commit 5d10d64cd5
14 changed files with 208 additions and 30 deletions

View File

@ -9,6 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.19.2", "express": "^4.19.2",
"mongoose": "^8.5.4" "mongoose": "^8.5.4"
@ -247,6 +248,19 @@
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -960,6 +974,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.2", "version": "1.13.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",

View File

@ -10,6 +10,7 @@
"author": "Jason", "author": "Jason",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.19.2", "express": "^4.19.2",
"mongoose": "^8.5.4" "mongoose": "^8.5.4"

View File

@ -1,4 +1,5 @@
const express = require('express'); const express = require('express');
const cors = require('cors');
require('dotenv').config(); require('dotenv').config();
const port = process.env.PORT || 5000; const port = process.env.PORT || 5000;
const connectDB = require('./config/db'); const connectDB = require('./config/db');
@ -16,6 +17,13 @@ app.get('/', (req, res) => {
res.json({ message: 'Welcome to the RandomIdeas API' }); res.json({ message: 'Welcome to the RandomIdeas API' });
}); });
//cors middleware
app.use(
cors({
origin: ['http://localhost:5000', 'http://localhost:5173'],
})
);
//registering the routes //registering the routes
const ideasRouter = require('./routes/ideas'); const ideasRouter = require('./routes/ideas');
app.use('/api/ideas', ideasRouter); app.use('/api/ideas', ideasRouter);

View File

@ -1,6 +1,11 @@
import IdeasApi from '../services/ideasApi';
import IdeaList from './IdeaList';
class IdeaForm { class IdeaForm {
constructor() { constructor() {
this._formModal = document.querySelector('#form-modal'); this._formModal = document.querySelector('#form-modal');
//instantiating the idea list since it is a class
this._ideaList = new IdeaList();
} }
//add all event listeners in a function //add all event listeners in a function
@ -8,9 +13,22 @@ class IdeaForm {
this._form.addEventListener('submit', this.handleSubmit.bind(this)); this._form.addEventListener('submit', this.handleSubmit.bind(this));
} }
handleSubmit(e) { async handleSubmit(e) {
//made this function async because we are dealing with a promise (axios)
e.preventDefault(); //stops the submit and allows us to determine when it should run e.preventDefault(); //stops the submit and allows us to determine when it should run
if (
!this._form.elements.text.value ||
!this._form.elements.tag.value ||
!this._form.elements.username.value
) {
alert('Please enter all fields');
return;
}
//save user to local storage
localStorage.setItem('username', this._form.elements.username.value);
//grabs values from the form //grabs values from the form
const idea = { const idea = {
text: this._form.elements.text.value, text: this._form.elements.text.value,
@ -18,10 +36,17 @@ class IdeaForm {
username: this._form.elements.username.value, username: this._form.elements.username.value,
}; };
//add idea to database
const newIdea = await IdeasApi.createIdea(idea);
//add idea to list and call render on the DOM
this._ideaList.addIdeaToList(newIdea.data.data_base);
//clear form fields after submit //clear form fields after submit
this._form.elements.text.value = ''; this._form.elements.text.value = '';
this._form.elements.tag.value = ''; this._form.elements.tag.value = '';
this._form.elements.username.value = ''; this._form.elements.username.value = '';
this.render();
//using the dispatch event method of the document object to dispatch a custom event //using the dispatch event method of the document object to dispatch a custom event
//to the Modal from the IdeaForm, telling the Modal to close the form on submit //to the Modal from the IdeaForm, telling the Modal to close the form on submit
@ -29,12 +54,18 @@ class IdeaForm {
} }
//create a render function like react that will output the HTML //create a render function like react that will output the HTML
//adding a turnary to check for username and saved in localstorage
render() { render() {
this._formModal.innerHTML = ` this._formModal.innerHTML = `
<form id="idea-form"> <form id="idea-form">
<div class="form-control"> <div class="form-control">
<label for="idea-text">Enter a Username</label> <label for="idea-text">Enter a Username</label>
<input type="text" name="username" id="username" /> <input type="text" name="username" id="username"
value="${
localStorage.getItem('username')
? localStorage.getItem('username')
: ''
}" />
</div> </div>
<div class="form-control"> <div class="form-control">
<label for="idea-text">What's Your Idea?</label> <label for="idea-text">What's Your Idea?</label>

View File

@ -1,32 +1,13 @@
//this class returns a list of cards to the DOM //this class returns a list of cards to the DOM
//by mapping (looping) over an array //by mapping (looping) over an array
import IdeasApi from '../services/ideasApi';
class IdeaList { class IdeaList {
constructor() { constructor() {
this._ideaListEl = document.querySelector('#idea-list'); this._ideaListEl = document.querySelector('#idea-list');
this._ideas = [ this._ideas = [];
{ this._getIdeas();
id: 1,
text: 'Idea 1',
username: 'John',
date: '02/01/2023',
tag: 'Business',
},
{
id: 2,
text: 'Idea 2',
username: 'Jimmy',
date: '02/01/2023',
tag: 'Technology',
},
{
id: 3,
text: 'Idea 3',
username: 'Jill',
date: '02/01/2023',
tag: 'Fashion',
},
];
//adding a set (datatype) //adding a set (datatype)
this._validTags = new Set(); this._validTags = new Set();
@ -38,6 +19,23 @@ class IdeaList {
this._validTags.add('inventions'); this._validTags.add('inventions');
} }
async _getIdeas() {
try {
const res = await IdeasApi.getIdeas();
this._ideas = res.data.data_base; //in axios, when you make a request the info comes wrapped in an object called data,
//data refers to the axios object and data_base refers to the info being returned from the backend
this.render();
// console.log(this._ideas);
} catch (error) {
console.log(error);
}
}
addIdeaToList(idea) {
this._ideas.push(idea);
this.render();
}
getTagClass(tag) { getTagClass(tag) {
tag = tag.toLowerCase(); tag = tag.toLowerCase();
let tagClass = ''; let tagClass = '';

View File

@ -4,8 +4,7 @@ import IdeaList from './components/IdeaList';
import '@fortawesome/fontawesome-free/css/all.css'; import '@fortawesome/fontawesome-free/css/all.css';
import './css/style.css'; import './css/style.css';
const modal = new Modal(); new Modal();
const ideaForm = new IdeaForm(); const ideaForm = new IdeaForm();
ideaForm.render(); ideaForm.render();
const ideaList = new IdeaList(); new IdeaList();
ideaList.render();

View File

@ -8,7 +8,8 @@
"name": "randomideas", "name": "randomideas",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.6.0" "@fortawesome/fontawesome-free": "^6.6.0",
"axios": "^1.7.5"
}, },
"devDependencies": { "devDependencies": {
"vite": "^5.3.4" "vite": "^5.3.4"
@ -645,6 +646,44 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz",
"integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
@ -684,6 +723,40 @@
"@esbuild/win32-x64": "0.21.5" "@esbuild/win32-x64": "0.21.5"
} }
}, },
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -699,6 +772,27 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.7", "version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@ -754,6 +848,12 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.19.0", "version": "4.19.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.19.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.19.0.tgz",

View File

@ -12,6 +12,7 @@
"vite": "^5.3.4" "vite": "^5.3.4"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.6.0" "@fortawesome/fontawesome-free": "^6.6.0",
"axios": "^1.7.5"
} }
} }

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,17 @@
import axios from 'axios';
class IdeasApi {
constructor() {
this._apiUrl = 'http://localhost:5000/api/ideas';
}
getIdeas() {
return axios.get(this._apiUrl);
}
createIdea(data) {
return axios.post(this._apiUrl, data);
}
}
export default new IdeasApi();