diff --git a/src/labzero/fe/js/main.js b/src/labzero/fe/js/main.js index 5726a4d..1b9246b 100644 --- a/src/labzero/fe/js/main.js +++ b/src/labzero/fe/js/main.js @@ -1,5 +1,27 @@ import Swal from 'sweetalert2'; +const toast = Swal.mixin({ + toast: true, + position: 'top-end', + showConfirmButton: false, + timer: 3500, + timerProgressBar: true, + customClass: { + popup: 'rounded-xl shadow-xl', + }, +}); + +function showToast(detail = {}) { + if (!detail.message) { + return; + } + + toast.fire({ + icon: detail.type || 'success', + title: detail.message, + }); +} + document.addEventListener('DOMContentLoaded', () => { const showSweetAlertButton = document.getElementById('showSweetAlertButton'); @@ -31,4 +53,8 @@ document.addEventListener('DOMContentLoaded', () => { }); }); } -}); \ No newline at end of file +}); + +document.body.addEventListener('labzero:notify', (event) => { + showToast(event.detail); +}); diff --git a/src/labzero/forms.py b/src/labzero/forms.py new file mode 100644 index 0000000..dec3249 --- /dev/null +++ b/src/labzero/forms.py @@ -0,0 +1,80 @@ +from django import forms +from django.contrib.auth import get_user_model +from django.contrib.auth import password_validation + + +class ProfileForm(forms.ModelForm): + current_password = forms.CharField( + label="Current password", + required=False, + strip=False, + widget=forms.PasswordInput(render_value=False), + help_text="Required only when setting a new password.", + ) + new_password1 = forms.CharField( + label="New password", + required=False, + strip=False, + widget=forms.PasswordInput(render_value=False), + help_text=password_validation.password_validators_help_text_html(), + ) + new_password2 = forms.CharField( + label="Confirm new password", + required=False, + strip=False, + widget=forms.PasswordInput(render_value=False), + ) + + class Meta: + model = get_user_model() + fields = ["name", "email"] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.password_changed = False + + def clean(self): + cleaned_data = super().clean() + current_password = cleaned_data.get("current_password") + new_password1 = cleaned_data.get("new_password1") + new_password2 = cleaned_data.get("new_password2") + password_requested = any([current_password, new_password1, new_password2]) + + if not password_requested: + return cleaned_data + + if not current_password: + self.add_error( + "current_password", + "Enter your current password to set a new password.", + ) + elif not self.instance.check_password(current_password): + self.add_error("current_password", "Your current password is incorrect.") + + if not new_password1: + self.add_error("new_password1", "Enter a new password.") + + if new_password1 and new_password2 and new_password1 != new_password2: + self.add_error("new_password2", "The new passwords do not match.") + + if ( + new_password1 + and not self.errors.get("current_password") + and not self.errors.get("new_password2") + ): + password_validation.validate_password(new_password1, self.instance) + + return cleaned_data + + def save(self, commit=True): + user = super().save(commit=False) + new_password = self.cleaned_data.get("new_password1") + + if new_password: + user.set_password(new_password) + self.password_changed = True + + if commit: + user.save() + + return user diff --git a/src/labzero/templates/labzero/base.html b/src/labzero/templates/labzero/base.html index 1940073..5073e61 100644 --- a/src/labzero/templates/labzero/base.html +++ b/src/labzero/templates/labzero/base.html @@ -6,9 +6,11 @@ {% vite_asset "css/app.css" "labzero" %} + {% block 'extra_head' %}{% endblock %} {% block 'content' %}{% endblock %} + {% block 'extra_body' %}{% endblock %} {% vite_asset "js/main.js" "labzero" %} diff --git a/src/labzero/templates/labzero/dashboard.html b/src/labzero/templates/labzero/dashboard.html index 4926049..635d2c4 100644 --- a/src/labzero/templates/labzero/dashboard.html +++ b/src/labzero/templates/labzero/dashboard.html @@ -1,118 +1,56 @@ -{% extends "base.html" %} +{% extends "labzero_base.html" %} -{% block 'content' %} -
- -
-
-

Admin Panel

-
- -
- - - - - Profile - -
- {% csrf_token %} - -
-
-
- - -
- -
-
-

Dashboard

-
-
-
- -
-
-
+{% block 'page_title' %}Dashboard{% endblock %} - -
-
-
-

New Users

-

1,234

-
-
-

Sales

-

$56,789

-
-
-

Subscriptions

-

5,432

-
-
+{% block 'page_content' %} +
+
+

New Users

+

1,234

+
+
+

Sales

+

$56,789

+
+
+

Subscriptions

+

5,432

+
+
-
- -
+
+ +
-
-

Recent Activity

- - - - - - - - - - - - - - - - - - - - - - - - - -
UserActivityTime
John DoeUpgraded to Pro2 hours ago
Jane SmithJoined5 hours ago
Sam WilsonUpdated profile1 day ago
-
-
-
+
+

Recent Activity

+ + + + + + + + + + + + + + + + + + + + + + + + + +
UserActivityTime
John DoeUpgraded to Pro2 hours ago
Jane SmithJoined5 hours ago
Sam WilsonUpdated profile1 day ago
{% endblock %} diff --git a/src/labzero/templates/labzero/profile_form.html b/src/labzero/templates/labzero/profile_form.html new file mode 100644 index 0000000..5752bf3 --- /dev/null +++ b/src/labzero/templates/labzero/profile_form.html @@ -0,0 +1,21 @@ +{% extends "labzero_base.html" %} +{% load django_umin_vite %} + +{% block 'extra_head' %} +{{ block.super }} +{% vite_asset "css/app.css" "django_umin" %} +{% endblock %} + +{% block 'page_title' %}Profile Settings{% endblock %} + +{% block 'page_content' %} +
+ {% include "django_umin/includes/messages.html" %} + {% include "django_umin/includes/form_page.html" %} +
+{% endblock %} + +{% block 'extra_body' %} + + +{% endblock %} diff --git a/src/labzero/templates/labzero/profile_form_htmx.html b/src/labzero/templates/labzero/profile_form_htmx.html new file mode 100644 index 0000000..128f40e --- /dev/null +++ b/src/labzero/templates/labzero/profile_form_htmx.html @@ -0,0 +1 @@ +{% include "django_umin/includes/form_card.html" %} diff --git a/src/labzero/templates/labzero_base.html b/src/labzero/templates/labzero_base.html index 8d9d40d..c14aa75 100644 --- a/src/labzero/templates/labzero_base.html +++ b/src/labzero/templates/labzero_base.html @@ -6,13 +6,13 @@
- + Profile {% if user.is_authenticated %} -
+ {% csrf_token %}