Skip to content

Commit be84605

Browse files
committed
[#3081] all works
1 parent ba7c487 commit be84605

File tree

18 files changed

+348
-237
lines changed

18 files changed

+348
-237
lines changed

src/open_inwoner/cms/collaborate/urls.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
PlanActionEditStatusTagView,
77
PlanActionEditView,
88
PlanActionHistoryView,
9-
PlanCreateView,
9+
PlanCreateNoTemplateView,
10+
PlanCreateWithTemplateView,
1011
PlanDetailView,
1112
PlanEditView,
1213
PlanExportView,
@@ -25,7 +26,12 @@
2526
PlanTemplateChooseView.as_view(),
2627
name="plan_choose_template",
2728
),
28-
path("create/", PlanCreateView.as_view(), name="plan_create"),
29+
path("create/", PlanCreateNoTemplateView.as_view(), name="plan_create_no_template"),
30+
path(
31+
"create-from-template/",
32+
PlanCreateWithTemplateView.as_view(),
33+
name="plan_create_with_template",
34+
),
2935
path("<uuid:uuid>/", PlanDetailView.as_view(), name="plan_detail"),
3036
path("<uuid:uuid>/edit/", PlanEditView.as_view(), name="plan_edit"),
3137
path("<uuid:uuid>/edit/goal/", PlanGoalEditView.as_view(), name="plan_edit_goal"),

src/open_inwoner/components/templates/components/Form/FormActions.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{% load button_tags %}
2-
<div class="form__actions {% if nogrid %}form__actions--nogrid{% endif %} {% if single %}form__actions--single{% endif %} {% if fullwidth %}form__actions--fullwidth{% endif %}">
2+
<div class="form__actions {% if single %}form__actions--single{% endif %} {% if fullwidth %}form__actions--fullwidth{% endif %}">
33
{% if secondary_text %}{% button href=secondary_href secondary=secondary text=secondary_text icon=secondary_icon icon_position=secondary_icon_position form_id=form_id %}{% endif %}
44
{% if secondary_name %}{% button name=secondary_name type="submit" secondary=secondary text=secondary_text icon=secondary_icon icon_position=secondary_icon_position form_id=form_id %}{% endif %}
55
{% if secondary_value %}{% button name=secondary_name value=secondary_value type="submit" secondary=secondary text=secondary_text icon=secondary_icon icon_position=secondary_icon_position form_id=form_id %}{% endif %}

