Skip to content

Commit

Permalink
feat: visualize storybook learning events (#1852)
Browse files Browse the repository at this point in the history
  • Loading branch information
jo-elimu authored Aug 25, 2024
2 parents c2cfb77 + 176b6d6 commit bef3f0e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@

import ai.elimu.dao.StoryBookLearningEventDao;
import ai.elimu.model.analytics.StoryBookLearningEvent;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -26,6 +33,36 @@ public String handleRequest(Model model) {

List<StoryBookLearningEvent> storyBookLearningEvents = storyBookLearningEventDao.readAllOrderedByTime();
model.addAttribute("storyBookLearningEvents", storyBookLearningEvents);

// Prepare data for chart in UI
List<String> monthList = new ArrayList<>();
List<Integer> eventCountList = new ArrayList<>();
if (!storyBookLearningEvents.isEmpty()) {
// Group event count by month (e.g. "Aug-2024", "Sep-2024")
Map<String, Integer> eventCountByMonthMap = new HashMap<>();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MMM-yyyy");
for (StoryBookLearningEvent event : storyBookLearningEvents) {
String eventMonth = simpleDateFormat.format(event.getTimestamp().getTime());
eventCountByMonthMap.put(eventMonth, eventCountByMonthMap.getOrDefault(eventMonth, 0) + 1);
}

// Iterate each month from 4 years ago until now
Calendar calendar4YearsAgo = Calendar.getInstance();
calendar4YearsAgo.add(Calendar.YEAR, -4);
Calendar calendarNow = Calendar.getInstance();
Calendar month = calendar4YearsAgo;
while (!month.after(calendarNow)) {
String monthAsString = simpleDateFormat.format(month.getTime());
monthList.add(monthAsString);

eventCountList.add(eventCountByMonthMap.getOrDefault(monthAsString, 0));

// Increase the date by 1 month
month.add(Calendar.MONTH, 1);
}
}
model.addAttribute("monthList", monthList);
model.addAttribute("eventCountList", eventCountList);

return "analytics/storybook-learning-event/list";
}
Expand Down
124 changes: 21 additions & 103 deletions src/main/webapp/WEB-INF/jsp/analytics/layout.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -45,111 +45,29 @@
</div>

<nav class="deep-purple lighten-1">
<div class="nav-wrapper container">
<a id="logo-container" href="<spring:url value='/' />" class="brand-logo">
<img src="<spring:url value='/static/img/logo-text-256x77.png' />" alt="elimu.ai" />
</a>
<sec:authorize access="!hasAnyRole('ROLE_ADMIN','ROLE_CONTRIBUTOR')">
<ul class="right hide-on-med-and-down">
<li><a href="<spring:url value='/sign-on' />"><fmt:message key="sign.on" /></a></li>
</ul>
<div class="row nav-wrapper">
<div class="col s1">
<ul id="nav-mobile" class="side-nav">
<li><a href="<spring:url value='/sign-on' />"><fmt:message key="sign.on" /></a></li>
</ul>
</sec:authorize>
<sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_CONTRIBUTOR')">
<ul class="right">
<a href="<spring:url value='/content' />">
<div class="chip">
<c:choose>
<c:when test="${not empty contributor.imageUrl}">
<img src="${contributor.imageUrl}" />
</c:when>
<c:when test="${not empty contributor.providerIdWeb3}">
<img src="https://effigy.im/a/<c:out value="${contributor.providerIdWeb3}" />.png" />
</c:when>
<c:otherwise>
<img src="<spring:url value='/static/img/placeholder.png' />" />
</c:otherwise>
</c:choose>
<c:choose>
<c:when test="${not empty contributor.firstName}">
<c:out value="${contributor.firstName}" />&nbsp;<c:out value="${contributor.lastName}" />
</c:when>
<c:when test="${not empty contributor.providerIdWeb3}">
${fn:substring(contributor.providerIdWeb3, 0, 6)}...${fn:substring(contributor.providerIdWeb3, 38, 42)}
</c:when>
</c:choose>
</div>
</a>
</ul>
</sec:authorize>

<ul class="right">
<script>
/**
* Fetch token balance
*/
async function getBalance(contributorAddress) {
console.info('getBalance');
// Connect to the web3 provider.
const provider = await connect()
window.web3 = new Web3(provider);
console.info('window.web3: ' + window.web3);
var contractAbi = [{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}];
var contractAddress = '0xe29797910d413281d2821d5d9a989262c8121cc2';
var contract = new window.web3.eth.Contract(contractAbi, contractAddress);
var balance = await contract.methods.balanceOf(contributorAddress).call();
return balance;
}
</script>
<c:choose>
<c:when test="${empty contributor.providerIdWeb3}">
<a class="btn tokenButton" href="<spring:url value='/sign-on/web3' />">
<svg style="width: 24px; height: 24px; top: 6px; position: relative; right: 5px;" viewBox="0 0 784.37 1277.39" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
<g>
<polygon fill="#343434" fill-rule="nonzero" points="392.07,0 383.5,29.11 383.5,873.74 392.07,882.29 784.13,650.54 "/>
<polygon fill="#8C8C8C" fill-rule="nonzero" points="392.07,0 -0,650.54 392.07,882.29 392.07,472.33 "/>
<polygon fill="#3C3C3B" fill-rule="nonzero" points="392.07,956.52 387.24,962.41 387.24,1263.28 392.07,1277.38 784.37,724.89 "/>
<polygon fill="#8C8C8C" fill-rule="nonzero" points="392.07,1277.38 392.07,956.52 -0,724.89 "/>
<polygon fill="#141414" fill-rule="nonzero" points="392.07,882.29 784.13,650.54 392.07,472.33 "/>
<polygon fill="#393939" fill-rule="nonzero" points="0,650.54 392.07,882.29 392.07,472.33 "/>
</g>
</svg>&nbsp;Connect wallet
</a>
</c:when>
<c:otherwise>
<c:set var="etherscanUrl" value="https://etherscan.io" />
<c:if test="${applicationScope.configProperties['env'] != 'PROD'}">
<c:set var="etherscanUrl" value="https://rinkeby.etherscan.io" />
</c:if>
<a class="btn tokenButton" href="${etherscanUrl}/token/0xe29797910d413281d2821d5d9a989262c8121cc2?a=${contributor.providerIdWeb3}" target="_blank">
<code><span id="tokenBalance">0</span> $ELIMU</code>
<li>
<a href="<spring:url value='/analytics' />">
<img style="max-width: 100%; vertical-align: middle; max-height: 60%;" src="<spring:url value='/static/img/logo-text-256x78.png' />" alt="elimu.ai" />
</a>
<script>
$(function() {
var contributorAddress = '${contributor.providerIdWeb3}';
getBalance(contributorAddress).then(function(result) {
console.info('result: ' + result);
var tokenBalance = result / 1000000000000000000;
console.info('tokenBalance: ' + tokenBalance);
var tokenBalanceFormatted = Intl.NumberFormat().format(Math.round(tokenBalance));
console.info('tokenBalanceFormatted ' + tokenBalanceFormatted);
$('#tokenBalance').html(tokenBalanceFormatted);
});
});
</script>
</c:otherwise>
</c:choose>
</ul>

<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
</li>

<li class="divider"></li>
<li class="grey-text"><b><fmt:message key="learning.events" /></b></li>
<li><a href="<spring:url value='/analytics/letter-learning-event/list' />"><i class="material-icons left">text_format</i><fmt:message key="letters" /></a></li>
<li><a href="<spring:url value='/analytics/word-learning-event/list' />"><i class="material-icons left">sms</i><fmt:message key="words" /></a></li>
<li><a href="<spring:url value='/analytics/storybook-learning-event/list' />"><i class="material-icons left">book</i><fmt:message key="storybooks" /></a></li>
</ul>
<a id="navButton" href="<spring:url value='/analytics' />" data-activates="nav-mobile" class="waves-effect waves-light"><i class="material-icons">dehaze</i></a>
</div>
<div class="col s11">
<a href="<spring:url value='/analytics' />" class="breadcrumb"><fmt:message key="analytics" /></a>
<c:if test="${!fn:contains(pageContext.request.requestURI, '/jsp/analytics/main.jsp')}">
<a class="breadcrumb"><content:gettitle /></a>
</c:if>
</div>
</div>
</nav>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,15 @@
<canvas id="myChart" width="400" height="100"></canvas>
<script>
const labels = [
'January',
'February',
'March',
'April',
'May',
'June',
<c:forEach var="month" items="${monthList}">'${month}',</c:forEach>
];
const data = {
labels: labels,
datasets: [{
label: 'My First dataset',
label: 'Learning events',
backgroundColor: 'rgba(149,117,205, 0.5)',
borderColor: 'rgba(149,117,205, 0.5)',
data: [0, 10, 5, 2, 20, 30, 45],
data: <c:out value="${eventCountList}" />
}]
};
const config = {
Expand Down

0 comments on commit bef3f0e

Please sign in to comment.