mirror of
https://github.com/bendtherules/smallcase-portfolio-builder.git
synced 2026-08-18 13:52:19 +00:00
Add portfolio overview (w/o chart)
This commit is contained in:
@@ -11,6 +11,8 @@ class PortfolioBuilderApp extends Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.allScripPrices = data.price;
|
this.allScripPrices = data.price;
|
||||||
|
this.allScripEPS = data.eps;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
portfolioScripPrices: {
|
portfolioScripPrices: {
|
||||||
// scrip name : current price
|
// scrip name : current price
|
||||||
@@ -102,6 +104,7 @@ class PortfolioBuilderApp extends Component {
|
|||||||
addScripToPortfolio={this.addScripToPortfolio}
|
addScripToPortfolio={this.addScripToPortfolio}
|
||||||
/>
|
/>
|
||||||
<PortfolioManager
|
<PortfolioManager
|
||||||
|
allScripEPS={this.allScripEPS}
|
||||||
portfolioScripPrices={this.state.portfolioScripPrices}
|
portfolioScripPrices={this.state.portfolioScripPrices}
|
||||||
portfolioScripCounts={this.state.portfolioScripCounts}
|
portfolioScripCounts={this.state.portfolioScripCounts}
|
||||||
addScripToPortfolio={this.addScripToPortfolio}
|
addScripToPortfolio={this.addScripToPortfolio}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.portfolio-manager {
|
.portfolio-manager {
|
||||||
margin: 2em 0;
|
margin-top: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.portfolio-manager .section-title .title-box {
|
.portfolio-manager .section-title .title-box {
|
||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
.portfolio-manager .body {
|
.portfolio-manager .body {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
margin-bottom: 2em;
|
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +94,6 @@
|
|||||||
right: 0.5em;
|
right: 0.5em;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #EE6723;
|
background-color: #EE6723;
|
||||||
color: white;
|
color: white;
|
||||||
@@ -120,7 +118,7 @@
|
|||||||
.portfolio-manager button {
|
.portfolio-manager button {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
min-height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.portfolio-manager button .btn-text {
|
.portfolio-manager button .btn-text {
|
||||||
@@ -155,4 +153,57 @@
|
|||||||
|
|
||||||
.portfolio-manager .rupee-sign {
|
.portfolio-manager .rupee-sign {
|
||||||
font-family: PingFangSC-Light, serif;
|
font-family: PingFangSC-Light, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Portfolio Overview */
|
||||||
|
|
||||||
|
.portfolio-manager .portfolio-overview .overview-header {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.5em;
|
||||||
|
color: #1D70CA;
|
||||||
|
margin-top: 0.25em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-manager .overview-body {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-manager .overview-body .overview-chart, .portfolio-manager .overview-body .overview-details {
|
||||||
|
float: left;
|
||||||
|
width: 50%;
|
||||||
|
min-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-manager .overview-body .overview-details {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-manager .overview-card {
|
||||||
|
float: left;
|
||||||
|
width: 50%;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-manager .overview-card .card-title {
|
||||||
|
font-size: 1.25em;
|
||||||
|
padding: .5em 0;
|
||||||
|
color: #287DCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-manager .overview-card .card-details {
|
||||||
|
font-size: 1.75em;
|
||||||
|
font-weight: 300;
|
||||||
|
padding-left: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portfolio-manager .overview-details .build-portfolio {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.25em;
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 1em;
|
||||||
|
background-image: linear-gradient(-90deg, #2BC4DD 0%, #3489D1 100%);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.30);
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ class PortfolioManager extends Component {
|
|||||||
|
|
||||||
calcNetWorth() {
|
calcNetWorth() {
|
||||||
let netWorth = 0;
|
let netWorth = 0;
|
||||||
|
|
||||||
Object.keys(this.props.portfolioScripCounts).forEach((scripName) => {
|
Object.keys(this.props.portfolioScripCounts).forEach((scripName) => {
|
||||||
const count = this.props.portfolioScripCounts[scripName];
|
const count = this.props.portfolioScripCounts[scripName];
|
||||||
const price = this.props.portfolioScripPrices[scripName];
|
const price = this.props.portfolioScripPrices[scripName];
|
||||||
@@ -19,6 +20,27 @@ class PortfolioManager extends Component {
|
|||||||
return netWorth;
|
return netWorth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calcTotalEarnings() {
|
||||||
|
let totalEarnings = 0;
|
||||||
|
Object.keys(this.props.portfolioScripCounts).forEach((scripName) => {
|
||||||
|
const count = this.props.portfolioScripCounts[scripName];
|
||||||
|
const eps = this.props.allScripEPS[scripName];
|
||||||
|
totalEarnings += (eps * count);
|
||||||
|
});
|
||||||
|
|
||||||
|
return totalEarnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
calcPortfolioPE() {
|
||||||
|
const portfolioPE = (this.calcNetWorth() / this.calcTotalEarnings());
|
||||||
|
|
||||||
|
if (Number.isNaN(portfolioPE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return portfolioPE;
|
||||||
|
}
|
||||||
|
|
||||||
weightInPortfolio(scripName) {
|
weightInPortfolio(scripName) {
|
||||||
const count = this.props.portfolioScripCounts[scripName];
|
const count = this.props.portfolioScripCounts[scripName];
|
||||||
const price = this.props.portfolioScripPrices[scripName];
|
const price = this.props.portfolioScripPrices[scripName];
|
||||||
@@ -31,9 +53,134 @@ class PortfolioManager extends Component {
|
|||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderPortfolioEditor() {
|
||||||
|
const portfolioScripPrices = this.props.portfolioScripPrices;
|
||||||
|
const portfolioScripCounts = this.props.portfolioScripCounts;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="portfolio-editor">
|
||||||
|
<div className="editor-header">
|
||||||
|
<div className="section-stock">
|
||||||
|
STOCK
|
||||||
|
</div>
|
||||||
|
<div className="section-price">
|
||||||
|
PRICE
|
||||||
|
</div>
|
||||||
|
<div className="section-shares">
|
||||||
|
SHARES
|
||||||
|
</div>
|
||||||
|
<div className="section-weight">
|
||||||
|
WEIGHT
|
||||||
|
</div>
|
||||||
|
<div className="section-remove-btn">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="clearfix" />
|
||||||
|
</div>
|
||||||
|
<div className="editor-body">
|
||||||
|
{
|
||||||
|
Object.keys(portfolioScripPrices).map((scripName) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="scrip-line-item"
|
||||||
|
key={scripName}
|
||||||
|
>
|
||||||
|
<div className="section-stock">
|
||||||
|
{scripName}
|
||||||
|
</div>
|
||||||
|
<div className="section-price">
|
||||||
|
<span className="rupee-sign">₹</span>
|
||||||
|
{Math.round(portfolioScripPrices[scripName])}
|
||||||
|
</div>
|
||||||
|
<div className="section-shares">
|
||||||
|
<button
|
||||||
|
className="shares-decrement-btn"
|
||||||
|
disabled={
|
||||||
|
portfolioScripCounts[scripName] <= 1
|
||||||
|
}
|
||||||
|
onClick={() => { this.props.addPortfolioScripCount(scripName, -1); }}
|
||||||
|
>
|
||||||
|
<span className="btn-text">-</span>
|
||||||
|
</button>
|
||||||
|
<span className="shares-value">
|
||||||
|
{portfolioScripCounts[scripName]}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
className="shares-increment-btn"
|
||||||
|
onClick={() => { this.props.addPortfolioScripCount(scripName, +1); }}
|
||||||
|
>
|
||||||
|
<span className="btn-text">+</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="section-weight">
|
||||||
|
{
|
||||||
|
Math.round(this.weightInPortfolio(scripName))
|
||||||
|
}
|
||||||
|
%
|
||||||
|
</div>
|
||||||
|
<div className="section-remove-btn">
|
||||||
|
<button onClick={() => { this.props.removeScripFromPortfolio(scripName); }}>
|
||||||
|
<span className="btn-text">-</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="clearfix" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPortfolioOverview() {
|
||||||
const portfolioScripPrices = this.props.portfolioScripPrices;
|
const portfolioScripPrices = this.props.portfolioScripPrices;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="portfolio-overview">
|
||||||
|
<div className="overview-header">
|
||||||
|
Portfolio Overview
|
||||||
|
</div>
|
||||||
|
<div className="overview-body">
|
||||||
|
<div className="overview-chart">
|
||||||
|
</div>
|
||||||
|
<div className="overview-details">
|
||||||
|
<div className="overview-card card-stocks">
|
||||||
|
<div className="card-title">Stocks</div>
|
||||||
|
<div className="card-details">
|
||||||
|
{Object.keys(portfolioScripPrices).length}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="overview-card card-net-worth">
|
||||||
|
<div className="card-title">Net Worth</div>
|
||||||
|
<div className="card-details">
|
||||||
|
<span className="rupee-sign">₹</span>
|
||||||
|
{
|
||||||
|
Math.round(this.calcNetWorth())
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="overview-card card-pe-ratio">
|
||||||
|
<div className="card-title">P/E Ratio</div>
|
||||||
|
<div className="card-details">
|
||||||
|
{
|
||||||
|
Math.round(this.calcPortfolioPE())
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="clearfix" />
|
||||||
|
<button className="build-portfolio">
|
||||||
|
BUILD PORTFOLIO
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="clearfix" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="portfolio-manager"
|
className="portfolio-manager"
|
||||||
@@ -46,82 +193,8 @@ class PortfolioManager extends Component {
|
|||||||
<SectionTitle titleText="Manage Portfolio" />
|
<SectionTitle titleText="Manage Portfolio" />
|
||||||
|
|
||||||
<div className="body">
|
<div className="body">
|
||||||
<div className="portfolio-editor">
|
{this.renderPortfolioEditor()}
|
||||||
<div className="editor-header">
|
{this.renderPortfolioOverview()}
|
||||||
<div className="section-stock">
|
|
||||||
STOCK
|
|
||||||
</div>
|
|
||||||
<div className="section-price">
|
|
||||||
PRICE
|
|
||||||
</div>
|
|
||||||
<div className="section-shares">
|
|
||||||
SHARES
|
|
||||||
</div>
|
|
||||||
<div className="section-weight">
|
|
||||||
WEIGHT
|
|
||||||
</div>
|
|
||||||
<div className="section-remove-btn">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div className="clearfix" />
|
|
||||||
</div>
|
|
||||||
<div className="editor-body">
|
|
||||||
{
|
|
||||||
Object.keys(portfolioScripPrices).map((scripName) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="scrip-line-item"
|
|
||||||
key={scripName}
|
|
||||||
>
|
|
||||||
<div className="section-stock">
|
|
||||||
{scripName}
|
|
||||||
</div>
|
|
||||||
<div className="section-price">
|
|
||||||
<span className="rupee-sign">₹</span>
|
|
||||||
{Math.round(this.props.portfolioScripPrices[scripName])}
|
|
||||||
</div>
|
|
||||||
<div className="section-shares">
|
|
||||||
<button
|
|
||||||
className="shares-decrement-btn"
|
|
||||||
disabled={
|
|
||||||
this.props.portfolioScripCounts[scripName] <= 1
|
|
||||||
}
|
|
||||||
onClick={() => { this.props.addPortfolioScripCount(scripName, -1); }}
|
|
||||||
>
|
|
||||||
<span className="btn-text">-</span>
|
|
||||||
</button>
|
|
||||||
<span className="shares-value">
|
|
||||||
{this.props.portfolioScripCounts[scripName]}
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
className="shares-increment-btn"
|
|
||||||
onClick={() => { this.props.addPortfolioScripCount(scripName, +1); }}
|
|
||||||
>
|
|
||||||
<span className="btn-text">+</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="section-weight">
|
|
||||||
{
|
|
||||||
Math.round(this.weightInPortfolio(scripName))
|
|
||||||
}
|
|
||||||
%
|
|
||||||
</div>
|
|
||||||
<div className="section-remove-btn">
|
|
||||||
<button onClick={() => { this.props.removeScripFromPortfolio(scripName); }}>
|
|
||||||
<span className="btn-text">-</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="clearfix" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="portfolio-overview">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div className="clearfix"></div>
|
<div className="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user