better info response types

This commit is contained in:
Ste Vaidis 2022-12-11 21:12:54 +02:00
parent 496c096531
commit 24c99868e1
7 changed files with 109 additions and 56 deletions

View File

@ -1,3 +1,5 @@
import { ReactNode } from "react";
export interface IGetGlobalResponse {
active_cryptocurrencies: number;
markets: number;
@ -17,18 +19,37 @@ export interface IGetCoinsCountResponse {
}
export interface IGetCoinInfoResponse {
[key: string]: any;
name: string;
id: string;
image: {
large: string;
};
description: {
en: string;
}
market_data: {
low_24h: { usd: number };
high_24h: { usd: number };
ath: { usd: number };
atl: { usd: number };
price_change_percentage_24h: number;
price_change_percentage_7d: number;
price_change_percentage_14d: number;
price_change_percentage_30d: number;
price_change_percentage_60d: number;
price_change_percentage_200d: number;
price_change_percentage_1y: number;
}
}
export interface IGetCoinInfoData {
data: IGetCoinInfoResponse
}
export interface IGetCoinInfoRequest {
id: string;
}
// export interface IGetCoinChartRequest {
// page: number;
// per_page: number;
// }
export interface IChartDataItem {
[index: number]: number,
}

View File

@ -1,3 +1,4 @@
import React from 'react'
import { useParams } from 'react-router-dom';
import { useGetCoinInfoQuery } from '../coinApi';
@ -12,22 +13,25 @@ import CoinInfo from './coinInfo';
const CoinDetails = (): JSX.Element => {
const { id } = useParams();
const {
data: data,
error: errorInfo,
isLoading: isLoadingInfo,
isSuccess: isSuccessInfo,
refetch: refetchInfo
data,
error,
isLoading,
isSuccess,
} = useGetCoinInfoQuery(id ? id : '');
React.useEffect(() => {
console.log(data)
}, [])
return (
<div className="details">
{isLoading && <div>Loading...</div>}
{
data && isSuccessInfo && <>
data && isSuccess && <>
<div className="details-title">
<img src={data.image.large} width="28" height="28" />
<h1>{data.name}</h1>
</div>
<Box>
<Grid container>
<Grid item xs={12} sm={12} md={8}>
@ -39,8 +43,8 @@ const CoinDetails = (): JSX.Element => {
<Grid item xs={12} style={{marginTop: 20}}>
<CoinChart coin={data.id} />
</Grid>
<Grid item xs={12}>
<div dangerouslySetInnerHTML={{ __html: data.description.en }} />
<Grid item xs={12} style={{marginTop: 40}}>
<div style={{lineHeight: 2}} dangerouslySetInnerHTML={{ __html: data.description.en }} />
</Grid>
</Grid>
</Box>

View File

@ -27,7 +27,7 @@ const CoinInfo = (props: ICoinInfoProps): JSX.Element => {
Current price: ${data.tickers[0].converted_last.usd}
</Grid>
<Grid item xs={12} style={{ marginTop: 20 }}>
Homepage: <a target="_blank" href={data.links.homepage}>{data.links.homepage}</a>
Homepage: <a target="_blank" href={data.links.homepage[0]}>{data.links.homepage[0]}</a>
</Grid>
<Grid item style={{ marginTop: 20 }}>
Votes: {data.sentiment_votes_up_percentage}%
@ -38,27 +38,35 @@ const CoinInfo = (props: ICoinInfoProps): JSX.Element => {
</Grid>
<Grid container justifyContent="flex-start" style={{ marginTop: 30, marginBottom: 30 }}>
{data.links.subreddit_url &&
<Button style={{ marginRight: 10 }} variant="outlined" startIcon={<RedditIcon />} href={data.links.subreddit_url}>
<Button style={{ marginRight: 10, marginTop: 10 }} variant="outlined" startIcon={<RedditIcon />} href={data.links.subreddit_url}>
Reddit
</Button>
}
{data.links.twitter_screen_name &&
<Button style={{ marginRight: 10 }} variant="outlined" startIcon={<TwitterIcon />} href={`https://twitter.com/${data.links.twitter_screen_name}`}>
<Button style={{ marginRight: 10, marginTop: 10 }} variant="outlined" startIcon={<TwitterIcon />} href={`https://twitter.com/${data.links.twitter_screen_name}`}>
Twitter
</Button>
}
{
Object.entries(data.links.chat_url).map(
([key, value]) => Boolean(value)
&& <Button
key={key}
style={{ marginRight: 10 }}
variant="outlined"
href={String(value)}
startIcon={<LinkIcon />}
([key, value]) => {
if (Boolean(value)) {
console.log(value);
const domain = new URL(String(value));
const label = domain.hostname.split(".")[0]
return (
<Button
key={key}
style={{ marginRight: 10, marginTop: 10 }}
variant="outlined"
href={String(value)}
startIcon={<LinkIcon />}
>
Discord
{label}
</Button>
)
}
}
)
}
</Grid>

View File

@ -5,12 +5,17 @@ import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
export interface ICoinStatsProps {
[key: string]: any;
import { IGetCoinInfoResponse, IGetCoinInfoData } from '../coinApi-types'
interface ICoinStatsProps {
data: IGetCoinInfoResponse;
}
const CoinStats = (props: ICoinStatsProps): JSX.Element => {
console.log("CoinStats props", props)
const { data } = props;
const tableData = [
{title: "24h Hight", value: `$${data.market_data.low_24h.usd}`},
{title: "24h Low", value: `$${data.market_data.high_24h.usd}`},

View File

@ -12,7 +12,17 @@ import { useGetCoinsListQuery, useGetGlobalQuery } from '../coinApi';
import Pager from './coinListPager';
export interface IData {
id: string;
image: string;
name: string;
market_cap_rank: number;
symbol: string;
current_price: string;
high_24h: number;
low_24h: number;
price_change_percentage_24h: number;
}
const CoinList = (): JSX.Element => {
@ -74,7 +84,7 @@ const CoinList = (): JSX.Element => {
</TableHead>
<TableBody>
{
data.map((row: any, index: any) => (
data.map((row: IData, index: number) => (
<TableRow
key={row.name}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
@ -119,7 +129,7 @@ const CoinList = (): JSX.Element => {
</Table>
</TableContainer>
}
<Pager page={page} per_page={per_page} setSearchParams={setSearchParams} />
<Pager page={page} per_page={per_page}/>
</div>
)
}

View File

@ -6,32 +6,37 @@ import ButtonGroup from '@mui/material/ButtonGroup';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid';
const Pager = (props:any): JSX.Element => {
const { page, per_page, } = props;
const { data, error, isLoading, isSuccess, refetch } = useGetCoinsCountQuery();
const navigate = useNavigate();
const lastPage = (data: number) => Math.ceil(data / per_page)
export interface IPagerProps {
page: number;
per_page: number;
}
function handlePager(page: number) {
const url = `/?page=${page}`
navigate(url)
const Pager = (props: IPagerProps): JSX.Element => {
const { page, per_page, } = props;
const { data, error, isLoading, isSuccess, refetch } = useGetCoinsCountQuery();
const navigate = useNavigate();
const lastPage = (data: number) => Math.ceil(data / per_page)
function handlePager(page: number) {
const url = `/?page=${page}`
navigate(url)
}
return (<>
{
data && isSuccess &&
<Grid container justifyContent="center" style={{ marginTop: 60 }}>
<ButtonGroup variant="contained" aria-label="outlined primary button group">
<Button disabled={page === 1} onClick={() => navigate("/")}>First</Button>
<Button disabled={page === 1} onClick={() => handlePager(page - 1)}>Prev</Button>
<Typography style={{ padding: 10 }}>Page {page} from {lastPage(data.count)}</Typography>
<Button disabled={page === lastPage(data.count)} onClick={() => handlePager(page + 1)}>Next</Button>
<Button disabled={page === lastPage(data.count)} onClick={() => handlePager(lastPage(data.count))}>Last</Button>
</ButtonGroup>
</Grid>
}
return (<>
{
data && isSuccess &&
<Grid container justifyContent="center" style={{marginTop: 60}}>
<ButtonGroup variant="contained" aria-label="outlined primary button group">
<Button disabled={page === 1} onClick={() => navigate("/")}>First</Button>
<Button disabled={page === 1} onClick={() => handlePager(page - 1)}>Prev</Button>
<Typography style={{ padding: 10}}>Page {page} from {lastPage(data.count)}</Typography>
<Button disabled={page === lastPage(data.count)} onClick={() => handlePager(page + 1)}>Next</Button>
<Button disabled={page === lastPage(data.count)} onClick={() => handlePager(lastPage(data.count))}>Last</Button>
</ButtonGroup>
</Grid>
}
</>
)
</>
)
}
export default Pager;

View File

@ -3,7 +3,7 @@
## What's inside
- **Frontend:** Typescript using React, Redux-Toolkit, MaterialUI, react-charts-2
- **Frontend:** Typescript using React, Redux-Toolkit, Material-UI, react-chartjs-2
- **Backend:** Javascript using Express
![Screenshot](./screenshot.png)