refactor datatables
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ urlpatterns = [
|
||||
path('faq/add/', views.FaqCreateOrUpdateView.as_view(), name='faq_add'),
|
||||
path('faq/edit/<int:pk>/', 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'),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -12,6 +12,7 @@ urlpatterns = [
|
||||
path("notification/edit/<int:pk>", 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"),
|
||||
|
||||
]
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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("<p>Hello, this is a test email!</p>")
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,33 +9,38 @@
|
||||
<div class="row layout-top-spacing">
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="font-weight-bold">No of Active Users</h6>
|
||||
<h4 class="m-0 font-weight-bold">{{active_user_count}}</h4>
|
||||
<a href="{% url 'module_auth:users'%}">
|
||||
<div class="card">
|
||||
<div class="card-body d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="font-weight-bold">No of Active Users</h6>
|
||||
<h4 class="m-0 font-weight-bold">{{active_user_count}}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card d-flex">
|
||||
<div class="card-body d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="font-weight-bold">No of Total Users</h6>
|
||||
<h4 class="m-0 font-weight-bold">{{total_user_count}}</h4>
|
||||
<a href="{% url 'module_auth:users'%}">
|
||||
<div class="card d-flex">
|
||||
<div class="card-body d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="font-weight-bold">No of Total Users</h6>
|
||||
<h4 class="m-0 font-weight-bold">{{total_user_count}}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 layout-spacing">
|
||||
<div class="widget widget-chart-three">
|
||||
<div class="widget-heading">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5>Users Graph</h5>
|
||||
</div>
|
||||
<h3>Users registration by month</h3>
|
||||
<select class="form-control text-center w-25" name="user_year_select" id="user_year_select">
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="widget-content">
|
||||
@@ -48,12 +53,10 @@
|
||||
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 layout-spacing">
|
||||
<div class="widget widget-chart-three">
|
||||
<div class="widget-heading">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5>Activity Graph</h5>
|
||||
<select class="form-control w-25" name="year_select" id="year_select">
|
||||
<h3>Activty Graph</h3>
|
||||
<select class="form-control text-center w-25" name="activity_year_select" id="activity_year_select">
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="widget-content">
|
||||
@@ -72,8 +75,8 @@
|
||||
<script>
|
||||
|
||||
// Function to populate the select element with years
|
||||
function populateYears() {
|
||||
var select = document.getElementById("year_select");
|
||||
function populateYears(id) {
|
||||
var select = id
|
||||
var currentYear = new Date().getFullYear();
|
||||
|
||||
// Add options for the current year and the last 5 years
|
||||
@@ -183,10 +186,6 @@ function fetchActivityChartData(year) {
|
||||
name: "Registration",
|
||||
data: [10, 41, 35, 51, 49, 62, 69, 91, 148]
|
||||
}],
|
||||
title: {
|
||||
text: 'User registration by Month',
|
||||
align: 'left'
|
||||
},
|
||||
grid: {
|
||||
row: {
|
||||
colors: ['#f1f2f3', 'transparent'], // takes an array which will be repeated on columns
|
||||
@@ -225,18 +224,27 @@ function fetchUserChartData(year) {
|
||||
|
||||
$(document).ready(function() {
|
||||
// Call the function to populate the select element when the page loads
|
||||
populateYears();
|
||||
activityYear = document.getElementById("activity_year_select")
|
||||
userYear = document.getElementById("user_year_select")
|
||||
populateYears(activityYear);
|
||||
populateYears(userYear);
|
||||
|
||||
// Add event listener for change event on the select element
|
||||
$("#year_select").change(function() {
|
||||
$(activityYear).change(function() {
|
||||
var selectedYear = $(this).val();
|
||||
fetchActivityChartData(selectedYear); // Call the fetchData function with the selected year
|
||||
});
|
||||
|
||||
$(userYear).change(function() {
|
||||
var selectedYear = $(this).val();
|
||||
fetchUserChartData(selectedYear); // Call the fetchData function with the selected year
|
||||
});
|
||||
|
||||
// Fetch data for the initial selected year
|
||||
var initialYear = $("#year_select").val();
|
||||
fetchActivityChartData(initialYear);
|
||||
fetchUserChartData(initialYear)
|
||||
var activityInitialYear = $(activityYear).val();
|
||||
var userInitialYear = $(userYear).val();
|
||||
fetchActivityChartData(activityInitialYear);
|
||||
fetchUserChartData(userInitialYear)
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -257,8 +257,7 @@
|
||||
<script>
|
||||
|
||||
// Define DataTable instance
|
||||
var dataTableInstance
|
||||
var mainUrl = "{% url 'module_activity:activity_list' principal_id=obj.id %}?date=2024-02-14";
|
||||
var activityMainUrl = "{% url 'module_activity:activity_list' principal_id=obj.id %}?date_range=40";
|
||||
var mealUrl = "{% url 'module_activity:meal_detail' pk=0 %}"
|
||||
var medicationUrl = "{% url 'module_activity:medication_detail' pk=0 %}"
|
||||
var bowelUrl = "{% url 'module_activity:bowel_detail' pk=0 %}"
|
||||
@@ -267,18 +266,18 @@ var reportUrl = "{% url 'module_activity:report_data' principal_id=obj.id %}?dat
|
||||
|
||||
// Entry point
|
||||
$(document).ready(function() {
|
||||
|
||||
dataTableInstance = initializeDataTable(dataTableInstance, mainUrl);
|
||||
tableName = $('#table');
|
||||
dataTableInstance = initializeDataTable(tableName, activityMainUrl);
|
||||
getReportData();
|
||||
});
|
||||
|
||||
// Function to initialize DataTable
|
||||
function initializeDataTable(dataTableInstance, mainUrl) {
|
||||
return $('#table').DataTable({
|
||||
function initializeDataTable(tableName, activityMainUrl) {
|
||||
return tableName.DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
url: mainUrl,
|
||||
url: activityMainUrl,
|
||||
type: "GET",
|
||||
},
|
||||
columns: [
|
||||
@@ -341,7 +340,6 @@ function initializeDataTable(dataTableInstance, mainUrl) {
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
buttons: [
|
||||
{ text: 'View Archive List', className: "btn btn-dark " }
|
||||
],
|
||||
oLanguage: {
|
||||
oPaginate: { "sPrevious": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>', "sNext": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>' },
|
||||
@@ -353,14 +351,46 @@ function initializeDataTable(dataTableInstance, mainUrl) {
|
||||
stripeClasses: [],
|
||||
lengthMenu: [5, 10, 20, 50],
|
||||
pageLength: 10,
|
||||
initComplete: function() {
|
||||
$(`<div class="dropdown">
|
||||
<a class="dropdown-toggle btn btn-primary" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">\
|
||||
Filter
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink" style="">
|
||||
<a class="dropdown-item" href="javascript:void(0)" onclick="filterActivityData(7)">Last 7 days</a>
|
||||
<a class="dropdown-item" href="javascript:void(0)" onclick="filterActivityData(20)">Last 20 days</a>
|
||||
<a class="dropdown-item" href="javascript:void(0)" onclick="filterActivityData(40)">Last 40 days</a>
|
||||
<a class="dropdown-item" href="javascript:void(0)" onclick="filterActivityData(60)">Last 60 days</a>
|
||||
</div>
|
||||
</div>`).appendTo('.dt--top-section .col-12:last');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to reload the DataTable
|
||||
function reloadDataTable() {
|
||||
dataTableInstance.Datatable().ajax.reload();
|
||||
dataTableInstance.ajax.reload();
|
||||
}
|
||||
|
||||
function filterActivityData(dateRange){
|
||||
var url = dateRange ? activityMainUrl.replace("1", dateRange) : activityMainUrl;
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'GET',
|
||||
success: function(response) {
|
||||
// Assuming response.data contains the filtered records
|
||||
var filteredData = response.data;
|
||||
|
||||
tableName.clear().rows.add(filteredData).draw();
|
||||
console.log("Filtered data loaded successfully:", filteredData);
|
||||
},
|
||||
error: function(response) {
|
||||
console.error("Error occurred while fetching filtered data:", response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getReportData(timeRange){
|
||||
var url = timeRange ? reportUrl.replace("7", timeRange) : reportUrl
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
<th class="checkbox-column text-center dt-no-sorting" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending" style="width: 50.2656px;">
|
||||
#</th>
|
||||
<th class="sorting_asc text-center" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 50.2656px;">#</th>
|
||||
aria-sort="ascending" style="width: 50.2656px;">Record id</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1" style="width: 44.2344px;">Name</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
@@ -49,20 +49,18 @@
|
||||
<th class="sorting text-center" tabindex="4" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Date of Birth</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead id="filterboxrow">
|
||||
<tr>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th rowspan="1" colspan="1">Email</th>
|
||||
<th rowspan="1" colspan="1">Name</th>
|
||||
<th rowspan="1" colspan="1">Phone No.</th>
|
||||
<th rowspan="1" colspan="1">Date of Birth</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<thead>
|
||||
<tbody>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -122,6 +120,7 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
{ targets: [1, 2, 3, 4, 5], searchable: true, orderable: true },
|
||||
{ targets: [0], searchable: false, orderable: false }
|
||||
],
|
||||
orderCellsTop: true,
|
||||
dom: "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
@@ -165,28 +164,40 @@ function renderCheckbox(data, type, row) {
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var api = this.api();
|
||||
var table = this.api();
|
||||
var tableId = this.api().table().node().id;
|
||||
|
||||
// Add individual search inputs to the first row of the thead section
|
||||
$('thead#filterboxrow th').each(function (index) {
|
||||
var title = $(this).text();
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '"/>')
|
||||
.on('keyup change', function () {
|
||||
if (api.column(index).search() !== this.value) {
|
||||
api.column(index).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
// Specify the column indexes for searchable fields (adjust as needed)
|
||||
var searchableColumns = [1, 2, 3, 4, 5];
|
||||
// Specify the column indexes for select input fields (adjust as needed)
|
||||
var selectDropdownInputColumns = [6]
|
||||
|
||||
$(this).empty().append(input);
|
||||
table.columns(searchableColumns).every(function() {
|
||||
var column = this;
|
||||
var title = $(this.header()).text().trim(); // Get the column title
|
||||
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '" />')
|
||||
.appendTo($("thead tr:eq(1) th").eq(this.index()))
|
||||
.on("keyup", function() {
|
||||
if (column.search() !== this.value) {
|
||||
column.search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $('#table tbody input.archive-checkbox:checked').length;
|
||||
var checkedCount = $(`#${tableId} tbody input.archive-checkbox:checked`).length;
|
||||
var archiveButton = $('.buttons-unarchive');
|
||||
archiveButton.toggle(checkedCount > 0);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function HideButton(className) {
|
||||
// Hide archive button
|
||||
$(`.${className}`).hide();
|
||||
}
|
||||
|
||||
|
||||
@@ -197,8 +208,8 @@ function unArchiveAction() {
|
||||
// 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
|
||||
});
|
||||
@@ -236,6 +247,7 @@ function unArchiveAction() {
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
HideButton("buttons-unarchive");
|
||||
// Optionally, you can reload the DataTable after successful archive
|
||||
reloadDataTable();
|
||||
},
|
||||
|
||||
@@ -42,11 +42,11 @@
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
<th class="checkbox-column text-center dt-no-sorting" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending" style="width: 50.2656px;">
|
||||
#</th>
|
||||
<th class="sorting_asc text-center" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 50.2656px;">id</th>
|
||||
aria-sort="ascending" style="width: 50.2656px;">Record id</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1" style="width: 44.2344px;">Name</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
@@ -57,11 +57,21 @@
|
||||
style="width: 79.7969px;">Date of Birth</th>
|
||||
<th class="sorting text-center" tabindex="5" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Active</th>
|
||||
<th class="sorting text-center" tabindex="6" aria-controls="style-3"
|
||||
<th class="text-center dt-no-sorting" tabindex="6" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Action</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead id="filterboxrow">
|
||||
{% comment %} <thead id="filterboxrow">
|
||||
<tr>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
@@ -69,10 +79,10 @@
|
||||
<th rowspan="1" colspan="1">Name</th>
|
||||
<th rowspan="1" colspan="1">Phone No.</th>
|
||||
<th rowspan="1" colspan="1">Date of Birth</th>
|
||||
<th class="invisible" rowspan="1" colspan="1">Active</th>
|
||||
<th class="" rowspan="1" colspan="1">Active</th>
|
||||
<th class="invisible" rowspan="1" colspan="1">Action</th>
|
||||
</tr>
|
||||
<thead>
|
||||
<thead> {% endcomment %}
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
@@ -139,10 +149,11 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
{ targets: [1, 2, 3, 4, 5], searchable: true, orderable: true },
|
||||
{ targets: [0, -1], searchable: false, orderable: false }
|
||||
],
|
||||
orderCellsTop: true,
|
||||
dom: "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
buttons: [
|
||||
buttons: [
|
||||
{
|
||||
text: 'Archive',
|
||||
className: "btn btn-dark buttons-archive",
|
||||
@@ -173,6 +184,85 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
});
|
||||
}
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var table = this.api();
|
||||
var tableId = this.api().table().node().id;
|
||||
console.log(tableId);
|
||||
|
||||
// Specify the column indexes for individual searchable fields (adjust as needed)
|
||||
var searchableColumns = [1, 2, 3, 4, 5, 6];
|
||||
// Specify the column indexes for select input fields (adjust as needed)
|
||||
var selectDropdownInputColumns = [6]
|
||||
|
||||
// will use this code in future
|
||||
/*
|
||||
table.columns(searchableColumns).every(function() {
|
||||
var column = this;
|
||||
var title = $(this.header()).text().trim(); // Get the column title
|
||||
|
||||
var inputGroup = $('<div class="input-group"></div>')
|
||||
.appendTo($("thead tr:eq(1) th").eq(this.index()));
|
||||
|
||||
var input = $('<input class="form-control py-2 border-right-0 border" type="search" placeholder="Search ' + title + '" aria-label="Search ' + title + '" />')
|
||||
.appendTo(inputGroup);
|
||||
|
||||
var clearButton = $('<span class="input-group-append"><div class="input-group-text bg-transparent">X</div></span>')
|
||||
.appendTo(inputGroup)
|
||||
.on("click", function() {
|
||||
input.val("");
|
||||
column.search("").draw();
|
||||
});
|
||||
|
||||
// Add keyup event listener for search functionality
|
||||
input.on("keyup", function() {
|
||||
if (column.search() !== this.value) {
|
||||
column.search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
table.columns(searchableColumns).every(function() {
|
||||
var column = this;
|
||||
var title = $(this.header()).text().trim(); // Get the column title
|
||||
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '" />')
|
||||
.appendTo($("thead tr:eq(1) th").eq(this.index()))
|
||||
.on("keyup", function() {
|
||||
if (column.search() !== this.value) {
|
||||
column.search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $(`#${tableId} tbody input.archive-checkbox:checked`).length;
|
||||
var archiveButton = $('.buttons-archive');
|
||||
archiveButton.toggle(checkedCount > 0);
|
||||
});
|
||||
|
||||
table.columns(selectDropdownInputColumns).every( function () {
|
||||
var column = this;
|
||||
console.log( column.index() );
|
||||
var nodeBelow = $(column.header()).closest('tr').next().children().eq( column.index() );
|
||||
var select = $('<select class="form-control"><option value="">All</option></select>')
|
||||
.appendTo( $(nodeBelow).empty() )
|
||||
.on( 'change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
if (column.search() !== this.value) {
|
||||
column.search(val).draw();
|
||||
}
|
||||
} );
|
||||
column.data().unique().sort().each( function ( d, j ) {
|
||||
console.log(`data is ${d}`)
|
||||
select.append( '<option value="'+d+'">'+d+'</option>' )
|
||||
} );
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
// Function to reload the DataTable
|
||||
function reloadDataTable() {
|
||||
dataTableInstance.ajax.reload();
|
||||
@@ -204,7 +294,7 @@ function renderActions(data, type, row) {
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink${row.id}" style="">
|
||||
<a class="dropdown-item view" href="${ viewUrl.replace('0',row.id)}" data-id="${row.id}">View</a>
|
||||
<a class="dropdown-item edit" href="${ editUrl.replace('0',row.id)}" data-id="${row.id}">Edit</a>
|
||||
{% comment %} <a class="dropdown-item edit" href="${ editUrl.replace('0',row.id)}" data-id="${row.id}">Edit</a> {% endcomment %}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -216,30 +306,9 @@ function redirectToArchive() {
|
||||
window.location.href = '/archive';
|
||||
}
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var api = this.api();
|
||||
|
||||
// Add individual search inputs to the first row of the thead section
|
||||
$('thead#filterboxrow th').each(function (index) {
|
||||
var title = $(this).text();
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '"/>')
|
||||
.on('keyup change', function () {
|
||||
if (api.column(index).search() !== this.value) {
|
||||
api.column(index).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
|
||||
$(this).empty().append(input);
|
||||
});
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $('#table tbody input.archive-checkbox:checked').length;
|
||||
var archiveButton = $('.buttons-archive');
|
||||
archiveButton.toggle(checkedCount > 0);
|
||||
});
|
||||
|
||||
function HideButton(className) {
|
||||
// Hide archive button
|
||||
$(`.${className}`).hide();
|
||||
}
|
||||
|
||||
|
||||
@@ -250,8 +319,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
|
||||
});
|
||||
@@ -289,6 +358,7 @@ function archiveAction() {
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
HideButton("buttons-archive");
|
||||
// Optionally, you can reload the DataTable after successful archive
|
||||
reloadDataTable();
|
||||
},
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
<th class="checkbox-column dt-no-sorting text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
style="width: 50.2656px;">Record ID</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Question</th>
|
||||
@@ -55,20 +55,10 @@
|
||||
style="width: 44.2344px;">Answer</th>
|
||||
<th class="sorting text-center" tabindex="3" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Active</th>
|
||||
<th class="sorting text-center" tabindex="5" aria-controls="style-3"
|
||||
<th class="text-center dt-no-sorting" tabindex="5" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead id="filterboxrow">
|
||||
<tr>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th rowspan="1" colspan="1">Question</th>
|
||||
<th rowspan="1" colspan="1">Answer</th>
|
||||
<th class="invisible" rowspan="1" colspan="1">Active</th>
|
||||
<th class="invisible" rowspan="1" colspan="1">Action</th>
|
||||
</tr>
|
||||
<thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
@@ -129,6 +119,7 @@ var dataTableInstance;
|
||||
var mainUrl = "{% url 'module_cms:faq_list' %}?deleted_flag=False"
|
||||
var editUrl = "{% url 'module_cms:faq_edit' pk=0 %}"
|
||||
var actionUrl = "{% url 'module_cms:faq_action' %}"
|
||||
var viewArchiveUrl = "{% url 'module_cms:faq_archive' %}"
|
||||
|
||||
// Entry point
|
||||
$(document).ready(function() {
|
||||
@@ -159,7 +150,7 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
debug: true,
|
||||
columnDefs: [
|
||||
{
|
||||
"targets": [1,2],
|
||||
"targets": [2,3],
|
||||
"render": function (data, type, row) {
|
||||
// Adjust the length of text you want to show before truncating
|
||||
var maxLength = 40;
|
||||
@@ -174,6 +165,11 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
searchable: true,
|
||||
orderable: true
|
||||
},
|
||||
{
|
||||
targets: [4],
|
||||
searchable: false,
|
||||
orderable: true
|
||||
},
|
||||
{
|
||||
targets: [0,-1], // Targeting the last column (action column)
|
||||
searchable: false,
|
||||
@@ -196,8 +192,7 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
text: 'View Archive List',
|
||||
className: "btn btn-dark ",
|
||||
action: function () {
|
||||
// Add your action here, e.g., redirect to archive page
|
||||
window.location.href = '/archive';
|
||||
window.location.href = viewArchiveUrl;
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -298,6 +293,7 @@ function archiveAction() {
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
HideButton("buttons-archive");
|
||||
// Optionally, you can reload the DataTable after successful archive
|
||||
reloadDataTable();
|
||||
},
|
||||
@@ -318,23 +314,11 @@ function archiveAction() {
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var api = this.api();
|
||||
|
||||
// Add individual search inputs to the first row of the thead section
|
||||
$('thead#filterboxrow th').each(function (index) {
|
||||
var title = $(this).text();
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '"/>')
|
||||
.on('keyup change', function () {
|
||||
if (api.column(index).search() !== this.value) {
|
||||
api.column(index).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
|
||||
$(this).empty().append(input);
|
||||
});
|
||||
var tableId = this.api().table().node().id;
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $('tbody input.archive-checkbox:checked').length;
|
||||
var checkedCount = $(`#${tableId} tbody input.archive-checkbox:checked`).length;
|
||||
var archiveButton = $('.buttons-archive');
|
||||
console.log("checkbox is checked", + checkedCount)
|
||||
archiveButton.toggle(checkedCount > 0);
|
||||
@@ -342,6 +326,11 @@ function initCompleteCallback() {
|
||||
|
||||
}
|
||||
|
||||
function HideButton(className) {
|
||||
// Hide archive button
|
||||
$(`.${className}`).hide();
|
||||
}
|
||||
|
||||
// Function to handle click event for view button
|
||||
function viewClickEvent(dataTableInstance) {
|
||||
$('body').on('click', '.view', function(){
|
||||
@@ -384,6 +373,7 @@ function activeSwitchEventListener() {
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
|
||||
// Reload the DataTable after successful toggle
|
||||
reloadDataTable();
|
||||
},
|
||||
|
||||
260
templates/module_cms/faq_archive.html
Normal file
260
templates/module_cms/faq_archive.html
Normal file
@@ -0,0 +1,260 @@
|
||||
{% extends 'base_structure/layout/base_template.html' %}
|
||||
{% load static %}
|
||||
{% block stylesheet %}
|
||||
<!-- include required css cdn link through html here -->
|
||||
{% include "cdn_through_html/datatable_cdn_css.html" %}
|
||||
{% include "cdn_through_html/switches_cdn_css.html" %}
|
||||
{% include "cdn_through_html/sweetalert2_cdn_css.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
<div class="row layout-top-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<a href="{% url 'module_cms:faq'%}" style="height: fit-content;width: fit-content;display: inline-block;">
|
||||
<h3 class="card-title m-2 d-flex align-items-center gap-2" style="width: fit-content;"><span class="fw-bold material-symbols-outlined">
|
||||
arrow_back
|
||||
</span><span>Faq Archive List</span></h3>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row layout-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="statbox widget box box-shadow">
|
||||
<div class="widget-content widget-content-area">
|
||||
<div id="table_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4 no-footer">
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="table" class="table style-3 dt-table-hover dataTable" role="grid"
|
||||
aria-describedby="style-3_info">
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column dt-no-sorting text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">Record ID</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Question</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Answer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
<!-- include required js cdn link through html here -->
|
||||
{% 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" %}
|
||||
|
||||
<script>
|
||||
|
||||
// Define DataTable instance
|
||||
var dataTableInstance;
|
||||
var mainUrl = "{% url 'module_cms:faq_list' %}?deleted_flag=True"
|
||||
var actionUrl = "{% url 'module_cms:faq_action' %}"
|
||||
|
||||
// Entry point
|
||||
$(document).ready(function() {
|
||||
|
||||
tableName = $('#table');
|
||||
dataTableInstance = initializeDataTable(tableName, mainUrl);
|
||||
viewClickEvent(dataTableInstance, viewUrl);
|
||||
editClickEvent();
|
||||
activeSwitchEventListener()
|
||||
});
|
||||
|
||||
// Function to initialize DataTable
|
||||
function initializeDataTable(tableName, mainUrl) {
|
||||
return tableName.DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
url: mainUrl,
|
||||
type: "GET",
|
||||
},
|
||||
columns: [
|
||||
{ data: null, className: "text-center", render: renderCheckbox },
|
||||
{ data: "id", className: "text-center" },
|
||||
{ data: "question" },
|
||||
{ data: "answer" },
|
||||
],
|
||||
debug: true,
|
||||
columnDefs: [
|
||||
{
|
||||
"targets": [2,3],
|
||||
"render": function (data, type, row) {
|
||||
// Adjust the length of text you want to show before truncating
|
||||
var maxLength = 40;
|
||||
// Truncate the text if it exceeds the maxLength
|
||||
var truncatedText = data.length > maxLength ? data.substr(0, maxLength) + '...' : data;
|
||||
// Return the truncated text
|
||||
return truncatedText;
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: [1, 2, 3],
|
||||
searchable: true,
|
||||
orderable: true
|
||||
},
|
||||
{
|
||||
targets: [0],
|
||||
searchable: false,
|
||||
orderable: false
|
||||
},
|
||||
],
|
||||
orderCellsTop: true,
|
||||
dom: "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
buttons: [
|
||||
{
|
||||
text: 'UnArchive',
|
||||
className: "btn btn-dark buttons-unarchive",
|
||||
action: unArchiveAction,
|
||||
init: function(api, node, config){
|
||||
$(node).hide();
|
||||
}
|
||||
}
|
||||
],
|
||||
oLanguage: {
|
||||
oPaginate: { "sPrevious": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>', "sNext": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>' },
|
||||
sInfo: "Showing page _PAGE_ of _PAGES_",
|
||||
sSearch: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>',
|
||||
sSearchPlaceholder: "Search...",
|
||||
sLengthMenu: " _MENU_",
|
||||
},
|
||||
stripeClasses: [],
|
||||
lengthMenu: [5, 10, 20, 50],
|
||||
pageLength: 10,
|
||||
initComplete: initCompleteCallback
|
||||
});
|
||||
}
|
||||
|
||||
// Function to reload the DataTable
|
||||
function reloadDataTable() {
|
||||
dataTableInstance.ajax.reload();
|
||||
}
|
||||
|
||||
// Render checkbox
|
||||
function renderCheckbox(data, type, row) {
|
||||
var checkboxHTML = '<div class="form-check form-check-danger">';
|
||||
checkboxHTML += '<input class="form-check-input archive-checkbox" type="checkbox" value="' + row.id + '" id="checkbox-' + row.id + '">';
|
||||
checkboxHTML += '</div>';
|
||||
return checkboxHTML;
|
||||
}
|
||||
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var table = this.api();
|
||||
var tableId = this.api().table().node().id;
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $(`#${tableId} tbody input.archive-checkbox:checked`).length;
|
||||
var archiveButton = $('.buttons-unarchive');
|
||||
archiveButton.toggle(checkedCount > 0);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function HideButton(className) {
|
||||
// Hide archive button
|
||||
$(`.${className}`).hide();
|
||||
}
|
||||
|
||||
|
||||
// Function to handle archive action
|
||||
function unArchiveAction() {
|
||||
// Get all the checked checkboxes
|
||||
var checkedCheckboxes = $('.archive-checkbox:checked');
|
||||
// If no checkboxes are checked, show an error message
|
||||
if (checkedCheckboxes.length === 0) {
|
||||
Swal.fire({
|
||||
title: 'No record selected',
|
||||
text: 'Please select at least one record to archive.',
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Get the IDs of the checked checkboxes
|
||||
var ids = checkedCheckboxes.map(function() {
|
||||
return $(this).val();
|
||||
}).get();
|
||||
// Perform archive action with the collected user IDs
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: 'Once archived, you will recover it from archive list!',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#d33',
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Yes, archive it!'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
// Perform archive action
|
||||
$.ajax({
|
||||
url: actionUrl, // Replace with your archive endpoint
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: "unarchive",
|
||||
ids: ids,
|
||||
csrfmiddlewaretoken: '{{csrf_token}}'
|
||||
},
|
||||
success: function(response) {
|
||||
// Show success message
|
||||
Swal.fire({
|
||||
title: 'Done!',
|
||||
text: response.msg,
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
HideButton("buttons-unarchive");
|
||||
// Optionally, you can reload the DataTable after successful archive
|
||||
reloadDataTable();
|
||||
},
|
||||
error: function(response) {
|
||||
// Show error message
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message,
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -179,7 +179,7 @@ function renderResources(data, type, row) {
|
||||
if (type === 'display' && row.resources) {
|
||||
let html = '<ul>';
|
||||
for (const [resource, actions] of Object.entries(row.resources)) {
|
||||
html += `<li class="mb-1"><span class="badge badge-primary">${resource}</span>`;
|
||||
html += `<li class="mb-1 d-flex gap-2"><span class="badge badge-primary">${resource}</span>`;
|
||||
for (const action of actions) {
|
||||
html += `<span class="badge badge-secondary">${action}</span>`;
|
||||
}
|
||||
|
||||
@@ -40,18 +40,20 @@
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
<th class="checkbox-column dt-no-sorting text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending" style="width: 50.2656px;">
|
||||
#</th>
|
||||
<th class="sorting_asc text-center" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 50.2656px;">#</th>
|
||||
aria-sort="ascending" style="width: 50.2656px;">Record Id</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1" style="width: 44.2344px;">Title</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
colspan="1" style="width: 44.2344px;">Message</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
colspan="1" style="width: 44.2344px;">Created on</th>
|
||||
<th class="sorting text-center" tabindex="5" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Active</th>
|
||||
<th class="sorting text-center" tabindex="6" aria-controls="style-3"
|
||||
<th class="text-center dt-no-sorting" tabindex="6" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
273
templates/module_notification/notification_archive.html
Normal file
273
templates/module_notification/notification_archive.html
Normal file
@@ -0,0 +1,273 @@
|
||||
{% extends 'base_structure/layout/base_template.html' %}
|
||||
{% load static %}
|
||||
{% block stylesheet %}
|
||||
<!-- include required css cdn link through html here -->
|
||||
|
||||
{% 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 %}
|
||||
|
||||
<div class="row layout-top-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<a href="{% url 'module_notification:notification'%}" style="height: fit-content;width: fit-content;display: inline-block;">
|
||||
<h3 class="card-title m-2 d-flex align-items-center gap-2" style="width: fit-content;"><span class="fw-bold material-symbols-outlined">
|
||||
arrow_back
|
||||
</span><span>Archive Notification</span></h3>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row layout-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="statbox widget box box-shadow">
|
||||
<div class="widget-content widget-content-area">
|
||||
<div id="table_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4 no-footer">
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="table" class="table style-3 dt-table-hover dataTable" role="grid"
|
||||
aria-describedby="style-3_info">
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column dt-no-sorting text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending" style="width: 50.2656px;">
|
||||
#</th>
|
||||
<th class="sorting_asc text-center" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 50.2656px;">Record Id</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1" style="width: 44.2344px;">Title</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
colspan="1" style="width: 44.2344px;">Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
|
||||
<!-- include required css cdn link through html here -->
|
||||
|
||||
{% 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" %}
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
// Define DataTable instance
|
||||
var dataTableInstance;
|
||||
var mainUrl = "{% url 'module_notification:notification_list' %}?deleted_flag=True"
|
||||
var actionUrl = '{% url "module_notification:notification_action" %}'
|
||||
|
||||
// Entry point
|
||||
$(document).ready(function() {
|
||||
|
||||
tableName = $('#table');
|
||||
dataTableInstance = initializeDataTable(tableName, mainUrl);
|
||||
});
|
||||
|
||||
// Function to initialize DataTable
|
||||
function initializeDataTable(tableName, mainUrl) {
|
||||
return tableName.DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
url: mainUrl,
|
||||
type: "GET",
|
||||
},
|
||||
columns: [
|
||||
{ data: null, className: "text-center", render: renderCheckbox },
|
||||
{ data: "id", className: "text-center" },
|
||||
{ data: "title", className: "text-center" },
|
||||
{ data: "message", className: "text-center" }
|
||||
],
|
||||
debug: true,
|
||||
columnDefs: [
|
||||
{
|
||||
targets: [3],
|
||||
render: function (data, type, row) {
|
||||
// Adjust the length of text you want to show before truncating
|
||||
var maxLength = 40;
|
||||
// Truncate the text if it exceeds the maxLength
|
||||
var truncatedText = data.length > maxLength ? data.substr(0, maxLength) + '...' : data;
|
||||
// Return the truncated text
|
||||
return truncatedText;
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: [1, 2, 3],
|
||||
searchable: true,
|
||||
orderable: true
|
||||
},
|
||||
{
|
||||
targets: [0], // Targeting the first and last column (action column)
|
||||
searchable: false,
|
||||
orderable: false
|
||||
},
|
||||
],
|
||||
orderCellsTop: true,
|
||||
dom: "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
buttons: [
|
||||
{
|
||||
text: 'UnArchive',
|
||||
className: "btn btn-dark buttons-unarchive",
|
||||
action: unArchiveAction,
|
||||
init: function(api, node, config){
|
||||
$(node).hide();
|
||||
}
|
||||
}
|
||||
],
|
||||
oLanguage: {
|
||||
oPaginate: { "sPrevious": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>', "sNext": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>' },
|
||||
sInfo: "Showing page _PAGE_ of _PAGES_",
|
||||
sSearch: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>',
|
||||
sSearchPlaceholder: "Search...",
|
||||
sLengthMenu: " _MENU_",
|
||||
},
|
||||
stripeClasses: [],
|
||||
lengthMenu: [5, 10, 20, 50],
|
||||
pageLength: 10,
|
||||
initComplete: initCompleteCallback
|
||||
});
|
||||
}
|
||||
|
||||
// Function to reload the DataTable
|
||||
function reloadDataTable() {
|
||||
dataTableInstance.ajax.reload();
|
||||
}
|
||||
|
||||
// Render checkbox
|
||||
function renderCheckbox(data, type, row) {
|
||||
|
||||
var checkboxHTML = '<div class="form-check form-check-danger">';
|
||||
checkboxHTML += '<input class="form-check-input archive-checkbox" type="checkbox" value="' + row.id + '" data-id="'+ row.id +'" id="checkbox-' + row.id + '">';
|
||||
checkboxHTML += '</div>';
|
||||
return checkboxHTML;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Render actions
|
||||
function renderActions(data, type, row) {
|
||||
return `
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink${row.id}" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-more-horizontal"><circle cx="12" cy="12" r="1"></circle><circle cx="19" cy="12" r="1"></circle><circle cx="5" cy="12" r="1"></circle></svg>
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink${row.id}" style="">
|
||||
<a class="dropdown-item view" href="javascript:void(0);" data-id="${row.id}">View</a>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var table = this.api();
|
||||
var tableId = this.api().table().node().id;
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $(`#${tableId} tbody input.archive-checkbox:checked`).length;
|
||||
var unarchiveButton = $('.buttons-unarchive');
|
||||
console.log("checkbox is checked", + checkedCount)
|
||||
unarchiveButton.toggle(checkedCount > 0);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function HideButton(className) {
|
||||
// Hide archive button
|
||||
$(`.${className}`).hide();
|
||||
}
|
||||
|
||||
|
||||
// Function to handle archive action
|
||||
function unArchiveAction() {
|
||||
// Get all the checked checkboxes
|
||||
var checkedCheckboxes = $('.archive-checkbox:checked');
|
||||
// If no checkboxes are checked, show an error message
|
||||
if (checkedCheckboxes.length === 0) {
|
||||
Swal.fire({
|
||||
title: 'No record selected',
|
||||
text: 'Please select at least one record to archive.',
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Get the IDs of the checked checkboxes
|
||||
var ids = checkedCheckboxes.map(function() {
|
||||
return $(this).val();
|
||||
}).get();
|
||||
// Perform archive action with the collected user IDs
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: 'Once archived, you will recover it from archive list!',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#d33',
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Yes, archive it!'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
// Perform archive action
|
||||
$.ajax({
|
||||
url: actionUrl, // Replace with your archive endpoint
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: "unarchive",
|
||||
ids: ids,
|
||||
csrfmiddlewaretoken: '{{csrf_token}}'
|
||||
},
|
||||
success: function(response) {
|
||||
// Show success message
|
||||
Swal.fire({
|
||||
title: 'Done!',
|
||||
text: response.msg,
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
HideButton("buttons-unarchive");
|
||||
// Optionally, you can reload the DataTable after successful archive
|
||||
reloadDataTable();
|
||||
},
|
||||
error: function(response) {
|
||||
// Show error message
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message,
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -33,50 +33,52 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="statbox widget box box-shadow">
|
||||
<div class="widget-content widget-content-area">
|
||||
<div id="faqs_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4 no-footer">
|
||||
<div id="table_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4 no-footer">
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="faqs" class="table style-3 dt-table-hover dataTable" role="grid"
|
||||
<table id="table" class="table style-3 dt-table-hover dataTable" role="grid"
|
||||
aria-describedby="style-3_info">
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
<th class="checkbox-column text-center dt-no-sorting" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
<th class="sorting_asc text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
style="width: 50.2656px;">RecordId</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Email Address</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Subject</th>
|
||||
<th class="sorting text-center" tabindex="3" aria-controls="style-3"
|
||||
<th class="sorting text-center" tabindex="3" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Message</th>
|
||||
<th class="sorting text-center" tabindex="4" aria-controls="style-3"
|
||||
<th class="sorting text-center" tabindex="4" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Reply</th>
|
||||
<th class="sorting text-center" tabindex="5" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Active</th>
|
||||
<th class="sorting text-center" tabindex="6" aria-controls="style-3"
|
||||
<th class="sorting text-center dt-no-sorting" tabindex="4" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Status</th>
|
||||
<th class="text-center dt-no-sorting" tabindex="6" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead id="filterboxrow">
|
||||
<tr>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th rowspan="1" colspan="1">Email Address</th>
|
||||
<th rowspan="1" colspan="1">Subject</th>
|
||||
<th rowspan="1" colspan="1">Message</th>
|
||||
<th rowspan="1" colspan="1">Reply</th>
|
||||
<th class="invisible" rowspan="1" colspan="1">Active</th>
|
||||
<th class="invisible" rowspan="1" colspan="1">Action</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
@@ -193,7 +195,7 @@ var replyUrl = "{% url 'module_support:contact_us_reply' id=0 %}"
|
||||
// Entry point
|
||||
$(document).ready(function() {
|
||||
|
||||
tableName = $('#faqs');
|
||||
tableName = $('#table');
|
||||
dataTableInstance = initializeDataTable(tableName, mainUrl);
|
||||
viewClickEvent(dataTableInstance)
|
||||
replyEvent(dataTableInstance)
|
||||
@@ -217,12 +219,29 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
{ data: "message" },
|
||||
{ data: "reply" },
|
||||
{ data: "active", className: "text-center", render: renderSwitch },
|
||||
{
|
||||
data: "reply",
|
||||
className: "text-center",
|
||||
render: function(data, type, row, meta) {
|
||||
var badgeText = "";
|
||||
if (data) {
|
||||
badgeText = "Completed";
|
||||
} else {
|
||||
badgeText = "Pending";
|
||||
// Change class name for pending badge
|
||||
return '<span class="badge badge-danger">' + badgeText + '</span>';
|
||||
}
|
||||
|
||||
// Return badge for completed items (optional)
|
||||
return '<span class="badge badge-primary">' + badgeText + '</span>';
|
||||
}
|
||||
},
|
||||
{ data: null, className: "text-center", render: renderActions }
|
||||
],
|
||||
debug: true,
|
||||
columnDefs: [
|
||||
{
|
||||
"targets": [3,4,5],
|
||||
"targets": [4, 5, 6],
|
||||
"render": function (data, type, row) {
|
||||
// Adjust the length of text you want to show before truncating
|
||||
var maxLength = 40;
|
||||
@@ -233,16 +252,17 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: [1, 2, 3],
|
||||
targets: [1, 2, 3, 4, 5, 6],
|
||||
searchable: true,
|
||||
orderable: true
|
||||
},
|
||||
{
|
||||
targets: [0,-1], // Targeting the last column (action column)
|
||||
targets: [0,7,-1], // Targeting the first and last column (action column)
|
||||
searchable: false,
|
||||
orderable: false
|
||||
},
|
||||
],
|
||||
orderCellsTop: true,
|
||||
dom: "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
@@ -278,6 +298,58 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
});
|
||||
}
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var table = this.api();
|
||||
var tableId = this.api().table().node().id;
|
||||
console.log(tableId);
|
||||
|
||||
// Specify the column indexes for individual searchable fields (adjust as needed)
|
||||
var searchableColumns = [1, 2, 3, 4, 5];
|
||||
// Specify the column indexes for select input fields (adjust as needed)
|
||||
var selectDropdownInputColumns = [6]
|
||||
|
||||
table.columns(searchableColumns).every(function() {
|
||||
var column = this;
|
||||
var title = $(this.header()).text().trim(); // Get the column title
|
||||
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '" />')
|
||||
.appendTo($("thead tr:eq(1) th").eq(this.index()))
|
||||
.on("keyup", function() {
|
||||
if (column.search() !== this.value) {
|
||||
column.search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $(`#${tableId} tbody input.archive-checkbox:checked`).length;
|
||||
var archiveButton = $('.buttons-archive');
|
||||
console.log("checkbox is checked", + checkedCount)
|
||||
archiveButton.toggle(checkedCount > 0);
|
||||
});
|
||||
|
||||
table.columns(selectDropdownInputColumns).every( function () {
|
||||
var column = this;
|
||||
console.log( column.index() );
|
||||
var nodeBelow = $(column.header()).closest('tr').next().children().eq( column.index() );
|
||||
var select = $('<select class="form-control"><option value="">All</option></select>')
|
||||
.appendTo( $(nodeBelow).empty() )
|
||||
.on( 'change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
if (column.search() !== this.value) {
|
||||
column.search(val).draw();
|
||||
}
|
||||
} );
|
||||
column.data().unique().sort().each( function ( d, j ) {
|
||||
console.log(`data is ${d}`)
|
||||
select.append( '<option value="'+d+'">'+d+'</option>' )
|
||||
} );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Function to reload the DataTable
|
||||
function reloadDataTable() {
|
||||
dataTableInstance.ajax.reload();
|
||||
@@ -315,6 +387,12 @@ function renderActions(data, type, row) {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function HideButton(className) {
|
||||
// Hide archive button
|
||||
$(`.${className}`).hide();
|
||||
}
|
||||
|
||||
|
||||
// Function to handle archive action
|
||||
function archiveAction() {
|
||||
// Get all the checked checkboxes
|
||||
@@ -322,8 +400,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
|
||||
});
|
||||
@@ -361,6 +439,7 @@ function archiveAction() {
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
HideButton("buttons-archive");
|
||||
// Optionally, you can reload the DataTable after successful archive
|
||||
reloadDataTable();
|
||||
},
|
||||
@@ -378,32 +457,7 @@ function archiveAction() {
|
||||
});
|
||||
}
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var api = this.api();
|
||||
|
||||
// Add individual search inputs to the first row of the thead section
|
||||
$('thead#filterboxrow th').each(function (index) {
|
||||
var title = $(this).text();
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '"/>')
|
||||
.on('keyup change', function () {
|
||||
if (api.column(index).search() !== this.value) {
|
||||
api.column(index).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
|
||||
$(this).empty().append(input);
|
||||
});
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $('tbody input.archive-checkbox:checked').length;
|
||||
var archiveButton = $('.buttons-archive');
|
||||
console.log("checkbox is checked", + checkedCount)
|
||||
archiveButton.toggle(checkedCount > 0);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Function to handle click event for view button
|
||||
function viewClickEvent(dataTableInstance) {
|
||||
@@ -472,49 +526,49 @@ function replyEvent(dataTableInstance){
|
||||
$('#recipient-name').text(rowData.email_address);
|
||||
$('#replyId').val(id);
|
||||
$('#replyModal').modal('show');
|
||||
|
||||
$('#replyModal').on('click', '#submitReply', function(e) {
|
||||
e.preventDefault();
|
||||
var id = $('#replyId').val();
|
||||
var replyMessage = $('#reply-text').val();
|
||||
console.log(id, message)
|
||||
|
||||
// Call the AJAX request
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: replyUrl.replace("0", id),
|
||||
data: { message: replyMessage, csrfmiddlewaretoken: '{{csrf_token}}' },
|
||||
success: function(response) {
|
||||
console.log('Response from server:', response);
|
||||
Swal.fire({
|
||||
title: 'Done!',
|
||||
text: response.msg,
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
// Close the modal
|
||||
$('#replyModal').modal('hide');
|
||||
|
||||
// Empty the input fields
|
||||
$('#reply-text').val('');
|
||||
// Reload the DataTable after successful toggle
|
||||
reloadDataTable();
|
||||
},
|
||||
error: function(error) {
|
||||
console.error('Error:', error);
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message,
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$('#replyModal').on('click', '#submitReply', function(e) {
|
||||
e.preventDefault();
|
||||
var id = $('#replyId').val();
|
||||
var replyMessage = $('#reply-text').val();
|
||||
console.log(id, replyMessage)
|
||||
|
||||
// Call the AJAX request
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: replyUrl.replace("0", id),
|
||||
data: { message: replyMessage, csrfmiddlewaretoken: '{{csrf_token}}' },
|
||||
success: function(response) {
|
||||
console.log('Response from server:', response);
|
||||
Swal.fire({
|
||||
title: 'Done!',
|
||||
text: response.msg,
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
// Close the modal
|
||||
$('#replyModal').modal('hide');
|
||||
|
||||
// Empty the input fields
|
||||
$('#reply-text').val('');
|
||||
// Reload the DataTable after successful toggle
|
||||
reloadDataTable();
|
||||
},
|
||||
error: function(error) {
|
||||
console.error('Error:', error);
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message,
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<a href="{% url 'module_cms:privacy_policy'%}" style="height: fit-content;width: fit-content;display: inline-block;">
|
||||
<a href="{% url 'module_support:contact_us'%}" style="height: fit-content;width: fit-content;display: inline-block;">
|
||||
<h3 class="card-title m-2 d-flex align-items-center gap-2" style="width: fit-content;"><span class="fw-bold material-symbols-outlined">
|
||||
arrow_back
|
||||
</span><span>Archive Contact Us</span></h3>
|
||||
@@ -36,39 +36,37 @@
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
<th class="checkbox-column text-center dt-no-sorting" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
style="width: 50.2656px;">Record Id</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Email Address</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Subject</th>
|
||||
<th class="sorting text-center" tabindex="3" aria-controls="style-3"
|
||||
<th class="sorting text-center" tabindex="3" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Message</th>
|
||||
<th class="sorting text-center" tabindex="4" aria-controls="style-3"
|
||||
<th class="sorting text-center" tabindex="4" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Reply</th>
|
||||
<th class="sorting text-center" tabindex="6" aria-controls="style-3"
|
||||
<th class="sorting text-center dt-no-sorting" tabindex="6" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead id="filterboxrow">
|
||||
<tr>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th class="text-center" rowspan="1" colspan="1">id</th>
|
||||
<th rowspan="1" colspan="1">Email Address</th>
|
||||
<th rowspan="1" colspan="1">Subject</th>
|
||||
<th rowspan="1" colspan="1">Message</th>
|
||||
<th rowspan="1" colspan="1">Reply</th>
|
||||
<th class="invisible" rowspan="1" colspan="1">Action</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
@@ -179,7 +177,7 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
debug: true,
|
||||
columnDefs: [
|
||||
{
|
||||
"targets": [3,4,5],
|
||||
"targets": [3, 4, 5],
|
||||
"render": function (data, type, row) {
|
||||
// Adjust the length of text you want to show before truncating
|
||||
var maxLength = 40;
|
||||
@@ -190,16 +188,17 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: [1, 2, 3],
|
||||
targets: [1, 2, 3, 4, 5],
|
||||
searchable: true,
|
||||
orderable: true
|
||||
},
|
||||
{
|
||||
targets: [0,-1], // Targeting the last column (action column)
|
||||
targets: [0,-1], // Targeting the first and last column (action column)
|
||||
searchable: false,
|
||||
orderable: false
|
||||
},
|
||||
],
|
||||
orderCellsTop: true,
|
||||
dom: "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
@@ -259,24 +258,29 @@ function renderActions(data, type, row) {
|
||||
|
||||
// Callback function for DataTable initialization complete event
|
||||
function initCompleteCallback() {
|
||||
var api = this.api();
|
||||
var table = this.api();
|
||||
var tableId = this.api().table().node().id;
|
||||
console.log(tableId);
|
||||
|
||||
// Specify the column indexes for individual searchable fields (adjust as needed)
|
||||
var searchableColumns = [1, 2, 3, 4, 5, 6];
|
||||
|
||||
// Add individual search inputs to the first row of the thead section
|
||||
$('thead#filterboxrow th').each(function (index) {
|
||||
var title = $(this).text();
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '"/>')
|
||||
.on('keyup change', function () {
|
||||
if (api.column(index).search() !== this.value) {
|
||||
api.column(index).search(this.value).draw();
|
||||
}
|
||||
});
|
||||
|
||||
$(this).empty().append(input);
|
||||
table.columns(searchableColumns).every(function() {
|
||||
var column = this;
|
||||
var title = $(this.header()).text().trim(); // Get the column title
|
||||
|
||||
var input = $('<input type="text" class="form-control" placeholder="Search ' + title + '" />')
|
||||
.appendTo($("thead tr:eq(1) th").eq(this.index()))
|
||||
.on("keyup", function() {
|
||||
if (column.search() !== this.value) {
|
||||
column.search(this.value).draw();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add event listener for checkbox change
|
||||
$('body').on('change', 'input[type="checkbox"]', function () {
|
||||
var checkedCount = $('tbody input.archive-checkbox:checked').length;
|
||||
var checkedCount = $(`#${tableId} tbody input.archive-checkbox:checked`).length;
|
||||
var unarchiveButton = $('.buttons-unarchive');
|
||||
console.log("checkbox is checked", + checkedCount)
|
||||
unarchiveButton.toggle(checkedCount > 0);
|
||||
@@ -284,6 +288,11 @@ function initCompleteCallback() {
|
||||
|
||||
}
|
||||
|
||||
function HideButton(className) {
|
||||
// Hide archive button
|
||||
$(`.${className}`).hide();
|
||||
}
|
||||
|
||||
// Function to handle click event for view button
|
||||
function viewClickEvent(dataTableInstance) {
|
||||
$('body').on('click', '.view', function(){
|
||||
@@ -347,6 +356,7 @@ function unArchiveAction() {
|
||||
icon: 'success',
|
||||
showConfirmButton: true
|
||||
});
|
||||
HideButton("buttons-unarchive");
|
||||
// Optionally, you can reload the DataTable after successful archive
|
||||
reloadDataTable();
|
||||
},
|
||||
|
||||
@@ -43,13 +43,13 @@
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc text-center" tabindex="0"
|
||||
aria-controls="style-3" aria-sort="ascending"
|
||||
style="width: 50.2656px;">#</th>
|
||||
style="width: 50.2656px;">Record Id</th>
|
||||
<th class="sorting text-center" tabindex="1" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Email Address</th>
|
||||
<th class="sorting text-center" tabindex="2" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Subject</th>
|
||||
style="width: 44.2344px;">Reaction</th>
|
||||
<th class="sorting text-center" tabindex="3" aria-controls="style-3"
|
||||
colspan="1"
|
||||
style="width: 44.2344px;">Message</th>
|
||||
@@ -161,8 +161,8 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
debug: true,
|
||||
columnDefs: [
|
||||
{
|
||||
"targets": [3],
|
||||
"render": function (data, type, row) {
|
||||
targets: [3],
|
||||
render: function (data, type, row) {
|
||||
// Adjust the length of text you want to show before truncating
|
||||
var maxLength = 40;
|
||||
// Truncate the text if it exceeds the maxLength
|
||||
@@ -172,10 +172,10 @@ function initializeDataTable(tableName, mainUrl) {
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: [1, 2, 3],
|
||||
targets: [0, 1, 2, 3],
|
||||
searchable: true,
|
||||
orderable: true
|
||||
}
|
||||
},
|
||||
],
|
||||
dom: "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'Bf>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
|
||||
Reference in New Issue
Block a user