src/open_inwoner/js/components/form/ChoiceListSingle.js

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export class ChoiceListSingle {
1919
// Add event listeners for click events
2020
this.labels.forEach((label) => {
2121
label.addEventListener('click', () => {
22-
console.log('A click on the .choice-list__label element.')
2322
const selectedListItem = node.querySelector('.selected')
2423
if (selectedListItem) {
2524
selectedListItem.classList.remove('selected')

src/open_inwoner/js/components/plan-preview/index.js

+59-3
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,10 @@ export class PlanPreview {
1212
openPreview(event) {
1313
event.stopPropagation()
1414
event.preventDefault()
15-
console.log('button for plan is clicked')
1615

1716
const modalId = this.node.dataset.id || 'modal'
1817
const modalElement = document.getElementById(modalId)
19-
2018
if (!modalElement) {
21-
console.error(`Modal with ID "${modalId}" not found`)
2219
return
2320
}
2421

@@ -31,6 +28,65 @@ export class PlanPreview {
3128
// Track the element that opened the modal
3229
modal.openedBy = this.node
3330

31+
// Find the corresponding radio input
32+
let radioInput = null
33+
34+
// First structure (original page)
35+
const templateRow = this.node.closest('.plan-template__row')
36+
if (templateRow) {
37+
radioInput = templateRow.querySelector('.radio__input')
38+
}
39+
40+
// Second structure (choice-list page)
41+
if (!radioInput) {
42+
const choiceListItem = this.node.closest('.choice-list__item')
43+
if (choiceListItem) {
44+
radioInput = choiceListItem.querySelector('.choice-list__radio')
45+
}
46+
}
47+
48+
// Get the template ID from the modalId
49+
const templateId = modalId.split('-')[1]
50+
51+
// As a fallback, try to find the radio by its ID
52+
if (!radioInput && templateId) {
53+
radioInput = document.getElementById(`id_template_${templateId}`)
54+
}
55+
56+
// Find all close buttons in the modal
57+
const closeButtons = modalElement.querySelectorAll(
58+
'.modal__close, .modal__close-title'
59+
)
60+
61+
// Add event listener to all close buttons to select the radio input
62+
if (radioInput) {
63+
closeButtons.forEach((closeButton) => {
64+
closeButton.addEventListener(
65+
'click',
66+
() => {
67+
// Select the radio input
68+
radioInput.checked = true
69+
70+
// If using the choice-list structure, add the 'selected' class to the parent list item
71+
const choiceListItem = radioInput.closest('.choice-list__item')
72+
if (choiceListItem) {
73+
// Remove 'selected' class from all items
74+
const allItems = document.querySelectorAll('.choice-list__item')
75+
allItems.forEach((item) => item.classList.remove('selected'))
76+
77+
// Add 'selected' class to the clicked item
78+
choiceListItem.classList.add('selected')
79+
}
80+
81+
// Trigger change event to ensure any listeners know the radio was changed
82+
const changeEvent = new Event('change', { bubbles: true })
83+
radioInput.dispatchEvent(changeEvent)
84+
},
85+
{ once: true }
86+
)
87+
})
88+
}
89+
3490
// Set the modal-closed callback to focus on the element that opened it
3591
modal.setModalClosedCallback(() => {
3692
if (modal.openedBy) {

src/open_inwoner/plans/templates/plans/preview.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<div class='plan-preview'>
44
<p class='plan-preview__key'>{% trans "Titel" %}</p>
5-
<h2 class="utrecht-heading-2">{{ plan_template.name }}</h2>
5+
<h2 class="utrecht-heading-4">{{ plan_template.name }}</h2>
66
{% if plan_template.goal %}
77
<p class='plan-preview__key'>{% trans "Doel" %}</p>
88
<div>{{ plan_template.goal|truncatewords:20 }}</div>

src/open_inwoner/plans/tests/test_logging.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ def setUp(self):
3232

3333
def test_created_plan_is_logged(self):
3434
plan = PlanFactory.build(created_by=self.user)
35-
form = self.app.get(reverse("collaborate:plan_create"), user=self.user).forms[
36-
"plan-form"
37-
]
35+
form = self.app.get(
36+
reverse("collaborate:plan_create_no_template"), user=self.user
37+
).forms["plan-form"]
3838
form["title"] = plan.title
3939
form["goal"] = plan.goal
4040
form["end_date"] = plan.end_date

src/open_inwoner/plans/tests/test_views.py

+21-14
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ def setUp(self) -> None:
4545
self.login_url = reverse("login")
4646
self.list_url = reverse("collaborate:plan_list")
4747
self.choose_template_url = reverse("collaborate:plan_choose_template")
48-
self.create_url = reverse("collaborate:plan_create")
48+
# TODO: new tests for choosing template form
49+
self.create_url = reverse("collaborate:plan_create_no_template")
50+
self.create_with_template_url = reverse("collaborate:plan_create_with_template")
51+
# TODO: new tests for creating plan from template where Title/Goal are prefilled, but Contact/Enddate are not.
4952
self.detail_url = reverse(
5053
"collaborate:plan_detail", kwargs={"uuid": self.plan.uuid}
5154
)
@@ -316,11 +319,11 @@ def test_plan_action_create_not_your_action(self):
316319
other_user = UserFactory()
317320
self.app.get(self.action_add_url, user=other_user, status=404)
318321

319-
def test_plan_create_login_required(self):
322+
def test_plan_create_no_template_login_required(self):
320323
response = self.app.get(self.create_url)
321324
self.assertRedirects(response, f"{self.login_url}?next={self.create_url}")
322325

323-
def test_plan_create_fields_required(self):
326+
def test_plan_create_no_template_fields_required(self):
324327
response = self.app.get(self.create_url, user=self.user)
325328
form = response.forms["plan-form"]
326329
response = form.submit()
@@ -334,7 +337,7 @@ def test_plan_create_fields_required(self):
334337
},
335338
)
336339

337-
def test_plan_create_fails_with_no_collaborators(self):
340+
def test_plan_create_no_template_fails_with_no_collaborators(self):
338341
response = self.app.get(self.create_url, user=self.user)
339342
form = response.forms["plan-form"]
340343
form["title"] = "Plan"
@@ -349,7 +352,7 @@ def test_plan_create_fails_with_no_collaborators(self):
349352
{"__all__": [_("At least one collaborator is required for a plan.")]},
350353
)
351354

352-
def test_plan_create_contains_expected_contacts(self):
355+
def test_plan_create_no_template_contains_expected_contacts(self):
353356
another_contact = UserFactory()
354357
self.user.user_contacts.add(another_contact)
355358
response = self.app.get(self.create_url, user=self.user)
@@ -362,7 +365,7 @@ def test_plan_create_contains_expected_contacts(self):
362365
self.assertIn(self.contact.get_full_name(), rendered_contacts)
363366
self.assertIn(another_contact.get_full_name(), rendered_contacts)
364367

365-
def test_plan_create_plan(self):
368+
def test_plan_create_no_template_plan(self):
366369
self.assertEqual(Plan.objects.count(), 1)
367370
response = self.app.get(self.create_url, user=self.user)
368371
form = response.forms["plan-form"]
@@ -379,10 +382,10 @@ def test_plan_create_plan(self):
379382
self.assertEqual(plan.goal, "Goal")
380383
self.assertEqual(plan.description, "Description")
381384

382-
def test_plan_create_plan_with_template(self):
385+
def test_plan_create_no_template_plan_with_template(self):
383386
plan_template = PlanTemplateFactory(file=None)
384387
self.assertEqual(Plan.objects.count(), 1)
385-
response = self.app.get(self.choose_template_url, user=self.user)
388+
response = self.app.get(self.create_url, user=self.user)
386389
form = response.forms["plan-form"]
387390
form["title"] = "Plan"
388391
form["end_date"] = "2022-01-01"
@@ -398,7 +401,7 @@ def test_plan_create_plan_with_template(self):
398401
self.assertEqual(plan.documents.count(), 0)
399402
self.assertEqual(plan.actions.count(), 0)
400403

401-
def test_plan_create_plan_with_template_and_field_overrides(self):
404+
def test_plan_create_no_template_plan_with_template_and_field_overrides(self):
402405
plan_template = PlanTemplateFactory(file=None)
403406
self.assertEqual(Plan.objects.count(), 1)
404407
response = self.app.get(self.create_url, user=self.user)
@@ -419,7 +422,7 @@ def test_plan_create_plan_with_template_and_field_overrides(self):
419422
self.assertEqual(plan.documents.count(), 0)
420423
self.assertEqual(plan.actions.count(), 0)
421424

422-
def test_plan_create_plan_with_template_and_file(self):
425+
def test_plan_create_no_template_plan_with_template_and_file(self):
423426
plan_template = PlanTemplateFactory()
424427
self.assertEqual(Plan.objects.count(), 1)
425428
response = self.app.get(self.create_url, user=self.user)
@@ -438,7 +441,7 @@ def test_plan_create_plan_with_template_and_file(self):
438441
self.assertEqual(plan.documents.count(), 1)
439442
self.assertEqual(plan.actions.count(), 0)
440443

441-
def test_plan_create_plan_with_template_and_actions(self):
444+
def test_plan_create_no_template_plan_with_template_and_actions(self):
442445
plan_template = PlanTemplateFactory(file=None)
443446
ActionTemplateFactory(plan_template=plan_template)
444447
self.assertEqual(Plan.objects.count(), 1)
@@ -458,7 +461,9 @@ def test_plan_create_plan_with_template_and_actions(self):
458461
self.assertEqual(plan.documents.count(), 0)
459462
self.assertEqual(plan.actions.count(), 1)
460463

461-
def test_plan_create_plan_validation_error_reselects_template_and_contact(self):
464+
def test_plan_create_no_template_plan_validation_error_reselects_template_and_contact(
465+
self,
466+
):
462467
plan_template = PlanTemplateFactory(file=None)
463468
ActionTemplateFactory(plan_template=plan_template)
464469
# make sure we have only one plan
@@ -484,12 +489,14 @@ def test_plan_create_plan_validation_error_reselects_template_and_contact(self):
484489
elem = response.pyquery("#id_plan_contacts_1")[0]
485490
self.assertEqual(elem.attrib.get("checked"), "checked")
486491

487-
def test_plan_create_contains_contact_create_link_when_no_contacts_exist(self):
492+
def test_plan_create_no_template_contains_contact_create_link_when_no_contacts_exist(
493+
self,
494+
):
488495
self.user.user_contacts.remove(self.contact)
489496
response = self.app.get(self.create_url, user=self.user)
490497
self.assertContains(response, reverse("profile:contact_create"))
491498

492-
def test_plan_create_does_not_contain_contact_create_link_when_contacts_exist(
499+
def test_plan_create_no_template_does_not_contain_contact_create_link_when_contacts_exist(
493500
self,
494501
):
495502
response = self.app.get(self.create_url, user=self.user)

src/open_inwoner/plans/views.py

+43-3
Original file line numberDiff line numberDiff line change
@@ -268,23 +268,63 @@ def get_success_url(self) -> str:
268268
return self.object.get_absolute_url()
269269

270270

271-
class PlanCreateView(
271+
class PlanCreateNoTemplateView(
272272
PlanActionsEnabledMixin,
273273
LogMixin,
274274
LoginRequiredMixin,
275275
CommonPageMixin,
276276
BaseBreadcrumbMixin,
277277
CreateView,
278278
):
279-
template_name = "pages/plans/create.html"
279+
template_name = "pages/plans/create-no-template.html"
280280
model = Plan
281281
form_class = PlanForm
282282

283283
@cached_property
284284
def crumbs(self):
285285
return [
286286
(_("Samenwerken"), reverse("collaborate:plan_list")),
287-
(_("Start nieuwe samenwerking"), reverse("collaborate:plan_create")),
287+
(
288+
_("Start nieuwe samenwerking"),
289+
reverse("collaborate:plan_create_no_template"),
290+
),
291+
]
292+
293+
def get_form_kwargs(self):
294+
kwargs = super().get_form_kwargs()
295+
kwargs.update(user=self.request.user)
296+
return kwargs
297+
298+
def form_valid(self, form):
299+
self.object = form.save(self.request.user)
300+
301+
# Add plan creator as a plan_contact as well
302+
self.object.plan_contacts.add(self.object.created_by)
303+
304+
self.log_addition(self.object, _("plan was created"))
305+
return HttpResponseRedirect(self.get_success_url())
306+
307+
def get_success_url(self) -> str:
308+
return self.object.get_absolute_url()
309+
310+
311+
class PlanCreateWithTemplateView(
312+
PlanActionsEnabledMixin,
313+
LogMixin,
314+
LoginRequiredMixin,
315+
CommonPageMixin,
316+
BaseBreadcrumbMixin,
317+
CreateView,
318+
):
319+
template_name = "pages/plans/create-with-template.html"
320+
model = Plan
321+
form_class = PlanForm
322+
323+
@cached_property
324+
def crumbs(self):
325+
return [
326+
(_("Samenwerken"), reverse("collaborate:plan_list")),
327+
(_("Gebruik dit voorstel"), reverse("collaborate:plan_choose_template")),
288328
]
289329

290330
def get_form_kwargs(self):

src/open_inwoner/scss/components/Card/Card.scss

-4
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,6 @@
196196
color: var(--color-body);
197197
font-size: var(--font-size-body-small);
198198
}
199-
.card__text--small ~ .link {
200-
background-color: yellow;
201-
margin-top: var(--spacing-medium);
202-
}
203199

204200
&__text--dark {
205201
color: var(--font-color-body);

src/open_inwoner/scss/components/Form/Form.scss

-6
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,6 @@
192192
margin-top: 0;
193193
}
194194

195-
&--nogrid {
196-
display: block;
197-
margin: 0;
198-
max-width: 100%;
199-
}
200-
201195
&--fullwidth {
202196
display: block;
203197
margin: 0;

0 commit comments

Comments
 (0)