Fix the selection modal for acpw for merging functionality

This commit is contained in:
2025-08-20 12:50:49 +02:00
parent 7843e5dfd1
commit a0b2d92ba2
10 changed files with 134 additions and 23 deletions

View File

@@ -266,10 +266,29 @@
data-label="{{ form.vars['label']|trans|escape('html_attr') }}"></div>
{% endblock %}
{% block pick_linked_entities_row %}
<div class="row">
<div class="col-md-12">
{{ form_label(form) }}
{{ form_help(form) }}
</div>
</div>
<div class="row justify-content-end">
<div class="col-md-7 col-sm-12">
{{ form_widget(form) }}
</div>
</div>
{% endblock %}
{% block pick_linked_entities_widget %}
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value|escape('html_attr') }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
<div data-module="pick-linked-entities"
<input type="hidden" {{ block('widget_attributes') }}
{% if value is not empty %}value="{{ value|escape('html_attr') }}" {% endif %}
data-input-uniqid="{{ form.vars['uniqid'] }}"/>
<div
data-input-uniqid="{{ form.vars['uniqid'] }}"
data-module="pick-linked-entities"
data-pick-entities-type="{{ form.vars['pick-entities-type'] }}"
data-suggested="{{ form.vars['suggested']|json_encode|escape('html_attr') }}"
></div>
{% endblock %}

View File

@@ -19,7 +19,9 @@ use Chill\PersonBundle\Service\AccompanyingPeriodWork\AccompanyingPeriodWorkMerg
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Contracts\Translation\TranslatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
@@ -92,6 +94,12 @@ class AccompanyingPeriodWorkDuplicateController extends AbstractController
$this->accompanyingPeriodWorkMergeService->merge($acpw1, $acpw2);
$session = $request->getSession();
if ($session instanceof Session) {
$session->getFlashBag()->add('success', new TranslatableMessage('acpw_duplicate.Successfully merged'));
}
return $this->redirectToRoute('chill_person_accompanying_period_work_show', ['id' => $acpw1->getId()]);
}

View File

