diff --git a/app/templates/app/includes/sidebar.html b/app/templates/app/includes/sidebar.html
index ff0bb3adb420af54f491adcdc994bd422f1991d6..69425f3e24b473e9953c78d53353d3d128c23dda 100644
--- a/app/templates/app/includes/sidebar.html
+++ b/app/templates/app/includes/sidebar.html
@@ -27,7 +27,7 @@
     </li>
 
     <li class="nav-item">
-        <a class="nav-link" href="#">
+        <a class="nav-link" href="{% url 'stats' %}">
             <span>Statisik Materi</span>
         </a>
     </li>
diff --git a/app/templates/statistik.html b/app/templates/statistik.html
new file mode 100644
index 0000000000000000000000000000000000000000..839895c7ddb791c8f492088381767aa6560d70de
--- /dev/null
+++ b/app/templates/statistik.html
@@ -0,0 +1,72 @@
+{% extends 'app/base_dashboard.html' %}
+{% load static %}
+
+{% block title %}
+<title>Unggah Materi dari Excel | Digipus</title>
+{% endblock %}
+
+{% block stylesheets %}
+<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"
+    integrity="sha512-d9xgZrVZpmmQlfonhQUvTR7lMPtO7NkZMkA0ABN3PHCbKA5nqylQ/yWlFAyY6hYgdF1Qh6nYiuADWwKB4C2WSw=="
+    crossorigin="anonymous"></script>
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.css"
+    integrity="sha512-/zs32ZEJh+/EO2N1b0PEdoA10JkdC3zJ8L5FTiQu82LR9S/rOQNfQN7U59U9BC12swNeRAz3HSzIL2vpp4fv3w=="
+    crossorigin="anonymous" />
+{% endblock %}
+
+{% block content %}
+
+
+<div class="container">
+
+    <h1 class="h3 mb-2 text-gray-800">Summary Materi per Kategori</h1>
+
+    <div class="card-body">
+        <div class="table-responsive">
+            <table class="table table-bordered">
+                <thead>
+                    <th>Kategori</th>
+                    <th>Jumlah Materi</th>
+                </thead>
+                <tbody>
+                    {% for s in stats %}
+                    <tr>
+                        <td>{{s.name}}</td>
+                        <td>{{s.num}}</td>
+                    </tr>
+                    {% endfor %}
+                </tbody>
+            </table>
+        </div>
+    </div>
+
+    <div class="col-lg-6 mx-auto">
+        <canvas id="myChart" width="400" height="400"></canvas>
+    </div>
+
+</div>
+
+<script type="text/javascript">
+
+    function displayChart(data) {
+        var ctx = document.getElementById('myChart').getContext('2d');
+
+        var myChart = new Chart(ctx, {
+            type: 'pie',
+            data: data
+        });
+    }
+
+
+    document.addEventListener("DOMContentLoaded", function(){
+        fetch('/stats?data=json')
+        .then(function(response) { 
+            return response.json()
+        })
+        .then(function(json) {
+            displayChart(json)
+       })
+    });
+
+</script>
+{% endblock %}
\ No newline at end of file
diff --git a/app/tests.py b/app/tests.py
index 9f10c73f27f528bd814fb834b1084391f60514d9..f69dc13a9ac0415d172b9a9e351395877fa5ae98 100644
--- a/app/tests.py
+++ b/app/tests.py
@@ -3,6 +3,7 @@ import pandas as pd
 from io import StringIO
 import re
 import time
+import random
 from django.test import override_settings
 
 from bs4 import BeautifulSoup
@@ -3443,3 +3444,53 @@ class MateriRecommendationTest(TestCase):
         list = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", response.content.decode())]
         self.assertEqual(list, [1, 2])
     
+class MateriStatsTest(TestCase):
+
+    def setUp(self):
+        self.credential = {
+            'email':"kontributor@gov.id", 
+            'password':"P@ssw0rd", 
+        }
+
+        self.path = '/stats/'
+        self.path_json = '/stats/?data=json'
+        self.header = 'Summary Materi per Kategori'
+
+        self.contributor = User.objects.create_contributor(**self.credential, name="kontributor")
+        self.client = Client()
+
+        categories = []
+        for i in range(10):
+            cat = Category(name=f'Cat{i}', description=f'Cat{i} description')
+            cat.save()
+            categories.append(cat)
+
+        for i in range(10):
+            for j in range(random.randint(1, 10)):
+                m = Materi(title=f'Title{i}-{j}')
+                m.save()
+                m.categories.add(categories[i])
+                m.save()
+
+
+    def test_stats_has_correct_template(self):
+        self.client.login(**self.credential)
+        response = self.client.get(self.path)
+        self.assertTemplateUsed(response, 'statistik.html')
+
+    def test_stats_as_authenticated(self):
+        self.client.login(**self.credential)
+        response = self.client.get(self.path)
+        self.assertContains(response, self.header)
+
+    def test_stats_as_anonymous(self):
+        response = self.client.get(self.path)
+        self.assertEqual(response.status_code, 302) #redirect
+        response = self.client.get(self.path_json)
+        self.assertEqual(response.status_code, 302) #redirect
+
+    def test_stats_api_correct_data(self):
+        self.client.login(**self.credential)
+        response = self.client.get(self.path_json)
+        jobj = json.loads(response.content)
+        self.assertEqual(len(jobj['labels']), 6)
diff --git a/app/urls.py b/app/urls.py
index a8c7281cbdd6821bf7eace5f939520e099f53ad5..3e0df237fcb184cf4884b2f39c0245bb54542825 100644
--- a/app/urls.py
+++ b/app/urls.py
@@ -2,7 +2,7 @@ from django.contrib.auth import views as auth_views
 from django.urls import path, re_path
 
 from app import views
