1
1
@page " /portfolios/{portfolioId:int}"
2
- @using Model
3
2
@using Services
4
3
@using Utils
5
4
@using CryptoStatsSource
6
- @using CryptoStatsSource .model
7
- @using System .Diagnostics
8
- @inject Microsoft .AspNetCore .Components .NavigationManager NavigationManager
5
+ @using Model
6
+ @inject NavigationManager NavigationManager
9
7
@inject IPortfolioService PortfolioService
10
8
@inject IPortfolioEntryService PortfolioEntryService
11
9
@inject IMarketOrderService MarketOrderService ;
31
29
bottom : 1rem ;
32
30
right : 1rem ;
33
31
}
34
-
35
- .mat-paper {
36
- display : flex ;
37
- flex-direction : column ;
38
- justify-content : center ;
39
- align-items : center ;
40
- padding : 1em ;
41
- }
42
32
</style >
43
33
<div class =" mat-layout-grid mat-layout-grid-align-center" >
44
34
<div class =" mat-layout-grid-inner center" >
45
-
46
35
<div class =" mat-layout-grid-cell mat-layout-grid-cell-span-2" ></div >
47
36
<div class =" mat-layout-grid-cell mat-layout-grid-cell-span-8" >
48
37
<MatH5 ><MatButton Outlined =" true" Icon =" keyboard_arrow_left" Style =" margin-right: 1rem;" OnClick =' () => { NavigationManager.NavigateTo($""); }' >Back</MatButton >Portfolio Detail</MatH5 >
49
- @if (ActivePortfolio != null )
38
+ @if (_activePortfolio != null )
50
39
{
51
40
<MatCard class =" demo-mat-card" >
52
41
<MatCardContent >
53
42
<div class =" demo-mat-card-content" >
54
43
<MatHeadline6 class =" clear-margin" >
55
44
<MatChipSet Style =" align-items: center" >
56
- <MatH5 Class =" clear-margin" >@ActivePortfolio .Name </MatH5 >
57
- <MatChip Style =" vertical-align: center" Label =" @CurrencyUtils.GetCurrencyLabel(ActivePortfolio .Currency)" />
45
+ <MatH5 Class =" clear-margin" >@_activePortfolio .Name </MatH5 >
46
+ <MatChip Style =" vertical-align: center" Label =" @CurrencyUtils.GetCurrencyLabel(_activePortfolio .Currency)" />
58
47
</MatChipSet >
59
48
</MatHeadline6 >
60
- <span style =" padding-left : 4px ;" >@ActivePortfolio .Description </span >
49
+ <span style =" padding-left : 4px ;" >@_activePortfolio .Description </span >
61
50
</div >
62
51
<MatBody2 class =" demo-mat-card-content clear-margin" >
63
52
<div class =" mat-layout-grid" >
64
53
<div class =" mat-layout-grid-inner" style =" align-items : center " >
65
- @if (PortfolioSummary != null )
54
+ @if (_portfolioSummary != null )
66
55
{
67
56
<div class =" mat-layout-grid-cell mat-layout-grid-cell-span-6" >
68
- <LabelDecimalValue Label =" Market Value" Value =" @(CurrencyUtils.Format(PortfolioSummary .MarketValue, ActivePortfolio .Currency))" ></LabelDecimalValue >
57
+ <LabelDecimalValue Label =" Market Value" Value =" @(CurrencyUtils.Format(_portfolioSummary .MarketValue, _activePortfolio .Currency))" ></LabelDecimalValue >
69
58
</div >
70
59
<div class =" mat-layout-grid-cell mat-layout-grid-cell-span-6" style =" text-align : end " >
71
- <LabelDecimalValue Positive =" PortfolioSummary .RelativeChange >= 0" ValueColorBasedOnValue =" true" Label =" Total Change" Value =" @(DecimalUtils.FormatTwoDecimalPlacesWithPlusSign(PortfolioSummary .RelativeChange * 100m) + " % " )" ></LabelDecimalValue >
60
+ <LabelDecimalValue Positive =" _portfolioSummary .RelativeChange >= 0" ValueColorBasedOnValue =" true" Label =" Total Change" Value =" @(DecimalUtils.FormatTwoDecimalPlacesWithPlusSign(_portfolioSummary .RelativeChange * 100m) + " % " )" ></LabelDecimalValue >
72
61
</div >
73
62
}
74
63
else
81
70
</MatCardContent >
82
71
</MatCard >
83
72
84
- @if (PortfolioEntryRows == null )
73
+ @if (_portfolioEntryRows == null )
85
74
{
86
75
<MatProgressBar Indeterminate =" true" ></MatProgressBar >
87
76
}
88
- else if (PortfolioEntryRows .Count > 0 )
77
+ else if (_portfolioEntryRows .Count > 0 )
89
78
{
90
- <MatTable Items =" @PortfolioEntryRows " Striped =" true" AllowSelection =" true" RowClass =" tester" class =" mat-elevation-z5" ShowPaging =" false" PageSize =" 9999" SelectionChanged =" SelectionChangedEvent" >
79
+ <MatTable Items =" @_portfolioEntryRows " Striped =" true" AllowSelection =" true" RowClass =" tester" class =" mat-elevation-z5" ShowPaging =" false" PageSize =" 9999" SelectionChanged =" SelectionChangedEvent" >
91
80
<MatTableHeader >
92
81
<th >Coin </th >
93
82
<th >Price </th >
97
86
<MatTableRow >
98
87
<td >@context.Symbol.ToUpper() </td >
99
88
<td >
100
- <div style =" min-width : 8rem " >@( CurrencyUtils .Format (context .CurrentPrice , ActivePortfolio .Currency )) </div >
89
+ <div style =" min-width : 8rem " >@( CurrencyUtils .Format (context .CurrentPrice , _activePortfolio .Currency )) </div >
101
90
</td >
102
91
<td style =' color : @(context.RelativeChange >= 0 ? " #17a104" : " #FF0000" ); min-width : 7rem ;' >
103
92
<div style =" min-width : 6rem " >@DecimalUtils.FormatTwoDecimalPlaces(context.RelativeChange) % </div >
104
93
</td >
105
- <td >@( CurrencyUtils .Format (context .MarketValue , ActivePortfolio .Currency )) (@(DecimalUtils .FormatTwoDecimalPlaces (context .Percentage ))% )</td >
94
+ <td >@( CurrencyUtils .Format (context .MarketValue , _activePortfolio .Currency )) (@(DecimalUtils .FormatTwoDecimalPlaces (context .Percentage ))% )</td >
106
95
</MatTableRow >
107
96
</MatTable >
108
97
}
109
98
else
110
99
{
111
- <MatPaper Elevation =" 2" ><span >No portfolio entries were found .</span ><div ><MatButton Style =" margin-top:1em;" Label =" Create a new portfolio entry" OnClick =' () => { NavigationManager.NavigateTo($"newportfolioentry/{ActivePortfolio.Id}");}' ></MatButton ></div ></MatPaper >
100
+ <MatPaper Elevation =" 2" >
101
+ <span >No portfolio entries were found .</span >
102
+ <div >
103
+ <MatButton Style =" margin-top:1em;" Label =" Create a new portfolio entry" OnClick =' () => { NavigationManager.NavigateTo($"newportfolioentry/{_activePortfolio.Id}"); }' ></MatButton >
104
+ </div >
105
+ </MatPaper >
112
106
}
113
107
}
114
108
else
119
113
<div class =" mat-layout-grid-cell mat-layout-grid-cell-span-2" ></div >
120
114
</div >
121
115
</div >
122
- <MatFAB Class =" app-fab--absolute" Icon =" @MatIconNames.Settings" Label =" Manage portfolio entries" OnClick =' () => { NavigationManager.NavigateTo($"newportfolioentry/{ActivePortfolio .Id}"); }' ></MatFAB >
116
+ <MatFAB Class =" app-fab--absolute" Icon =" @MatIconNames.Settings" Label =" Manage portfolio entries" OnClick =' () => { NavigationManager.NavigateTo($"newportfolioentry/{_activePortfolio .Id}"); }' ></MatFAB >
123
117
124
118
125
119
@code
126
120
{
127
121
[Parameter ]
128
122
public int PortfolioId { get ; set ; }
129
123
130
- protected Portfolio ActivePortfolio ;
124
+ private Portfolio _activePortfolio ;
131
125
132
- protected ISummaryService .Summary PortfolioSummary = null ;
126
+ private ISummaryService .Summary _portfolioSummary ;
133
127
134
- protected List <PortfolioEntry > ActivePortfolioEntries ;
128
+ private List <PortfolioEntry > _activePortfolioEntries ;
135
129
136
- protected List <PortfolioEntryRow > PortfolioEntryRows ;
130
+ private List <PortfolioEntryRow > _portfolioEntryRows ;
137
131
138
132
protected record PortfolioEntryRow (string Symbol , decimal CurrentPrice , decimal RelativeChange , decimal Percentage , decimal AbsoluteChange , decimal MarketValue , int EntryId );
139
133
140
134
protected override void OnInitialized ()
141
135
{
142
- ActivePortfolio = PortfolioService .GetPortfolio (PortfolioId );
143
- ActivePortfolioEntries = PortfolioEntryService .GetPortfolioEntries (PortfolioId );
136
+ _activePortfolio = PortfolioService .GetPortfolio (PortfolioId );
137
+ _activePortfolioEntries = PortfolioEntryService .GetPortfolioEntries (PortfolioId );
144
138
_loadEntryInfo ();
145
139
}
146
140
150
144
// resolve names of all portfolio entries
151
145
await CryptocurrencyResolver .Refresh ();
152
146
var portfolioCryptocurrencyEntries = await Task .WhenAll (
153
- ActivePortfolioEntries .Select (
147
+ _activePortfolioEntries .Select (
154
148
async entry => (await CryptocurrencyResolver .Resolve (entry .Symbol )))
155
149
);
156
150
157
151
// fetch market entries of all entries of the portfolio
158
152
var marketEntries = await CryptoStatsSource .GetMarketEntries (
159
- CurrencyUtils .GetCurrencyLabel (ActivePortfolio .Currency ).ToLower (), portfolioCryptocurrencyEntries .Select (c => c .Id ).ToArray ()
153
+ CurrencyUtils .GetCurrencyLabel (_activePortfolio .Currency ).ToLower (), portfolioCryptocurrencyEntries .Select (c => c .Id ).ToArray ()
160
154
);
161
155
162
156
// create a dictionary where a symbol is mapped to a market entry
163
157
var symbolsToMarketEntries = marketEntries .ToDictionary (entry => entry .Symbol , entry => entry );
164
158
165
- // TODO fix low low low market cap non existing altcoins
166
159
// compute portfolio entry summaries
167
- var entrySummaries = ActivePortfolioEntries .Select (
160
+ var entrySummaries = _activePortfolioEntries .Select (
168
161
portfolioEntry =>
169
162
{
170
163
// find the evaluation of the entry's asset
171
164
var marketEntry = symbolsToMarketEntries .GetValueOrDefault (portfolioEntry .Symbol );
172
165
173
- if (marketEntry == null )
174
- {
175
- // TODO market entry is null
176
- }
177
-
178
166
// fetch all orders of the currently iterated portfolio entry
179
167
var entryMarketOrders = MarketOrderService .GetPortfolioEntryOrders (portfolioEntry .Id );
180
-
168
+
181
169
// compute the summary of the entry based on market orders
182
170
return SummaryService .GetPortfolioEntrySummary (entryMarketOrders , marketEntry .CurrentPrice );
183
171
}
184
172
).ToList ();
185
173
186
174
// compute portfolio's summary based on summaries of it's entries
187
- PortfolioSummary = SummaryService .GetPortfolioSummary (entrySummaries );
175
+ _portfolioSummary = SummaryService .GetPortfolioSummary (entrySummaries );
188
176
189
177
// if the cost of the summary is zero, set the relative change to zero
190
- if (PortfolioSummary .Cost == 0 )
178
+ if (_portfolioSummary .Cost == 0 )
191
179
{
192
- PortfolioSummary = PortfolioSummary with {
180
+ _portfolioSummary = _portfolioSummary with {
193
181
RelativeChange = 0
194
- };
182
+ };
195
183
}
196
184
197
185
// compute the total value of the portfolio by summing market values of all entries
198
186
var portfolioTotalMarketValue = entrySummaries .Sum (summary => summary .MarketValue );
199
187
200
188
// create portfolio entry table rows
201
- PortfolioEntryRows = entrySummaries .Zip (ActivePortfolioEntries ).Select (
189
+ _portfolioEntryRows = entrySummaries .Zip (_activePortfolioEntries ).Select (
202
190
tuple => new PortfolioEntryRow (
203
191
// symbol of the portfolio entry
204
192
tuple .Second .Symbol ,
216
204
tuple .Second .Id
217
205
)
218
206
).ToList ();
219
-
207
+
208
+ // update the UI
220
209
StateHasChanged ();
221
210
}
222
211
223
212
public void SelectionChangedEvent (object row )
224
213
{
225
214
if (row != null )
226
215
{
216
+ // entry row has been clicked, open it's detail
227
217
NavigationManager .NavigateTo ($" entries/{((PortfolioEntryRow ) row ).EntryId }" );
228
218
}
229
219
}
230
-
231
220
}
0 commit comments