Skip to content

Commit

Permalink
feat(stats): afficher les stats quotidiennes des Diagnostics Parcours…
Browse files Browse the repository at this point in the history
… IAE (#660)

## Description

🎸 Afficher dans la page `statistiques`, le nombre de `dsp` généré depuis
le lancement de l'expé
🎸 Afficher à partir de la page `statistiques`, le graphe de nombre de
`dsp` quotidiens sur les 3 derniers mois

## Type de changement

🎢 Nouvelle fonctionnalité (changement non cassant qui ajoute une
fonctionnalité).

### Points d'attention

🦺 mutualisation de la génération des vues de détails et de leur
templates avec `MonthlyVisitorsView`

### Captures d'écran (optionnel)

vue de la page `statistique`


![image](https://github.com/gip-inclusion/itou-communaute-django/assets/11419273/012d0c94-dce4-478c-9b72-a9a3d19f5b7a)

vue de la page de détail


![image](https://github.com/gip-inclusion/itou-communaute-django/assets/11419273/0bc25d9e-9281-49aa-b898-505cbaa1e935)

---------

Co-authored-by: hellodeloo <[email protected]>
  • Loading branch information
vincentporte and hellodeloo authored Jun 10, 2024
1 parent bb341cb commit 5c74c56
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 61 deletions.
40 changes: 40 additions & 0 deletions lacommunaute/forum_stats/tests/__snapshots__/tests_views.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# serializer version: 1
# name: TestDailyDSPView.test_navigation[breadcrumb]
'''
<nav aria-label="Fil d'ariane" class="c-breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">Retourner vers</li>
<li class="breadcrumb-item">
<a href="/statistiques/">Statistiques</a>
</li>
</ol>
</nav>
'''
# ---
# name: TestMonthlyVisitorsView.test_navigation[breadcrumb]
'''
<nav aria-label="Fil d'ariane" class="c-breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">Retourner vers</li>
<li class="breadcrumb-item">
<a href="/statistiques/">Statistiques</a>
</li>
</ol>
</nav>
'''
# ---
# name: TestStatistiquesPageView.test_dsp_count[dsp]
'''
<div class="s-section__row row" id="daily_dsp">
<div class="s-section__col col-12">
<div class="c-box mb-3 mb-md-5">
<h2>10 Diagnostiques Parcours IAE</h2>
<p>
Réalisés sur la communauté de l'inclusion depuis le 24 février 2024
<span class="fs-sm">(<a href="/statistiques/dsp/">Voir les détails</a>)</span>
</p>
</div>
</div>
</div>
'''
# ---
57 changes: 50 additions & 7 deletions lacommunaute/forum_stats/tests/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

from lacommunaute.forum_stats.enums import Period
from lacommunaute.forum_stats.factories import StatFactory
from lacommunaute.surveys.factories import DSPFactory
from lacommunaute.utils.math import percent
from lacommunaute.utils.testing import parse_response_to_soup


faker = Faker()
Expand Down Expand Up @@ -119,6 +121,15 @@ def test_navigation(self):
self.assertContains(response, f"<a href={reverse('forum_stats:monthly_visitors')}>")


class TestStatistiquesPageView:
def test_dsp_count(self, client, db, snapshot):
DSPFactory.create_batch(10)
url = reverse("forum_stats:statistiques")
response = client.get(url)
assert response.status_code == 200
assert str(parse_response_to_soup(response, selector="#daily_dsp")) == snapshot(name="dsp")


class TestMonthlyVisitorsView:
def test_context_data(self, client, db):
url = reverse("forum_stats:monthly_visitors")
Expand All @@ -135,33 +146,65 @@ def test_context_data(self, client, db):
response = client.get(url)
assert response.status_code == 200
assertContains(response, "Utilisateurs uniques mensuels")
assert response.context["monthly_visitors"] == empty_res
assert response.context["box_title"] == "Utilisateurs uniques mensuels"
assert response.context["stats"] == empty_res

# undesired data
StatFactory(name="nb_uniq_visitors_returning", period=Period.DAY, date=today)
StatFactory(name=faker.word(), period=Period.MONTH, date=today)
StatFactory(name="nb_uniq_visitors", period=Period.MONTH, date=today - relativedelta(months=9), value=1)
response = client.get(url)
assert response.status_code == 200
assert response.context["monthly_visitors"] == empty_res
assert response.context["stats"] == empty_res

# expected data
StatFactory(name="nb_uniq_visitors_returning", period=Period.MONTH, date=today, value=2)
StatFactory(name="nb_uniq_visitors", period=Period.MONTH, date=today - relativedelta(months=8), value=10)
response = client.get(url)
assert response.status_code == 200
assert response.context["monthly_visitors"] == {
assert response.context["stats"] == {
"date": [(today - relativedelta(months=8)).strftime("%Y-%m-%d"), today.strftime("%Y-%m-%d")],
"nb_uniq_visitors": [10],
"nb_uniq_active_visitors": [],
"nb_uniq_engaged_visitors": [],
"nb_uniq_visitors_returning": [2],
}

def test_navigation(self, client, db):
url = reverse("forum_stats:monthly_visitors")
def test_navigation(self, client, db, snapshot):
url = reverse("forum_stats:dsp")
response = client.get(url)
assert response.status_code == 200
assertContains(
response, f"<a href=\"{reverse('forum_stats:statistiques')}\">retour vers la page statistiques</a>"
assert str(parse_response_to_soup(response, selector=".c-breadcrumb")) == snapshot(name="breadcrumb")


class TestDailyDSPView:
def test_context_data(self, client, db):
today = localdate()

# undesired datas
StatFactory(name="dsp", period=Period.DAY, date=today - relativedelta(months=3), value=20)
StatFactory(name=faker.word(), period=Period.DAY, date=today, value=21)

# expected datas
StatFactory(
name="dsp", period=Period.DAY, date=today - relativedelta(months=3) + relativedelta(days=1), value=3
)
StatFactory(name="dsp", period=Period.DAY, date=today, value=2)

url = reverse("forum_stats:dsp")
response = client.get(url)
assert response.status_code == 200
assert response.context["box_title"] == "Diagnostics Parcours IAE quotidiens"
assert response.context["stats"] == {
"date": [
(today - relativedelta(months=3) + relativedelta(days=1)).strftime("%Y-%m-%d"),
today.strftime("%Y-%m-%d"),
],
"dsp": [3, 2],
}

def test_navigation(self, client, db, snapshot):
url = reverse("forum_stats:dsp")
response = client.get(url)
assert response.status_code == 200
assert str(parse_response_to_soup(response, selector=".c-breadcrumb")) == snapshot(name="breadcrumb")
3 changes: 2 additions & 1 deletion lacommunaute/forum_stats/urls.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from django.urls import path

from lacommunaute.forum_stats.views import MonthlyVisitorsView, StatistiquesPageView
from lacommunaute.forum_stats.views import DailyDSPView, MonthlyVisitorsView, StatistiquesPageView


app_name = "forum_stats"

urlpatterns = [
path("", StatistiquesPageView.as_view(), name="statistiques"),
path("monthly-visitors/", MonthlyVisitorsView.as_view(), name="monthly_visitors"),
path("dsp/", DailyDSPView.as_view(), name="dsp"),
]
47 changes: 34 additions & 13 deletions lacommunaute/forum_stats/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.views.generic.base import TemplateView

from lacommunaute.forum_stats.models import Stat
from lacommunaute.surveys.models import DSP
from lacommunaute.utils.json import extract_values_in_list
from lacommunaute.utils.math import percent

Expand Down Expand Up @@ -66,35 +67,55 @@ def get_monthly_visitors(self):
)
return extract_values_in_list(datas, indicator_names)

def get_dsp_count(self):
return DSP.objects.count()

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["stats"] = self.get_daily_stats()
context["impact"] = self.get_monthly_visitors()
context["dsp_count"] = self.get_dsp_count()
context = {**context, **self.get_funnel_data()}

return context


class MonthlyVisitorsView(TemplateView):
template_name = "forum_stats/monthly_visitors.html"

def get_monthly_visitors(self):
indicator_names = [
"nb_uniq_visitors",
"nb_uniq_active_visitors",
"nb_uniq_engaged_visitors",
"nb_uniq_visitors_returning",
]
class BaseDetailStatsView(TemplateView):
def get_detailled_stats(self):
datas = (
Stat.objects.filter(
period="month", name__in=indicator_names, date__gt=localdate() - relativedelta(months=9)
period=self.period,
name__in=self.indicator_names,
date__gt=localdate() - relativedelta(months=self.months),
)
.values("name", "value")
.annotate(date=Cast("date", CharField()))
)
return extract_values_in_list(datas, indicator_names)
return extract_values_in_list(datas, self.indicator_names)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["monthly_visitors"] = self.get_monthly_visitors()
context["stats"] = self.get_detailled_stats()
context["box_title"] = self.box_title
return context


class MonthlyVisitorsView(BaseDetailStatsView):
template_name = "forum_stats/monthly_visitors.html"
box_title = "Utilisateurs uniques mensuels"
indicator_names = [
"nb_uniq_visitors",
"nb_uniq_active_visitors",
"nb_uniq_engaged_visitors",
"nb_uniq_visitors_returning",
]
period = "month"
months = 9


class DailyDSPView(BaseDetailStatsView):
template_name = "forum_stats/daily_dsp.html"
box_title = "Diagnostics Parcours IAE quotidiens"
indicator_names = ["dsp"]
period = "day"
months = 3
44 changes: 44 additions & 0 deletions lacommunaute/templates/forum_stats/base_detail_stats.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% extends "layouts/base.html" %}
{% load str_filters %}
{% load static %}
{% load i18n %}
{% block title %}Statistiques{{ block.super }}{% endblock %}
{% block body_class %}p-statistiques{{ block.super }}{% endblock %}
{% block breadcrumb %}
<div class="container">
<nav class="c-breadcrumb" aria-label="Fil d'ariane">
<ol class="breadcrumb">
<li class="breadcrumb-item">{% trans "Back to" %}</li>
<li class="breadcrumb-item">
<a href="{% url 'forum_stats:statistiques' %}">Statistiques</a>
</li>
</ol>
</nav>
</div>
{% endblock %}
{% block content %}
<section class="s-title-01 mt-lg-5">
<div class="s-title-01__container container">
<div class="s-title-01__row row">
<div class="s-title-01__col col-12">
<h1 class="s-title-01__title h1">
<strong>Statistiques</strong>
</h1>
</div>
</div>
</div>
</section>
<section class="s-section">
<div class="s-section__container container">
<div class="s-section__row row">
<div class="s-section__col col-12">
<div class="c-box mb-3 mb-md-5">
<h2>{{ box_title }}</h2>
<canvas id="statChart"></canvas>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
{% block extra_js %}{{ block.super }}{% endblock %}
29 changes: 29 additions & 0 deletions lacommunaute/templates/forum_stats/daily_dsp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{% extends "./base_detail_stats.html" %}
{% load js_filters %}
{% block extra_js %}
{{ block.super }}
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script nonce="{{ request.csp_nonce }}">
const ctx_stats = document.getElementById('statChart');
new Chart(ctx_stats, {
type: 'line',
data: {
labels: {{ stats.date | js }},
datasets: [
{
label: 'Diagnostics Parcours IAE',
data: {{ stats.dsp | js }},
borderColor: 'rgba(54, 162, 235)',
backgroundColor: 'rgba(154, 208, 245)',
},

]
},
options: {
responsive:true,
cubicInterpolationMode: 'monotone',
tension: 0.4,
}
});
</script>
{% endblock %}
46 changes: 6 additions & 40 deletions lacommunaute/templates/forum_stats/monthly_visitors.html
Original file line number Diff line number Diff line change
@@ -1,39 +1,5 @@
{% extends "layouts/base.html" %}
{% load str_filters %}
{% extends "./base_detail_stats.html" %}
{% load js_filters %}
{% load static %}
{% block title %}Statistiques{{ block.super }}{% endblock %}
{% block body_class %}p-statistiques{{ block.super }}{% endblock %}
{% block content %}
<section class="s-title-01 mt-lg-5">
<div class="s-title-01__container container">
<div class="s-title-01__row row">
<div class="s-title-01__col col-12">
<h1 class="s-title-01__title h1">
<strong>Statistiques</strong>
</h1>
</div>
</div>
</div>
</section>
<section class="s-section">
<div class="s-section__container container">
<div class="s-section__row row">
<div class="s-section__col col-12">
<div class="c-box mb-3 mb-md-5">
<h2>Utilisateurs uniques mensuels</h2>
<canvas id="statChart"></canvas>
<p class="mt-1">
<small>
<a href="{% url 'forum_stats:statistiques' %}">retour vers la page statistiques</a>
</small>
</p>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
{% block extra_js %}
{{ block.super }}
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
Expand All @@ -42,29 +8,29 @@ <h2>Utilisateurs uniques mensuels</h2>
new Chart(ctx_stats, {
type: 'line',
data: {
labels: {{ monthly_visitors.date | js }},
labels: {{ stats.date | js }},
datasets: [
{
label: 'Utilisateurs',
data: {{ monthly_visitors.nb_uniq_visitors | js }},
data: {{ stats.nb_uniq_visitors | js }},
borderColor: 'rgba(54, 162, 235)',
backgroundColor: 'rgba(154, 208, 245)',
},
{
label: 'Utilisateurs actifs',
data: {{ monthly_visitors.nb_uniq_active_visitors | js }},
data: {{ stats.nb_uniq_active_visitors | js }},
borderColor: 'rgba(76, 120, 83)',
backgroundColor: 'rgba(112, 178, 123)',
},
{
label: 'Utilisateurs engagés',
data: {{ monthly_visitors.nb_uniq_engaged_visitors | js }},
data: {{ stats.nb_uniq_engaged_visitors | js }},
borderColor: 'rgba(255, 159, 64)',
backgroundColor: 'rgba(255, 207, 159)',
},
{
label: 'Utilisateurs retour',
data: {{ monthly_visitors.nb_uniq_visitors_returning | js }},
data: {{ stats.nb_uniq_visitors_returning | js }},
borderColor: 'rgba(98, 42, 86)',
backgroundColor: 'rgba(155, 67, 136)',
},
Expand Down
11 changes: 11 additions & 0 deletions lacommunaute/templates/forum_stats/statistiques.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ <h2>Vue quotidienne</h2>
</div>
</div>
</div>
<div class="s-section__row row" id="daily_dsp">
<div class="s-section__col col-12">
<div class="c-box mb-3 mb-md-5">
<h2>{{ dsp_count }} Diagnostique{{ dsp_count|pluralizefr }} Parcours IAE</h2>
<p>
Réalisé{{ dsp_count|pluralizefr }} sur la communauté de l'inclusion depuis le 24 février 2024
<span class="fs-sm">(<a href={% url 'forum_stats:dsp' %}>Voir les détails</a>)</span>
</p>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
Expand Down

0 comments on commit 5c74c56

Please sign in to comment.