Skip to content

Commit 7a30b02

Browse files
author
dmk
committed
stats by person
1 parent 4edc7c3 commit 7a30b02

3 files changed

Lines changed: 149 additions & 98 deletions

File tree

TCBlazor/Client/Components/TourStaistics.razor

Lines changed: 140 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -7,132 +7,158 @@
77
@using System.Globalization
88

99
<!--
10-
1. spendings by category
11-
2. chart
10+
1. spendings by category
11+
2. chart
1212
-->
13-
<div class="gtid-table" style="grid-template-columns: auto">
13+
<div class="gtid-table" style="grid-template-columns: auto; min-width: 350px;">
1414
<div class="grid-cell">
15-
<SimplePieChart Data="summary"
15+
<input type="checkbox" @bind="@chartDataByCat" id="chart_data" /> <label for="chart_data">@(chartDataByCat ? "By Category" : "By Person")</label>
16+
@if (chartDataByCat)
17+
{
18+
<SimplePieChart Data="summary"
1619
ColorSequenceGenerator="csg"
1720
ShowSubcategories=@true
1821
ShowAbsoluteNumbers=@true
1922
RenderExtraControls="settings.Show_Debug_UI">
20-
<ExtraControls>
21-
Current Seed color: <span style="color: @csg.Seed">@csg.Seed</span>
22-
@{
23-
if (Magic == -1) Magic = (int)(csg.Magic * 1000);
24-
if (Seed == null) Seed = csg.Seed.ToString("#");
25-
}
26-
<input type="color" @bind-value="@SeedBind"/>
27-
<AntDesign.InputNumber Size="@InputSize.Small" @bind-Value="MagicBind"/>
28-
</ExtraControls>
29-
</SimplePieChart>
23+
<ExtraControls>
24+
Current Seed color: <span style="color: @csg.Seed">@csg.Seed</span>
25+
@{
26+
if (Magic == -1) Magic = (int)(csg.Magic * 1000);
27+
if (Seed == null) Seed = csg.Seed.ToString("#");
28+
}
29+
<input type="color" @bind-value="@SeedBind"/>
30+
<AntDesign.InputNumber Size="@InputSize.Small" @bind-Value="MagicBind"/>
31+
</ExtraControls>
32+
</SimplePieChart>
33+
} else {
34+
<SimplePieChart Data="summaryByPersons"
35+
ColorSequenceGenerator="csg"
36+
ShowSubcategories=@true
37+
ShowAbsoluteNumbers=@true
38+
RenderExtraControls="settings.Show_Debug_UI">
39+
<ExtraControls>
40+
Current Seed color: <span style="color: @csg.Seed">@csg.Seed</span>
41+
@{
42+
if (Magic == -1) Magic = (int)(csg.Magic * 1000);
43+
if (Seed == null) Seed = csg.Seed.ToString("#");
44+
}
45+
<input type="color" @bind-value="@SeedBind" />
46+
<AntDesign.InputNumber Size="@InputSize.Small" @bind-Value="MagicBind" />
47+
</ExtraControls>
48+
</SimplePieChart>
49+
}
3050
</div>
31-
<div class="grid-cell">
51+
<div class="grid-cell">
3252
@{
3353
var currencies = (Tour?.Currencies?.OrderByDescending(c => c.CurrencyRate) ?? Enumerable.Empty<Currency>()).Select((x, i) => (x, i)).ToArray();
3454
var cLen = currencies.Count();
3555
var currenciesNum = currencies.Length + 1;
3656
}
3757
<div class="grid-table" style="grid-template-columns: repeat(@currenciesNum,auto)">
38-
<div class="row">
39-
<div class="grid-header">
40-
<Select @bind-Value=@selectedCat
41-
TItemValue="string"
42-
TItem="string"
43-
AllowClear=@true
44-
DataSource=@totalSpentByCat.Keys
45-
IgnoreItemChangesLeadsToException="false" />
58+
<div class="row">
59+
<div class="grid-header">
60+
<Select @bind-Value=@selectedCat
61+
TItemValue="string"
62+
TItem="string"
63+
AllowClear=@true
64+
DataSource=@totalSpentByCat.Keys
65+
IgnoreItemChangesLeadsToException="false" />
66+
</div>
67+
@{
68+
foreach (var (c, i) in currencies)
69+
{
70+
<div class="grid-cell" align="center" style="@(c == Tour?.Currency ? "font-weight: bold; color: green;" : "")">@c.Name</div>
71+
}
72+
}
73+
</div>
74+
<div class="row">
75+
<div class="grid-cell">Total</div>
76+
@foreach (var (c, i) in currencies)
77+
{
78+
var pp = totalSpentByCat[selectedCat];
79+
var cc = Tour?.Currency ?? new();
80+
var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate;
81+
var amountInCurrency = pp * rate;
82+
<div class="grid-cell balance total">
83+
<b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b>
84+
@if (Tour?.IsMultiCurrency() ?? false) {
85+
<span style="font-size: x-small">&nbsp;@(c.Name)</span>
86+
}
4687
</div>
47-
@{
48-
foreach (var (c, i) in currencies)
49-
{
50-
<div class="grid-cell" align="center" style="@(c == Tour?.Currency ? "font-weight: bold; color: green;" : "")">@c.Name</div>
51-
}
52-
}
53-
</div>
54-
<div class="row">
55-
<div class="grid-cell">Total</div>
56-
@foreach (var (c, i) in currencies)
57-
{
58-
var pp = totalSpentByCat[selectedCat];
59-
var cc = Tour?.Currency ?? new();
60-
var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate;
61-
var amountInCurrency = pp * rate;
62-
<div class="grid-cell balance total">
63-
<b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b>
64-
@if (Tour?.IsMultiCurrency() ?? false) {
65-
<span style="font-size: x-small">&nbsp;@(c.Name)</span>
66-
}
67-
</div>
68-
}
69-
</div>
70-
<div class="row">
71-
<div class="grid-cell">Per Person (@adultPersonWeight w)</div>
72-
@foreach (var (c, i) in currencies)
73-
{
74-
var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]);
75-
var cc = Tour?.Currency ?? new();
76-
var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate;
77-
var amountInCurrency = pp * rate;
78-
<div class="grid-cell balance">
79-
<b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b>
80-
@if (Tour?.IsMultiCurrency() ?? false) {
81-
<span style="font-size: x-small">&nbsp;@(c.Name)</span>
82-
}
83-
</div>
84-
}
85-
</div>
86-
<div class="row">
87-
<div class="grid-cell">
88-
Per Day: <input type="number" @bind-value="duration" min="1" max="50"/>
89-
88+
}
9089
</div>
91-
@foreach (var (c, i) in currencies)
92-
{
93-
var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]);
94-
var cc = Tour?.Currency ?? new();
95-
var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate;
96-
var amountInCurrency = pp * rate / (duration == 0 ? 1 : duration);
97-
<div class="grid-cell balance">
98-
<b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated)) </b>
99-
@if (Tour?.IsMultiCurrency() ?? false) {
100-
<span style="font-size: x-small">&nbsp;@(c.Name)</span>
101-
}
102-
</div>
103-
}
104-
</div>
105-
@if (Tour.IsMultiCurrency())
90+
<div class="row">
91+
<div class="grid-cell">Per Person (@adultPersonWeight w)</div>
92+
@foreach (var (c, i) in currencies)
10693
{
107-
<div class="row">
108-
<div class="grid-cell">
109-
Currency: <b style='color: green'>@Tour?.Currency?.Name</b>
110-
</div>
111-
@foreach (var (c, i) in currencies)
112-
{
113-
var cc = Tour?.Currency ?? new ();
114-
var rate = cc.CurrencyRate > c.CurrencyRate ? cc.CurrencyRate * 1.0 / c.CurrencyRate : c.CurrencyRate * 1.0 / cc.CurrencyRate;
115-
var (fc, sc) = cc.CurrencyRate > c.CurrencyRate ? (cc, c) : (c, cc);
116-
<div class="grid-cell">
117-
@if (cc != c)
118-
{
119-
<span style="font-size: x-small"><b style="@(fc == cc ? "color:green" : "")">@fc.Name</b> / <b style="@(sc == cc ? "color:green" : "")">@sc.Name:</b> @($"{rate:#.00}")</span>
120-
}
121-
</div>
94+
var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]);
95+
var cc = Tour?.Currency ?? new();
96+
var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate;
97+
var amountInCurrency = pp * rate;
98+
<div class="grid-cell balance">
99+
<b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b>
100+
@if (Tour?.IsMultiCurrency() ?? false) {
101+
<span style="font-size: x-small">&nbsp;@(c.Name)</span>
102+
}
103+
</div>
104+
}
105+
</div>
106+
<div class="row">
107+
<div class="grid-cell">
108+
Per Day: <input type="number" @bind-value="duration" min="1" max="50"/>
109+
110+
</div>
111+
@foreach (var (c, i) in currencies)
112+
{
113+
var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]);
114+
var cc = Tour?.Currency ?? new();
115+
var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate;
116+
var amountInCurrency = pp * rate / (duration == 0 ? 1 : duration);
117+
<div class="grid-cell balance">
118+
<b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated)) </b>
119+
@if (Tour?.IsMultiCurrency() ?? false) {
120+
<span style="font-size: x-small">&nbsp;@(c.Name)</span>
122121
}
123122
</div>
124123
}
124+
</div>
125+
@if (Tour.IsMultiCurrency())
126+
{
127+
<div class="row">
128+
<div class="grid-cell">
129+
Currency: <b style='color: green'>@Tour?.Currency?.Name</b>
130+
</div>
131+
@foreach (var (c, i) in currencies)
132+
{
133+
var cc = Tour?.Currency ?? new ();
134+
var rate = cc.CurrencyRate > c.CurrencyRate ? cc.CurrencyRate * 1.0 / c.CurrencyRate : c.CurrencyRate * 1.0 / cc.CurrencyRate;
135+
var (fc, sc) = cc.CurrencyRate > c.CurrencyRate ? (cc, c) : (c, cc);
136+
<div class="grid-cell">
137+
@if (cc != c)
138+
{
139+
<span style="font-size: x-small"><b style="@(fc == cc ? "color:green" : "")">@fc.Name</b> / <b style="@(sc == cc ? "color:green" : "")">@sc.Name:</b> @($"{rate:#.00}")</span>
140+
}
141+
</div>
142+
}
143+
</div>
144+
}
125145
</div>
126-
</div>
146+
</div>
127147
</div>
128148
@code {
129149
[Parameter]
130150
public Tour Tour { get; set; } = new Tour();
131151

152+
private bool chartDataByCat { get; set; } = true;
153+
132154
private IEnumerable<(string Name, int Amount)> summary = new List<(string Name, int Amount)>()
133155
{
134156
("A", 10)
135157
};
158+
private IEnumerable<(string Name, int Amount)> summaryByPersons = new List<(string Name, int Amount)>()
159+
{
160+
("N/A", 10)
161+
};
136162

137163
private int duration { get; set; } = 4;
138164

@@ -194,6 +220,7 @@
194220
duration = Tour.Duration;
195221
settings = await engine.GetUISettings();
196222
summary = GetSpendingForStat();
223+
summaryByPersons = GetSpendingByPersonForStat();
197224
CalculatePerPerson();
198225
csg = new() { Magic = settings.Magic_Piechart_Color_Scheme_Number * 1.0 / 1000 };
199226
}
@@ -202,6 +229,7 @@
202229
{
203230
duration = Tour.Duration;
204231
summary = GetSpendingForStat();
232+
summaryByPersons = GetSpendingByPersonForStat();
205233
CalculatePerPerson();
206234
}
207235

