Skip to content

Commit f5bd2a3

Browse files
authored
Merge pull request #14 from gencat/feat/candidate_charts
Candidates charts
2 parents 9751fa8 + 42cd3ec commit f5bd2a3

File tree

8 files changed

+160
-35
lines changed

8 files changed

+160
-35
lines changed

app/controllers/decidim/stratified_sortitions/admin/stratified_sortitions_controller.rb

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,19 +104,8 @@ def upload_sample
104104
@sample_participants_count = @stratified_sortition.sample_participants.count
105105
@last_sample = SampleImport.where(stratified_sortition: @stratified_sortition).order(created_at: :desc).first
106106
@samples = SampleImport.where(stratified_sortition: @stratified_sortition).order(created_at: :asc)
107-
108-
@strata_data = @stratified_sortition.strata.map do |stratum|
109-
chart_data = stratum.substrata.map do |substratum|
110-
weighing_value = substratum.weighing.present? ? substratum.weighing.to_f : 0.0
111-
label_with_percentage = "#{translated_attribute(substratum.name)} (#{weighing_value}%)"
112-
[label_with_percentage, weighing_value]
113-
end
114-
chart_data = chart_data.reject { |_name, value| value.zero? }
115-
{
116-
stratum:,
117-
chart_data:,
118-
}
119-
end
107+
@strata_data = strata_data(@stratified_sortition)
108+
@candidates_data = candidates_data(@stratified_sortition)
120109
end
121110

122111
private
@@ -144,6 +133,71 @@ def blank_stratum
144133
def blank_substratum(stratum_form)
145134
Decidim::StratifiedSortitions::Admin::SubstratumForm.new(stratum: stratum_form.model)
146135
end
136+
137+
def strata_data(stratified_sortition)
138+
stratified_sortition.strata.map do |stratum|
139+
chart_data = stratum.substrata.map do |substratum|
140+
weighing_value = substratum.weighing.present? ? substratum.weighing.to_f : 0.0
141+
label_with_percentage = "#{translated_attribute(substratum.name)} (#{weighing_value}%)"
142+
[label_with_percentage, weighing_value]
143+
end
144+
chart_data = chart_data.reject { |_name, value| value.zero? }
145+
{
146+
stratum:,
147+
chart_data:,
148+
}
149+
end
150+
end
151+
152+
def candidates_data(stratified_sortition)
153+
sample_candidates_ids = stratified_sortition.sample_participants.pluck(:id)
154+
sample_candidates_stratum = fetch_sample_candidates_stratum(sample_candidates_ids)
155+
by_stratum = group_by_stratum(sample_candidates_stratum)
156+
by_stratum_and_substratum = group_by_stratum_and_substratum(sample_candidates_stratum)
157+
158+
stratified_sortition.strata.map do |stratum|
159+
build_stratum_chart(stratum, by_stratum, by_stratum_and_substratum)
160+
end
161+
end
162+
163+
def fetch_sample_candidates_stratum(sample_candidates_ids)
164+
Decidim::StratifiedSortitions::SampleParticipantStratum
165+
.where(decidim_stratified_sortitions_sample_participant_id: sample_candidates_ids)
166+
.select(:decidim_stratified_sortitions_sample_participant_id,
167+
:decidim_stratified_sortitions_stratum_id,
168+
:decidim_stratified_sortitions_substratum_id)
169+
.distinct
170+
.to_a
171+
end
172+
173+
def group_by_stratum(sample_candidates_stratum)
174+
sample_candidates_stratum.group_by(&:decidim_stratified_sortitions_stratum_id)
175+
end
176+
177+
def group_by_stratum_and_substratum(sample_candidates_stratum)
178+
sample_candidates_stratum.group_by do |s|
179+
[s.decidim_stratified_sortitions_stratum_id, s.decidim_stratified_sortitions_substratum_id]
180+
end
181+
end
182+
183+
def build_stratum_chart(stratum, by_stratum, by_stratum_and_substratum)
184+
substrata = stratum.substrata
185+
total = by_stratum[stratum.id]&.map(&:decidim_stratified_sortitions_sample_participant_id)&.uniq&.count || 0
186+
chart_data = substrata.map do |substratum|
187+
build_substratum_chart_row(stratum, substratum, by_stratum_and_substratum, total)
188+
end
189+
chart_data = chart_data.reject { |_name, value| value.zero? }
190+
{ stratum:, chart_data: }
191+
end
192+
193+
def build_substratum_chart_row(stratum, substratum, by_stratum_and_substratum, total)
194+
ids = (by_stratum_and_substratum[[stratum.id, substratum.id]] || [])
195+
.map(&:decidim_stratified_sortitions_sample_participant_id).uniq
196+
count = ids.count
197+
percentage = total.positive? ? ((count.to_f / total) * 100).round(1) : 0.0
198+
label = "#{translated_attribute(substratum.name)} (#{percentage}%)"
199+
[label, count]
200+
end
147201
end
148202
end
149203
end

