Skip to content

Commit

Permalink
support multiple profiles
Browse files Browse the repository at this point in the history
  • Loading branch information
rrelyea committed Jun 22, 2023
1 parent 4793b37 commit 499e17d
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 119 deletions.
12 changes: 2 additions & 10 deletions Pages/Portfolio.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@page "/portfolio"
@page "/portfolio/reload"
@page "/portfolio/topic/{TopicValue}"
@page "/portfolio/{stepPath}"
@inject HttpClient Http
@inject IAppData appData
Expand Down Expand Up @@ -63,7 +62,7 @@ Portfolio@(stepPath==null?": review":": "+stepPath.Replace('-',' ')) - bogle.too
familyData.UpdatePercentages();

<h4 style="max-width:450px">
Portfolio <br/>
Portfolio (@appData.CurrentProfileName)<br/>
</h4>

<p>Organizing information about your portfolio will help you optimize your finances.</p>
Expand Down Expand Up @@ -263,7 +262,7 @@ Portfolio@(stepPath==null?": review":": "+stepPath.Replace('-',' ')) - bogle.too
string nextPage = folderName + nextStep?.step;

<h4 style="max-width:450px">
<NavLink href=/portfolio>Portfolio</NavLink> &gt; @step.title (@step.number)<br/>
<NavLink href=/portfolio>Portfolio (@appData.CurrentProfileName)</NavLink> &gt; @step.title (@step.number)<br/>
<a style='font-size:24pt' href="@nextPage"><span class="oi oi-arrow-right m-2 aria-hidden="true"></span></a>
<br/>
</h4>
Expand Down Expand Up @@ -1005,9 +1004,6 @@ Portfolio@(stepPath==null?": review":": "+stepPath.Replace('-',' ')) - bogle.too
[Parameter]
public string? stepPath { get; set; }

[Parameter]
public string? TopicValue { get; set; }

public bool ShowMarkup { get; set; }
public string? currentAccountIndex { get; set; }
private Step[]? steps;
Expand All @@ -1030,10 +1026,6 @@ Portfolio@(stepPath==null?": review":": "+stepPath.Replace('-',' ')) - bogle.too
protected override async Task OnInitializedAsync()
{
steps = await Http.GetFromJsonAsync<Step[]>("data/portfolio-assets-steps.json");

if (!string.IsNullOrEmpty(TopicValue)) {
await LoadPortfolioForTopic(TopicValue);
}
}

private ElementReference tickerN;
Expand Down
45 changes: 45 additions & 0 deletions Pages/Profiles.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@page "/profiles"
@inject IAppData appData
@inject NavigationManager Navigation
@inject LocalStorageAccessor LocalStorageAccessor
@inject IRSData irsData

<PageTitle>bogle.tools profiles</PageTitle>

<h1>bogle.tools profiles</h1>


Profiles:<br/>
<ul>

@foreach(var profileName in appData.ProfileNames)
{
<li><a href=/portfolio @onclick="@(e=>gotoProfile(e,profileName))" @onclick:preventDefault>@profileName</a></li>
}

</ul>

<label>Create new profile:</label><br/>
<InputText placeholder="name" @bind-Value="@newProfileName" /><button @onclick="createProfile">create</button>

@code {
private async Task gotoProfile(EventArgs e, string profileName)
{
appData.CurrentProfileName = profileName;
await ProfileUtilities.Load(appData);
Navigation.NavigateTo("/portfolio");
}
private async Task createProfile()
{
if (!string.IsNullOrEmpty(newProfileName)) {
appData.ProfileNames.Add(newProfileName);
await ProfileUtilities.Save(newProfileName, new FamilyData(irsData));
newProfileName = "";
}
}
protected override async Task OnInitializedAsync()
{

}
private string newProfileName { get; set; }
}
4 changes: 0 additions & 4 deletions Pages/Retirement.razor
Original file line number Diff line number Diff line change
Expand Up @@ -686,10 +686,6 @@ Retirement - bogle.tools
familyData.Accounts[index].Edit = true;
}

private async Task OnLoadPortfolioForTopic() {
await LoadPortfolioForTopic(TopicValue);
}

