mirror of
https://github.com/Sosokker/ku-polls.git
synced 2025-12-18 21:14:05 +01:00
Merge pull request #26 from Sosokker/iteration2
Iteration2 - Update UI + Fix pub_date to editable + Format with prettier and black.py
This commit is contained in:
commit
287c69e9db
@ -26,15 +26,8 @@ SECRET_KEY = config('SECRET_KEY', default='k2pd1p)zwe0qy0k25=sli+7+n^vd-0h*&6vga
|
||||
#! SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = config('DEBUG', default=False, cast=bool)
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='*', cast=Csv())
|
||||
|
||||
TIME_ZONE = config('TIME_ZONE', default='UTC', cast=str)
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
@ -113,7 +106,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = config('TIME_ZONE', default='UTC', cast=str)
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
@ -124,6 +117,9 @@ USE_TZ = True
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
# ! On production -> Configure your web server to serve the files in STATIC_ROOT under the URL STATIC_URL
|
||||
# * https://docs.djangoproject.com/en/4.2/howto/static-files/deployment/
|
||||
STATIC_ROOT = BASE_DIR / "assets"
|
||||
STATICFILES_DIRS = [BASE_DIR]
|
||||
|
||||
# Default primary key field type
|
||||
|
||||
@ -11,6 +11,7 @@ class ChoiceInline(admin.TabularInline):
|
||||
class QuestionAdmin(admin.ModelAdmin):
|
||||
fieldsets = [
|
||||
(None, {"fields": ["question_text"]}),
|
||||
("Published date", {"fields": ["pub_date"], "classes": ["collapse"]}),
|
||||
("End date", {"fields": ["end_date"], "classes": ["collapse"]}),
|
||||
("Vote count", {"fields": ["up_vote_count", "down_vote_count"]}),
|
||||
("Participant count", {"fields": ["participant_count"]}),
|
||||
|
||||
19
polls/migrations/0008_alter_question_pub_date.py
Normal file
19
polls/migrations/0008_alter_question_pub_date.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.4 on 2023-09-09 15:16
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('polls', '0007_question_participant_count'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='question',
|
||||
name='pub_date',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='date published'),
|
||||
),
|
||||
]
|
||||
@ -23,16 +23,32 @@ class Question(models.Model):
|
||||
Attributes:
|
||||
question_text (str): The text of the poll question.
|
||||
pub_date (datetime): The date and time when the question was published.
|
||||
end_date (datetime): The date and time when the question will end.
|
||||
long_description (str): The long description of the poll question.
|
||||
short_description (str): The short description of the poll question.
|
||||
up_vote_count (int): The number of up votes the question has received.
|
||||
down_vote_count (int): The number of down votes the question has received.
|
||||
participant_count (int): The number of participants in the poll.
|
||||
"""
|
||||
|
||||
question_text = models.CharField(max_length=100)
|
||||
short_description = models.CharField(max_length=200, default="Cool kids have polls")
|
||||
long_description = models.TextField(max_length=2000, default="No description provide for this poll.")
|
||||
pub_date = models.DateTimeField("date published", default=timezone.now, editable=False)
|
||||
long_description = models.TextField(
|
||||
max_length=2000, default="No description provide for this poll."
|
||||
)
|
||||
pub_date = models.DateTimeField(
|
||||
"date published", default=timezone.now, editable=True
|
||||
)
|
||||
end_date = models.DateTimeField("date ended", null=True)
|
||||
up_vote_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
|
||||
down_vote_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
|
||||
participant_count = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
|
||||
up_vote_count = models.PositiveIntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]
|
||||
)
|
||||
down_vote_count = models.PositiveIntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]
|
||||
)
|
||||
participant_count = models.PositiveIntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]
|
||||
)
|
||||
|
||||
def was_published_recently(self):
|
||||
"""
|
||||
@ -101,13 +117,13 @@ class Question(models.Model):
|
||||
|
||||
time_left_str = ""
|
||||
if days > 0:
|
||||
time_left_str += f"{int(days)} D "
|
||||
time_left_str += f"{int(days)} Days "
|
||||
elif hours > 0:
|
||||
time_left_str += f"{int(hours)} H "
|
||||
time_left_str += f"{int(hours)} Hours "
|
||||
elif minutes > 0:
|
||||
time_left_str += f"{int(minutes)} M "
|
||||
time_left_str += f"{int(minutes)} Mins "
|
||||
elif seconds > 0:
|
||||
time_left_str += f"{int(seconds)} S "
|
||||
time_left_str += f"{int(seconds)} Sec "
|
||||
|
||||
return time_left_str.strip()
|
||||
|
||||
@ -116,6 +132,7 @@ class Question(models.Model):
|
||||
return self.calculate_time_left()
|
||||
|
||||
def calculate_vote_percentage(self):
|
||||
"""Calculate the percentage of up votes and down votes."""
|
||||
total_vote = self.up_vote_count + self.down_vote_count
|
||||
if total_vote == 0:
|
||||
return (0, 0)
|
||||
@ -146,25 +163,32 @@ class Choice(models.Model):
|
||||
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE)
|
||||
choice_text = models.CharField(max_length=200)
|
||||
votes = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)])
|
||||
votes = models.PositiveIntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(2147483647)]
|
||||
)
|
||||
|
||||
def tailwind_width_class(self):
|
||||
"""
|
||||
Calculate and return the Tailwind CSS width class based on the 'votes' percentage.
|
||||
"""
|
||||
total_votes = self.question.choice_set.aggregate(Sum('votes')).get('votes__sum', 0)
|
||||
total_votes = self.question.choice_set.aggregate(Sum("votes")).get(
|
||||
"votes__sum", 0
|
||||
)
|
||||
#! Tailwind w-0 to w-48
|
||||
if total_votes == 0:
|
||||
return 'w-0'
|
||||
return "w-0"
|
||||
|
||||
ratio = self.votes / total_votes
|
||||
|
||||
scaled_value = ratio * 48
|
||||
|
||||
return f'w-{int(round(scaled_value))}'
|
||||
return f"w-{int(round(scaled_value))}"
|
||||
|
||||
def calculate_percentage(self):
|
||||
total_votes_for_question = self.question.choice_set.aggregate(Sum('votes'))['votes__sum'] or 0
|
||||
"""Calculate percentage of votes for all choices."""
|
||||
total_votes_for_question = (
|
||||
self.question.choice_set.aggregate(Sum("votes"))["votes__sum"] or 0
|
||||
)
|
||||
|
||||
if total_votes_for_question == 0:
|
||||
return 0
|
||||
@ -176,4 +200,3 @@ class Choice(models.Model):
|
||||
Returns a string representation of the choice.
|
||||
"""
|
||||
return self.choice_text
|
||||
|
||||
38
polls/static/polls/js/detail.js
Normal file
38
polls/static/polls/js/detail.js
Normal file
@ -0,0 +1,38 @@
|
||||
const toggleChoice = (button, choiceId) => {
|
||||
const choiceInput = document.querySelector(`input[name="choice"][value="${choiceId}"]`);
|
||||
|
||||
if (choiceInput) {
|
||||
// already selected -> unselect it
|
||||
if (choiceInput.checked) {
|
||||
choiceInput.checked = false;
|
||||
button.classList.remove('bg-green-500', 'border-solid', 'border-2', 'border-black', 'hover:bg-green-600');
|
||||
button.classList.add('bg-white', 'border-solid', 'border-2', 'border-black', 'hover:bg-white');
|
||||
// Clear display
|
||||
document.getElementById('selected-choice').textContent = 'Please Select a Choice😊';
|
||||
} else {
|
||||
// Unselect all choices
|
||||
document.querySelectorAll('input[name="choice"]').forEach((choice) => {
|
||||
choice.checked = false;
|
||||
});
|
||||
|
||||
// Select the clicked choice
|
||||
choiceInput.checked = true;
|
||||
|
||||
// Reset the style of all choice buttons
|
||||
document.querySelectorAll('.choice-button').forEach((btn) => {
|
||||
btn.classList.remove('bg-green-500', 'border-solid', 'border-2', 'border-black', 'hover:bg-green-600');
|
||||
btn.classList.add('bg-white', 'border-solid', 'border-2', 'border-black', 'hover:bg-white');
|
||||
});
|
||||
|
||||
button.classList.remove('bg-white', 'border-solid', 'border-2', 'border-black', 'hover:bg-white');
|
||||
button.classList.add('bg-green-500', 'border-solid', 'border-2', 'border-black', 'hover:bg-green-600');
|
||||
|
||||
const choiceText = button.textContent.trim();
|
||||
document.getElementById('selected-choice').textContent = `You select: ${choiceText}`;
|
||||
}
|
||||
|
||||
// Enable the "Vote" button -> if select
|
||||
const voteButton = document.getElementById('vote-button');
|
||||
voteButton.disabled = !document.querySelector('input[name="choice"]:checked');
|
||||
}
|
||||
};
|
||||
@ -2,16 +2,20 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/htmx.org@1.7.0/dist/htmx.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<title>Your Poll Website</title>
|
||||
</head>
|
||||
<body class="bg-gray-100">
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
</body>
|
||||
</html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script
|
||||
src="https://unpkg.com/htmx.org@1.9.5"
|
||||
integrity="sha384-xcuj3WpfgjlKF+FXhSQFQ0ZNr39ln+hwjN3npfM9VBnUskLolQAcN80McRIVOPuO"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="{% static 'polls/js/detail.js' %}"></script>
|
||||
<script src="{% static 'polls/base.css' %}"></script>
|
||||
<title>Your Poll Website</title>
|
||||
</head>
|
||||
<body class="bg-neutral-100">
|
||||
{% block content %} {% endblock content %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,110 +1,102 @@
|
||||
{% extends 'polls/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% extends 'polls/base.html' %} {% block content %}
|
||||
<main>
|
||||
<!-- Vote Page Content -->
|
||||
<div class="container mx-auto p-4">
|
||||
<h1 class="text-3xl font-semibold mb-2">{{ question_text }}</h1>
|
||||
<hr class="h-px my-4 bg-gray-200 border-0 dark:bg-gray-700">
|
||||
<p class="text-gray-600 mb-4 hover:bg-amber-100 text-black px-2 py-1 rounded-md mr-2">{{ long_description }}</p>
|
||||
<nav class="bg-white p-4 shadow-xl border-b-2 border-solid border-neutral-700">
|
||||
<div class="container mx-auto flex items-center justify-between">
|
||||
<div class="text-2xl font-bold text-black">🤔{{ question.question_text }}</div>
|
||||
|
||||
<!-- Tags and Stats Section (tag) to be add -->
|
||||
<div class="flex flex-wrap items-center text-gray-600 mb-4">
|
||||
<div class="flex items-center bg-orange-100 text-black px-2 py-1 rounded-md mr-2">
|
||||
<span class="mr-2">👤 {{ participant_count }} Participants</span>
|
||||
<span class="mr-2">👍 {{ question.up_vote_percentage }}% Upvoted</span>
|
||||
<span>👎 {{ question.down_vote_percentage }}% Downvoted</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
<div>
|
||||
<div class="flex flex-wrap items-center space-x-2">
|
||||
<header class="flex items-center justify-center">
|
||||
<div class="flex flex-wrap items-center space-x-2">
|
||||
<!--End-->
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Modern Choice Selection -->
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4 ">
|
||||
<h2 class="text-xl font-semibold mb-4">Which one would you prefer:</h2>
|
||||
<!-- Vote Page Content -->
|
||||
<div class="container mx-auto p-4">
|
||||
<!-- Participant + UP DOWN zone -->
|
||||
<div class="flex flex-wrap items-center text-gray-600 mb-4 place-content-center">
|
||||
<div class="flex items-center text-black py-1 rounded-md mr-2">
|
||||
<div class="relative">
|
||||
<div class="rounded-lg bg-white p-4 shadow-md border-solid border-2 border-neutral-500 relative z-10">
|
||||
<span class="mr-2">👤 {{ participant_count }} Participants</span>
|
||||
<span class="mr-2">👍 {{ question.up_vote_percentage }}% Upvoted</span>
|
||||
<span>👎 {{ question.down_vote_percentage }}% Downvoted</span>
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 mt-1 ml-1 h-full w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-green-400 to-blue-500"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col space-y-4">
|
||||
<form action="{% url 'polls:vote' question.id %}" method="post" class="poll-form" id="poll-form">
|
||||
{% csrf_token %}
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<div id="selected-choice" class="mt-4 text-lg font-bold text-green-500">Please Select a Choice😊</div>
|
||||
</div>
|
||||
{% if error_message %}
|
||||
<div class="bg-red p-4 rounded-lg shadow-md mb-4 ">
|
||||
<p class="error-message text-red-500"><strong>{{ error_message }}</strong></p>
|
||||
</div
|
||||
{% endif %}
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<!-- Buttons as choices (hidden) -->
|
||||
{% for choice in question.choice_set.all %}
|
||||
<label>
|
||||
<input type="radio" name="choice" value="{{ choice.id }}" class="hidden" />
|
||||
<button
|
||||
type="button"
|
||||
class="choice-button bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg shadow-md transition-colors duration-300 w-full py-5 font-bold text-lg truncate"
|
||||
onclick="toggleChoice(this, '{{ choice.id }}')"
|
||||
>
|
||||
{{ choice.choice_text }}
|
||||
</button>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit -->
|
||||
<div class="flex flex-row-reverse">
|
||||
<a href="{% url 'polls:index' %}" class="bg-orange-400 text-white px-4 py-2 rounded-lg hover:bg-orange-500 transition-colors duration-300">
|
||||
Back to Polls
|
||||
</a>
|
||||
<button type="submit" class="bg-orange-400 text-white px-4 py-2 rounded-lg hover:bg-orange-600 transition-colors duration-300 hidden" id="vote-button">
|
||||
Go Back
|
||||
</button>
|
||||
<button class="bg-blue-500 text-white px-4 py-2 mx-5 rounded-lg hover:bg-blue-600 transition-colors duration-300">Vote</button>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modern Choice Selection -->
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<div class="relative">
|
||||
<div class="rounded-lg bg-white p-4 shadow-md border-solid border-2 border-neutral-500 relative z-10">
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<p class="bg-white p-4 border-neutral-700 text-lg font-semibold overflow-hidden break-words">
|
||||
{{ long_description }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col space-y-4">
|
||||
<form action="{% url 'polls:vote' question.id %}" method="post" class="poll-form" id="poll-form">
|
||||
{% csrf_token %}
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<div id="selected-choice" class="mt-4 text-lg font-bold text-green-500">Please Select a Choice😊</div>
|
||||
</div>
|
||||
{% if error_message %}
|
||||
<div class="bg-red p-4 rounded-lg shadow-md mb-4">
|
||||
<p class="error-message text-red-500"><strong>{{ error_message }}</strong></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<!-- Buttons as choices (hidden) -->
|
||||
{% for choice in question.choice_set.all %}
|
||||
<label>
|
||||
<input type="radio" name="choice" value="{{ choice.id }}" class="hidden" />
|
||||
<button
|
||||
type="button"
|
||||
class="choice-button bg-white-500 border-2 border-black hover:bg-neutral-200 text-black px-4 py-2 rounded-lg shadow-md transition-colors duration-300 w-full py-5 font-bold text-lg truncate"
|
||||
onclick="toggleChoice(this, '{{ choice.id }}')">
|
||||
{{ choice.choice_text }}
|
||||
</button>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit -->
|
||||
<div class="flex flex-row-reverse">
|
||||
<a
|
||||
href="{% url 'polls:index' %}"
|
||||
class="bg-orange-400 text-white px-4 py-2 rounded-lg hover:bg-orange-500 transition-colors duration-300">
|
||||
Back to Polls
|
||||
</a>
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-orange-400 text-white px-4 py-2 rounded-lg hover:bg-orange-600 transition-colors duration-300 hidden"
|
||||
id="vote-button">
|
||||
Go Back
|
||||
</button>
|
||||
<button
|
||||
class="bg-blue-500 text-white px-4 py-2 mx-5 rounded-lg hover:bg-blue-600 transition-colors duration-300">
|
||||
Vote
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 mt-1 ml-1 h-full w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-green-400 to-blue-500"></div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const toggleChoice = (button, choiceId) => {
|
||||
const choiceInput = document.querySelector(`input[name="choice"][value="${choiceId}"]`);
|
||||
|
||||
if (choiceInput) {
|
||||
// already selected -> unselect it
|
||||
if (choiceInput.checked) {
|
||||
choiceInput.checked = false;
|
||||
button.classList.remove('bg-green-500', 'border-solid', 'border-2', 'border-green-500', 'hover:bg-green-600');
|
||||
button.classList.add('bg-blue-500', 'hover:bg-blue-600');
|
||||
// Clear display
|
||||
document.getElementById('selected-choice').textContent = 'Please Select a Choice😊';
|
||||
} else {
|
||||
// Unselect all choices
|
||||
document.querySelectorAll('input[name="choice"]').forEach((choice) => {
|
||||
choice.checked = false;
|
||||
});
|
||||
|
||||
// Select the clicked choice
|
||||
choiceInput.checked = true;
|
||||
|
||||
// Reset the style of all choice buttons
|
||||
document.querySelectorAll('.choice-button').forEach((btn) => {
|
||||
btn.classList.remove('bg-green-500', 'border-solid', 'border-2', 'border-green-500', 'hover:bg-green-600');
|
||||
btn.classList.add('bg-blue-500', 'hover:bg-blue-600');
|
||||
});
|
||||
|
||||
button.classList.remove('bg-blue-500', 'hover:bg-blue-600');
|
||||
button.classList.add('bg-green-500', 'border-solid', 'border-2', 'border-green-500', 'hover:bg-green-600');
|
||||
|
||||
const choiceText = button.textContent.trim();
|
||||
document.getElementById('selected-choice').textContent = `You selected: ${choiceText}`;
|
||||
}
|
||||
|
||||
// Enable the "Vote" button -> if select
|
||||
const voteButton = document.getElementById('vote-button');
|
||||
voteButton.disabled = !document.querySelector('input[name="choice"]:checked');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,97 +1,183 @@
|
||||
{% extends 'polls/base.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% extends 'polls/base.html' %} {% block content %}
|
||||
<main>
|
||||
<!-- Navbar -->
|
||||
<nav class="bg-blue-500 p-4">
|
||||
<div class="container mx-auto flex items-center justify-between">
|
||||
<div class="text-2xl font-semibold text-white">KU POLL</div>
|
||||
<!-- Navbar -->
|
||||
<nav class="bg-blue-500 p-4 shadow-xl border-b-2 border-solid border-neutral-700">
|
||||
<div class="container mx-auto flex items-center justify-between">
|
||||
<div class="text-2xl font-bold text-white">📝KU POLL</div>
|
||||
|
||||
<!-- Button -->
|
||||
<div>
|
||||
{% comment %} <button class="mr-4 rounded-md bg-green-500 px-4 py-2 text-white">New Poll</button> {% endcomment %}
|
||||
<button class="text-white">Sign In</button>
|
||||
<!-- Button -->
|
||||
<div>
|
||||
{% comment %}
|
||||
<button class="mr-4 rounded-md bg-green-500 px-4 py-2 text-white">New Poll</button>
|
||||
{% endcomment %}
|
||||
<div class="flex flex-wrap items-center space-x-2">
|
||||
<header class="flex items-center justify-center">
|
||||
<div class="flex flex-wrap items-center space-x-2">
|
||||
<!--Searchhhh-->
|
||||
<form class="group relative z-30 flex flex-grow flex-col items-center space-y-2 rounded-lg border-2 border-neutral-700 bg-white p-1 pl-2 text-lg md:flex-row md:space-y-0 md:space-x-1 md:rounded-full">
|
||||
<div class="flex w-full items-center rounded-lg bg-neutral-200 py-1 px-2 focus-within:outline-none focus-within:ring-2 focus-within:ring-purple-400 md:rounded-full">
|
||||
<div>🔎</div>
|
||||
<input type="text" name="q" class="font-semibold w-full border-none bg-transparent focus:outline-none focus:ring focus:ring-transparent text-sm">
|
||||
</div>
|
||||
<button type="submit">
|
||||
<span class="flex items-center whitespace-nowrap rounded-full border border-transparent bg-green-500 px-5 py-2 text-sm font-bold text-white transition duration-150 ease-in-out hover:scale-[101%] hover:bg-green-700 focus:bg-green-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-green-900">
|
||||
Search
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
<!--End-->
|
||||
<button class="flex items-center whitespace-nowrap rounded-full border border-transparent bg-green-500 px-5 py-2 text-sm font-bold text-white transition duration-150 ease-in-out hover:scale-[101%] hover:bg-green-700 focus:bg-green-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-green-900">
|
||||
New Poll
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mx-auto p-4">
|
||||
<header class="mb-4 flex items-center justify-between">
|
||||
<h1 class="text-2xl font-semibold">Explore Polls</h1>
|
||||
<button class="rounded-md bg-green-500 px-4 py-2 text-white">New Poll</button>
|
||||
</header>
|
||||
|
||||
<!-- Filter Section -->
|
||||
<div class="mb-4">
|
||||
<input type="text" placeholder="Search for polls..." class="w-full rounded-md border border-gray-300 px-4 py-2" />
|
||||
</div>
|
||||
|
||||
<!-- Trends Polls Section -->
|
||||
<section class="mb-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold">Trending</h2>
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
|
||||
{% for question in latest_question_list %}
|
||||
<a class="rounded-lg bg-white p-4 shadow-md">
|
||||
<h2 class="mb-2 text-xl font-semibold">{{ question.question_text }}</h2>
|
||||
<hr class="h-px my-2 bg-gray-200 border-0 dark:bg-gray-400">
|
||||
<p class="mb-2 text-gray-600">{{ question.short_description }}</p>
|
||||
<div class="mb-2 flex items-center text-gray-600">
|
||||
<span class="mr-2">👍</span>
|
||||
<span>{{ question.up_vote_percentage }}% Upvoted</span>
|
||||
|
||||
<span class="ml-4 mr-2">👎</span>
|
||||
<span>{{ question.down_vote_percentage }}% Downvoted</span>
|
||||
</div>
|
||||
<!-- Tag / Time -->
|
||||
<div class="flex items-center text-gray-600">
|
||||
<span class="mr-2 rounded-md bg-green-500 px-2 py-1 text-white">🕒 {{ question.time_left }}</span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black"> {{ question.participant_count }} Participants 👤</span>
|
||||
</div>
|
||||
<div class="flex items-center text-gray-600 py-4">
|
||||
<button onclick="window.location.href='{% url 'polls:detail' question.id %}'" class="mr-2 rounded-md bg-white px-2 py-1 text-black border-solid border-2 border-black hover:bg-gray-500 transform translate-y-0 hover:translate-y-1 transition-transform">VOTE</button>
|
||||
<button onclick="window.location.href='{% url 'polls:results' question.id %}'" class="mr-2 rounded-md bg-white px-2 py-1 text-black border-solid border-2 border-black hover:bg-gray-500 transform translate-y-0 hover:translate-y-1 transition-transform">VIEW</button>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Poll Cards Section -->
|
||||
<section>
|
||||
<h2 class="mb-4 text-2xl font-semibold">Polls</h2>
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3">
|
||||
|
||||
{% for question in latest_question_list %}
|
||||
<a href="{% url 'polls:detail' question.id %}" class="rounded-lg bg-white p-4 shadow-md">
|
||||
<h2 class="mb-2 text-xl font-semibold">{{ question.question_text }}</h2>
|
||||
<p class="mb-2 text-gray-600">{{ question.short_description }}</p>
|
||||
<div class="mb-2 flex items-center text-gray-600">
|
||||
|
||||
<span class="mr-2">👍</span>
|
||||
<span>{{ question.up_vote_percentage }}% Upvoted</span>
|
||||
|
||||
<span class="ml-4 mr-2">👎</span>
|
||||
<span>{{ question.down_vote_percentage }}% Downvoted</span>
|
||||
</div>
|
||||
<!-- Tag Time -->
|
||||
<div class="flex items-center text-gray-600">
|
||||
<span class="mr-2 rounded-md bg-green-500 px-2 py-1 text-white">🕒 {{ question.time_left }}</span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black"> {{ question.participant_count }} Participants 👤</span>
|
||||
</div>
|
||||
<div class="flex items-center text-gray-600 py-4">
|
||||
<button onclick="window.location.href='{% url 'polls:detail' question.id %}'" class="mr-2 rounded-md bg-white px-2 py-1 text-black border-solid border-2 border-black hover:bg-gray-500 transform translate-y-0 hover:translate-y-1 transition-transform">VOTE</button>
|
||||
<button onclick="window.location.href='{% url 'polls:results' question.id %}'" class="mr-2 rounded-md bg-white px-2 py-1 text-black border-solid border-2 border-black hover:bg-gray-500 transform translate-y-0 hover:translate-y-1 transition-transform">VIEW</button>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</header>
|
||||
<a href=""
|
||||
class="flex items-center whitespace-nowrap rounded-full border border-transparent bg-neutral-800 px-5 py-2 text-sm font-bold text-white transition duration-150 ease-in-out hover:scale-[101%] hover:bg-neutral-700 focus:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-neutral-900">
|
||||
<span>Sign in <span class="hidden sm:inline-block">😎</span></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!--MAIN-->
|
||||
<!-- Search Section -->
|
||||
<div class="container mx-auto p-4">
|
||||
{% comment %} <header class="mb-4 flex items-center justify-center">
|
||||
<div class="flex flex-wrap items-center space-x-2">
|
||||
<form wire:submit.prevent="claimUsername" class="group relative z-30 flex flex-grow flex-col items-center space-y-2 rounded-lg border-2 border-neutral-700 bg-white p-1 pl-2 text-lg md:flex-row md:space-y-0 md:space-x-1 md:rounded-full">
|
||||
<div class="flex w-full items-center rounded-lg bg-neutral-200 py-1 px-2 focus-within:outline-none focus-within:ring-2 focus-within:ring-purple-400 md:rounded-full">
|
||||
<div>🔎</div>
|
||||
<input type="text" name="username" id="username" wire:model="username" class="font-semibold w-full border-none bg-transparent focus:outline-none focus:ring focus:ring-transparent text-sm">
|
||||
</div>
|
||||
<button type="submit">
|
||||
<span class="flex items-center whitespace-nowrap rounded-full border border-transparent bg-green-500 px-5 py-2 text-sm font-bold text-white transition duration-150 ease-in-out hover:scale-[101%] hover:bg-green-700 focus:bg-green-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-green-900">
|
||||
Search
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
<button class="flex items-center whitespace-nowrap rounded-full border border-transparent bg-green-500 px-5 py-2 text-sm font-bold text-white transition duration-150 ease-in-out hover:scale-[101%] hover:bg-green-700 focus:bg-green-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-green-900">New Poll</button>
|
||||
</div>
|
||||
</header> {% endcomment %}
|
||||
|
||||
<!-- Filter Section -->
|
||||
{% comment %} <div class="mb-4">
|
||||
<input type="text" placeholder="Search for polls..." class="w-full rounded-md border border-gray-300 px-4 py-2" />
|
||||
</div> {% endcomment %}
|
||||
|
||||
<!-- Trends Polls Section -->
|
||||
<section class="mb-6">
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<h2 class="text-2xl font-bold bg-gradient-to-r from-red-600 via-orange-600 to-yellow-600 bg-clip-text text-transparent lg:inline">Top Polls Today</h2>
|
||||
<hr class="h-px my-4 bg-gray-200 border-0 dark:bg-gray-400" />
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{% for question in latest_question_list %}
|
||||
<div class="relative">
|
||||
<!-- INFO -->
|
||||
<div class="rounded-lg bg-white p-4 shadow-md border-solid border-2 border-yellow-500 relative z-10 transform translate-y-0 hover:translate-y-1 transition-transform">
|
||||
<h2 class="mb-2 text-xl font-bold">{{ question.question_text }}</h2>
|
||||
<hr class="h-px my-2 bg-gray-200 border-0 dark:bg-gray-400" />
|
||||
<p class="mb-2 text-gray-600">{{ question.short_description }}</p>
|
||||
<div class="mb-2 flex items-center text-gray-600">
|
||||
<span class="mr-2">👍</span>
|
||||
<span>{{ question.up_vote_percentage }}% Upvoted</span>
|
||||
|
||||
<span class="ml-4 mr-2">👎</span>
|
||||
<span>{{ question.down_vote_percentage }}% Downvoted</span>
|
||||
</div>
|
||||
<!-- Tag / Time -->
|
||||
<div class="flex items-center text-gray-600">
|
||||
<span class="mr-2 rounded-md bg-green-500 px-2 py-1 text-white">🕒 {{ question.time_left }}</span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black">{{ question.participant_count }} Participants 👤</span>
|
||||
</div>
|
||||
<div class="flex items-center text-gray-600 py-4">
|
||||
<button
|
||||
onclick="window.location.href='{% url 'polls:detail' question.id %}'"
|
||||
class="mr-2 rounded-md bg-yellow-100 px-2 py-1 text-black font-semibold border-solid border-2 border-yellow-500 hover:bg-yellow-500 transform translate-y-0 hover:translate-y-1 transition-transform">
|
||||
VOTE
|
||||
</button>
|
||||
<button
|
||||
onclick="window.location.href='{% url 'polls:results' question.id %}'"
|
||||
class="mr-2 rounded-md bg-yellow-100 px-2 py-1 text-black font-semibold border-solid border-2 border-yellow-500 hover:bg-yellow-500 transform translate-y-0 hover:translate-y-1 transition-transform">
|
||||
VIEW
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute inset-0 mt-1 ml-1 h-full w-full rounded-lg border-2 border-yellow-700 bg-gradient-to-r from-yellow-600 via-yellow-300 to-yellow-600">
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Poll Cards Section -->
|
||||
<section>
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<h2 class="mb-4 text-2xl font-bold">All Polls</h2>
|
||||
<hr class="h-px my-4 bg-gray-200 border-0 dark:bg-gray-400" />
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3">
|
||||
{% for question in latest_question_list %}
|
||||
<div class="relative">
|
||||
<!-- INFO -->
|
||||
<div class="rounded-lg bg-white p-4 shadow-md border-solid border-2 border-neutral-500 relative z-10 transform translate-y-0 hover:translate-y-1 transition-transform">
|
||||
<h2 class="mb-2 text-xl font-semibold">{{ question.question_text }}</h2>
|
||||
<hr class="h-px my-2 bg-gray-200 border-0 dark:bg-gray-400" />
|
||||
<p class="mb-2 text-gray-600">{{ question.short_description }}</p>
|
||||
<div class="mb-2 flex items-center text-gray-600">
|
||||
<span class="mr-2">👍</span>
|
||||
<span>{{ question.up_vote_percentage }}% Upvoted</span>
|
||||
|
||||
<span class="ml-4 mr-2">👎</span>
|
||||
<span>{{ question.down_vote_percentage }}% Downvoted</span>
|
||||
</div>
|
||||
<!-- Tag / Time -->
|
||||
<div class="flex items-center text-gray-600">
|
||||
<span class="mr-2 rounded-md bg-green-500 px-2 py-1 text-white">🕒 {{ question.time_left }}</span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black">{{ question.participant_count }} Participants 👤</span>
|
||||
</div>
|
||||
<div class="flex items-center text-gray-600 py-4">
|
||||
<button
|
||||
onclick="window.location.href='{% url 'polls:detail' question.id %}'"
|
||||
class="mr-2 rounded-md bg-white px-2 py-1 text-black border-solid border-2 border-black hover:bg-gray-500 transform translate-y-0 hover:translate-y-1 transition-transform">
|
||||
VOTE
|
||||
</button>
|
||||
<button
|
||||
onclick="window.location.href='{% url 'polls:results' question.id %}'"
|
||||
class="mr-2 rounded-md bg-white px-2 py-1 text-black border-solid border-2 border-black hover:bg-gray-500 transform translate-y-0 hover:translate-y-1 transition-transform">
|
||||
VIEW
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% if forloop.counter|divisibleby:2 %}
|
||||
<div class="absolute inset-0 mt-1 ml-1 h-full w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-green-400 to-blue-500">
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="absolute inset-0 mt-1 ml-1 h-full w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-orange-400 to-red-500">
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="border-t border-neutral-700 bg-white">
|
||||
<div class="container mx-auto flex max-w-7xl flex-col items-center py-8 px-8 sm:flex-row">
|
||||
<a href="{% url 'polls:index' %}" class="flex items-center gap-3 font-bold tracking-tight text-neutral-900">
|
||||
<span>Ku Poll</span>
|
||||
</a>
|
||||
<p class="mt-4 text-sm text-neutral-500 sm:ml-4 sm:mt-0 sm:border-l sm:border-neutral-200 sm:pl-4">
|
||||
Ku Poll is a project in <a href="https://cpske.github.io/ISP/" class="text-neutral-900">ISP</a>.
|
||||
</p>
|
||||
<span
|
||||
class="mt-4 inline-flex items-center justify-center space-x-5 text-sm sm:ml-auto sm:mt-0 sm:justify-start">
|
||||
<a href="https://github.com/Sosokker/ku-polls" class="text-neutral-400 hover:text-blue-500">
|
||||
<span>Repository</span>
|
||||
</a>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
|
||||
@ -2,116 +2,155 @@
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<!-- Result Page Content -->
|
||||
<div class="container mx-auto p-4">
|
||||
<h1 class="text-3xl font-semibold mb-4">{{ question.question_text }}</h1>
|
||||
<hr class="h-px my-4 bg-gray-200 border-0 dark:bg-gray-700">
|
||||
<nav class="bg-white p-4 shadow-xl border-b-2 border-solid border-neutral-700">
|
||||
<div class="container mx-auto flex items-center justify-between">
|
||||
<div class="text-2xl font-bold text-black">🤔{{ question.question_text }}</div>
|
||||
|
||||
<!-- Result Summary -->
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<h2 class="text-xl font-semibold mb-2">Result Summary:</h2>
|
||||
|
||||
{% for choice in question.choice_set.all %}
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<span>{{ choice.choice_text }}</span>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-2">👍 {{ choice.votes }}</span>
|
||||
<div class="percentage-bar">
|
||||
<div class="bar bg-blue-500 h-2" style="width: {{ choice.calculate_percentage }}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
<div>
|
||||
<div class="flex flex-wrap items-center space-x-2">
|
||||
<header class="flex items-center justify-center">
|
||||
<div class="flex flex-wrap items-center space-x-2">
|
||||
<!--End-->
|
||||
<button
|
||||
onclick="window.location.href='{% url 'polls:index' %}'"
|
||||
class="flex items-center whitespace-nowrap rounded-full border border-transparent bg-orange-400 px-5 py-2 text-sm font-bold text-white transition duration-150 ease-in-out hover:scale-[101%] hover:bg-orange-700 focus:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-orange-900">
|
||||
Back to Polls
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Result Page Content -->
|
||||
<div class="container mx-auto p-4">
|
||||
|
||||
<!-- Result Summary -->
|
||||
<div class="relative">
|
||||
<div class="bg-white p-4 rounded-lg shadow-md mb-4 z-10 relative border-black border-solid border-2">
|
||||
<h2 class="text-xl font-semibold mb-2">Result Summary:</h2>
|
||||
|
||||
{% for choice in question.choice_set.all %}
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<span>{{ choice.choice_text }}</span>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-2">👍 {{ choice.votes }}</span>
|
||||
<div class="percentage-bar">
|
||||
<div class="bar bg-blue-500 h-2" style="width: {{ choice.calculate_percentage }}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 mt-1 ml-1 w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-green-400 to-blue-500 h-full"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Result Page Content -->
|
||||
<div class="container mx-auto grid grid-cols-3 gap-4">
|
||||
<!-- Statistics -->
|
||||
<div class="col-span-1 bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<h2 class="text-xl font-semibold mb-2">🕵️ Statistics</h2>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black"> {{ question.participant_count }} Participants 👤</span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black">👍 {{ question.up_vote_percentage }}% </span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black" >👎 {{ question.down_vote_percentage }}% </span>
|
||||
<!-- Statistics -->
|
||||
<div class="relative">
|
||||
<div class="col-span-1 bg-white py-4 rounded-lg shadow-md mb-4 relative z-10 border-solid border-black border-2 h-full">
|
||||
<h2 class="text-xl font-semibold mb-2">🕵️ Statistics</h2>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black">
|
||||
{{ question.participant_count }} Participants 👤
|
||||
</span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black">👍 {{ question.up_vote_percentage }}% </span>
|
||||
<span class="mr-2 rounded-md bg-orange-100 px-2 py-1 text-black">👎 {{ question.down_vote_percentage }}% </span>
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 mt-1 ml-1 w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-green-400 to-blue-500 h-full"></div>
|
||||
</div>
|
||||
|
||||
<!-- Pie Chart -->
|
||||
<div class="col-span-1 bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<h2 class="text-xl font-semibold mb-2">👋 Vote Percentage</h2>
|
||||
<div class="w-full h-48 bg-gray-100 rounded-lg">
|
||||
<canvas id="percentageChart"></canvas>
|
||||
</div>
|
||||
<!-- Pie Chart -->
|
||||
<div class="relative">
|
||||
<div class="col-span-1 bg-white py-4 rounded-lg shadow-md mb-4 relative z-10 border-solid border-black border-2 h-full">
|
||||
<h2 class="text-xl font-semibold mb-2">👋 Vote Percentage</h2>
|
||||
<div class="w-full h-48 bg-white rounded-lg">
|
||||
<canvas id="percentageChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 mt-1 ml-1 w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-green-400 to-blue-500 h-full"></div>
|
||||
</div>
|
||||
|
||||
<!-- Bar Chart -->
|
||||
<div class="col-span-1 bg-white p-4 rounded-lg shadow-md mb-4">
|
||||
<h2 class="text-xl font-semibold mb-2">👏 Vote Count</h2>
|
||||
<div class="w-full h-48 bg-gray-100 rounded-lg">
|
||||
<canvas id="voteCountChart"></canvas>
|
||||
</div>
|
||||
<!-- Bar Chart -->
|
||||
<div class="relative">
|
||||
<div class="col-span-1 bg-white py-4 rounded-lg shadow-md mb-4 relative z-10 border-solid border-black border-2 h-full">
|
||||
<h2 class="text-xl font-semibold mb-2">👏 Vote Count</h2>
|
||||
<div class="w-full h-48 bg-white rounded-lg">
|
||||
<canvas id="voteCountChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Back to Polls Button -->
|
||||
<a href="{% url 'polls:index' %}" class="bg-orange-400 text-white px-4 py-2 rounded-lg hover:bg-orange-500 transition-colors duration-300">
|
||||
Back to Polls
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 mt-1 ml-1 w-full rounded-lg border-2 border-neutral-700 bg-gradient-to-r from-green-400 to-blue-500 h-full"></div>
|
||||
</div>
|
||||
|
||||
<!-- Back to Polls Button -->
|
||||
{% comment %} <a
|
||||
href="{% url 'polls:index' %}"
|
||||
class="bg-orange-400 text-white px-4 py-2 rounded-lg hover:bg-orange-500 transition-colors duration-300">
|
||||
Back to Polls
|
||||
</a> {% endcomment %}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
var percentageCtx = document.getElementById('percentageChart').getContext('2d');
|
||||
var percentageChart = new Chart(percentageCtx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: [{% for choice in question.choice_set.all %}"{{ choice.choice_text }}",{% endfor %}],
|
||||
datasets: [{
|
||||
label: 'Percentage',
|
||||
data: [{% for choice in question.choice_set.all %}{{ choice.calculate_percentage }},{% endfor %}],
|
||||
backgroundColor: [
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(255, 99, 132, 1)',
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
}
|
||||
});
|
||||
var voteCountCtx = document.getElementById('voteCountChart').getContext('2d');
|
||||
var voteCountChart = new Chart(voteCountCtx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: [{% for choice in question.choice_set.all %}"{{ choice.choice_text }}",{% endfor %}],
|
||||
datasets: [{
|
||||
label: 'Vote Count',
|
||||
data: [{% for choice in question.choice_set.all %}{{ choice.votes }},{% endfor %}],
|
||||
backgroundColor: [
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(255, 99, 132, 1)',
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var percentageCtx = document.getElementById('percentageChart').getContext('2d');
|
||||
var percentageChart = new Chart(percentageCtx, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: [{% for choice in question.choice_set.all %}"{{ choice.choice_text }}",{% endfor %}],
|
||||
datasets: [{
|
||||
label: 'Percentage',
|
||||
data: [{% for choice in question.choice_set.all %}{{ choice.calculate_percentage }},{% endfor %}],
|
||||
backgroundColor: [
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(255, 99, 132, 1)',
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
}
|
||||
});
|
||||
var voteCountCtx = document.getElementById('voteCountChart').getContext('2d');
|
||||
var voteCountChart = new Chart(voteCountCtx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: [{% for choice in question.choice_set.all %}"{{ choice.choice_text }}",{% endfor %}],
|
||||
datasets: [{
|
||||
label: 'Vote Count',
|
||||
data: [{% for choice in question.choice_set.all %}{{ choice.votes }},{% endfor %}],
|
||||
backgroundColor: [
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(255, 99, 132, 1)',
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock content %}
|
||||
{% endblock content %}
|
||||
|
||||
@ -49,7 +49,7 @@ class QuestionModelTests(TestCase):
|
||||
Questions with the default pub_date (now) are displayed on the index page.
|
||||
"""
|
||||
question = Question.objects.create(question_text="Default pub date question.")
|
||||
|
||||
|
||||
response = self.client.get(reverse("polls:index"))
|
||||
self.assertQuerySetEqual(
|
||||
response.context["latest_question_list"],
|
||||
@ -215,4 +215,3 @@ class QuestionDetailViewTests(TestCase):
|
||||
url = reverse("polls:detail", args=(past_question.id,))
|
||||
response = self.client.get(url)
|
||||
self.assertContains(response, past_question.question_text)
|
||||
|
||||
@ -9,4 +9,3 @@ urlpatterns = [
|
||||
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
|
||||
path("<int:question_id>/vote/", views.vote, name="vote"),
|
||||
]
|
||||
|
||||
@ -16,7 +16,9 @@ class IndexView(generic.ListView):
|
||||
|
||||
def get_queryset(self):
|
||||
"""Return the last five published questions."""
|
||||
return Question.objects.filter(pub_date__lte=timezone.now()).order_by("-pub_date")[:5]
|
||||
return Question.objects.filter(pub_date__lte=timezone.now()).order_by(
|
||||
"-pub_date"
|
||||
)[:5]
|
||||
|
||||
|
||||
class DetailView(generic.DetailView):
|
||||
@ -36,18 +38,18 @@ class DetailView(generic.DetailView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
question = self.object
|
||||
|
||||
context['question_text'] = question.question_text
|
||||
context['short_description'] = question.short_description
|
||||
context['long_description'] = question.long_description
|
||||
context['pub_date'] = question.pub_date
|
||||
context['end_date'] = question.end_date
|
||||
context['up_vote_count'] = question.up_vote_count
|
||||
context['down_vote_count'] = question.down_vote_count
|
||||
context['participant_count'] = question.participant_count
|
||||
|
||||
|
||||
context["question_text"] = question.question_text
|
||||
context["short_description"] = question.short_description
|
||||
context["long_description"] = question.long_description
|
||||
context["pub_date"] = question.pub_date
|
||||
context["end_date"] = question.end_date
|
||||
context["up_vote_count"] = question.up_vote_count
|
||||
context["down_vote_count"] = question.down_vote_count
|
||||
context["participant_count"] = question.participant_count
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@ -57,7 +59,7 @@ class ResultsView(generic.DetailView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['question'] = self.object
|
||||
context["question"] = self.object
|
||||
return context
|
||||
|
||||
def render_to_response(self, context, **response_kwargs):
|
||||
@ -86,4 +88,3 @@ def vote(request, question_id):
|
||||
selected_choice.votes += 1
|
||||
selected_choice.save()
|
||||
return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user