diff --git a/app/org_eleicoes/votepeloclima/candidature/fields.py b/app/org_eleicoes/votepeloclima/candidature/fields.py index fd044884..a7aa38cb 100644 --- a/app/org_eleicoes/votepeloclima/candidature/fields.py +++ b/app/org_eleicoes/votepeloclima/candidature/fields.py @@ -6,6 +6,7 @@ from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError +from django.contrib.postgres.forms import SimpleArrayField from django_select2.forms import Select2Widget from captcha.fields import ReCaptchaField @@ -184,9 +185,14 @@ def clean(self, value): return value.replace("on-", "") -class InlineArrayWidget(forms.TextInput): +class InlineArrayWidget(forms.MultiWidget): template_name = "forms/widgets/inline_array.html" + def __init__(self, widget, size, attrs=None): + widgets = [widget() if isinstance(widget, type) else widget for _ in range(size)] + super().__init__(widgets, attrs) + self.size = size + @property def media(self): return forms.Media( @@ -194,5 +200,30 @@ def media(self): "https://code.jquery.com/jquery-3.5.1.min.js", "js/inline-array-widget.js", ], - # css={"screen": select2_css + ["django_select2/django_select2.css"]}, ) + + def decompress(self, value): + if isinstance(value, list): + return value + if value is None: + return [] + return [v.strip() for v in value.split(',')] + + def value_from_datadict(self, data, files, name): + values = [] + for key, value in data.items(): + if key.startswith(f'{name}_'): + values.append(value) + return values + + def get_context(self, name, value, attrs): + context = super().get_context(name, value, attrs) + context['widget'].update({'size':self.size}) + + return context + + +class InlineArrayField(SimpleArrayField): + def __init__(self, base_field, size=5, delimiter=",", max_length=None, min_length=None, **kwargs): + super().__init__(base_field, delimiter=delimiter, max_length=max_length, min_length=min_length, **kwargs) + self.widget = InlineArrayWidget(widget=base_field.widget, size=size) diff --git a/app/org_eleicoes/votepeloclima/candidature/forms.py b/app/org_eleicoes/votepeloclima/candidature/forms.py index b1017782..f7c95437 100644 --- a/app/org_eleicoes/votepeloclima/candidature/forms.py +++ b/app/org_eleicoes/votepeloclima/candidature/forms.py @@ -9,7 +9,7 @@ StateCepField, CityCepField, CheckboxTextField, - InlineArrayWidget, + InlineArrayField, ) @@ -62,7 +62,11 @@ class ProfileForm(DisabledMixin, forms.Form): gender = forms.CharField(label="Gênero") color = forms.CharField(label="Raça") sexuality = forms.CharField(label="Sexualidade", required=False) - social_media = SimpleArrayField(forms.URLField(), widget=InlineArrayWidget()) + social_media = InlineArrayField(forms.URLField(required=False), required=False) + + def clean_social_media(self): + value = self.cleaned_data['social_media'] + return value class Meta: title = "Complemente seu perfil" @@ -72,7 +76,11 @@ class TrackForm(DisabledMixin, forms.Form): education = forms.CharField(label="Escolaridade", required=False) employment = forms.CharField(label="Ocupação", required=False) short_description = forms.CharField(label="Minibio", widget=forms.Textarea()) - milestones = SimpleArrayField(forms.CharField(max_length=140), widget=InlineArrayWidget()) + milestones = InlineArrayField(forms.CharField(max_length=140, required=False), required=False) + + def clean_milestones(self): + value = self.cleaned_data['milestones'] + return value class Meta: title = "Sobre sua trajetória" diff --git a/app/org_eleicoes/votepeloclima/candidature/migrations/0006_alter_candidature_options_and_more.py b/app/org_eleicoes/votepeloclima/candidature/migrations/0006_alter_candidature_options_and_more.py new file mode 100644 index 00000000..5508a239 --- /dev/null +++ b/app/org_eleicoes/votepeloclima/candidature/migrations/0006_alter_candidature_options_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2 on 2024-07-22 21:30 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('candidature', '0005_alter_candidatureflow_candidature_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='candidature', + options={'verbose_name': 'Candidatura'}, + ), + migrations.AlterModelOptions( + name='candidatureflow', + options={'verbose_name': 'Formulário'}, + ), + migrations.AddField( + model_name='candidature', + name='milestones', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=140), blank=True, null=True, size=5), + ), + migrations.AddField( + model_name='candidature', + name='social_media', + field=django.contrib.postgres.fields.ArrayField(base_field=models.URLField(blank=True), blank=True, null=True, size=5), + ), + ] diff --git a/app/org_eleicoes/votepeloclima/candidature/models.py b/app/org_eleicoes/votepeloclima/candidature/models.py index 7dc3d2df..5ff3de25 100644 --- a/app/org_eleicoes/votepeloclima/candidature/models.py +++ b/app/org_eleicoes/votepeloclima/candidature/models.py @@ -1,5 +1,6 @@ from django.db import models from django.contrib.auth.models import User +from django.contrib.postgres.fields import ArrayField from django.core.serializers.json import DjangoJSONEncoder @@ -28,10 +29,12 @@ class Candidature(models.Model): gender = models.CharField(max_length=30) color = models.CharField(max_length=30) sexuality = models.CharField(max_length=30, null=True, blank=True) + social_media = ArrayField(models.URLField(blank=True), size=5, null=True, blank=True) # Step 4 education = models.CharField(max_length=50, null=True, blank=True) employment = models.CharField(max_length=50, null=True, blank=True) short_description = models.TextField() + milestones = ArrayField(models.CharField(max_length=140, blank=True), size=5, null=True, blank=True) # Step 5 flags = models.JSONField(blank=True) # Step 6 diff --git a/app/org_eleicoes/votepeloclima/candidature/static/js/inline-array-widget.js b/app/org_eleicoes/votepeloclima/candidature/static/js/inline-array-widget.js index 82b22756..9664668a 100644 --- a/app/org_eleicoes/votepeloclima/candidature/static/js/inline-array-widget.js +++ b/app/org_eleicoes/votepeloclima/candidature/static/js/inline-array-widget.js @@ -1,16 +1,45 @@ (function ($) { "use strict"; $(function () { + const maxSize = $('#inline-array-add').data('size'); + const name = $('#inline-array').data('name'); + + function updateInlineArray() { + const totalInputs = $('#inline-array .d-flex').length; + if (totalInputs === 1) { + $('#inline-array .d-flex').find('button').hide(); + } else { + $('#inline-array .d-flex').find('button').show(); + } + + if (totalInputs === maxSize) { + $('#inline-array-add').attr('disabled', 'disabled'); + } else { + $('#inline-array-add').removeAttr('disabled'); + } + + $('#inline-array .d-flex').each((i, item) => { + $(item).find('input').attr('name', `${name}_${i}`) + }) + } + $('#inline-array-add').click(() => { - const $div = $('#inline-array .d-flex').first().clone(); - $div.find('input').val(''); - $('#inline-array').append($div); + const totalInputs = $('#inline-array .d-flex').length; + if (totalInputs < maxSize) { + const $div = $('#inline-array .d-flex').first().clone(); + $div.find('input').val(''); + $div.find('button').show(); + $('#inline-array').append($div); + updateInlineArray(); + } }); function inlineDelete(target) { $(target).parent().remove(); + updateInlineArray(); }; - window.inlineDelete=inlineDelete; + updateInlineArray(); + window.inlineDelete = inlineDelete; }); }(jQuery)); \ No newline at end of file diff --git a/app/org_eleicoes/votepeloclima/candidature/templates/forms/widgets/inline_array.html b/app/org_eleicoes/votepeloclima/candidature/templates/forms/widgets/inline_array.html index da93bb26..5a57ffc6 100644 --- a/app/org_eleicoes/votepeloclima/candidature/templates/forms/widgets/inline_array.html +++ b/app/org_eleicoes/votepeloclima/candidature/templates/forms/widgets/inline_array.html @@ -1,12 +1,15 @@ -