Skip to content

Commit

Permalink
Blogifier Analytics #245
Browse files Browse the repository at this point in the history
  • Loading branch information
rxtur committed Apr 16, 2021
1 parent 0210156 commit 02da56c
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 39 deletions.
119 changes: 83 additions & 36 deletions src/Blogifier.Admin/Components/Dashboard/AnalyticsComponent.razor
Expand Up @@ -13,42 +13,47 @@
<div class="dash-pan-title me-auto">@_localizer["Analytics"]</div>
<div class="dropdown dropdown-flush">
<a class="text-muted" type="button" id="dropdownAnalytics" data-bs-toggle="dropdown" aria-expanded="false" href="#">
<span>@(_hideList ? "Chart" : "List")</span> - <span>7 @_localizer["days"]</span>
<span>@(_hideList ? "Chart" : "List")</span> - <span>@PeriodLabel()</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" />
</svg>
</a>

<div class="dropdown-menu dropdown-menu-end p-3" aria-labelledby="dropdownAnalytics">
<div class="mb-1 text-muted">Date:</div>
<ul class="mb-3 list-unstyled">
<li><button type="button" class="py-1 px-2 rounded dropdown-item">@_localizer["Today"]</button></li>
<li><button type="button" class="py-1 px-2 rounded dropdown-item">@_localizer["Yesterday"]</button></li>
<li><button type="button" class="py-1 px-2 rounded dropdown-item active">7 @_localizer["days"]</button></li>
<li><button type="button" class="py-1 px-2 rounded dropdown-item">30 @_localizer["days"]</button></li>
<li><button type="button" class="py-1 px-2 rounded dropdown-item">90 @_localizer["days"]</button></li>
@if (_dateOptions != null && _model != null)
{
foreach (var option in _dateOptions)
{
var cls = _model.DisplayPeriod == (AnalyticsPeriod)option.Id ? "py-1 px-2 rounded dropdown-item active" : "py-1 px-2 rounded dropdown-item";
<li><button type="button" class="@cls" @onclick="() => DateOptionSelect(option.Id)">@option.Title</button></li>
}
}
</ul>
<div class="mb-1 text-muted">View:</div>
<div class="btn-group w-100" role="group" aria-label="Basic radio toggle button group">
@if(_hideList)
@if (_hideList)
{
<input type="radio" class="btn-check" name="btnradio" id="btnradio1" autocomplete="off" checked @onchange="() => ToggleAnalyticsView(true)">
<input type="radio" class="btn-check" name="btnradio" id="btnradio1" autocomplete="off" checked @onchange="() => ToggleAnalyticsView(true)">
}
else
{
<input type="radio" class="btn-check" name="btnradio" id="btnradio1" autocomplete="off" @onchange="() => ToggleAnalyticsView(true)">
<input type="radio" class="btn-check" name="btnradio" id="btnradio1" autocomplete="off" @onchange="() => ToggleAnalyticsView(true)">
}
<label class="btn btn-sm btn-outline-blogifier w-50" for="btnradio1">@_localizer["Chart"]</label>
@if(_hideGraph)
@if (_hideGraph)
{
<input type="radio" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off" checked @onchange="() => ToggleAnalyticsView(false)">
<input type="radio" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off" checked @onchange="() => ToggleAnalyticsView(false)">
}
else
{
<input type="radio" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off" @onchange="() => ToggleAnalyticsView(false)">
<input type="radio" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off" @onchange="() => ToggleAnalyticsView(false)">
}
<label class="btn btn-sm btn-outline-blogifier w-50" for="btnradio2">@_localizer["List"]</label>
</div>
</div>

</div>
</div>

Expand All @@ -68,12 +73,12 @@
{
foreach (var visit in _visits)
{
<li class="dash-list-item">
<span class="dash-list-title">@visit.Name</span>
<span class="dash-list-text pe-2">@visit.Value</span>
</li>
<li class="dash-list-item">
<span class="dash-list-title">@visit.Name</span>
<span class="dash-list-text pe-2">@visit.Value</span>
</li>
}
}
}
</ul>

<!--
Expand All @@ -93,52 +98,78 @@

protected bool _hideGraph = false;
protected bool _hideList = true;
// string _checkedGraph = "checked";
// string _checkedList = "";

protected List<OptionItem> _dateOptions;
protected AnalyticsModel _model;

protected override async Task OnInitializedAsync()
{
_config = new BarConfig
{
Options = new BarOptions
{
Responsive = true,
Legend = new Legend
{
Position = Position.Top
}
}
};
_config = GetConfig();

_dateOptions = new List<OptionItem>();
_dateOptions.Add(new OptionItem { Id = 1, Title = "Today" });
_dateOptions.Add(new OptionItem { Id = 2, Title = "Yesterday" });
_dateOptions.Add(new OptionItem { Id = 3, Title = "7 days" });
_dateOptions.Add(new OptionItem { Id = 4, Title = "30 days" });
_dateOptions.Add(new OptionItem { Id = 5, Title = "90 days" });

await Load();
}

protected async Task Load()
{
IDataset<int> dataset = new BarDataset<int>()
{
Label = "Latest Post Views",
BackgroundColor = ColorUtil.FromDrawingColor(Color.FromArgb(98, 42, 255)),
BorderWidth = 0
};

var model = await _http.GetFromJsonAsync<AnalyticsModel>("api/analytics");
_model = await _http.GetFromJsonAsync<AnalyticsModel>("api/analytics");

if (model == null || model.LatestPostViews == null)
if (_model == null || _model.LatestPostViews == null)
{
LoadData(dataset, TestData());
}
else
{
_hideList = model.DisplayType == AnalyticsListType.Graph;
_hideGraph = model.DisplayType == AnalyticsListType.List;
_hideList = _model.DisplayType == AnalyticsListType.Graph;
_hideGraph = _model.DisplayType == AnalyticsListType.List;

LoadData(dataset, model.LatestPostViews);
LoadData(dataset, _model.LatestPostViews);
}

if (_config.Data.Datasets.Count > 0)
{
_config.Data.Datasets.Clear();
}

_config.Data.Datasets.Add(dataset);
}

protected BarConfig GetConfig()
{
return new BarConfig
{
Options = new BarOptions
{
Responsive = true,
Legend = new Legend
{
Position = Position.Top
}
}
};
}

protected void LoadData(IDataset<int> dataset, BarChartModel model)
{
_visits = new List<PostVisit>();
var labels = model.Labels.ToList();
var values = model.Data.ToList();

_config.Data.Labels.Clear();

for (int i = 0; i < labels.Count; i++)
{
_config.Data.Labels.Add(labels[i]);
Expand All @@ -159,6 +190,15 @@
Toaster.Toast(await _http.PutAsJsonAsync<int>($"api/analytics/displayType/{typeId}", typeId));
}

protected async Task DateOptionSelect(int id)
{
Blog blog = await _http.GetFromJsonAsync<Blog>("api/blog");
blog.AnalyticsPeriod = id;
_model.DisplayPeriod = (AnalyticsPeriod)id;
Toaster.Toast(await _http.PutAsJsonAsync<Blog>("api/blog", blog));
await Load();
}

protected BarChartModel TestData()
{
return new BarChartModel()
Expand All @@ -167,4 +207,11 @@
Data = new List<int>() { 12036, 15350, 9457, 11104, 7938, 8136 }
};
}

protected string PeriodLabel()
{
if (_model == null)
return "";
return _model.DisplayPeriod.ToString();
}
}
2 changes: 1 addition & 1 deletion src/Blogifier.Core/Blogifier.Core.csproj
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Version>2.9.1.3</Version>
<Version>2.9.1.4</Version>
<Authors>blogifierdotnet</Authors>
<Description>Blogifier is an open-source publishing platform Written in .NET 5.0 and Blazor WebAssembly.</Description>
<Copyright>Blogifier.Net</Copyright>
Expand Down
26 changes: 24 additions & 2 deletions src/Blogifier.Core/Providers/AnalyticsProvider.cs
Expand Up @@ -49,14 +49,17 @@ public async Task<bool> SaveDisplayType(int type)

public async Task<bool> SaveDisplayPeriod(int period)
{
var blog = await _db.Blogs.FirstOrDefaultAsync();
var blog = await _db.Blogs.OrderBy(b => b.Id).FirstAsync();
blog.AnalyticsPeriod = period;
return await _db.SaveChangesAsync() > 0;
}

private BarChartModel GetLatestPostViews()
{
var posts = _db.Posts.AsNoTracking().Where(p => p.Published > DateTime.MinValue).OrderByDescending(p => p.Published).Take(7);
var blog = _db.Blogs.OrderBy(b => b.Id).First();
var period = blog.AnalyticsPeriod == 0 ? 3 : blog.AnalyticsPeriod;

var posts = _db.Posts.AsNoTracking().Where(p => p.Published > DateTime.MinValue).OrderByDescending(p => p.Published).Take(GetDays(period));
if (posts == null || posts.Count() < 3)
return null;

Expand All @@ -68,5 +71,24 @@ private BarChartModel GetLatestPostViews()
Data = posts.Select(p => p.PostViews).ToList()
};
}

private int GetDays(int id)
{
switch ((AnalyticsPeriod)id)
{
case AnalyticsPeriod.Today:
return 1;
case AnalyticsPeriod.Yesterday:
return 2;
case AnalyticsPeriod.Days7:
return 7;
case AnalyticsPeriod.Days30:
return 30;
case AnalyticsPeriod.Days90:
return 90;
default:
throw new ApplicationException("Unknown analytics period");
}
}
}
}
2 changes: 2 additions & 0 deletions src/Blogifier.Core/Providers/BlogProvider.cs
Expand Up @@ -69,6 +69,8 @@ public async Task<bool> Update(Blog blog)
existing.Logo = blog.Logo;
existing.HeaderScript = blog.HeaderScript;
existing.FooterScript = blog.FooterScript;
existing.AnalyticsListType = blog.AnalyticsListType;
existing.AnalyticsPeriod = blog.AnalyticsPeriod;

return await _db.SaveChangesAsync() > 0;
}
Expand Down
8 changes: 8 additions & 0 deletions src/Blogifier.Shared/Models/OptionItem.cs
@@ -0,0 +1,8 @@
namespace Blogifier.Shared
{
public class OptionItem
{
public int Id { get; set; }
public string Title { get; set; }
}
}

0 comments on commit 02da56c

Please sign in to comment.