@@ -274,6 +302,20 @@
274302
summary[s.Type] += s.AmountInCurrentCurrency(Tour);
275303
}
276304
return summary.DistinctBy(s => s.Key).OrderByDescending(s => s.Value).Select(s => (s.Key, (int)s.Value));
277-
}
305+
}
306+
public IEnumerable<(string Name, int Amount)> GetSpendingByPersonForStat()
307+
{
308+
var ss = Tour.Spendings
309+
.Where(s => !s.Planned && !string.IsNullOrWhiteSpace(s.Type) && (!s.IsDryRun || s.IncludeDryRunInCalc))
310+
;
311+
Dictionary<string, long> summary = new Dictionary<string, long>();
312+
foreach (var s in ss)
313+
{
314+
var pName = (Tour.Persons.Where(pp => pp.GUID == s.FromGuid).FirstOrDefault()?.Name ?? "N/A").AsShortString();
315+
if (!summary.ContainsKey(pName)) summary[pName] = 0;
316+
summary[pName] += s.AmountInCurrentCurrency(Tour);
317+
}
318+
return summary.DistinctBy(s => s.Key).OrderByDescending(s => s.Value).Select(s => (s.Key, (int)s.Value));
319+
}
278320

279321
}

TCBlazor/Client/SharedCode/StringExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,11 @@ public static IEnumerable<string> ChunksUpto(string str, int maxChunkSize)
1414
for (int i = 0; i < str.Length; i += maxChunkSize)
1515
yield return str.Substring(i, Math.Min(maxChunkSize, str.Length - i));
1616
}
17+
public static string AsShortString(this string str, int maxLen = 10)
18+
{
19+
if (string.IsNullOrWhiteSpace(str)) return "";
20+
if (str.Length < maxLen) return str;
21+
return str.Substring(0, maxLen-1) + "…";
22+
}
1723
}
1824
}

TCBlazor/Client/wwwroot/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@
187187
.center {
188188
text-align: center;
189189
}
190+
.center-children {
191+
margin: auto;
192+
}
190193
.grid-cell-span-all-cols {
191194
grid-column: 1 / -1;
192195
text-align: center;

0 commit comments

Comments
 (0)