mirror of
https://github.com/bendtherules/smallcase-portfolio-builder.git
synced 2026-08-18 22:02:56 +00:00
Complete portfolio manager functionalities
This commit is contained in:
@@ -16,6 +16,4 @@
|
||||
.portfolio-builder-app>.body>.title {
|
||||
font-size: 2em;
|
||||
color: #17BCD9;
|
||||
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
@@ -21,6 +21,8 @@ class PortfolioBuilderApp extends Component {
|
||||
};
|
||||
|
||||
this.addScripToPortfolio = this.addScripToPortfolio.bind(this);
|
||||
this.removeScripFromPortfolio = this.removeScripFromPortfolio.bind(this);
|
||||
this.addPortfolioScripCount = this.addPortfolioScripCount.bind(this);
|
||||
}
|
||||
|
||||
addScripToPortfolio(scripName) {
|
||||
@@ -32,7 +34,7 @@ class PortfolioBuilderApp extends Component {
|
||||
|
||||
const oldPortfolioScripCounts = oldState.portfolioScripCounts;
|
||||
const newPortfolioScripCounts = deepCloneNaive(oldPortfolioScripCounts);
|
||||
newPortfolioScripCounts[scripName] = newPortfolioScripCounts[scripName] || 0;
|
||||
newPortfolioScripCounts[scripName] = newPortfolioScripCounts[scripName] || 1;
|
||||
|
||||
return {
|
||||
portfolioScripPrices: newPortfolioScripPrices,
|
||||
@@ -61,6 +63,21 @@ class PortfolioBuilderApp extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
addPortfolioScripCount(scripName, incrementBy) {
|
||||
this.setState((oldState) => {
|
||||
if (scripName in this.state.portfolioScripPrices) {
|
||||
const oldPortfolioScripCounts = oldState.portfolioScripCounts;
|
||||
const newPortfolioScripCounts = deepCloneNaive(oldPortfolioScripCounts);
|
||||
newPortfolioScripCounts[scripName] += incrementBy;
|
||||
|
||||
return {
|
||||
portfolioScripCounts: newPortfolioScripCounts,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
calcRemainingScripPrices() {
|
||||
const remainingScripPrices = {};
|
||||
Object.keys(this.allScripPrices).forEach((scripName) => {
|
||||
@@ -86,7 +103,10 @@ class PortfolioBuilderApp extends Component {
|
||||
/>
|
||||
<PortfolioManager
|
||||
portfolioScripPrices={this.state.portfolioScripPrices}
|
||||
portfolioScripCounts={this.state.portfolioScripCounts}
|
||||
addScripToPortfolio={this.addScripToPortfolio}
|
||||
removeScripFromPortfolio={this.removeScripFromPortfolio}
|
||||
addPortfolioScripCount={this.addPortfolioScripCount}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,3 +11,122 @@
|
||||
.portfolio-manager .section-title .title-tail {
|
||||
border-top: 1.5em solid #15569C;
|
||||
}
|
||||
|
||||
.portfolio-manager .body {
|
||||
margin-left: 1em;
|
||||
margin-bottom: 2em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.portfolio-manager .portfolio-editor, .portfolio-manager .portfolio-overview {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.portfolio-manager .portfolio-editor {
|
||||
width: 45%;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.portfolio-manager .portfolio-overview {
|
||||
width: 55%;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.portfolio-manager .editor-header, .portfolio-manager .editor-body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.portfolio-manager .editor-header {
|
||||
background-color: #8FB9E7;
|
||||
color: white;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
.portfolio-manager .editor-body {
|
||||
box-shadow: 0 0 .25em 0 rgba(0, 0, 0, 0.20);
|
||||
border-radius: .25em;
|
||||
min-height: 5em;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.portfolio-manager .editor-body .scrip-line-item {
|
||||
padding: .5em 0;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-stock, .portfolio-manager .section-price, .portfolio-manager .section-shares, .portfolio-manager .section-weight {
|
||||
float: left;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-stock {
|
||||
width: 35%;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-shares {
|
||||
width: 23%;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-price, .portfolio-manager .section-weight {
|
||||
width: 17%;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-remove-btn {
|
||||
float: left;
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
.portfolio-manager .editor-body .section-stock {
|
||||
padding-left: 1.5em;
|
||||
color: #287DCE;
|
||||
}
|
||||
|
||||
.portfolio-manager .editor-body .section-remove-btn {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.portfolio-manager .editor-body .section-price, .portfolio-manager .editor-body .section-weight {
|
||||
text-align: right;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
.portfolio-manager button {
|
||||
position: relative;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
/* +,-,remove Button styles */
|
||||
|
||||
.portfolio-manager button .btn-text {
|
||||
position: absolute;
|
||||
font-size: 1em;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.portfolio-manager .section-shares {
|
||||
border-radius: .25em;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-shares>* {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 33.33%;
|
||||
height: 1.25em;
|
||||
border: 1px solid #DDDDDD;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-shares .btn-text {
|
||||
color: #287DCE;
|
||||
}
|
||||
|
||||
.portfolio-manager .section-shares .shares-value {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Rupee styling */
|
||||
.portfolio-manager .rupee-sign {
|
||||
font-family: PingFangSC-Light, serif;
|
||||
}
|
||||
@@ -8,6 +8,29 @@ class PortfolioManager extends Component {
|
||||
super();
|
||||
}
|
||||
|
||||
calcNetWorth() {
|
||||
let netWorth = 0;
|
||||
Object.keys(this.props.portfolioScripCounts).forEach((scripName) => {
|
||||
const count = this.props.portfolioScripCounts[scripName];
|
||||
const price = this.props.portfolioScripPrices[scripName];
|
||||
netWorth += (price * count);
|
||||
});
|
||||
|
||||
return netWorth;
|
||||
}
|
||||
|
||||
weightInPortfolio(scripName) {
|
||||
const count = this.props.portfolioScripCounts[scripName];
|
||||
const price = this.props.portfolioScripPrices[scripName];
|
||||
const weight = ((count * price) / this.calcNetWorth()) * 100;
|
||||
|
||||
if (Number.isNaN(weight)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
render() {
|
||||
const portfolioScripPrices = this.props.portfolioScripPrices;
|
||||
|
||||
@@ -22,21 +45,86 @@ class PortfolioManager extends Component {
|
||||
>
|
||||
<SectionTitle titleText="Manage Portfolio" />
|
||||
|
||||
<div className="drop-block" style={{ width: '100%', height: '500px', border: '1px solid black' }} />
|
||||
Please drop here
|
||||
<ul>
|
||||
{
|
||||
Object.keys(portfolioScripPrices).map((scripName) => {
|
||||
return (
|
||||
<li
|
||||
key={scripName}
|
||||
>
|
||||
{scripName} | {portfolioScripPrices[scripName]}
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<div className="body">
|
||||
<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(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>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ class StockPicker extends Component {
|
||||
</div>
|
||||
<div className="scrip-details">
|
||||
<div className="scrip-price">
|
||||
<span className="rupee-sign">₹ </span>
|
||||
<span className="rupee-sign">₹</span>
|
||||
{Math.round(currentPageScripPrices[scripName])}
|
||||
</div>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user