Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created candidatures search filters view #247

Merged
merged 28 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
891e1fb
feat(votepeloclima): Created candidatures search filters view
sergiomario Aug 14, 2024
9fd7253
feat(votepeloclima): Implemented keyword and is_colletive_mandate fil…
sergiomario Aug 15, 2024
ed7b76a
feat(votepeloclima): Implemented primary e secundary session filters
sergiomario Aug 16, 2024
8d44042
Merge branch 'release/votepeloclima' into feature/candidate-search
sergiomario Aug 16, 2024
76b613f
Merge branch 'release/votepeloclima' into feature/candidate-search
sergiomario Aug 19, 2024
c27ccad
feat(votepeloclima): add candidature card in search
miguelzinh3 Aug 20, 2024
f8acec4
feat(votepeloclima): Update secundary forms
sergiomario Aug 20, 2024
8ed3ce8
Merge branch 'release/votepeloclima' into feature/candidate-search
sergiomario Aug 20, 2024
6398924
Merge branch 'feature/candidate-search' into feature/candidate-card-s…
sergiomario Aug 20, 2024
d3dd38e
feat(votepeloclima): Adjusted card candidate template
sergiomario Aug 20, 2024
a648d14
feat(votepeloclima): convert template filtor to django form
sergiomario Aug 20, 2024
f3988c7
feat(votepeloclima): add proposesmixin view and add card styles
miguelzinh3 Aug 20, 2024
b86c43a
feat(votepeloclima): reorg forms search view
sergiomario Aug 20, 2024
c66c3fd
Merge branch 'feature/candidate-search' into feature/candidate-card-s…
miguelzinh3 Aug 20, 2024
7fbb316
Merge pull request #253 from nossas/feature/candidate-card-search
miguelzinh3 Aug 20, 2024
8bc1e6c
feat(votepeloclima): created multiple select widget
sergiomario Aug 21, 2024
1400eb2
fix(vote): organize filters and views to use on Candidature Search
igr-santos Aug 27, 2024
b06d360
feat(vote): filters works to list candidatures
igr-santos Aug 28, 2024
4f2c246
fix(vote): adjusts styles
igr-santos Aug 28, 2024
0818e40
feat(vote): add custom styles to filters sidebar
igr-santos Aug 28, 2024
2a4b77f
Merge branch 'release/votepeloclima' into feature/candidate-search
igr-santos Aug 28, 2024
dc5401d
feat(vote): form submit on select tags candidature search
igr-santos Aug 28, 2024
5449e76
feat(vote): add empty box to search is empty
igr-santos Aug 28, 2024
2cd2f7a
feat(vote): hide filters input mobile
igr-santos Aug 28, 2024
e7c5e74
feat(vote): show/hide sidebar on mobile version
igr-santos Aug 28, 2024
f18ca12
fix(vote): reload city when state is selected
igr-santos Aug 29, 2024
f308f65
fix(vote): reorganize files in app candidature
igr-santos Aug 29, 2024
18b296b
Merge branch 'release/votepeloclima' into feature/candidate-search
igr-santos Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions app/org_eleicoes/votepeloclima/candidature/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ class CandidatureFlowStatus(models.TextChoices):


class IntendedPosition(models.TextChoices):
empty = "", "Selecione uma opção"
empty = "", "Cargo"
prefeitura = "prefeitura", "Prefeitura"
vereacao = "vereacao", "Vereação"


class PoliticalParty(models.TextChoices):
empty = "", "Selecione seu partido"
empty = "", "Partido político"
pdt = "pdt", "PDT"
novo = "novo", "Novo"
psdb= "psdb", "PSDB"
Expand Down Expand Up @@ -60,20 +60,19 @@ class PoliticalParty(models.TextChoices):


class Gender(models.TextChoices):
empty = "", "Selecione uma opção"
empty = "", "Gênero"
mulher_cis = "mulher_cis", "Mulher cis"
mulher_trans = "mulher_trans", "Mulher trans"
homem_cis = "homem_cis", "Homem cis"
homem_trans = "homem_trans", "Homem trans"
pessoa_nao_binaria = "pessoa_nao_binaria", "Pessoa não binária"
travesti = "travesti", "Travesti"
queer = "queer", "Queer"
mandato_coletivo = "mandato_coletivo", "Mandato Coletivo"
nao_declarado = "nao_declarado", "Não declarado"


