From 2a4f507a6f3243eb13a03dca85ef6374b2dbd1aa Mon Sep 17 00:00:00 2001 From: bobbyvish Date: Tue, 26 Mar 2024 13:22:29 +0530 Subject: [PATCH] refactor datatables --- module_activity/api/views.py | 8 +- module_activity/views.py | 24 +- module_auth/forms.py | 24 +- module_auth/views.py | 16 +- module_cms/urls.py | 1 + module_cms/views.py | 40 ++- module_notification/urls.py | 1 + module_notification/views.py | 68 +++-- module_project/service.py | 76 +++-- module_support/views.py | 38 +-- .../base_structure/layout/dashboard.html | 70 +++-- templates/module_auth/user_view.html | 48 ++- templates/module_auth/users_archive_list.html | 66 +++-- templates/module_auth/users_list.html | 138 ++++++--- templates/module_cms/faq.html | 50 ++-- templates/module_cms/faq_archive.html | 260 +++++++++++++++++ templates/module_iam/iam_role.html | 2 +- .../module_notification/notification.html | 59 ++-- .../notification_archive.html | 273 ++++++++++++++++++ templates/module_support/contact_us.html | 234 +++++++++------ .../contactus_archive_list.html | 74 +++-- templates/module_support/feedback.html | 12 +- 22 files changed, 1191 insertions(+), 391 deletions(-) create mode 100644 templates/module_cms/faq_archive.html create mode 100644 templates/module_notification/notification_archive.html diff --git a/module_activity/api/views.py b/module_activity/api/views.py index f4cb2c5..16ed30b 100644 --- a/module_activity/api/views.py +++ b/module_activity/api/views.py @@ -196,7 +196,7 @@ class IntoleranceListCreateAPIView(APIView): model = Intolerance def get(self, request): - obj = self.model.objects.filter(principal=request.user) + obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) @@ -227,7 +227,7 @@ class SymptomsListCreateAPIView(APIView): model = Symptoms def get(self, request): - obj = self.model.objects.filter(principal=request.user) + obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) @@ -258,7 +258,7 @@ class PastTreatmentListCreateAPIView(APIView): model = PastTreatment def get(self, request): - obj = self.model.objects.filter(principal=request.user) + obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) @@ -289,7 +289,7 @@ class ChronicConditionListCreateAPIView(APIView): model = ChronicCondition def get(self, request): - obj = self.model.objects.filter(principal=request.user) + obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) diff --git a/module_activity/views.py b/module_activity/views.py index aa0efc0..47a6ee9 100644 --- a/module_activity/views.py +++ b/module_activity/views.py @@ -259,30 +259,26 @@ class UserActivityRecordView(generic.View): } def get(self, request, *args, **kwargs): + try: principal_id = self.kwargs.get("principal_id") - date = request.GET.get("date") - print( - f"principal_id is {principal_id} data is {date} and type is {type(date)}" - ) - if not date: - return JsonResponseUtil.error(message="Date parameter is missing") + date_range = request.GET.get("date_range") - try: - date_obj = datetime.strptime(date, "%Y-%m-%d").date() - except ValueError: - return JsonResponseUtil.error(message="Invalid date format") + if not date_range: + return JsonResponseUtil.error(message="Date range parameter is missing") + + start_date, end_date = date_utils.get_date_range(date_range) # Retrieve data from different models meal_records = MealRecord.objects.filter( - principal=principal_id, date=date_obj + principal=principal_id, date__range=(start_date, end_date) ) medication_records = Medication.objects.filter( - principal=principal_id, date=date_obj + principal=principal_id, date__range=(start_date, end_date) ) - bowel_records = Bowel.objects.filter(principal=principal_id, date=date_obj) + bowel_records = Bowel.objects.filter(principal=principal_id, date__range=(start_date, end_date)) meal_symptom_records = MealSymptomRecord.objects.filter( - principal=principal_id, date=date_obj + principal=principal_id, date__range=(start_date, end_date) ) print(f"==================meal record {meal_records}") # Prepare combined results diff --git a/module_auth/forms.py b/module_auth/forms.py index efbef3b..3e745ce 100644 --- a/module_auth/forms.py +++ b/module_auth/forms.py @@ -18,7 +18,6 @@ class LoginForm(forms.Form): ) - class UserForm(forms.ModelForm): password = forms.CharField( widget=forms.PasswordInput(attrs={"autocomplete": "off"}), @@ -44,11 +43,26 @@ class UserForm(forms.ModelForm): "first_name": "Name", } + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + instance = kwargs.get("instance") + if instance and instance.pk: + # Remove password and confirm_password fields if instance exists (update action) + self.fields.pop("password") + self.fields.pop("confirm_password") + # Make email field readonly + self.fields["email"].widget.attrs["readonly"] = True + def clean_email(self): - email = self.cleaned_data.get('email') - if IAmPrincipal.objects.filter(email=email).exists(): - raise forms.ValidationError("This email address is already in use.") - return email + # Prevent email from being updated + instance = self.instance + if instance and instance.pk: + return instance.email + else: + email = self.cleaned_data.get("email") + if IAmPrincipal.objects.filter(email=email).exclude(pk=instance.pk).exists(): + raise forms.ValidationError("This email address is already in use.") + return email def clean(self): cleaned_data = super().clean() diff --git a/module_auth/views.py b/module_auth/views.py index bab9b42..c13f07e 100644 --- a/module_auth/views.py +++ b/module_auth/views.py @@ -160,19 +160,17 @@ class UserListJson(BaseDatatableView): print(f"request is {self.request.GET}") search_value = self.request.GET.get("search[value]", None) if search_value: - qs = qs.filter( - Q(id__icontains=search_value) - | Q(first_name__icontains=search_value) - | Q(email__icontains=search_value) - | Q(date_of_birth__icontains=search_value) - | Q(phone_no__icontains=search_value) - ) + qs = super().filter_queryset(qs) # Call the built-in filtering first for column in self.columns: - # print(f"columen index pattern {}") + print(f" columen index pattern {self.request.GET.get(f'columns[{self.columns.index(column)+1}][search][value]', None)}") search_value = self.request.GET.get(f'columns[{self.columns.index(column)+1}][search][value]', None) if search_value: - qs = qs.filter(**{f"{column}__icontains": search_value}) + column_data = self.request.GET.get(f'columns[{self.columns.index(column)+1}][data]') + if column_data == "is_active": + qs = qs.filter(**{f"{column}": search_value}) + else: + qs = qs.filter(**{f"{column}__icontains": search_value}) return qs diff --git a/module_cms/urls.py b/module_cms/urls.py index 0bb6342..db1c841 100644 --- a/module_cms/urls.py +++ b/module_cms/urls.py @@ -10,6 +10,7 @@ urlpatterns = [ path('faq/add/', views.FaqCreateOrUpdateView.as_view(), name='faq_add'), path('faq/edit//', views.FaqCreateOrUpdateView.as_view(), name='faq_edit'), path('faq/action/', views.FaqActionView.as_view(), name='faq_action'), + path('faq/archive/', views.FaqArchiveView.as_view(), name='faq_archive'), path('about-us/', views.AboutUsView.as_view(), name='about_us'), path('about-us/edit/', views.AboutUsCreateOrUpdateView.as_view(), name='about_us_add'), diff --git a/module_cms/views.py b/module_cms/views.py index b849e78..5330386 100644 --- a/module_cms/views.py +++ b/module_cms/views.py @@ -44,23 +44,18 @@ class FaqListJson(BaseDatatableView): return self.model.objects.filter(deleted=deleted_flag) - def filter_queryset(self, qs): - # Implement your custom filtering logic here - print(f"request is {self.request.GET}") - search_value = self.request.GET.get("search[value]", None) - if search_value: - qs = qs.filter( - Q(id__icontains=search_value) - | Q(question__icontains=search_value) - | Q(answer__icontains=search_value) - ) + # def filter_queryset(self, qs): + # # Implement your custom filtering logic here + # print(f"request is {self.request.GET}") + # search_value = self.request.GET.get("search[value]", None) + # if search_value: + # qs = qs.filter( + # Q(id__icontains=search_value) + # | Q(question__icontains=search_value) + # | Q(answer__icontains=search_value) + # ) - for column in self.columns: - search_value = self.request.GET.get(f'columns[{self.columns.index(column)+1}][search][value]', None) - if search_value: - qs = qs.filter(**{f"{column}__icontains": search_value}) - - return qs + # return qs def ordering(self, qs): order = self.request.GET.get('order[0][dir]', None) @@ -143,6 +138,19 @@ class FaqCreateOrUpdateView(LoginRequiredMixin, generic.View): class FaqActionView(ActionMixin): model = Faqs + +class FaqArchiveView(LoginRequiredMixin, generic.TemplateView): + page_name = iam_constant.RESOURCE_MANAGE_FAQS + resource = None + action = None + template_name = "module_cms/faq_archive.html" + model = Faqs + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["page_name"] = self.page_name + return context + class AboutUsView(LoginRequiredMixin, generic.DetailView): page_name = iam_constant.RESOURCE_MANAGE_CMS template_name = "module_cms/about_us_view.html" diff --git a/module_notification/urls.py b/module_notification/urls.py index a5fbd54..91e962a 100644 --- a/module_notification/urls.py +++ b/module_notification/urls.py @@ -12,6 +12,7 @@ urlpatterns = [ path("notification/edit/", views.NotificationCreateOrUpdateView.as_view(), name="notification_edit"), path("notification/list/", views.NotificationListJsonView.as_view(), name="notification_list"), path("notification/action/", views.NotificationActionView.as_view(), name="notification_action"), + path("notification/archive/list/", views.NotificationArchiveView.as_view(), name="notification_archive"), path("notification/send/", views.NotificationSendView.as_view(), name="notification_send"), ] diff --git a/module_notification/views.py b/module_notification/views.py index 3a46b00..441bdfe 100644 --- a/module_notification/views.py +++ b/module_notification/views.py @@ -15,7 +15,7 @@ from django_datatables_view.base_datatable_view import BaseDatatableView from module_iam import iam_constant from module_iam.iam_constant import PRINCIPAL_TYPE_USER from module_iam.models import IAmPrincipal -from module_project import constants +from module_project import constants, date_utils from module_project.mixins import ActionMixin from module_project.service import OneSignalService from module_project.utils import JsonResponseUtil @@ -43,19 +43,36 @@ class NotificationListJsonView(BaseDatatableView): def get_initial_queryset(self): deleted_flag = self.request.GET.get("deleted_flag", None) - return self.model.objects.filter(deleted=deleted_flag) + + # def render_column(self, row, column): + # if column == "timestamp": + # return date_utils.format_date_to_string(row.timestamp) + # return super().render_column(row, column) - def filter_queryset(self, qs): - # Implement your custom filtering logic here - print(f"request is {self.request.GET}") - search_value = self.request.GET.get("search[value]", None) - if search_value: - qs = qs.filter( - Q(id__icontains=search_value) - | Q(question__icontains=search_value) - | Q(answer__icontains=search_value) - ) + # def filter_queryset(self, qs): + # # Implement your custom filtering logic here + # print(f"request is {self.request.GET}") + # search_value = self.request.GET.get("search[value]", None) + # if search_value: + # qs = qs.filter( + # Q(id__icontains=search_value) + # | Q(question__icontains=search_value) + # | Q(answer__icontains=search_value) + # ) + + # return qs + + def ordering(self, qs): + order = self.request.GET.get('order[0][dir]', None) + if order: + column_index = int(self.request.GET.get('order[0][column]', None)) - 1 + order_column = self.order_columns[column_index] + + if order == "asc": + qs = qs.order_by(order_column) + elif order == "desc": + qs = qs.order_by("-" + order_column) return qs @@ -128,6 +145,17 @@ class NotificationCreateOrUpdateView(LoginRequiredMixin, generic.View): class NotificationActionView(ActionMixin): model = PushNotification +class NotificationArchiveView(LoginRequiredMixin, generic.TemplateView): + page_name = iam_constant.RESOURCE_MANAGE_NOTIFICATION + resource = None + action = None + template_name = "module_notification/notification_archive.html" + model = PushNotification + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["page_name"] = self.page_name + return context class NotificationSendView(generic.View): model = PushNotification @@ -141,6 +169,17 @@ class NotificationSendView(generic.View): def post(self, request, *args, **kwargs): id = request.POST.get("id") obj = self.model.objects.filter(pk=int(id)).first() + + if not obj: + return JsonResponseUtil.error( + message="No notification with such ID exists." + ) + + if not obj.active: + return JsonResponseUtil.error( + message="The notification cannot be sent because it is inactive. Please activate the notification before attempting to send it." + ) + # Get the current date and subtract 15 days fifteen_days_ago = datetime.now() - timedelta(days=3) @@ -154,11 +193,6 @@ class NotificationSendView(generic.View): # removing none from list player_ids = list(itertools.filterfalse(lambda x: x is None, player_ids)) - if not obj: - return JsonResponseUtil.error( - message="No notification with such ID exists." - ) - try: notification = OneSignalService() response = notification.send_notification( diff --git a/module_project/service.py b/module_project/service.py index 1b28e2a..197d766 100644 --- a/module_project/service.py +++ b/module_project/service.py @@ -27,61 +27,95 @@ logger = logging.getLogger(__name__) class EmailService: - email = None - body = None - subject = None - to = None - from_email = None + """ + A reusable class for sending emails - content_subtype = "html" + Example: + ```python + email_service = EmailService( + subject="Hello", + to="recipient@example.com", + from_email="sender@example.com", + ) + email_service.set_html_body("