-from app.views import (DashboardKontributorView, ProfilView,
+from app.views import (DashboardKontributorView, ProfilView, StatisticsView,
                        SuksesLoginAdminView, SuksesLoginKontributorView, DownloadHistoryView,
                        SuntingProfilView, UploadMateriHTML, UploadMateriView, UploadMateriExcelView, PostsView,
                        ReqMateriView, KatalogPerKontributorView, MateriFavorite, PasswordChangeViews, password_success, SubmitVisitorView)
@@ -41,4 +41,5 @@ urlpatterns = [
     path("password_success/", views.password_success, name="password_success"),
     path("given-rating/", views.see_given_rating, name="see_given_rating"),
     path("submit-visitor/", SubmitVisitorView.as_view(), name="submit-visitor"),
+    path("stats/", StatisticsView.as_view(), name="stats"),
 ]
diff --git a/app/views.py b/app/views.py
index a0062ed070c2065cc77c3e37757c749b70f470d1..d0dd5bb0206e04485f95cd88142d1b5d67827030 100644
--- a/app/views.py
+++ b/app/views.py
@@ -12,7 +12,7 @@ from django.contrib.auth.views import PasswordChangeView
 from django.core.exceptions import PermissionDenied, FieldError
 from django.core.mail import send_mail
 from django.core.paginator import Paginator
-from django.db.models import Q, Avg
+from django.db.models import Q, Avg, Count
 from django.http import (Http404, HttpResponse, HttpResponseRedirect,
                          JsonResponse)
 from django.shortcuts import get_object_or_404, redirect
@@ -780,3 +780,60 @@ class SubmitVisitorView(TemplateView):
             return JsonResponse({"success": False, "msg": "Missing parameter"})
         SubmitVisitor(msg=title, user_id=user_id, email=email).save()
         return JsonResponse({"success": True, "msg": "Buku tamu berhasil ditambahkan"})
+
+class StatisticsView(TemplateView):
+    template_name = "statistik.html"
+
+    def dispatch(self, request, *args, **kwargs):
+        if request.user.is_authenticated == False:
+            return HttpResponseRedirect("/login/")
+        return super(StatisticsView, self).dispatch(request, *args, **kwargs)
+
+    def get_stat_json(self):
+        query = Category.objects.annotate(num=Count('materi')).order_by('-num')
+
+        # Take maximum 10 Category
+        result = []
+        for e in query:
+            if len(result) >= 6:
+                break
+            else:
+                result.append(e)
+
+        chart_data = {
+                'labels': [e.name for e in result],
+                'datasets': [{
+                    'label': 'Jumlah Materi per Kategori',
+                    'data': [e.num for e in result],
+                    'backgroundColor': [
+                        'rgba(255, 99, 132, 0.2)',
+                        'rgba(54, 162, 235, 0.2)',
+                        'rgba(255, 206, 86, 0.2)',
+                        'rgba(75, 192, 192, 0.2)',
+                        'rgba(153, 102, 255, 0.2)',
+                        'rgba(255, 159, 64, 0.2)'
+                    ],
+                    'borderColor': [
+                        'rgba(255, 99, 132, 1)',
+                        'rgba(54, 162, 235, 1)',
+                        'rgba(255, 206, 86, 1)',
+                        'rgba(75, 192, 192, 1)',
+                        'rgba(153, 102, 255, 1)',
+                        'rgba(255, 159, 64, 1)'
+                    ],
+                    'borderWidth': 1
+                }]
+            }
+        return chart_data
+
+    def get(self, request, *args, **kwargs):
+        if request.GET.get('data') == 'json':
+            return JsonResponse(self.get_stat_json())
+
+        else:
+            context = self.get_context_data(**kwargs)
+
+            query = Category.objects.annotate(num=Count('materi'))
+            context['stats'] = query
+
+            return self.render_to_response(context)