I would like my website users to pay for minting using their metamask account, but then when they press the mint button, I want the actual minting to be done via a central Ethereum account.
Before I had a simple website where in the index.html file, I had a react app that ran in the background listening for mint calls (code of App.js attached in the as the second code block).
But I have modified my approach. Now on my website server, I have a node.js app running that listens for Javascript API fetch Posts (see first code block below). The hash value gets sent from other websites via API Post - where all the minting is done in a central Ethereum account.
Now I want my website server to mint from both sources: hash sent from API POST and also from the same website. From the front end, I want the users to be able to pay for the minting using their Ethereum account from their metamask wallet. In doing so the mint function in the App.js should be called (as I want to use the account coded in that function) from the front end after the user pays for the minting from his metamask wallet. I am hoping this can be done. Having another react app running may be too much as I don't want two apps running (one to handle API Posts and one for the React app). Can I somehow make payment through the Metamask wallet and still call the mint function in the App.js?
//Current App.js that listens for API Posts
const web3 = require('web3');
const ethers = require('ethers');
const express = require('express');
const path = require('path');
const LocationNFT = require('./abis/Location.json')
const fromAddress = <address>
const nftAddress = <address>
const app = express();
const port = 3000;
app.use(express.urlencoded({extended: true}));
app.use(express.json());
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/posthash', async function (request, response) {
var hashValue = request.body.hash;
console.log('Received hash: ' + hashValue);
if (!hashValue) {
return response.status(400).send({ error:true, message: 'Please provide hash value' });
} else{
const timestamp = Date.now();
var time = getTimestamp();
console.log(time + ' Adding hash:::::', hashValue);
//call the mint function
var success = await mint(hashValue);
console.log('success' + success) ;
response.send(success);
}
var transactionRecord = {
datetimestamp: time,
hash: hashValue
};
response.json("Hash added to blockchain: " + hashValue);
});
// mint the nft
async function mint(location)
{
const Provider = require('#truffle/hdwallet-provider');
const privateKey = <>;
let provider = ethers.getDefaultProvider('rinkeby');
//maybe this is not needed
var fromAddress = <>;
let wallet = new ethers.Wallet(privateKey, provider);
let balancePromise = wallet.getBalance();
console.log('balancePromise: ' + balancePromise + ' balancePromise ' +
JSON.stringify(balancePromise));
balancePromise.then((balance) => {
console.log('Balance before minting : ' + balance);
});
let transactionCountPromise = wallet.getTransactionCount();
transactionCountPromise.then((transactionCount) => {
console.log('transactionCount: ' + transactionCount);
});
//console.log ('wallet: ' + JSON.stringify(wallet));
let nftAddress = <>;
console.log ('nftAddress: ' + nftAddress);
try {
var mainContract = new ethers.Contract(nftAddress, LocationNFT.abi, wallet);
console.log("Mining...please wait.");
if(mainContract)
console.log ('mainContract data there: ');
const nft2 = await mainContract.mintNFT(location)
return nft2.hash;
} catch (e) {
console.log(e) // This gets executed when process times out in ~30 minutes
}
} //end of mint function
Before, I had a react app running in the background on my website server. Here is the code from the App.js
//Previous App.js
import React, { Component, useState } from 'react';
import Web3 from 'web3'
import './App.css';
import Location from '../abis/Location.json'
class App extends Component {
async componentWillMount() {
await this.loadWeb3()
await this.loadBlockchainData()
}
async loadWeb3() {
if (window.ethereum) {
window.web3 = new Web3(window.ethereum)
await window.ethereum.enable()
}
else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider)
}
else {
window.alert('Non-Ethereum browser detected. You should consider trying MetaMask!')
}
}
async loadBlockchainData() {
const web3 = window.web3
// Load account
const accounts = await web3.eth.getAccounts()
this.setState({ account: accounts[0] })
const networkId = await web3.eth.net.getId()
const networkData = Location.networks[networkId]
if(networkData) {
const abi = Location.abi
const address = networkData.address
const contract = new web3.eth.Contract(abi, address)
this.setState({ contract })
const totalSupply = await contract.methods.totalSupply().call()
this.setState({ totalSupply })
// Load Colors
for (var i = 1; i <= totalSupply; i++) {
const location = await contract.methods.locations(i - 1).call()
this.setState({
locations: [...this.state.locations, location]
})
}
} else {
window.alert('Smart contract not deployed to detected network.')
}
}
// mint the nft
mint = (location) => {
this.state.contract.methods.mint(location).send({ from: this.state.account })
.once('receipt', (receipt) => {
this.setState({
locations: [...this.state.locations, location]
})
})
}
constructor(props) {
super(props)
this.state = {
account: '',
contract: null,
totalSupply: 0,
locations: []
}
}
render() {
return (
<div>
<nav className="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
<a className="navbar-brand col-sm-3 col-md-2 mr-0"
href="http://www.dappuniversity.com/bootcamp"
target="_blank" rel="noopener noreferrer">
Location Tokens
</a>
<ul className="navbar-nav px-3">
<li className="nav-item text-nowrap d-none d-sm-none d-sm-block">
<small className="text-white"><span id="account">{this.state.account}</span></small>
</li>
</ul>
</nav>
<div className="container-fluid mt-5">
<div className="row">
<main role="main" className="col-lg-12 d-flex text-center">
<div className="content mr-auto ml-auto">
<h1>Issue Token</h1>
<form onSubmit={(event) => {
event.preventDefault()
const location = this.location.value
this.mint(location)
}}>
<input type='text' className='form-control mb-1'
placeholder='e.g. #FFFFFF' ref={(input) => { this.location = input }} />
<input type='submit' className='btn btn-block btn-primary' value='MINT' />
</form>
</div>
</main>
</div>
<hr/>
<div className="row text-center">
{ this.state.locations.map((location, key) => {
return(
<div key={key} className="col-md-3 mb-3">
<div>{location}</div>
</div>
)
})}
</div>
</div>
</div>
);
}
}
export default App;
This is the code in the index.html file I am currently working on to check for metamask account. I want users to pay using their matamask wallet using their account within the wallet.
//The code in the index.html that I am working on
<script type="text/javascript">
window.addEventListener('load', function ()
{
if (typeof web3 !== 'undefined') {
console.log('Web3 Detected! ' + web3.currentProvider.constructor.name)
window.web3 = new Web3(web3.currentProvider);
} else {
console.log('No Web3 Detected... using HTTP Provider')
}
web3.eth.defaultAccount = web3.eth.accounts[1];
})
addEventListener('DOMContentLoaded', function() {
loadWeb3();
loadBlockchainData();
});
async function loadWeb3() {
console.log('Inside loadWeb3() fn')
if (window.ethereum) {
window.web3 = new Web3(window.ethereum)
await window.ethereum.enable()
console.log('window.ethereum')
}
else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider)
}
else {
console.log('Non-Ethereum browser detected. You should consider trying MetaMask!')
}
}
async function loadBlockchainData() {
console.log('Inside loadBlockchainData() fn')
const web3 = window.web3
// Load account
const accounts = await web3.eth.getAccounts()
this.setState({ account: accounts[0] })
console.log('web3' + web3)
const networkId = await web3.eth.net.getId()
const networkData = Location.networks[networkId]
if(networkData) {
const abi = Location.abi
const address = networkData.address
const contract = new web3.eth.Contract(abi, address)
this.setState({ contract })
const totalSupply = await contract.methods.totalSupply().call()
this.setState({ totalSupply })
// Load Locations
for (var i = 1; i <= totalSupply; i++) {
const location = await contract.methods.locations(i - 1).call()
this.setState({
locations: [...this.state.locations, location]
})
}
} else {
window.alert('Smart contract not deployed to detected network.')
}
}
Related
I'm building a web app using Node, Express, Cors and Body Parser. The app uses the fetch api to fetch data from online apis. Now I have written all the code with a server.js file, an index.html and an app.js. My server.js file contains the express server functions and middleware. My app.js contains the main functionality. Here are my files:
Index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Weather Journal</title>
</head>
<body>
<div id="app">
<div class="holder headline">
Weather Journal App
</div>
<form id="userInfo">
<div class="holder zip">
<label for="zip">Enter City here</label>
<input type="text" id="city" placeholder="enter city here" required>
</div>
<div class="holder feel">
<label for="date">Enter departure date</label>
<input type="datetime-local" id="date" required>
<button id="submitBtn" type="submit"> Generate </button>
</div>
</form>
<div class="holder entry">
<div class="title">Most Recent Entry</div>
<div id="entryHolder">
<div id="lat"></div>
<div id="lng"></div>
<div id="countryName"></div>
<div id="temp"></div>
</div>
</div>
</div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>
My app.js:
const geoURL = "http://api.geonames.org/searchJSON?";
const geoUsername = `rohanasif1990`;
const weatherURL = "https://api.weatherbit.io/v2.0/forecast/daily?"
const weatherKey = "20028a8267a24bba9a807362767bc4a7"
let d = new Date();
let newDate = d.getMonth() + 1 + "." + d.getDate() + "." + d.getFullYear();
const submitBtn = document.getElementById("submitBtn");
submitBtn.addEventListener("click", (e) => {
e.preventDefault();
const city = document.getElementById("city").value;
if (city !== "") {
getCity(geoURL, city, geoUsername)
.then(function (data) {
getWeather(weatherURL, weatherKey, data["geonames"][0]['lat'], data["geonames"][0]['lng'])
}).then(weatherData => {
postWeatherData("/addWeather", { temp: weatherData })
}).then(function () {
receiveWeatherData()
}).catch(function (error) {
console.log(error);
alert("Invalid city");
})
}
})
const getCity = async (geoURL, city, geoUsername) => {
const res = await fetch(`${geoURL}q=${city}&username=${geoUsername}`);
try {
const cityData = await res.json();
return cityData;
}
catch (error) {
console.log("error", error);
}
}
const postWeatherData = async (url = "", data = {}) => {
const response = await fetch(url, {
method: "POST",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
temp: data.temp
})
});
try {
const newData = await response.json();
return newData;
}
catch (error) {
console.log(error);
}
}
const receiveWeatherData = async () => {
const request = await fetch("/allWeather");
try {
const allData = await request.json()
document.getElementById("temp").innerHTML = allData.temp;
}
catch (error) {
console.log("error", error)
}
}
const getWeather = async (weatherURL, weatherKey, lat, lon) => {
const res = await fetch(`${weatherURL}&lat=${lat}&lon=${lon}&key=${weatherKey}`);
try {
const weatherData = await res.json();
return weatherData;
}
catch (error) {
console.log("error", error);
}
}
My server.js:
// Setup empty JS object to act as endpoint for all routes
cityData = {};
weatherData = {};
picturesData = {};
// Require Express to run server and routes
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
// Start up an instance of app
const app = express();
/* Middleware*/
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
app.use(cors())
// Initialize the main project folder
app.use(express.static('website'));
app.get("/all", function sendData(req, res) {
res.send(cityData);
})
app.get("/allWeather", function sendWeather(req, res) {
res.send(weatherData);
})
app.get("allPictures", function sendPictures(req, res) {
res.send(picturesData);
})
app.post("/add", (req, res) => {
projectData['lat'] = req.body.lat;
projectData['lng'] = req.body.lng;
projectData['countryName'] = req.body.countryName
res.send(cityData);
})
app.post("/addWeather", (req, res) => {
weatherData['temp'] = req.body.temp;
res.send(weatherData);
})
app.post("/addPicture", (req, res) => {
picturesData['pic'] = req.body.pic;
res.send(picturesData);
})
// Setup Server
app.listen(3000, () => {
console.log("App listening on port 3000")
console.log("Go to http://localhost:3000")
})
I am trying to get the geonames api to fetch the latitude and longitude of a city . Then I want to use the latitude and longitude to fetch the weather for that location. The pictures api is not implemented yet. I just want to use the data fetched from one api (geonames.org) as input to the other api (weatherbit.io). Right the app returns undefined when I console.log the final data.
You are breaking the Promise then chain. You do not return any promise so that it can be chained. Pasting modified example withe capital RETURN
statements
getCity(geoURL, city, geoUsername)
.then(function (data) {
RETURN getWeather(weatherURL, weatherKey, data["geonames"][0]['lat'], data["geonames"][0]['lng'])
}).then(weatherData => {
RETURN postWeatherData("/addWeather", { temp: weatherData })
}).then(function () {
RETURN receiveWeatherData()
}).catch(function (error) {
console.log(error);
alert("Invalid city");
})
A better would be to write the function as Async, I see you have done that already
So
submitBtn.addEventListener("click", async (e) => {
e.preventDefault();
const city = document.getElementById("city").value;
if (city !== "") {
try {
const city = await getCity(geoURL, city, geoUsername);
const weatherData = await getWeather(weatherURL, weatherKey, city["geonames"][0]['lat'], city["geonames"][0]['lng']);
//and so on
} catch (e) {
console.log(error);
alert("Invalid city");
}
}
})
The problem was here:
const receiveWeatherData = async () => {
const request = await fetch("/allWeather");
try {
const allData = await request.json()
document.getElementById("temp").innerHTML = allData['temp'];
}
catch (error) {
console.log("error", error)
}
}
I replaced allData['data'] with allData['temp']
When I type a wallet address and press the Save button I want to show a Metamask sign in popup to that wallet.
for now, It's just randomly connects with the selected wallet. Basically, I want to be able to connect wallets with just wallet address.
profile.jsx
import React from "react";
import { useContext, MainContext } from "../hook/Context";
import Web3 from "web3";
const Profile = () => {
const { data, setData } = useContext(MainContext);
const detectCurrentProvider = () => {
let provider;
if (window.ethereum) {
provider = window.ethereum;
} else if (window.web3) {
provider = window.web3.currentProvider;
} else {
alert(
"Non-Ethereum browser detected. You should consider trying MetaMask!"
);
}
return provider;
};
const onConnect = async (e) => {
e.preventDefault();
try {
const currentProvider = detectCurrentProvider();
if (currentProvider) {
if (currentProvider !== window.ethereum) {
alert(
"Non-Ethereum browser detected. You should consider trying MetaMask!"
);
}
await currentProvider.request({ method: "eth_requestAccounts" });
const web3 = new Web3(currentProvider);
const userAccount = await web3.eth.getAccounts();
const chainId = await web3.eth.getChainId();
const account = userAccount[0];
let ethBalance = await web3.eth.getBalance(account); // Get wallet balance
ethBalance = web3.utils.fromWei(ethBalance, "ether"); //Convert balance to wei
setData(ethBalance, account, chainId);
if (userAccount.length === 0) {
console.log("Please connect to meta mask");
}
}
} catch (err) {
alert(
"There was an error fetching your accounts. Make sure your Ethereum client is configured correctly."
);
}
};
return (
<div className="container-fluid">
<div className="wallets__wrapper">
Your wallets:
{data.account}
</div>
<form className="token__form" onSubmit={onConnect}>
<input type="text" placeholder="Account Name" />
<input type="text" placeholder="Wallet Adress" />
<button className="add__btn">SAVE</button>
</form>
</div>
);
};
export default Profile;
try to load web3 in this way, this will ask you to connect to metamask first(pop-up)
const getWeb3 = () => {
return new Promise((resolve, reject) => {
// Wait for loading completion to avoid race conditions with web3 injection timing.
window.addEventListener("load", async () => {
// Modern dapp browsers...
if (window.ethereum) {
const web3 = new Web3(window.ethereum);
try {
// Request account access if needed
await window.ethereum.enable();
// Acccounts now exposed
resolve(web3);
} catch (error) {
reject(error);
}
}
// Legacy dapp browsers...
else if (window.web3) {
// Use Mist/MetaMask's provider.
const web3 = window.web3;
console.log("Injected web3 detected.");
resolve(web3);
}
// Fallback to localhost; use dev console port by default...
else {
const provider = new Web3.providers.HttpProvider(
"http://localhost:9545"
);
const web3 = new Web3(provider);
console.log("No web3 instance injected, using Local web3.");
resolve(web3);
}
});
});
};
load this in your useEffect:
useEffect(() => {
const init = async () => {
const web3 = await getWeb3();
//set accounts ,etc to state from web3 by awaiting them
const accounts = await web3.eth.getAccounts();
}
init();
}
const showAccount = document.querySelector('.showAccount');
const showBalance = document.querySelector('.showBalance');
const Web3 = require("web3");
getAccount();
getBalance();
getAccount returns the wallet id
async function getAccount() {
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
const account = accounts[0];
showAccount.innerHTML = account;
}
getBalance returns undefined instead of the amount of Ether from Metamask
async function getBalance() {
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
const account = accounts[0];
showBalance.innerHTML = account.balance;
}
Maybe someone knows a good API for retrieving more values than just these two with examples or got a nice video to learn from.
I found the properties for my accounts object: here
I customized your code and now it displays the amount of Ether from the Account:
const showAccount = document.querySelector('.showAccount');
const showBalance = document.querySelector('.showBalance');
getAccount();
loadBalance();
async function getAccount() {
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
const account = accounts[0];
showAccount.innerHTML = account;
}
function loadBalance(){
web3Provider = null;
contracts = {};
account = '0x0';
const Web3 = require("web3");
const ethEnabled = async () => {
if (window.ethereum) {
await window.ethereum.send('eth_requestAccounts');
window.web3 = new Web3(window.ethereum);
return true;
}
}
if (typeof web3 !== 'undefined') {
// If a web3 instance is already provided by Meta Mask.
web3Provider = web3.currentProvider;
web3 = new Web3(web3.currentProvider);
} else {
// Specify default instance if no web3 instance provided
web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
web3 = new Web3(App.web3Provider);
}
$.getJSON("Market.json", function (market) {
console.log("initializing Market contract")
// Instantiate a new truffle contract from the artifact
contracts.Market = TruffleContract(market);
// Connect provider to interact with contract
contracts.Market.setProvider(web3Provider);
});
$.getJSON("Users.json", function (users) {
console.log("initializing User contract")
// Instantiate a new truffle contract from the artifact
contracts.Users = TruffleContract(users);
// Connect provider to interact with contract
contracts.Users.setProvider(App.web3Provider);
});
var marketInstance;
var userInstance;
var loader = $("#loader");
var content = $("#content");
//loader.show();
content.show();
// Load account data
console.log("loading account data")
var currentAccount;
web3.eth.getCoinbase(function (err, account) {
if (err === null) {
console.log("Your Account: " + account)
account = account;
currentAccount = account;
web3.eth.getBalance(account, function(err, balance) {
if (err === null) { //Note:set id="accountBalance" in your html page
$("#accountBalance").text(web3.fromWei(balance, "ether") + " ETH");
}
});
}
});
}
I'm making a full stack Rick and Morty application. Characters on the screen and the user can login and click on them to add them to favorites and then click on them on the favorites page to delete them from the favorites page.
The application works but crashes after a few minutes saying that a fetch request didn't work. In network section of the developer tools, these requests to add or delete characters are coming up as (pending) and then coming up as failures like two minutes later. At the same time, the requests are working from the perspective of the application, meaning that if I add or delete characters as a user and then logout and log back in, the changes are still there. The register and login requests to the backend are working normally with statuses of 200 as well. What's happening here?
The backend:
const express = require('express');
const application = express();
const mongoose = require('mongoose');
application.use(express.json());
mongoose.connect('process.env.DATABASE_PASSWORD')
.then(console.log('Connected to database'));
const db = mongoose.connection;
const port = process.env.PORT || 8080;
application.post('/register', (request, response) => {
const username = request.body.username;
const password = request.body.password;
const favorites = [];
db.collection('data').insertOne({
username,
password,
favorites,
});
});
application.post('/login', async (request, response) => {
const username = request.body.username;
const password = request.body.password;
const findUser = await db.collection('data').findOne({
username,
password,
});
if (findUser) {
response.send({ message: 'Welcome, ' + username + "!", user: username, favorites: findUser.favorites });
} else {
response.send({ message: 'Login unsuccessful'});
}
});
application.post('/addFavorite', (request, response) => {
const userNow = request.body.username;
const favoritesHere = request.body.favoritesCopy;
console.log({userNow, favoritesHere});
db.collection('data').updateOne(
{ username: userNow },
{ $set: { favorites: favoritesHere }},
)
});
application.post('/deleteFavorite', (request, response) => {
const userNow = request.body.username;
const favoritesHere = request.body.theData;
db.collection('data').updateOne(
{ username: userNow },
{ $set: { favorites: favoritesHere }},
);
});
application.listen(port, () => {
console.log('Application listening');
});
The frontend fetch add request (the delete request is similar):
import React, { useState, useEffect } from 'react';
import logo from '../rickandmortylogo.png';
import { useSelector, useDispatch } from 'react-redux';
import { addFavorite } from '../index.js';
const Body = () => {
const [characters, setCharacters] = useState([]);
const [currentName, setCurrentName] = useState('Placeholder');
const [nameInput, setNameInput] = useState('');
const [locationInput, setLocationInput] = useState('');
const [loading, setLoading] = useState(true);
const favorites = useSelector(state => state.favoritesList);
const userNow = useSelector(state => state.currentUser);
const loggedIn = useSelector(state => state.loggedIn);
const dispatch = useDispatch();
useEffect(() => {
let isMounted = true;
let url = 'https://rickandmortyapi.com/api/character/';
let array = [];
const getData = async () => {
for (let i = 1; i < 4; i++) {
let response = await fetch(url);
let data = await response.json();
for (let j = 0; j < 20; j++) {
array.push(data.results[j]);
}
url = data.info.next;
}
if (isMounted) {
setCharacters(array);
setLoading(false);
}}
getData();
return () => {
isMounted = false;
}
}, []);
const readInput = (e) => {
setNameInput(e.target.value);
}
const readLocationInput = (e) => {
setLocationInput(e.target.value);
}
const addData = (a, b, c, d) => {
const array = [a, b, c, d];
const favoritesCopy = [...favorites];
favoritesCopy.push(array);
dispatch(addFavorite(array));
if (loggedIn === true) {
fetch('/addFavorite', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
favoritesCopy,
username: userNow,
}),
});
}
};
return (
<div className="pt-5">
<div className="text-center mt-5">
<img src={logo} className="img-fluid" />
</div>
<h2>Click on a character here to add them to your favorites. Choose "Check Favorites" in the menu bar to see your favorites and "Search Characters" to come back.</h2>
<div className="all">
<h4>Search by name:</h4>
<input onChange={readInput} />
<h4>Search by location:</h4>
<input onChange={readLocationInput} />
<br />
<div className="row m-1">
{loading ? 'Loading can take a few seconds. Your Rick and Morty experience will be ready soon!' : characters.filter((item) => {
if (nameInput == "") {
return item;
} else {
if (item.name.toLowerCase().includes(nameInput.toLowerCase())) {
return item;
}
}
}).filter((item) => {
if (locationInput == "") {
return item;
} else {
if (item.location.name.toLowerCase().includes(locationInput.toLowerCase())) {
return item;
}
}
}).map((item, id) => {
return (
<>
<div className="col-md-4 border border-dark rounded" id="square" onClick={() => addData(item.name, item.image, item.location.name, item.status)}>
<h2>{item.name}</h2>
<img src={item.image} className="border rounded" />
<h4>Location: {item.location.name}</h4>
<h4>Status: {item.status}</h4>
</div>
</>
)
})}
</div>
</div>
</div>
);
};
export default Body;
You never end the request. You don't send anything in the response and don't call response.end either, nor next. That's why your request never ends.
Here are some examples:
Success message with content
res.status(200).json({ success: true});
Success message without content
res.sendStatus(204);
Of course requests are pending, you never send anything on related actions:
Use res.send and send something, or at least in case of success, send a success status like:
204 for a no content success operation, like a DELETE for example.
201 for a POST operation creating a new resource.
5xx for errors
This is my first app doing it with node.js and express. This is a basic app where I connect to an external API to show temperature and take a user input "zipcode and feeling" and show it to the UI. I can't get the data.
I ran the app and entered data in the zipcode and feeling text area, What am I doing wrong?
the server.js
// Setup empty JS object to act as endpoint for all routes
projectData = {};
const port = 3000
// Require Express to run server and routes
const express = require("express")
const bodyParser = require("body-parser")
const cors = require("cors")
// Start up an instance of app
const app = express();
/* Middleware*/
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
app.use(cors())
// Initialize the main project folder
app.use(express.static('website'));
app.get('/getWeather',(req,res) => {
res.send(projectData)
})
app.post('/addWeather',(req,res) => {
newEntry = {
data:req.body.data,
temp: req.body.temp,
content: req.body.content
}
projectData = newEntry;
})
// Setup Server
app.listen(port, () => {
console.log(`Your server is running on port ${port}`);
})
website/app.js
/* Global Variables */
//const { request } = require("express");
// Create a new date instance dynamically with JS
let d = new Date();
let newDate = (d.getMonth()+1) +'.'+ d.getDate()+'.'+ d.getFullYear();
//let zipcode = document.querySelector("#zip").value;
const APIkey = "2f12ba4132bf221863be475a1a6b34f6";
//let fullURL=`https://api.openweathermap.org/data/2.5/weather?zip=${zipcode}&appid=${APIkey}$units=metric`
const button1 = document.querySelector("#generate")
button1.addEventListener("click", getDataOfWeather)
function getDataOfWeather(){
const feeling = document.querySelector("#feelings").value;
const zipcode = document.querySelector("#zip").value;
getTemp(zipcode)
.then(function(temp){
/* console.log(temp);
addData('/addWeather',{ data: newDate , temp: temp, content: feeling});*/
addData(temp,feeling)
})
.then(
updateUI()
)
}
const getTemp = async(zipcode) => {
try {
if(!zipcode){
alert("you didnot enter zip code");
}
const fullURL=`https://api.openweathermap.org/data/2.5/weather?zip=${zipcode}&appid=${APIkey}&units=metric`
const res = await fetch(fullURL)
if(res.status === 200){
const data = await res.json();
console.log(data.main.temp);
return data.main.temp;
}
else if(res.status === 404){
alert("error in ZIP code ");
return false;}
/* const data = await res.json();
return data;*/
}
catch (err)
{
console.log(err);
}
}
const addData = async(temp,fell) => {
console.log(fell);
const response = await fetch("/addWeather",{
method: "POST",
credentials: "same-origin",
body:{
data : newDate,
temp:temp,
content: fell,
}
})
try {
const nData = await response.json();
return nData;
}
catch(err)
{
console.log(err);
}
}
/*const addData = async(url = '', data = {})=> {
const response = await fetch (url , {
method: 'POST',
credentials: 'same-origin',
headers: {
'content-Type': 'application/json',
},
body: JSON.stringify(data),
})
try {
const nData = await response.json();
return nData;
}
catch(err)
{
console.log(err);
}
}*/
const updateUI = async() => {
const request = await fetch('/getWeather');
try {
const allOfData = await request.json();
console.log(allOfData);
document.getElementById('data').innerHTML = allOfData.newDate;
document.getElementById('temp').innerHTML = allOfData.temp;
document.getElementById('content').innerHTML = allOfData.content;
}
catch (err)
{
console.log("error",err);
}
}
website/index.js
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Weather Journal</title>
<link href="https://fonts.googleapis.com/css?family=Oswald:400,600,700|Ranga:400,700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id = "app">
<div class ="holder headline">
Weather Journal App
</div>
<div class ="holder zip">
<label for="zip">Enter Zipcode here</label>
<input type="text" id="zip" placeholder="enter zip code here">
</div>
<div class ="holder feel">
<label for="feelings">How are you feeling today?</label>
<textarea class= "myInput" id="feelings" placeholder="Enter your feelings here" rows="3" cols="30"></textarea>
<button id="generate" type = "submit"> Generate </button>
</div>
<div class ="holder entry">
<div class = "title">Most Recent Entry</div>
<div id = "entryHolder">
<div id = "date"></div>
<div id = "temp"></div>
<div id = "content"></div>
</div>
</div>
</div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>
Your Id is date not data in update UI function in app.js
const updateUI = async() => {
const request = await fetch('/getWeather');
try {
const allOfData = await request.json();
console.log(allOfData);
document.getElementById('date').innerHTML = allOfData.newDate; // change data to date
document.getElementById('temp').innerHTML = allOfData.temp;
document.getElementById('content').innerHTML = allOfData.content;
}
catch (err)
{
console.log("error",err);
}
}