I’m having 2 errors I’m stuck in:
1/ I don’t why I get the error and I was having NaN for the Ethereum total.
2/ Was trying to add a component in another one
Here is the code
Assets.jsx
import React, { useEffect, useState } from "react";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import { makeStyles } from "@material-ui/core/styles";
import { Avatar, Box, Typography } from "@material-ui/core";
import MonetizationOnOutlinedIcon from "@material-ui/icons/MonetizationOnOutlined";
import PieChartIcon from "@material-ui/icons/PieChart";
import { useCoinData } from "../hooks/coinData";
import { c2 } from "../utils";
import Login from "./Login";
import { useMoralis } from "react-moralis";
import Calendar from 'react-calendar';
import 'react-calendar/dist/Calendar.css';
import imageNoteBack from '../data/noteback.jpg';
import Transactions from "./Transactions";
const useStyles = makeStyles((theme) => ({
tokenImg: {
height: "2rem",
width: "2rem",
},
}));
export default function Assets() {
const { isAuthenticated } = useMoralis();
const [valueDate, onChange] = useState(new Date());
useEffect(() => {
if(isAuthenticated){
onChangeDate(valueDate);
console.log("valueDate in useeffect: " + valueDate)
}
}, [isAuthenticated]);
async function onChangeDate(nextValue) {
onChange(nextValue);
console.log("nextValue: " + nextValue)
console.log("valueDate: " + valueDate)
}
const { coinList, portfolioValue, isLoading } = useCoinData();
const styles = useStyles();
if (!coinList || !coinList.length || isLoading) {
return (
<Box display="flex" flexDirection="column" alignItems="center">
<Typography variant="h4" gutterBottom>DDiary</Typography>
<Typography>Connect an Ethereum wallet to manage your diary</Typography>
<Login />
</Box>
);
}
return (
<div style={{ backgroundImage: `url(${imageNoteBack})` }}>
<Box my={2}>
<Typography variant="h5" my={2}>
{c2.format(portfolioValue)}
<PieChartIcon fontSize="small" />
</Typography>
</Box>
<Card variant="outlined">
<CardContent>
<Typography gutterBottom>All Assets</Typography>
{coinList.map((token, i) => (
<Box display="flex" justifyContent="space-between" mb={2} key={i}>
<Box display="flex">
<Box display="flex" alignItems="center">
{token.image ? (
<Avatar
className={styles.tokenImg}
src={token.image}
alt={token.symbol}
/>
) : (
<Avatar>
<MonetizationOnOutlinedIcon fontSize="large" />
</Avatar>
)}
</Box>
<Box display="flex" flexDirection="column" ml={1}>
<Typography variant="subtitle2">{token.name}</Typography>
<Typography variant="body1">
{token.valueTxt} {c2.format(token.price)}
</Typography>
</Box>
</Box>
<Typography variant="body1">{c2.format(token.value)}</Typography>
</Box>
))}
</CardContent>
</Card>
<Card variant="outlined">
<CardContent>
<div style={{display: 'flex', justifyContent: 'center', alignItems:'center'}}>
<Calendar
onChange={onChangeDate}
value={valueDate}
maxDate={new Date()}
/>
</div>
<br />
<div id="container">
<Transactions date={valueDate}/>
</div>
</CardContent>
</Card>
</div>
);
}
Transactions.jsx
import React, { useEffect, useState } from "react";
import pageflip from "../data/pageflip.mp3";
import { Moralis } from "moralis";
function saveToMoralis () {
alert("button was clicked");
}
function millisecondsToTime (ms) {
let minutes = Math.floor(ms / (1000 * 60));
let hours = Math.floor(ms / (1000 * 60 * 60));
let days = Math.floor(ms / (1000 * 60 * 60 * 24));
if (days < 1) {
if (hours < 1) {
if (minutes < 1) {
return `less than a minute ago`
} else return `${minutes} minutes(s) ago`
} else return `${hours} hours(s) ago`
} else return `${days} days(s) ago`
}
const pageflipAudio = new Audio(pageflip);
const playSound = audioFile => {
audioFile.play();
}
export default async function setDivDate ({date}) {
//const { Moralis } = useMoralis();
// set lessThan date
let nextDate = new Date(date);
nextDate.setDate(nextDate.getDate()+1);
let query = new Moralis.Query('EthTransactions')
query.greaterThan("block_timestamp", date);
query.lessThan("block_timestamp", nextDate);
const resultDateTransaction = await query.find()
if (resultDateTransaction.length > 0) {
return (
<table border = "1" bordercolor = "blue">
<caption>${resultDateTransaction.length} transaction(s) ${date.toLocaleDateString()}</caption>
<thead>
<tr>
<th scope="col">Transaction</th>
<th scope="col">Block Number</th>
<th scope="col">Age</th>
<th scope="col">Type</th>
<th scope="col">Fee</th>
<th scope="col">Value</th>
<th scope="col">Notes</th>
</tr>
</thead>
<tbody>
{resultDateTransaction.forEach((t) => {
return (
<tr>
<td><a href='https://etherscan.io/tx/${t.attributes.hash}' target="_blank" rel="noopener noreferrer">${t.attributes.hash}</a></td>
<td><a href='https://etherscan.io/block/${t.attributes.block_number}' target="_blank" rel="noopener noreferrer">${t.attributes.block_number}</a></td>
<td>${millisecondsToTime(Date.parse(new Date()) - Date.parse(t.attributes.block_timestamp))}</td>
<td>${t.attributes.from_address == Moralis.User.current().get('ethAddress') ? 'Outgoing' : 'Incoming'}</td>
<td>${((t.attributes.gas * t.attributes.gas_price) / 1e18).toFixed(5)} ETH</td>
<td>${(t.attributes.value / 1e18).toFixed(5)} ETH</td>
<td><input type="text" id="name" name="name"></input><button>Save</button></td>
</tr>
);
})}
</tbody>
</table>
);
playSound(pageflipAudio);
}
}
CoinData.js
import { useMemo } from "react";
import { useEffect } from "react";
import { useState } from "react";
import { useMoralis, useMoralisCloudFunction } from "react-moralis";
import coinGeckoList from "../data/coinGeckoTokenList.json";
import { tokenValue, tokenValueTxt } from "../utils";
const emptyList = [];
const coinGeckoApiUrl = "https://api.coingecko.com/api/v3/coins/markets";
export const useCoinData = () => {
const { user } = useMoralis();
const userAddress = useMemo(() => user?.attributes.ethAddress, [user]);
const { data: tokens, isLoading } = useMoralisCloudFunction("getTokens", {
userAddress,
});
const [coinList, setCoinList] = useState(emptyList);
const [portfolioValue, setPortfolioValue] = useState(0);
useEffect(() => {
if (tokens?.length) {
// get list of CoinGecko IDs for user tokens
const ids = tokens
.map((token) => coinGeckoList[token.symbol.toLowerCase()]?.id)
.filter((id) => Boolean(id))
.join(",");
const url = `${coinGeckoApiUrl}?vs_currency=usd&ids=${ids}`;
console.log("url:", url);
// fetch coin price data by ID
fetch(url, {
method: "GET",
mode: "cors",
headers: { "Access-Control-Allow-Origin": true },
})
.then((response) => response.json())
.then((data) => {
// pivot into a dictionary
console.log("fetch data:", data);
const marketData = {};
data.forEach((d) => (marketData[d.symbol.toUpperCase()] = d));
console.log("marketData:", marketData);
return marketData;
})
.then((data) => {
// add token balance, formatted output for UI
let totalBalance = 0;
const newList = tokens.map((token) => {
const output = { ...token };
const tokenData = data[token.symbol.toUpperCase()];
output.price = tokenData?.current_price || 0;
output.image = tokenData?.image;
output.amount = tokenValue(+output.balance, +output.decimals);
output.value = output.price ? output.amount * output.price : 0;
totalBalance += output.value;
output.valueTxt = tokenValueTxt(
+output.balance,
+output.decimals,
output.symbol
);
return output;
});
console.log("output list:", newList);
setCoinList(newList);
setPortfolioValue(totalBalance);
});
} else {
setCoinList(emptyList);
}
}, [tokens]);
return { coinList, isLoading, portfolioValue };
};