app/packs/stylesheets/decidim/stratified_sortitions/admin/stratified_sortitions.scss

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@
3030

3131
.chart-row {
3232
display: flex;
33-
gap: 4em;
3433
margin-top: 1em;
35-
flex-wrap: wrap;
36-
justify-content: start;
34+
justify-content: space-around;
3735
}
3836

3937
.chart-col {
@@ -42,12 +40,24 @@
4240
max-width: 450px;
4341
display: flex;
4442
flex-direction: column;
43+
margin-top: 1em;
4544
}
4645

4746
.chart-place {
4847
max-width: 380px;
4948
}
5049

50+
.charts-column {
51+
width: 100%;
52+
display: flex;
53+
flex-direction: column;
54+
align-items: center;
55+
}
56+
57+
.target {
58+
border-right: 1px solid #6B7280CC;
59+
}
60+
5161
@media (max-width: 900px) {
5262
.chart-row {
5363
gap: 2em;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<span>
2+
<h1 class="item_show__header-title">
3+
<%= local_assigns[:title] || "" %>
4+
</h1>
5+
</span>
6+
<% (strata_data || []).each do |stratum_data| %>
7+
<div class="column chart-col">
8+
<b><%= translated_attribute(stratum_data[:stratum].name).upcase %></b>
9+
<% if stratum_data[:chart_data].present? %>
10+
<%= pie_chart stratum_data[:chart_data],
11+
legend: "bottom",
12+
donut: false %>
13+
<% else %>
14+
<p class="text-muted">
15+
<%= t('decidim.stratified_sortitions.admin.stratified_sortitions.upload_sample.no_data') %>
16+
</p>
17+
<% end %>
18+
</div>
19+
<% end %>

app/views/decidim/stratified_sortitions/admin/stratified_sortitions/upload_sample.html.erb

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
<div class="row mt-4">
2323
<%= form_tag samples_path(id: @stratified_sortition.id), multipart: true, class: 'form' do %>
2424
<div class="flex">
25-
2625
<%= file_field_tag :file, id: 'sample-file-input' %>
2726

2827
<% if @stratified_sortition.strata_and_substrata_configured? %>
@@ -61,25 +60,13 @@
6160
</div>
6261
</div>
6362
<div class="mt-4 mb-4">
64-
<span>
65-
<h1 class="item_show__header-title">
66-
<%= t(".target") %>
67-
</h1>
68-
</span>
6963
<div class="row chart-row">
70-
<% @strata_data.each do |stratum_data| %>
71-
<div class="column chart-col">
72-
<b><%= translated_attribute(stratum_data[:stratum].name).upcase %></b>
73-
<% if stratum_data[:chart_data].present? %>
74-
<%= pie_chart stratum_data[:chart_data],
75-
legend: "bottom",
76-
donut: false
77-
%>
78-
<% else %>
79-
<p class="text-muted"><%= t('.no_data') %></p>
80-
<% end %>
81-
</div>
82-
<% end %>
64+
<div class="col-md-6 charts-column target">
65+
<%= render partial: "strata_charts", locals: { strata_data: @strata_data, title: t(".target") } %>
66+
</div>
67+
<div class="col-md-6 charts-column">
68+
<%= render partial: "strata_charts", locals: { strata_data: @candidates_data, title: t(".candidates") } %>
69+
</div>
8370
</div>
8471
<div class="mt-16 census_file_type">
8572
<span>

config/locales/ca.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ ca:
9696
success: Sorteig estratificat actualitzat amb èxit
9797
upload_sample:
9898
age: Grup d'edat
99+
candidates: Candidats
99100
census_file: Triar un fitxer
100101
census_file_label: Arxiu excel.csv amb les dades del cens
101102
configure_strata_first: Primer has de configurar els estrats i subestrats

config/locales/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ en:
9494
success: Stratified sortition successfully updated
9595
upload_sample:
9696
age: Age group
97+
candidates: Candidates
9798
census_file: Choose a file
9899
census_file_label: Excel.csv file with census data
99100
configure_strata_first: You must configure strata and substrata first

config/locales/es.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ es:
9696
success: Sorteo estratificado actualizado con éxito
9797
upload_sample:
9898
age: Grupo de edad
99+
candidates: Candidatos
99100
census_file: Elegir un archivo
100101
census_file_label: Archivo excel.csv con los datos del censo
101102
configure_strata_first: Primero debes configurar los estratos y subestratos

spec/controllers/decidim/sortitions/admin/stratified_sortitions_controller_spec.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,58 @@ module Admin
205205
end
206206
end
207207
end
208+
209+
describe "upload_sample" do
210+
let(:stratified_sortition) { create(:stratified_sortition) }
211+
let(:params) do
212+
{
213+
participatory_process_slug: component.participatory_space.slug,
214+
id: stratified_sortition.id,
215+
}
216+
end
217+
218+
before do
219+
stratum_1 = create(:stratum, stratified_sortition:, kind: "value", name: { ca: "Gènere", es: "Género", en: "Gender" })
220+
substratum_1 = create(:substratum, stratum: stratum_1, name: { ca: "Home", es: "Hombre", en: "Man" }, value: "H", weighing: "50")
221+
substratum_2 = create(:substratum, stratum: stratum_1, name: { ca: "Dona", es: "Mujer", en: "Woman" }, value: "D", weighing: "50")
222+
223+
sample_import = create(:sample_import, stratified_sortition:)
224+
participant_1 = create(:sample_participant, decidim_stratified_sortition: stratified_sortition, decidim_stratified_sortitions_sample_import: sample_import)
225+
participant_2 = create(:sample_participant, decidim_stratified_sortition: stratified_sortition, decidim_stratified_sortitions_sample_import: sample_import)
226+
227+
create(:sample_participant_stratum, decidim_stratified_sortitions_sample_participant: participant_1, decidim_stratified_sortitions_stratum: stratum_1, decidim_stratified_sortitions_substratum: substratum_1)
228+
create(:sample_participant_stratum, decidim_stratified_sortitions_sample_participant: participant_2, decidim_stratified_sortitions_stratum: stratum_1, decidim_stratified_sortitions_substratum: substratum_2)
229+
end
230+
231+
it "renders the upload_sample template" do
232+
get(:upload_sample, params:)
233+
expect(response).to render_template(:upload_sample)
234+
end
235+
236+
it "assigns @stratified_sortition" do
237+
get(:upload_sample, params:)
238+
expect(assigns(:stratified_sortition)).to eq(stratified_sortition)
239+
end
240+
241+
it "assigns @sample_participants_count" do
242+
get(:upload_sample, params:)
243+
expect(assigns(:sample_participants_count)).to eq(stratified_sortition.sample_participants.count)
244+
end
245+
246+
it "assigns @strata_data and @candidates_data" do
247+
get(:upload_sample, params:)
248+
expect(assigns(:strata_data)).to be_an(Array)
249+
expect(assigns(:candidates_data)).to be_an(Array)
250+
expect(assigns(:strata_data).first[:stratum]).to be_present
251+
expect(assigns(:candidates_data).first[:stratum]).to be_present
252+
end
253+
254+
it "@candidates_data refleja los datos importados" do
255+
get(:upload_sample, params:)
256+
imported = assigns(:candidates_data).first[:chart_data].map(&:last)
257+
expect(imported.sum).to eq(stratified_sortition.sample_participants.count)
258+
end
259+
end
208260
end
209261
end
210262
end

0 commit comments

Comments
 (0)