Hello, this is a test email!

") + email_service.send() + ``` + This class provides methods to set the subject, recipient(s), sender, and body of the email. + It also supports loading email content from templates and attaching files. + """ def __init__(self, subject=None, to=None, from_email=None): self.subject = subject - self.to = (to,) + self.to = to if isinstance(to, (list, tuple)) else [to] self.from_email = from_email - - def set_to(self, to): - self.to = to + self.body = None + self.content_subtype = "html" def set_subject(self, subject): self.subject = subject + def set_to(self, to): + """ + Set the recipient email address or addresses. + + Parameters: + - to (str or list): The recipient email address or a list of recipient email addresses. + """ + self.to = to if isinstance(to, (list, tuple)) else [to] + def set_from_email(self, from_email): self.from_email = from_email def set_text_body(self, body): + """Set the plain text body of the email.""" self.body = strip_tags(body) def set_html_body(self, html_body): + """Set the HTML body of the email.""" self.body = html_body def load_template(self, path=None, context={}): + """ + Load an email template from a file and render it with the provided context. + + Parameters: + - path (str): The path to the email template file. + - context (dict): The context data to render the template. + """ if path is None: - raise Exception("Email temaplate path is not provided.") + raise Exception("Email template path is not provided.") self.content_subtype = "html" - html_body = render_to_string(path, context=context) - self.body = html_body + self.body = render_to_string(path, context=context) def attach(self, file_path): - self.email.attach_file(file_path) + """ + Attach a file to the email. + + Parameters: + - file_path (str): The path to the file to be attached. + """ + if not hasattr(self, 'attachments'): + self.attachments = [] + self.attachments.append(file_path) def send(self): try: - self.email = EmailMessage( + email = EmailMessage( subject=self.subject, body=self.body, to=self.to, from_email=self.from_email, ) + email.content_subtype = self.content_subtype - self.email.content_subtype = self.content_subtype - - self.email.send() - except SMTPException as e: - logger.error(str(e)) - + if hasattr(self, 'attachments'): + for attachment in self.attachments: + email.attach_file(attachment) + email.send() + except Exception as e: + logger.error(f"Error sending email: {str(e)}") class SMSError(Exception): def __init__(self, message, payload=None): self.message = message diff --git a/module_support/views.py b/module_support/views.py index 5430301..70a0ac8 100644 --- a/module_support/views.py +++ b/module_support/views.py @@ -35,8 +35,8 @@ class ContactUsView(LoginRequiredMixin, generic.TemplateView): class ContactUsListJson(BaseDatatableView): model = ContactUs - columns = ["id", "email_address", "subject", "message", "active", "deleted"] - order_columns = ["id", "email_address", "subject", "message", "active", "deleted"] + columns = ["id", "email_address", "subject", "message", "reply", "active"] + order_columns = ["id", "email_address", "subject", "message", "reply", "active"] def get_initial_queryset(self): deleted_flag = self.request.GET.get('deleted_flag', None) @@ -44,20 +44,20 @@ class ContactUsListJson(BaseDatatableView): return self.model.objects.filter(deleted=deleted_flag) def filter_queryset(self, qs): - # Implement your custom filtering logic here print(f"request is {self.request.GET}") search_value = self.request.GET.get("search[value]", None) if search_value: - qs = qs.filter( - Q(id__icontains=search_value) - | Q(question__icontains=search_value) - | Q(answer__icontains=search_value) - ) + qs = super().filter_queryset(qs) # Call the built-in filtering first for column in self.columns: + print(f" columen index pattern {self.request.GET.get(f'columns[{self.columns.index(column)+1}][search][value]', None)}") search_value = self.request.GET.get(f'columns[{self.columns.index(column)+1}][search][value]', None) if search_value: - qs = qs.filter(**{f"{column}__icontains": search_value}) + column_data = self.request.GET.get(f'columns[{self.columns.index(column)+1}][data]') + if column_data == "active": + qs = qs.filter(**{f"{column}": search_value}) + else: + qs = qs.filter(**{f"{column}__icontains": search_value}) return qs @@ -98,8 +98,8 @@ class ContactUsReplyView(LoginRequiredMixin, generic.View): def post(self, request, *args, **kwargs): id = self.kwargs.get("id") message = request.POST.get("message") - - if id or message: + print(f"id and message is {id} {message}") + if id and message: try: instance = self.model.objects.get(id=id) instance.reply = message @@ -107,21 +107,20 @@ class ContactUsReplyView(LoginRequiredMixin, generic.View): email_service = EmailService( subject=f"Reply of your inquiry - {instance.subject}", - body=message, - to=instance.email, + to=instance.email_address, from_email=settings.EMAIL_HOST_USER, ) + email_service.set_text_body(message) email_service.send() - JsonResponseUtil.success(message=self.success_message) + print(f"email service is {email_service}") + return JsonResponseUtil.success(message=self.success_message) except self.model.DoesNotExist: - JsonResponseUtil.error(message=constants.FAILURE, errors="Invalid contact us ID.") + return JsonResponseUtil.error(message=constants.FAILURE, errors="Invalid contact us ID.") except Exception as e: - JsonResponseUtil.error(message=constants.FAILURE, errors=str(e)) + return JsonResponseUtil.error(message=constants.FAILURE, errors=str(e)) else: - JsonResponseUtil.error(message=constants.FAILURE, errors="Missing 'id' or 'message' in the request") + return JsonResponseUtil.error(message=constants.FAILURE, errors="Missing 'id' or 'message' in the request") - # Redirect to the desired URL after form submission - return JsonResponseUtil.success(message=constants.SUCCESS) class FeedbackView(LoginRequiredMixin, generic.TemplateView): @@ -156,6 +155,7 @@ class FeedbackListJson(BaseDatatableView): qs = qs.filter( Q(id__icontains=search_value) | Q(feedback_reaction__icontains=search_value) + | Q(principal__email__icontains=search_value) | Q(comment__icontains=search_value) ) return qs diff --git a/templates/base_structure/layout/dashboard.html b/templates/base_structure/layout/dashboard.html index 447a498..2440c76 100644 --- a/templates/base_structure/layout/dashboard.html +++ b/templates/base_structure/layout/dashboard.html @@ -9,33 +9,38 @@
-
-
-
-
No of Active Users
-

{{active_user_count}}

+ +
+
+
+
No of Active Users
+

{{active_user_count}}

+
-
+
-
-
-
-
No of Total Users
-

{{total_user_count}}

+ +
+
+
+
No of Total Users
+

{{total_user_count}}

+
-
+
-
-
Users Graph
-
+

Users registration by month

+
@@ -48,12 +53,10 @@
-
-
Activity Graph
- - -
+
@@ -72,8 +75,8 @@ diff --git a/templates/module_auth/user_view.html b/templates/module_auth/user_view.html index 77f04b5..f97783a 100644 --- a/templates/module_auth/user_view.html +++ b/templates/module_auth/user_view.html @@ -257,8 +257,7 @@ +{% endblock %} \ No newline at end of file diff --git a/templates/module_iam/iam_role.html b/templates/module_iam/iam_role.html index 7c85521..8fd03df 100644 --- a/templates/module_iam/iam_role.html +++ b/templates/module_iam/iam_role.html @@ -179,7 +179,7 @@ function renderResources(data, type, row) { if (type === 'display' && row.resources) { let html = '
    '; for (const [resource, actions] of Object.entries(row.resources)) { - html += `
  • ${resource}`; + html += `
  • ${resource}`; for (const action of actions) { html += `${action}`; } diff --git a/templates/module_notification/notification.html b/templates/module_notification/notification.html index d507f89..adff5f2 100644 --- a/templates/module_notification/notification.html +++ b/templates/module_notification/notification.html @@ -40,18 +40,20 @@ - # # + aria-sort="ascending" style="width: 50.2656px;">Record Id Title Message + Created on Active - Action @@ -86,7 +88,7 @@ var dataTableInstance var actionUrl = '{% url "module_notification:notification_action" %}' var mainUrl = '{% url "module_notification:notification_list" %}?deleted_flag=False'; var editUrl = "{% url 'module_notification:notification_edit' pk=0 %}" -var viewArchiveUrl = "{% url 'module_notification:notification_action' %}" +var viewArchiveUrl = "{% url 'module_notification:notification_archive' %}" var notifyUrl = "{% url 'module_notification:notification_send' %}" // Entry point @@ -111,6 +113,7 @@ function initializeDataTable(tableName, mainUrl) { { data: "id", className: "text-center" }, { data: "title", className: "text-center" }, { data: "message", className: "text-center" }, + { data: "timestamp", className: "text-center" }, { data: "active", className: "text-center", render: renderSwitch }, { data: null, className: "text-center", render: renderActions } ], @@ -203,6 +206,11 @@ function initCompleteCallback() { } +function HideButton(className) { + // Hide archive button +$(`.${className}`).hide(); +} + // Function to handle archive action function archiveAction() { // Get all the checked checkboxes @@ -210,8 +218,8 @@ function archiveAction() { // If no checkboxes are checked, show an error message if (checkedCheckboxes.length === 0) { Swal.fire({ - title: 'No users selected', - text: 'Please select at least one user to archive.', + title: 'No record selected', + text: 'Please select at least one record to archive.', icon: 'error', showConfirmButton: true }); @@ -249,16 +257,17 @@ function archiveAction() { icon: 'success', showConfirmButton: true }); + HideButton("buttons-archive"); // Optionally, you can reload the DataTable after successful archive reloadDataTable(); }, - error: function(response) { - // Show error message + error: function(jqXHR, textStatus, errorThrown) { + var response = JSON.parse(jqXHR.responseText); Swal.fire({ - title: 'Error!', - text: response.message, - icon: 'error', - showConfirmButton: true + title: 'Error!', + text: response.message, + icon: 'error', + showConfirmButton: true }); } }); @@ -294,13 +303,13 @@ function activeSwitchEventListener() { // Reload the DataTable after successful toggle reloadDataTable(); }, - error: function(response) { - // Show error message + error: function(jqXHR, textStatus, errorThrown) { + var response = JSON.parse(jqXHR.responseText); Swal.fire({ - title: 'Error!', - text: response.message, - icon: 'error', - showConfirmButton: true + title: 'Error!', + text: response.message, + icon: 'error', + showConfirmButton: true }); } }); @@ -311,8 +320,6 @@ function sendNotificationAction() { $('body').on('click', '.send', function() { var id = $(this).closest('tr').find('.send').data('id'); - console.log("=================================================id is", + id); - Swal.fire({ title: 'Send Notification?', text: 'Once sent, the notification will be delivered to the user.', @@ -341,13 +348,13 @@ function sendNotificationAction() { }); // Optionally, you can perform any other actions after sending the notification }, - error: function(response) { - // Show error message + error: function(jqXHR, textStatus, errorThrown) { + var response = JSON.parse(jqXHR.responseText); Swal.fire({ - title: 'Error!', - text: response.message, - icon: 'error', - showConfirmButton: true + title: 'Error!', + text: response.message, + icon: 'error', + showConfirmButton: true }); } }); diff --git a/templates/module_notification/notification_archive.html b/templates/module_notification/notification_archive.html new file mode 100644 index 0000000..c8df091 --- /dev/null +++ b/templates/module_notification/notification_archive.html @@ -0,0 +1,273 @@ +{% extends 'base_structure/layout/base_template.html' %} +{% load static %} +{% block stylesheet %} + + + {% include "cdn_through_html/datatable_cdn_css.html" %} + {% include "cdn_through_html/animate_cdn_css.html" %} + {% include "cdn_through_html/modal_cdn_css.html" %} + {% include "cdn_through_html/sweetalert2_cdn_css.html" %} + +{% endblock %} + +{% block content %} + +
    +
    + + +
    +
    +
    +
    + +
    +
    +
    +
    + +{% endblock content %} + +{% block javascript %} + + + + {% include "cdn_through_html/datatable_cdn_js.html" %} + {% include "cdn_through_html/datatable_button_cdn_js.html" %} + {% include "cdn_through_html/sweetalert2_cdn_js.html" %} + + +{% endblock %} \ No newline at end of file diff --git a/templates/module_support/contact_us.html b/templates/module_support/contact_us.html index 8de7aa9..3f78c2f 100644 --- a/templates/module_support/contact_us.html +++ b/templates/module_support/contact_us.html @@ -33,50 +33,52 @@
    -