Add politicians question type
This commit is contained in:
parent
4fe218166f
commit
2893f2bc53
16 changed files with 101 additions and 33 deletions
|
@ -1 +1,5 @@
|
|||
/* Entry point for your PostCSS build */
|
||||
.politicians-listing {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
|
|
@ -20,4 +20,8 @@ class QuestionsController < ApplicationController
|
|||
)
|
||||
@answer.save!
|
||||
end
|
||||
|
||||
def handle_politicians_answer
|
||||
@answer.update!(data: params[:order])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
module QuestionsHelper
|
||||
def reorder_with_indices(array, indices)
|
||||
array.sort {|a1, a2| indices.index(a1[1]) <=> indices.index(a2[1])}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Entry point for the build script in your package.json
|
||||
import initSimpleQuestions from './simple_input.js'
|
||||
import initImageQuestions from './image_input.js'
|
||||
import initPoliticianQuestions from './politicians_answer.js'
|
||||
|
||||
addEventListener("DOMContentLoaded", () => {
|
||||
initSimpleQuestions()
|
||||
initImageQuestions()
|
||||
initPoliticianQuestions()
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const csrfToken = document.querySelector("[name='csrf-token']").content
|
||||
import { submitValue } from './submit_value.js'
|
||||
|
||||
export default function initImageQuestions() {
|
||||
document.querySelectorAll('[data-behaviour="question_image_input"]').forEach((input) => {
|
||||
|
@ -8,17 +8,10 @@ export default function initImageQuestions() {
|
|||
const file = input.files[0];
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (ev) => {
|
||||
fetch(submitUrl, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
"x-csrf-token": csrfToken,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
filename: file.name,
|
||||
mimetype: file.type,
|
||||
data: ev.target.result.replace(/^data:[a-zA-Z0-9!#$%^&\\*_\-+{}|'.`~]+\/[a-zA-Z0-9!#$%^&\\*_\-+{}|'.`~]+;base64,/, ""),
|
||||
})
|
||||
submitValue(submitUrl, {
|
||||
filename: file.name,
|
||||
mimetype: file.type,
|
||||
data: ev.target.result.replace(/^data:[a-zA-Z0-9!#$%^&\\*_\-+{}|'.`~]+\/[a-zA-Z0-9!#$%^&\\*_\-+{}|'.`~]+;base64,/, ""),
|
||||
})
|
||||
}
|
||||
fileReader.readAsDataURL(file);
|
||||
|
|
20
app/javascript/politicians_answer.js
Normal file
20
app/javascript/politicians_answer.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { Sortable, Swap } from 'sortablejs'
|
||||
|
||||
import { submitValue } from './submit_value.js'
|
||||
|
||||
export default function initPoliticianQuestions() {
|
||||
|
||||
Sortable.mount(new Swap())
|
||||
|
||||
document.querySelectorAll('[data-behaviour="politicians_answer').forEach((list) => {
|
||||
const submitUrl = list.dataset.submitUrl
|
||||
|
||||
Sortable.create(list, {
|
||||
swap: true,
|
||||
onUpdate: (event) => {
|
||||
const newOrder = Array.from(event.to.children).map((el) => Number.parseInt(el.dataset.id))
|
||||
submitValue(submitUrl, { order: newOrder })
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,23 +1,11 @@
|
|||
import debounce from 'debounce'
|
||||
|
||||
const csrfToken = document.querySelector("[name='csrf-token']").content
|
||||
import { submitValueDebounced } from './submit_value.js'
|
||||
|
||||
export default function initSimpleQuestions() {
|
||||
document.querySelectorAll('[data-behaviour="question_simple_input"]').forEach((input) => {
|
||||
const submitUrl = input.dataset.submitUrl
|
||||
const submit = submitValueDebounced()
|
||||
|
||||
const handleInput = debounce(() => {
|
||||
fetch(submitUrl, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
"x-csrf-token": csrfToken,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ value: input.value }),
|
||||
})
|
||||
}, 300)
|
||||
|
||||
input.addEventListener('change', handleInput)
|
||||
input.addEventListener('input', handleInput)
|
||||
input.addEventListener('change', () => submit(submitUrl, {value: input.value}))
|
||||
input.addEventListener('input', () => submit(submitUrl, {value: input.value}))
|
||||
})
|
||||
}
|
||||
|
|
18
app/javascript/submit_value.js
Normal file
18
app/javascript/submit_value.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import debounce from 'debounce'
|
||||
|
||||
const csrfToken = document.querySelector("[name='csrf-token']").content
|
||||
|
||||
export function submitValue(url, value) {
|
||||
fetch(url, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
"x-csrf-token": csrfToken,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(value),
|
||||
})
|
||||
}
|
||||
|
||||
export function submitValueDebounced() {
|
||||
return debounce(submitValue, 300)
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#
|
||||
# id :integer not null, primary key
|
||||
# answer_kind :integer not null
|
||||
# data :text
|
||||
# public_asset_path :string
|
||||
# question_kind :integer default("simple"), not null
|
||||
# text :text not null
|
||||
|
@ -25,4 +26,6 @@ class Question < ApplicationRecord
|
|||
|
||||
belongs_to :section
|
||||
has_one :answer
|
||||
|
||||
serialize :data, coder: JSON
|
||||
end
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
<div>
|
||||
This one's going to be hard...
|
||||
<div class="politicians-listing">
|
||||
<div>
|
||||
<% question.data["left"].each do |l| %>
|
||||
<p><%= l %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<div data-behaviour="politicians_answer"
|
||||
data-submit-url="<%= answer_question_url(question.id) %>"
|
||||
>
|
||||
<% answers = question.data["right"].each.with_index.to_a %>
|
||||
<% answers = reorder_with_indices(answers, question.answer.data) if question.answer.present? %>
|
||||
<% answers.each do |a, i| %>
|
||||
<p data-id="<%= i %>"><%= a %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
5
db/migrate/20250515124656_question_add_data_field.rb
Normal file
5
db/migrate/20250515124656_question_add_data_field.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class QuestionAddDataField < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :questions, :data, :text
|
||||
end
|
||||
end
|
3
db/schema.rb
generated
3
db/schema.rb
generated
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_04_26_202909) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_05_15_124656) do
|
||||
create_table "active_storage_attachments", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.string "record_type", null: false
|
||||
|
@ -55,6 +55,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_04_26_202909) do
|
|||
t.datetime "updated_at", null: false
|
||||
t.integer "question_kind", default: 0, null: false
|
||||
t.string "public_asset_path"
|
||||
t.text "data"
|
||||
t.index ["section_id"], name: "index_questions_on_section_id"
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
"postcss": "^8.5.3",
|
||||
"postcss-cli": "^11.0.1",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-nesting": "^13.0.1"
|
||||
"postcss-nesting": "^13.0.1",
|
||||
"sortablejs": "^1.15.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.3"
|
||||
|
|
9
test/fixtures/questions.yml
vendored
9
test/fixtures/questions.yml
vendored
|
@ -6,6 +6,7 @@
|
|||
#
|
||||
# id :integer not null, primary key
|
||||
# answer_kind :integer not null
|
||||
# data :text
|
||||
# public_asset_path :string
|
||||
# question_kind :integer default("simple"), not null
|
||||
# text :text not null
|
||||
|
@ -115,7 +116,13 @@ politics_regenpijpen:
|
|||
|
||||
politics_schepenen:
|
||||
section: politics
|
||||
text: Verbind de schepenen en hun bevoegdheden.
|
||||
text: Verplaats de bevoegdheden zodat ze bij de juiste schepen staan.
|
||||
data: '<%=
|
||||
JSON.dump({
|
||||
left: ["Mathias De Clercq", "Hafsa El-Bazioui", "Astrid De Bruycker", "Sofie Bracke", "Evita Willaert", "Joris Vandenbroucke", "Bram Van Braeckevelt", "Burak Nalli", "Filip Watteeuw", "Cristophe Peeters"].shuffle,
|
||||
right: ["Burgemeester", "Participatie, Buurtwerk, Mondiale Solidariteit, Facilitair Management en Digitalisering", "Sociale Vooruitgang, Gezondheid, Ouderenbeleid en Cultuur", "Economie, Haven, Handel, Toerisme en Openbare netheid", "Onderwijs, Opvoeding, Jeugd, Gezin en Outreachend Werk", "Mobiliteit, Ruimte, Stadsontwikkeling en Plezier", "Natuur en Groen, Werk en Sociale Economie, Gelijke kansen en Sport", "Personeelsbeleid, Burgerzaken en Dienstverlening", "Wonen, Milieu, Klimaat en Energie", "Financiën, Stedenbouw, Erfgoed en Administratieve vereenvoudiging"].shuffle
|
||||
})
|
||||
%>'
|
||||
answer_kind: <%= Question.answer_kinds[:politicians] %>
|
||||
question_kind: <%= Question.question_kinds[:simple] %>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#
|
||||
# id :integer not null, primary key
|
||||
# answer_kind :integer not null
|
||||
# data :text
|
||||
# public_asset_path :string
|
||||
# question_kind :integer default("simple"), not null
|
||||
# text :text not null
|
||||
|
|
|
@ -559,6 +559,11 @@ slash@^5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce"
|
||||
integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==
|
||||
|
||||
sortablejs@^1.15.6:
|
||||
version "1.15.6"
|
||||
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.6.tgz#ff93699493f5b8ab8d828f933227b4988df1d393"
|
||||
integrity sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==
|
||||
|
||||
source-map-js@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue