diff --git a/dash/__init__.py b/dash/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/dash/admin.py b/dash/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/dash/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/dash/apps.py b/dash/apps.py
new file mode 100644
index 0000000..51fd062
--- /dev/null
+++ b/dash/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class DashConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'dash'
diff --git a/dash/migrations/__init__.py b/dash/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/dash/models.py b/dash/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/dash/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/dash/templates/dash/common/base.html b/dash/templates/dash/common/base.html
new file mode 100644
index 0000000..4e13853
--- /dev/null
+++ b/dash/templates/dash/common/base.html
@@ -0,0 +1,22 @@
+
+{% load static %}
+
+
+
+
+ {{ title }}| Hostea Dashbaord
+ {% include "common/components/meta.html" %}
+
+
+
+ {% include "dash/common/components/primary-nav.html" %}
+
+
+ {% include "dash/common/components/secondary-nav.html" %}
+
+ {% block dash %} {% endblock %}
+ {% include "common/components/footer.html" %}
+
+
+
+
diff --git a/dash/templates/dash/common/components/primary-nav.html b/dash/templates/dash/common/components/primary-nav.html
new file mode 100644
index 0000000..c43a801
--- /dev/null
+++ b/dash/templates/dash/common/components/primary-nav.html
@@ -0,0 +1,36 @@
+{% load static %}
+
diff --git a/dash/templates/dash/common/components/secondary-nav.html b/dash/templates/dash/common/components/secondary-nav.html
new file mode 100644
index 0000000..274868a
--- /dev/null
+++ b/dash/templates/dash/common/components/secondary-nav.html
@@ -0,0 +1,15 @@
+
diff --git a/dash/templates/dash/home/index.html b/dash/templates/dash/home/index.html
new file mode 100644
index 0000000..ce6446f
--- /dev/null
+++ b/dash/templates/dash/home/index.html
@@ -0,0 +1,6 @@
+{% extends 'dash/common/base.html' %}
+{% block dash %}
+{% include "common/components/error.html" %}
+{{ title }}
+ {% include "common/components/error.html" %}
+{% endblock %}
diff --git a/dash/tests.py b/dash/tests.py
new file mode 100644
index 0000000..ab7e5ef
--- /dev/null
+++ b/dash/tests.py
@@ -0,0 +1,71 @@
+# Copyright © 2022 Aravinth Manivannan
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+from django.contrib.auth import get_user_model
+from django.utils.http import urlencode
+from django.urls import reverse
+from django.test import TestCase, Client, override_settings
+from django.contrib.auth import authenticate
+from django.conf import settings
+
+class DashHome(TestCase):
+ """
+ Tests create new app view
+ """
+
+ def setUp(self):
+ self.password = "password121231"
+ self.username = "dashboard_home_user"
+ self.email = f"{self.username}@example.org"
+ self.user = get_user_model().objects.create(
+ username=self.username,
+ email=self.email,
+ )
+ self.user.set_password(self.password)
+ self.user.save()
+
+ def test_dash_is_protected(self):
+ """
+ Tests if dashboard template renders
+ """
+ resp = self.client.get(reverse("dash.home"))
+ self.assertEqual(resp.status_code, 302)
+
+ # default LOGIN redirect URI that is used by @login_required decorator is
+ # /accounts/login. There's a redirection endpoint at /accounts/login/ that
+ # will redirect user to /login. Hence the /accounts prefix
+ redirect_login_uri = f"/accounts{reverse('accounts.login')}?next={reverse('dash.home')}"
+ self.assertEqual(resp.headers["location"], redirect_login_uri)
+
+ def test_dash_home_renders(self):
+ """
+ Tests if login template renders
+ """
+ c = Client()
+
+ # username login works
+ payload = {
+ "login": self.username,
+ "password": self.password,
+ }
+ resp = c.post(reverse("accounts.login"), payload)
+ self.assertEqual(resp.status_code, 302)
+ self.assertEqual(resp.headers["location"], reverse("accounts.home"))
+
+ # email login works
+ resp = c.get(reverse('dash.home'))
+ self.assertEqual(resp.status_code, 200)
+ self.assertEqual(b"Billing" in resp.content, True)
+ self.assertEqual(b"Support" in resp.content, True)
+ self.assertEqual(b"Logout" in resp.content, True)
diff --git a/dash/urls.py b/dash/urls.py
new file mode 100644
index 0000000..80bcfa8
--- /dev/null
+++ b/dash/urls.py
@@ -0,0 +1,24 @@
+# Copyright © 2022 Aravinth Manivannan
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+from django.contrib import admin
+from django.urls import path, include
+
+from .views import (
+ home
+)
+
+urlpatterns = [
+ path("", home, name="dash.home"),
+]
diff --git a/dash/views.py b/dash/views.py
new file mode 100644
index 0000000..9f7c17c
--- /dev/null
+++ b/dash/views.py
@@ -0,0 +1,36 @@
+# Copyright © 2022 Aravinth Manivannan
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+from django.shortcuts import render, redirect, get_object_or_404
+from django.utils.http import urlencode
+from django.contrib.auth import authenticate, login, logout
+from django.contrib.auth import get_user_model
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponse
+from django.views.decorators.csrf import csrf_protect
+from django.urls import reverse
+
+def default_ctx(title: str):
+ return {
+ "title": title,
+ }
+
+
+
+@login_required
+def home(request):
+ PAGE_TITLE = "Home"
+ ctx = default_ctx(title=PAGE_TITLE)
+
+ return render(request, "dash/home/index.html", context=ctx)
diff --git a/static/css/main.css b/static/css/main.css
index d5914c4..755d654 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -34,9 +34,11 @@ h2 {
body {
width: 100%;
min-height: 100vh;
+ /*
display: flex;
flex-direction: column;
justify-content: space-between;
+ */
}
a:hover {
@@ -99,6 +101,7 @@ header {
width: 100%;
padding-top: 5px;
border-bottom: 1px solid rgb(211, 211, 211);
+ height: 63px;
}
.nav__home-btn {
@@ -469,3 +472,56 @@ footer {
}
/* footer ends */
+
+/* dashbaord starts */
+
+.panel__container {
+/* background-color: green; */
+}
+
+/* secondary nav starts */
+.secondary-nav__container {
+ box-sizing: border-box;
+ overflow-x: auto;
+ flex: 1;
+ position: fixed;
+ top: 63px;
+ bottom: 0;
+ z-index: 1000;
+ width: 260px;
+ border-right: 1px solid rgb(217, 217, 217);
+}
+
+.secondary-nav {
+ width: 100%;
+ height: 100%;
+ position: relative;
+ box-sizing: border-box;
+}
+
+
+.secondary-nav__options {
+ display: flex;
+ flex-direction: column;
+ border-bottom: 1px solid rgb(217, 217, 217);
+}
+
+.secondary-nav__option-link {
+ padding: 20px 0 20px 20px;
+}
+
+.secondary-nav__option-link:hover {
+ background-color: lightslategray;
+}
+
+/* secondary nav ends */
+
+.dash__main {
+ flex: 2;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ min-height: calc(-63px + 100vh);
+}
+
+/* dashbaord ends */