private void OnClearPortfolio() {
familyData = new FamilyData(irsData);
Navigation.NavigateTo("/portfolio");
Expand Down
1 change: 1 addition & 0 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
if (irsData != null) {
builder.Services.AddSingleton<IRSData>(irsData);
var appData = new AppData(new FamilyData(irsData));
appData.CurrentProfileName = "your";
builder.Services.AddSingleton<IAppData>(appData);
} else {
throw new Exception("irsData is null");
Expand Down
14 changes: 14 additions & 0 deletions Shared/Models/FamilyData/AppData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,18 @@ public AppData(FamilyData familyData) {
}

public FamilyData FamilyData { get; set; }
public List<string> ProfileNames {get; set;}
public string CurrentProfileName {get; set;}

public string CurrentProfileKey
{
get {
switch (CurrentProfileName) {
case "your":
return "localSave";
default:
return CurrentProfileName;
}
}
}
}
4 changes: 4 additions & 0 deletions Shared/Models/FamilyData/IAppData.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
public interface IAppData {
public FamilyData FamilyData { get; set; }
public List<string> ProfileNames {get; set;}
public string CurrentProfileName {get; set;}
public string CurrentProfileKey { get; }

}
61 changes: 61 additions & 0 deletions Shared/Models/ProfileUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using IRS;

public static class ProfileUtilities
{
public static string Key { get; set; } = "localSave";
public static string Value { get; set; } = "";
public static string storedJson { get; set; } = "";

public static LocalStorageAccessor? LocalStorageAccessor { get; set; }

public static async Task Save(string key, FamilyData familyData)
{
var options = new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
IgnoreReadOnlyProperties = true,
WriteIndented = true,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
var jsonOut = JsonSerializer.Serialize(familyData, options);

await LocalStorageAccessor.SetValueAsync(key, jsonOut);
}

public static async Task Load(IAppData appData)
{
try {
storedJson = await LocalStorageAccessor.GetValueAsync<string>(appData.CurrentProfileKey);
var options = new JsonSerializerOptions()
{
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};

appData.FamilyData = FamilyData.LoadFromJson(appData.FamilyData, storedJson, options);
}
catch (Exception e)
{
// Key + " in local storage not found...loading default."
Console.WriteLine(e.GetType().Name + " " + e.Message);
}
}

public static async Task Clear(IAppData appData, IRSData irsData)
{
appData.FamilyData = new FamilyData(irsData);
await LocalStorageAccessor.RemoveAsync(Key);
}

public static async Task ClearAllAsync()
{
await LocalStorageAccessor.Clear();
}
}
128 changes: 25 additions & 103 deletions Shared/TopLine.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,124 +7,46 @@
@inject IJSRuntime JS

<div style=position:absolute;right:0px;padding:10px>
Your data is <a style=margin-left:0px href=/about>kept private</a>: <button @onclick=@Save>Save</button> or
<a href=/profiles>Profile list.</a> Data is <a style=margin-left:0px href=/about>kept private</a>: <button @onclick=@Save>Save</button> or
<button @onclick=@Clear>Erase</button>
</div>

@code{
public string Key { get; set; } = "localSave";
public string Value { get; set; } = "";
public string storedJson { get; set; } = "";

public async Task Save()
{
var options = new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
IgnoreReadOnlyProperties = true,
WriteIndented = true,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
var jsonOut = System.Text.Json.JsonSerializer.Serialize(familyData, options);

await LocalStorageAccessor.SetValueAsync(Key, jsonOut);
}
private async Task Save() {
await ProfileUtilities.Save(appData.CurrentProfileKey, appData.FamilyData);
}

public async Task Load()
{
try {
storedJson = await LocalStorageAccessor.GetValueAsync<string>(Key);
var options = new JsonSerializerOptions()
{
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};

familyData = FamilyData.LoadFromJson(familyData, storedJson, options);
}
catch (Exception)
{
// Key + " in local storage not found...loading default."
}
}

public async Task Clear()
{
familyData = new FamilyData(irsData);
await LocalStorageAccessor.RemoveAsync(Key);
private async Task Clear() {
ProfileUtilities.Clear(appData, irsData);
Navigation.NavigateTo("/");
}

public async Task ClearAllAsync()
{
await LocalStorageAccessor.Clear();
}

private async Task OnLoadPortfolio(InputFileChangeEventArgs e)
protected override async Task OnInitializedAsync()
{
var files = e.GetMultipleFiles();
ProfileUtilities.LocalStorageAccessor = LocalStorageAccessor;
appData.CurrentProfileName = "your";
await ProfileUtilities.Load(appData);

if (files != null)
var keys = new List<string>();
var keysJsonElement = await LocalStorageAccessor.GetKeys();
foreach (var el in keysJsonElement.EnumerateArray())
{
var options = new JsonSerializerOptions()
{
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};

foreach (var file in files)
{
using (var stream = file.OpenReadStream()) {
familyData = await FamilyData.LoadFromJsonStream(familyData, stream, options);
string? value = el.GetString();
if (value != null) {
switch (value) {
case "i18nextLng":
break;
case "localSave":
keys.Add("your");
break;
default:
keys.Add(value);
break;
}
}
}
}

private async Task DownloadPortfolio() {
var options = new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
IgnoreReadOnlyProperties = true,
WriteIndented = true,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
await DownloadFileFromStream(familyData, options, "bogle-tools-data.json");
}

private async Task DownloadFileFromStream(object data, JsonSerializerOptions options, string fileName)
{
var jsonOut = System.Text.Json.JsonSerializer.Serialize(data, options);

using (MemoryStream ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(jsonOut)))
{
using var streamRef = new DotNetStreamReference(stream: ms);
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
}

private FamilyData familyData {
get {
return appData.FamilyData;
}
set {
appData.FamilyData = value;
}
}

protected override async Task OnInitializedAsync()
{
await Load();
appData.ProfileNames = keys;
}

}
4 changes: 2 additions & 2 deletions src.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

<ItemGroup>
<Compile Remove="api/**/*.cs" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.*" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.*" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.7" PrivateAssets="all" />
<PackageReference Include="DocumentFormat.OpenXml" Version="2.19.0" />
<ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
</ItemGroup>
Expand Down

0 comments on commit 499e17d

Please sign in to comment.