@@ -26,6 +26,7 @@ class FindAccompanyingPeriodWorkType extends AbstractType
->add('acpw', PickLinkedAccompanyingPeriodWorkType::class, [
'label' => 'Accompanying period work',
'multiple' => false,
'accompanyingPeriod' => $options['accompanyingPeriod'],
])
->add('direction', HiddenType::class, [
'data' => 'starting',

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Form\Type;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
@@ -29,6 +30,8 @@ class PickLinkedAccompanyingPeriodWorkType extends AbstractType
$view->vars['suggested'] = [];
$view->vars['as_id'] = true === $options['as_id'] ? '1' : '0';
$view->vars['submit_on_adding_new_entity'] = false;
$view->vars['pick-entities-type'] = 'acpw';
$view->vars['attr']['data-accompanying-period-id'] = $options['accompanyingPeriod']->getId();
foreach ($options['suggested'] as $suggestion) {
$view->vars['suggested'][] = $this->normalizer->normalize($suggestion, 'json', ['groups' => 'read']);
@@ -38,6 +41,8 @@ class PickLinkedAccompanyingPeriodWorkType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setRequired('accompanyingPeriod')
->setAllowedTypes('accompanyingPeriod', [AccompanyingPeriod::class])
->setDefault('multiple', false)
->setAllowedTypes('multiple', ['bool'])
->setDefault('compound', false)

View File

@@ -1,12 +0,0 @@
import { createApp } from "vue";
import AccompanyingPeriodWorkSelectorModal from "../../vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkSelectorModal.vue";
document.addEventListener("DOMContentLoaded", () => {
const el = document.getElementById("linked-acpw-selector");
if (el) {
const accompanyingPeriodId = el.dataset.accompanyingPeriod;
createApp(AccompanyingPeriodWorkSelectorModal, {
accompanyingPeriodId,
}).mount(el);
}
});

View File

@@ -0,0 +1,52 @@
import { createApp } from "vue";
import AccompanyingPeriodWorkSelectorModal from "../../vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkSelectorModal.vue";
import { AccompanyingPeriodWork } from "../../types";
document.addEventListener("DOMContentLoaded", () => {
const elements = document.querySelectorAll<HTMLDivElement>(
'div[data-pick-entities-type="acpw"]',
);
elements.forEach((el) => {
const uniqid = el.dataset.inputUniqid;
if (undefined === uniqid) {
throw "Uniqid not found on this element";
}
const input = document.querySelector<HTMLInputElement>(
`input[data-input-uniqid="${uniqid}"]`,
);
if (null === input) {
throw "Element with uniqid not found: " + uniqid;
}
const accompanyingPeriodIdAsString = input.dataset.accompanyingPeriodId;
if (undefined === accompanyingPeriodIdAsString) {
throw "accompanying period id not found";
}
const accompanyingPeriodId = Number.parseInt(
accompanyingPeriodIdAsString,
);
const app = createApp({
template:
'<accompanying-period-work-selector-modal :accompanying-period-id="accompanyingPeriodId" @pickWork="pickWork"></accompanying-period-work-selector-modal>',
components: { AccompanyingPeriodWorkSelectorModal },
data() {
return { accompanyingPeriodId };
},
methods: {
pickWork: function (payload: { work: AccompanyingPeriodWork }) {
console.log("payload", payload);
input.value = payload.work.id?.toString() ?? '';
},
},
});
app.mount(el);
});
});

View File

@@ -29,15 +29,24 @@ import { defineProps, ref, watch } from "vue";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const props = defineProps<{
accompanyingPeriodWorks: AccompanyingPeriodWork[];
selectedAcpw?: AccompanyingPeriodWork | null;
}>();
const selectedAcpw = ref<AccompanyingPeriodWork | null>(null);
const selectedAcpw = ref<AccompanyingPeriodWork | null>(props.selectedAcpw ?? null);
// eslint-disable-next-line vue/valid-define-emits
const emit = defineEmits();
const emit = defineEmits<{
'update:selectedAcpw': [value: AccompanyingPeriodWork | null];
}>();
watch(() => props.selectedAcpw, (val) => {
selectedAcpw.value = val ?? null;
});
watch(selectedAcpw, (newValue) => {
emit("update:selectedAcpw", newValue);
});
</script>
<style>

View File

@@ -78,7 +78,11 @@ const props = defineProps({
isEvaluationSelector: Boolean,
});
const emit = defineEmits(["closeModal", "update:selectedEvaluation"]);
const emit = defineEmits<{
pickWork: [payload: { work: AccompanyingPeriodWork | null }];
closeModal: [];
"update:selectedEvaluation": [evaluation: AccompanyingPeriodWorkEvaluation];
}>();
onMounted(() => {
if (props.accompanyingPeriodId) {
@@ -112,8 +116,13 @@ watch(selectedAcpw, (newValue) => {
"find_accompanying_period_work_acpw",
) as HTMLInputElement;
if (inputField) {
inputField.value = String(newValue?.id);
inputField.value = String(newValue?.id || '');
}
/* if (!props.isEvaluationSelector) {
console.log("Emitting from watch:", { work: newValue });
emit("pickWork", { work: newValue });
}*/
});
const openModal = () => {
@@ -122,15 +131,22 @@ const openModal = () => {
const closeModal = () => {
showModal.value = false;
selectedEvaluation.value = null;
selectedAcpw.value = null;
// selectedAcpw.value = null;
emit("closeModal");
};
const confirmSelection = () => {
selectedAcpw.value = selectedAcpw.value;
console.log('selectedAcpw', selectedAcpw.value)
if (false === props.isEvaluationSelector) {
if (!props.isEvaluationSelector) {
if (selectedAcpw.value) { // only emit if something is actually selected!
emit("pickWork", { work: selectedAcpw.value });
closeModal();
}
// optionally show some error or warning if not selected
return;
}
if (selectedAcpw.value && props.isEvaluationSelector) {
evaluations.value = selectedAcpw.value.accompanyingPeriodWorkEvaluations;

View File

@@ -2,11 +2,22 @@
{% set activeRouteKey = 'chill_person_accompanying_period_work_assign_duplicate' %}
{% import '@ChillPerson/AccompanyingPeriodWorkDuplicate/_details.html.twig' as details %}
{% block title %}{{ 'Assign an accompanying period work duplicate' }}{% endblock %}
{% block content %}
<div class="person-duplicate">
<div class="col">
<h4>{{ 'acpw_duplicate.to keep'|trans ~ ':' }}</h4>
<div class="accompanying-course-work">
<div class="flex-table">
{{ details.details(acpw, accompanyingCourse) }}
</div>
</div>
</div>
<h1>{{ 'acpw_duplicate.Assign duplicate'|trans }}</h1>
{{ form_start(form) }}
{%- if form.acpw is defined -%}
@@ -22,7 +33,7 @@
</a>
</li>
<li>
<button class="btn btn-save" type="submit">{{ 'Next'|trans }}</button>
<button class="btn btn-action" type="submit">{{ 'Next'|trans }}</button>
</li>
</ul>
@@ -32,9 +43,11 @@
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_duplicate_selector') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_duplicate_selector') }}
{% endblock %}

View File

@@ -66,6 +66,6 @@ module.exports = function (encore, entries) {
);
encore.addEntry(
"mod_duplicate_selector",
__dirname + "/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.js",
__dirname + "/Resources/public/mod/DuplicateSelector/AccompanyingPeriodWorkSelector.ts",
);
};