class Sexuality(models.TextChoices):
empty = "", "Selecione uma opção"
empty = "", "Sexualidade"
heterossexual = "heterossexual", "Heterossexual"
pansexual = "pansexual", "Pansexual"
assexual = "assexual", "Assexual"
Expand All @@ -85,7 +84,7 @@ class Sexuality(models.TextChoices):


class Color(models.TextChoices):
empty = "", "Selecione uma opção"
empty = "", "Raça"
preta = "preta", "Preta"
parda = "parda", "Parda"
indigena = "indigena", "Indígena"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{% load crispy_forms_filters %}

<form method="get" action="{% url 'candidature_search' %}">
<select name="state" id="state">
<option value="">Estado</option>
{% for value, label in states %}
<option value="{{ value }}" {% if request.GET.state == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<select name="city" id="city" {% if not request.GET.state %}disabled{% endif %}>
<option value="">Cidade</option>
{% for value, label in cities %}
<option value="{{ value }}" {% if request.GET.city == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<select name="intended_position" id="intended_position">
{% for value, label in intended_position_choices %}
<option value="{{ value }}" {% if request.GET.intended_position == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<select name="political_party" id="political_party">
{% for value, label in political_party_choices %}
<option value="{{ value }}" {% if request.GET.political_party == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>

<input type="hidden" name="initial_search" value="true">
<button type="submit">Buscar</button>
</form>

{% if initial_search == 'true' %}
<aside class="sidebar">
<form method="get">
<select name="gender" id="gender">
{% for value, label in gender_choices %}
<option value="{{ value }}" {% if request.GET.gender == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<select name="color" id="color">
{% for value, label in color_choices %}
<option value="{{ value }}" {% if request.GET.color == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<select name="sexuality" id="sexuality">
{% for value, label in sexuality_choices %}
<option value="{{ value }}" {% if request.GET.sexuality == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>

<input type="text" name="ballot_name" placeholder="Nome na Urna" value="{{ request.GET.ballot_name }}">
<input type="text" name="keyword" id="keyword" placeholder="Palavra-chave" value="{{ request.GET.keyword }}">
<label for="is_collective_mandate">Candidatura Coletiva:</label>
<input type="checkbox" name="is_collective_mandate" id="is_collective_mandate" {% if request.GET.is_collective_mandate %}checked{% endif %}>

<input type="hidden" name="initial_search" value="true">
<button type="submit">Buscar</button>
</form>
</aside>
{% endif %}


{% for candidature in candidatures %}
<p>{{ candidature.legal_name }} - {{ candidature.intended_position }} - {{ candidature.political_party }}</p>
<p>{{ candidature.short_description }}</p>
{% if candidature.is_collective_mandate %}
<p><strong>Candidatura Coletiva</strong></p>
{% endif %}
{% endfor %}

<script>
// Método que carrega as cidades de acordo com o estado selecionado
document.getElementById('state').addEventListener('change', function() {
const stateValue = this.value;
const citySelect = document.getElementById('city');

if (stateValue) {
citySelect.disabled = false;
fetch(`/address/?state=${stateValue}`)
.then(response => response.json())
.then(data => {
citySelect.innerHTML = '<option value="">Selecione uma cidade</option>';
data.forEach(city => {
const option = document.createElement('option');
option.value = city.code;
option.textContent = city.name;
citySelect.appendChild(option);
});
});
} else {
citySelect.disabled = true;
citySelect.innerHTML = '<option value="">Selecione uma cidade</option>';
}
});
</script>
74 changes: 69 additions & 5 deletions app/org_eleicoes/votepeloclima/candidature/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
from django.http import JsonResponse
from django.views import View
from django.contrib.auth.models import User, AnonymousUser
from django.views.generic import TemplateView
from django.db.models import Q
from django.views.generic import TemplateView, ListView

from django.http import HttpResponseForbidden
from django.urls import reverse_lazy, reverse
from django.core.files.storage import default_storage
Expand All @@ -16,8 +18,14 @@
from contrib.oauth.utils import send_confirmation_email
from ..models import CandidatureFlow, CandidatureFlowStatus, Candidature
from ..forms import register_form_list, ProposeForm, AppointmentForm
from ..locations_utils import get_choices

from ..locations_utils import get_ufs, get_choices
from ..choices import (
PoliticalParty,
IntendedPosition,
Color,
Gender,
Sexuality,
)

initial_step_name = register_form_list[2][0]
disable_edit_steps = [
Expand Down Expand Up @@ -348,10 +356,66 @@ class AddressView(View):
def get(self, request, *args, **kwargs):
state = request.GET.get("state")
cities = get_choices(state)

return JsonResponse([{'code': code, 'name': name} for code, name in cities], safe=False)


class CandidatureSearchView(ListView):
model = Candidature
template_name = "candidature/candidature_search.html"
context_object_name = "candidatures"

def get_queryset(self):
queryset = super().get_queryset()
sergiomario marked this conversation as resolved.
Show resolved Hide resolved

# Filtros principais
for field in ['state', 'city', 'intended_position', 'political_party']:
value = self.request.GET.get(field)
if value:
queryset = queryset.filter(**{f"{field}__icontains": value})
sergiomario marked this conversation as resolved.
Show resolved Hide resolved

# Verificar se a busca inicial foi feita
if self.request.GET.get('initial_search') == 'true':
#Filtros secundários
for field in ['gender', 'color', 'sexuality', 'ballot_name']:
value = self.request.GET.get(field)
if value:
queryset = queryset.filter(**{f"{field}__icontains": value})

keyword = self.request.GET.get('keyword')
if keyword:
queryset = queryset.filter(
Q(short_description__icontains=keyword) |
Q(milestones__icontains=keyword) |
Q(flags__icontains=keyword) |
Q(appointments__icontains=keyword)
)

is_collective_mandate = self.request.GET.get('is_collective_mandate')
if is_collective_mandate:
queryset = queryset.filter(is_collective_mandate=True)

return queryset

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
sergiomario marked this conversation as resolved.
Show resolved Hide resolved
context['sexuality_choices'] = Sexuality.choices
context['gender_choices'] = Gender.choices
context['color_choices'] = Color.choices
context['intended_position_choices'] = IntendedPosition.choices
context['political_party_choices'] = PoliticalParty.choices

context['states'] = get_ufs()
selected_state = self.request.GET.get('state')
if selected_state:
context['cities'] = get_choices(selected_state)
else:
context['cities'] = []

context['initial_search'] = self.request.GET.get('initial_search', 'false')

return context


class PublicCandidatureView(View):
template_name = "candidature/candidate_profile.html"

Expand All @@ -375,4 +439,4 @@ def get(self, request, slug):
if candidature.status() != CandidatureFlowStatus.is_valid.label:
return render(request, 'candidature/not_approved.html', context)

return render(request, self.template_name, context)
return render(request, self.template_name, context)
3 changes: 2 additions & 1 deletion app/org_eleicoes/votepeloclima/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.urls import path, include, re_path

from .candidature.views import AddressView, PublicCandidatureView
from .candidature.views import AddressView, CandidatureSearchView, PublicCandidatureView
from .candidature.views.create import CreateUpdateCandidatureView
from .candidature.views.oauth import DashboardView, UpdateCandidatureStatusView

Expand All @@ -33,6 +33,7 @@
re_path(r"^candidatura/cadastro/(?P<step>.+)/$", register_view, name="register_step",),
path("candidatura/cadastro/", register_view, name="register"),
re_path(r"^c(andidatura)*/(?P<slug>.+)/$", PublicCandidatureView.as_view(), name='candidate_profile'),
path('candidaturas/busca/', CandidatureSearchView.as_view(), name='candidature_search'),
# API
path('api/candidatura/buscar-endereco/', AddressView.as_view(), name='address'),
path("api/candidatura/validar/", UpdateCandidatureStatusView.as_view()),
Expand Down
Loading