feat: calmer questionnaire form with selects and clickable answer rows
This commit is contained in:
1 parent
af97468b2d
commit
0b736b51fb
5 files changed
+65
-5
No files matched your search
@@ -35,6 +35,7 @@ sections:
|
||||
- key: bus_company
|
||||
label: "Bus-Unternehmen:"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: boonk, label: "Boonk Reisen" }
|
||||
@@ -80,6 +81,7 @@ sections:
|
||||
- key: overall_impression
|
||||
label: "Gesamteindruck des Busses"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_good, label: "Sehr gut" }
|
||||
@@ -91,6 +93,7 @@ sections:
|
||||
- key: vehicle_age
|
||||
label: "Alter des Fahrzeugs"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_new, label: "Sehr neu" }
|
||||
@@ -102,6 +105,7 @@ sections:
|
||||
- key: seating_comfort
|
||||
label: "Sitzkomfort im Bus"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_good, label: "Sehr gut" }
|
||||
@@ -113,6 +117,7 @@ sections:
|
||||
- key: driver_friendliness
|
||||
label: "Freundlichkeit der Fahrer"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_friendly, label: "Sehr freundlich" }
|
||||
@@ -124,6 +129,7 @@ sections:
|
||||
- key: breaks
|
||||
label: "Pausenzeiten"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_good, label: "Sehr gut" }
|
||||
@@ -135,6 +141,7 @@ sections:
|
||||
- key: temperature
|
||||
label: "Temperatur im Bus"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_good, label: "Sehr gut" }
|
||||
@@ -146,6 +153,7 @@ sections:
|
||||
- key: guest_behaviour
|
||||
label: "Verhalten der Gäste im Bus"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_good, label: "Sehr gut" }
|
||||
@@ -188,6 +196,7 @@ sections:
|
||||
- key: video
|
||||
label: "Video/DVD-Gerät"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: working, label: "funktionstüchtig" }
|
||||
@@ -197,6 +206,7 @@ sections:
|
||||
- key: wc
|
||||
label: "WC"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: working, label: "funktionstüchtig" }
|
||||
@@ -206,6 +216,7 @@ sections:
|
||||
- key: luggage
|
||||
label: "Gepäck"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: trailer, label: "Anhänger" }
|
||||
@@ -216,6 +227,7 @@ sections:
|
||||
- key: smoking
|
||||
label: "Rauchen im Bus"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: driver, label: "Busfahrer hat im Bus geraucht" }
|
||||
@@ -225,6 +237,7 @@ sections:
|
||||
- key: snow_chains
|
||||
label: "Schneeketten"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: fitted, label: "Fahrer hat Ketten aufgezogen" }
|
||||
@@ -237,6 +250,7 @@ sections:
|
||||
- key: bus_damage
|
||||
label: "Entstanden während der Fahrt Schäden am Bus?"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: none, label: "Keine Schäden" }
|
||||
|
||||
@@ -42,6 +42,7 @@ sections:
|
||||
- key: team_week_seminar
|
||||
label: "War das Wochenteam-Seminar hilfreich für dich? Warst du bzw. wurdest du gut vorbereitet?"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_helpful, label: "Ja, die Schulung war sehr hilfreich und ich fühlte mich bestens vorbereitet." }
|
||||
@@ -84,6 +85,7 @@ sections:
|
||||
- key: house_manager_problem_handling
|
||||
label: "Wie ist deine Hausleitung mit Problemen vor Ort umgegangen?"
|
||||
type: choice
|
||||
widget: dropdown
|
||||
required: true
|
||||
options:
|
||||
- { key: very_good, label: "Sehr gut – Probleme wurden schnell, fair und lösungsorientiert behandelt." }
|
||||
|
||||
@@ -151,14 +151,20 @@ class QuestionnaireType extends AbstractType
|
||||
return match ($question->type) {
|
||||
QuestionType::TEXT => [TextType::class, $common],
|
||||
QuestionType::TEXTAREA => [AutosizeTextareaType::class, $common + ['min_rows' => 3]],
|
||||
QuestionType::CHOICE => [ChoiceType::class, $common + $this->choices($question) + [
|
||||
'expanded' => ChoiceWidget::RADIO === $question->widget,
|
||||
// a radio list needs no "none" entry, a select needs an empty first line
|
||||
'placeholder' => ChoiceWidget::RADIO === $question->widget ? false : 'Bitte wählen',
|
||||
]],
|
||||
QuestionType::CHOICE => [ChoiceType::class, $common + $this->choices($question) + (ChoiceWidget::RADIO === $question->widget ? [
|
||||
'expanded' => true,
|
||||
// a radio list needs no "none" entry
|
||||
'placeholder' => false,
|
||||
'block_prefix' => 'questionnaire_choice',
|
||||
] : [
|
||||
'expanded' => false,
|
||||
// a select needs an empty first line, or the first option would be preselected
|
||||
'placeholder' => 'Bitte wählen',
|
||||
])],
|
||||
QuestionType::MULTI => [ChoiceType::class, $common + $this->choices($question) + [
|
||||
'expanded' => true,
|
||||
'multiple' => true,
|
||||
'block_prefix' => 'questionnaire_choice',
|
||||
]],
|
||||
QuestionType::DATE => [DatepickerType::class, $common + [
|
||||
'input' => 'string',
|
||||
|
||||
@@ -207,6 +207,23 @@
|
||||
</fieldset>
|
||||
{%- endblock questionnaire_section_row -%}
|
||||
|
||||
{#
|
||||
# A questionnaire's radio or checkbox list: each answer a whole clickable row that lights up on
|
||||
# hover and stays marked once chosen, so it is plain where to click. Questionnaire-only; the
|
||||
# app's other choice lists keep choice_widget_expanded.
|
||||
#}
|
||||
{%- block questionnaire_choice_widget -%}
|
||||
<div class="flex flex-col gap-y-1" {{ block('widget_container_attributes') }}>
|
||||
{%- for child in form -%}
|
||||
<label for="{{ child.vars.id }}"
|
||||
class="{{ html_classes('flex cursor-pointer select-none items-center gap-x-3 rounded-md px-3 py-2 text-sm ring-1 ring-inset transition-colors hover:bg-gray-100 has-[:checked]:bg-primary/10 has-[:checked]:ring-primary', { 'ring-red-500': errors|length, 'ring-gray-200': not errors|length }) }}">
|
||||
{{- form_widget(child, { attr: { class: 'h-4 w-4 shrink-0 border-gray-300 text-primary focus:ring-primary' } }) -}}
|
||||
<span class="text-gray-900">{{ child.vars.label }}</span>
|
||||
</label>
|
||||
{%- endfor -%}
|
||||
</div>
|
||||
{%- endblock questionnaire_choice_widget -%}
|
||||
|
||||
{# A 1-5 rating as a row of buttons, the radios themselves hidden. #}
|
||||
{%- block questionnaire_rating_widget -%}
|
||||
<div class="flex gap-x-2" role="radiogroup">
|
||||
|
||||
@@ -59,6 +59,27 @@ class QuestionnaireTemplateTest extends KernelTestCase
|
||||
$this->assertSame([$this->definition()->title, $this->busDefinition()->title], $headings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Long scales are selects, starting empty; Ja/Nein stays radios, each answer a clickable row.
|
||||
*/
|
||||
public function testLongScalesAreSelectsAndYesNoAreClickableRows(): void
|
||||
{
|
||||
$crawler = $this->renderForm();
|
||||
|
||||
$seminar = $crawler->filter('[data-question-key="teamer_feedback.team_week_seminar"] select');
|
||||
$this->assertCount(1, $seminar);
|
||||
$this->assertSame('', $seminar->filter('option')->first()->attr('value'));
|
||||
$this->assertCount(1, $crawler->filter('[data-question-key="bus_feedback.wc"] select'));
|
||||
|
||||
// the labels wrapping a radio: the whole row is the click target
|
||||
$rows = $crawler
|
||||
->filter('[data-question-key="teamer_feedback.had_organisational_problems"] label')
|
||||
->reduce(static fn (Crawler $label): bool => 1 === $label->filter('input[type="radio"]')->count())
|
||||
;
|
||||
$this->assertCount(2, $rows);
|
||||
$this->assertStringContainsString('hover:', $rows->first()->attr('class'));
|
||||
}
|
||||
|
||||
public function testRatingIsFiveRadiosInARadioGroup(): void
|
||||
{
|
||||
$group = $this->renderForm()->filter('[data-question-key="teamer_feedback.office_briefing_rating"] [role="radiogroup"]');
|
||||
|
||||
Reference in new issue
Block a user