Skip to content

Instantly share code, notes, and snippets.

@MateuszNaKodach
Created April 8, 2021 19:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MateuszNaKodach/e467a4a8990b89977770875c41469c56 to your computer and use it in GitHub Desktop.
Save MateuszNaKodach/e467a4a8990b89977770875c41469c56 to your computer and use it in GitHub Desktop.
CodersCampReact
import React, {useEffect, useState} from "react";
import {AppProps} from "./LegacyApp";
import {StockApi, StockInfo, StockSymbol, SubscriptionId} from "../api";
function App(props: AppProps) {
const [state, setState] = useState({selectedSymbol: props.symbols[0]})
const handleOnClick = (e: React.MouseEvent<HTMLDivElement>) => {
e.preventDefault();
const symbol = (e.target as HTMLAnchorElement).getAttribute(
"aria-controls"
);
setState({selectedSymbol: symbol as StockSymbol});
};
return (
<div className="row p-2 shadow" style={{width: "500px"}}>
<div className="col-4">
<div
className="list-group"
id="list-tab"
role="tablist"
onClick={handleOnClick}
>
{props.symbols.map((stockSymbol, idx) => (
<a
key={stockSymbol}
className={`list-group-item list-group-item-action ${
idx === 0 ? "active" : ""
}`}
id={`list-${stockSymbol}-list`}
data-toggle="list"
href={`#list-${stockSymbol}`}
role="tab"
aria-controls={stockSymbol}
>
{stockSymbol}
</a>
))}
</div>
</div>
<div className="col-8">
<div className="tab-content h-100" id="nav-tabContent">
{props.symbols.map((stockSymbol, idx) => (
<div
key={stockSymbol}
className={`tab-pane fade h-100 ${
idx === 0 ? "show active" : ""
}`}
id={`list-${stockSymbol}`}
role="tabpanel"
aria-labelledby={`list-${stockSymbol}-list`}
>
{stockSymbol === state.selectedSymbol && (
<LiveStockView symbol={stockSymbol} />
)}
</div>
))}
</div>
</div>
</div>
);
}
interface LiveStockViewProps {
readonly symbol: StockSymbol;
}
interface LiveStockViewState {
prevStockInfo?: StockInfo;
stockInfo?: StockInfo;
subscriptionId?: SubscriptionId;
}
function transformPrice(price: number) {
const cents = price % 100;
return `${Math.floor(price / 100)}.${
cents === 0 ? "00" : cents < 10 ? "0" + cents : cents
}`;
}
enum StockChange {
Up,
Down,
None,
}
function LiveStockView(props: LiveStockViewProps) {
const [state, setState] = useState<LiveStockViewState>({
subscriptionId: undefined,
prevStockInfo: undefined,
stockInfo: undefined,
})
const calculateStockChange = () => {
if (state.stockInfo && state.prevStockInfo) {
if (state.stockInfo.price > state.prevStockInfo.price)
return StockChange.Up;
if (state.stockInfo.price < state.prevStockInfo.price)
return StockChange.Down;
}
return StockChange.None;
};
const handelChange = (stockInfo: StockInfo) => {
setState({
...state,
stockInfo,
prevStockInfo: state.stockInfo,
});
};
useEffect(() => {
const subscriptionId = StockApi.subscribeToStock(
props.symbol,
handelChange
);
setState({...state, subscriptionId});
return () => {
if (subscriptionId) {
StockApi.unsubscribeFromStock(subscriptionId)
}
}
}, [])
const stockChange = calculateStockChange();
return (
<div
data-testid={props.symbol}
className="d-flex flex-column justify-content-center align-items-center h-100"
>
{state.stockInfo === undefined ? (
<div
className="spinner-border text-primary"
role="status"
style={{
width: "100px",
height: "100px",
borderWidth: "5px",
}}
>
<span className="sr-only">Loading...</span>
</div>
) : (
<>
<h2>
Price:
<span
className={`ml-2 ${
stockChange === StockChange.Up
? "text-success"
: stockChange === StockChange.Down
? "text-danger"
: ""
}`}
>
{transformPrice(state.stockInfo.price)}
<span className="ml-2">
{stockChange === StockChange.Up ? (
<i className="bi bi-caret-up-fill" />
) : stockChange === StockChange.Down ? (
<i className="bi bi-caret-down-fill" />
) : (
<i className="bi bi-caret-up-fill" />
)}
</span>
</span>
</h2>
<div className="d-flex flex-column justify-content-start">
<h6 className="mt-2">
Time: {state.stockInfo.date.toLocaleTimeString()}
</h6>
<h6 className="mt-2">
Date: {state.stockInfo.date.toLocaleDateString()}
</h6>
</div>
</>
)}
</div>
);
}
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment