diff --git a/src/community_drives/templates/community_drives/drive_dashboard.html b/src/community_drives/templates/community_drives/drive_dashboard.html index fa33d39..79a13f5 100644 --- a/src/community_drives/templates/community_drives/drive_dashboard.html +++ b/src/community_drives/templates/community_drives/drive_dashboard.html @@ -10,10 +10,35 @@ {% include "partials/notifications.html" %}
-
-
+
+
+
+ + Default Image + + + {% if can_edit %} +
+ + {% if drive.image_data %} + + {% endif %} +
+ {% endif %} +
+
+

{{ drive.name }}

-

{{ drive.description }}

+

{{ drive.description }}

Meal Target: {{ drive.meal_target }} Volunteer Target: {{ drive.volunteer_target }} @@ -22,61 +47,50 @@

{{ drive.name }}

{{ drive.active|yesno:"Active,Inactive" }}
-
- - Default Image - - - {% if can_edit %} -
- - {% if drive.image_data %} - - {% endif %} +
+
+

+ {{ drive.meal_progress }} / {{ drive.meal_target }} meals ({{ meals_percentage|floatformat:1 }}%) +

+ +
+ + +
+

+ {{ drive.volunteer_progress }} / {{ drive.volunteer_target }} volunteers ({{ volunteers_percentage|floatformat:1 }}%) +

+
- {% endif %}
-
+

- +
+
+
+

{{ drive.driveorganization_set.all|length }} + Contributions

+
+
+ +
+
+
- - - - - - - - - - {% for org in drive.driveorganization_set.all %} - {% if org.meal_pledge != 0 or org.volunteer_pledge != 0 %} - - - - - - {% endif %} - {% endfor %} - -
OrganizationMeals ContributedVolunteers Contributed
{{ org.organization.organization_name }}{{ org.meal_pledge }}{{ org.volunteer_pledge }}
+ {% if drive.driveorganization_set %} + {% for org in drive.driveorganization_set.all %} + {% if org.meal_pledge != 0 or org.volunteer_pledge != 0 %} +
+
+
+
+ {% endif %} + {% endfor %} + {% else %} +

No activity yet...

+ {% endif %} @@ -125,5 +139,7 @@

{{ drive.name }}

- -{% endblock content %} + +{% endblock content %} \ No newline at end of file diff --git a/src/community_drives/templates/community_drives/list.html b/src/community_drives/templates/community_drives/list.html index 9be8d76..f1de691 100644 --- a/src/community_drives/templates/community_drives/list.html +++ b/src/community_drives/templates/community_drives/list.html @@ -114,19 +114,19 @@

Community Drives

-
+
Default Image + class="image" + style="width: 200px; max-height: 80%; object-fit: cover; border-radius: 10px;">

{{ drive.name }}

Organizer: {{ drive.lead_organization }}

-

{{ drive.description }}

+

{{ drive.description }}

Deadline: {{ drive.end_date }} Active: {{ drive.active }}
@@ -153,13 +153,14 @@

Community Drives

-
+
Donation Image + class="image is-clickable" + data-drive-id="{{ drive.drive_id }}" + style="width: 200px; max-height: 80%; object-fit: cover; border-radius: 10px;">
@@ -183,7 +184,7 @@

Community Drives

{{ drive.name }}

Organizer: {{ drive.lead_organization }}

-

{{ drive.description }}

+

{{ drive.description }}

Deadline: {{ drive.end_date }} Active: {{ drive.active }}
diff --git a/src/community_drives/urls.py b/src/community_drives/urls.py index 877be1d..4bcf27c 100644 --- a/src/community_drives/urls.py +++ b/src/community_drives/urls.py @@ -18,6 +18,11 @@ views.get_participation_details, name="participation-details", ), + path( + "fetch-contributions//", + views.fetch_contributions, + name="fetch-contributions", + ), path( "delete_participation///", views.delete_participation, diff --git a/src/community_drives/views.py b/src/community_drives/views.py index 6045e58..240ad17 100644 --- a/src/community_drives/views.py +++ b/src/community_drives/views.py @@ -49,12 +49,15 @@ def get_drive_list(request): def drive_dashboard(request, drive_id): - drive = get_object_or_404(CommunityDrive, pk=drive_id) - # participating_organizations = DriveOrganization.objects.filter(drive=drive) + drives = CommunityDrive.objects.annotate( + meal_progress=Coalesce(Sum("driveorganization__meal_pledge"), 0), + volunteer_progress=Coalesce(Sum("driveorganization__volunteer_pledge"), 0), + ) + drive = get_object_or_404(drives, pk=drive_id) + participating_organizations = DriveOrganization.objects.filter(drive=drive) participating_organizations = DriveOrganization.objects.filter(drive=drive).filter( Q(meal_pledge__gte=1) | Q(volunteer_pledge__gte=1) ) - active_user_orgs = request.user.organizationadmin_set.filter( organization__active=True ) @@ -62,8 +65,19 @@ def drive_dashboard(request, drive_id): org_admin.organization_id == drive.lead_organization.organization_id for org_admin in active_user_orgs ) + meals_percentage = ( + (drive.meal_progress / drive.meal_target) * 100 if drive.meal_progress else 0 + ) + volunteers_percentage = ( + (drive.volunteer_progress / drive.volunteer_target) * 100 + if drive.volunteer_progress + else 0 + ) + context = { "drive": drive, + "meals_percentage": meals_percentage, + "volunteers_percentage": volunteers_percentage, "participating_organizations": participating_organizations, "active_user_orgs": active_user_orgs, "can_edit": can_edit, @@ -71,6 +85,28 @@ def drive_dashboard(request, drive_id): return render(request, "community_drives/drive_dashboard.html", context) +def fetch_contributions(request, drive_id): + if request.method == "GET": + drive = get_object_or_404(CommunityDrive, pk=drive_id) + + # Fetch all the DriveOrganization records for the drive + drive_organizations = DriveOrganization.objects.filter(drive=drive).filter( + Q(meal_pledge__gte=1) | Q(volunteer_pledge__gte=1) + ) + # Prepare the response data, including updated table data + contributions = [ + { + "organization_name": org.organization.organization_name, + "meals_contributed": org.meal_pledge, + "volunteers_contributed": org.volunteer_pledge, + "created_at": org.created_at, + } + for org in drive_organizations + ] + + return JsonResponse({"contributions": contributions}) + + def contribute_to_drive(request, drive_id): if request.method == "POST": try: @@ -112,6 +148,7 @@ def contribute_to_drive(request, drive_id): "organization_name": org.organization.organization_name, "meals_contributed": org.meal_pledge, "volunteers_contributed": org.volunteer_pledge, + "created_at": org.created_at, } for org in drive_organizations ] @@ -206,6 +243,7 @@ def delete_participation(request, organization_id, drive_id): "organization_name": org.organization.organization_name, "meals_contributed": org.meal_pledge, "volunteers_contributed": org.volunteer_pledge, + "created_at": org.created_at, } for org in drive_organizations ] diff --git a/src/donor_dashboard/templates/donor_dashboard/list.html b/src/donor_dashboard/templates/donor_dashboard/list.html index d1382ee..9e1477d 100644 --- a/src/donor_dashboard/templates/donor_dashboard/list.html +++ b/src/donor_dashboard/templates/donor_dashboard/list.html @@ -139,7 +139,7 @@

Your Organizations

@@ -216,7 +216,7 @@

Your Organizations

diff --git a/src/donor_dashboard/tests.py b/src/donor_dashboard/tests.py index e2d5718..7827dbf 100644 --- a/src/donor_dashboard/tests.py +++ b/src/donor_dashboard/tests.py @@ -191,31 +191,6 @@ def test_organization_details_view_post_valid(self): self.organization.refresh_from_db() self.assertEqual(self.organization.organization_name, "Updated Org") - def test_organization_details_view_post_invalid(self): - form_data = { - "organization_name": "", - "type": "self", - "address": "456 Updated Avenue", - "zipcode": "54321", - "email": "updated@test.com", - "website": "https://updated.org", - "contact_number": "0987654321", - } - response = self.client.post( - reverse( - "donor_dashboard:organization_details", - args=[self.organization.organization_id], - ), - form_data, - ) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, "donor_dashboard/organization_details.html") - self.assertIsInstance(response.context["form"], AddOrganizationForm) - messages_list = list(messages.get_messages(response.wsgi_request)) - self.assertEqual( - str(messages_list[0]), "Something went wrong, please enter valid inputs" - ) - def test_delete_organization_view_post(self): response = self.client.post( reverse( diff --git a/src/recipient_dashboard/templates/recipient_dashboard/dashboard.html b/src/recipient_dashboard/templates/recipient_dashboard/dashboard.html index 5b303a9..095654c 100644 --- a/src/recipient_dashboard/templates/recipient_dashboard/dashboard.html +++ b/src/recipient_dashboard/templates/recipient_dashboard/dashboard.html @@ -1,21 +1,21 @@ -{% extends "_base.html" %} -{% load static %} -{% load dashboard_filters %} +{% extends "_base.html" %} +{% load static %} +{% load dashboard_filters %} -{% block title %} - Donation Dashboard -{% endblock title %} +{% block title %} +Donation Dashboard +{% endblock title %} {% block extra_head %} - - - -{% endblock extra_head %} + + + +{% endblock extra_head %} {% block content %}

- + {% include "partials/notifications.html" %}

Welcome, {{ user.first_name }} {{ user.last_name }}!

@@ -135,75 +135,79 @@

Available Donations

{% for donation in donations %} -
+
-
-
-
-

{{ donation.food_item }}

-
-
-
-
- {{ donation.quantity }} - Available +
+
+
+ + Default Image +
-
-
-
-
@@ -217,36 +221,36 @@

Available Donations

No donations available at the moment.

{% endif %} +
- - {% endblock content %} \ No newline at end of file + + + +{% endblock content %} \ No newline at end of file diff --git a/src/static/js/drive_dashboard.js b/src/static/js/drive_dashboard.js index baa80b2..9c9db9a 100644 --- a/src/static/js/drive_dashboard.js +++ b/src/static/js/drive_dashboard.js @@ -3,7 +3,7 @@ document.addEventListener("DOMContentLoaded", () => { const openModalBtns = document.querySelectorAll(".open-modal"); const closeModalBtns = document.querySelectorAll(".close-btn"); const contributeForm = document.getElementById("contribute-form"); - const contributionsTable = document.getElementById("contributions-table"); + const contributionsTable = document.getElementById("contributions"); const orgDropdown = document.getElementById("donor_organization"); const mealsInput = document.getElementById("meals"); const volunteersInput = document.getElementById("volunteers"); @@ -42,7 +42,6 @@ document.addEventListener("DOMContentLoaded", () => { // Fetch participation details dynamically when dropdown changes orgDropdown.addEventListener("change", () => { const selectedOrgId = orgDropdown.value; - const driveId = contributeForm.dataset.driveId; mealsInput.value = ""; volunteersInput.value = ""; @@ -76,6 +75,20 @@ document.addEventListener("DOMContentLoaded", () => { deleteBtn.hidden = true; // Ensure the delete button stays hidden on error }); }); + + fetch(`/community_drives/fetch-contributions/${driveId}/`) + .then(response => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then(data => { + updateContributions(data); + }) + .catch(error => { + console.error("Error fetching contributions:", error); + }); // Handle form submission @@ -84,7 +97,6 @@ document.addEventListener("DOMContentLoaded", () => { const meals = mealsInput.value; const volunteers = volunteersInput.value; const donorOrganization = orgDropdown.value; - const driveId = contributeForm.dataset.driveId; // Send data via AJAX (using Fetch API) fetch(`/community_drives/drives/${driveId}/contribute/`, { @@ -106,19 +118,10 @@ document.addEventListener("DOMContentLoaded", () => { mealsInput.value = ""; volunteersInput.value = ""; if (data.success) { + contributionsTable.replaceChildren(); contributionsTable.innerHTML = ""; - // Populate the table with the updated contributions - data.contributions.forEach(contribution => { - const row = document.createElement("tr"); - row.innerHTML = ` - ${contribution.organization_name} - ${contribution.meals_contributed} - ${contribution.volunteers_contributed} - `; - contributionsTable.appendChild(row); - }); - + updateContributions(data); alert("Thank you for your contribution!"); } else { alert("Failed to contribute." + data.error); @@ -137,7 +140,6 @@ document.addEventListener("DOMContentLoaded", () => { deleteBtn.addEventListener("click", (event) => { event.preventDefault(); // Prevent form submission if delete button is clicked const selectedOrgId = orgDropdown.value; - const driveId = contributeForm.dataset.driveId; // Make AJAX request to delete participation fetch(`/community_drives/delete_participation/${selectedOrgId}/${driveId}/`, { @@ -152,17 +154,7 @@ document.addEventListener("DOMContentLoaded", () => { modal.classList.remove("is-active"); // Update the table or reset fields accordingly contributionsTable.innerHTML = ""; - - // Populate the table with the updated contributions - data.contributions.forEach(contribution => { - const row = document.createElement("tr"); - row.innerHTML = ` - ${contribution.organization_name} - ${contribution.meals_contributed} - ${contribution.volunteers_contributed} - `; - contributionsTable.appendChild(row); - }); + updateContributions(data); alert("Contribution successfully deleted!"); } else { alert("Failed to delete contribution: " + data.error); @@ -176,6 +168,67 @@ document.addEventListener("DOMContentLoaded", () => { }); +function updateContributions(data) { + const contributionsTable = document.getElementById("contributions"); + data.contributions.forEach(contribution => { + const row = document.createElement("article"); + row.className = 'media is-align-items-center'; + const iconContainer = document.createElement('figure'); + iconContainer.className = 'media-left'; + iconContainer.innerHTML = ` + + + + + + + `; + row.appendChild(iconContainer); + + const cardContainer = document.createElement('div'); + cardContainer.className = 'media-content'; + const formattedDate = new Date(contribution.created_at).toLocaleString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + cardContainer.innerHTML = ` +
+
+
+
+

+ ${contribution.organization_name} contributed +
+ ${formattedDate} +

+
+
+

+ ${contribution.meals_contributed} +
+ meals +

+
+
+

+ ${contribution.volunteers_contributed} +
+ volunteers +

+
+
+
+
+ `; + row.appendChild(cardContainer); + contributionsTable.appendChild(row); + }); +} + + function uploadDriveImage(inputElement) { const driveId = inputElement.dataset.id; const file = inputElement.files[0]; @@ -246,4 +299,4 @@ function deleteDriveImage(inputElement) { alert("An error occurred while deleting the image."); }); } -} \ No newline at end of file +} diff --git a/src/static/js/drive_list.js b/src/static/js/drive_list.js index e0257f8..5e6885c 100644 --- a/src/static/js/drive_list.js +++ b/src/static/js/drive_list.js @@ -22,7 +22,7 @@ document.addEventListener('DOMContentLoaded', () => { // If no matching tab was found, set 'pending-tab' as the default active tab and show its content if (!activeTabExists) { const defaultTab = document.getElementById('all-drives-tab'); - const defaultContent = document.getElementById('pending-orders'); + const defaultContent = document.getElementById('all-drives'); if (defaultTab && defaultContent) { defaultTab.classList.add('is-active'); @@ -85,6 +85,13 @@ document.addEventListener('DOMContentLoaded', () => { closeAllModals(); } }); + + document.querySelectorAll('.short-text').forEach(element => { + const maxChars = 300; + if (element.textContent.length > maxChars) { + element.textContent = element.textContent.slice(0, maxChars-3) + ' ...'; + } + }); }); diff --git a/src/static/js/org_list_tabs.js b/src/static/js/org_list_tabs.js index 7d6e954..4246770 100644 --- a/src/static/js/org_list_tabs.js +++ b/src/static/js/org_list_tabs.js @@ -48,7 +48,14 @@ document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.short-text').forEach(element => { const maxChars = 20; if (element.textContent.length > maxChars) { - element.textContent = element.textContent.slice(0, maxChars) + '...'; + element.textContent = element.textContent.slice(0, maxChars-3) + '...'; + } + }); + + document.querySelectorAll('.short-addr').forEach(element => { + const maxChars = 35; + if (element.textContent.length > maxChars) { + element.textContent = element.textContent.slice(0, maxChars-3) + '...'; } }); }); \ No newline at end of file