mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-04 03:08:25 +00:00 
			
		
		
		
	Compare commits
	
		
			9 Commits
		
	
	
		
			v4.4.0
			...
			366-pick-u
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1af3e4c7ec | |||
| 5d0fc7a189 | |||
| 483d50e776 | |||
| b4c6ccf309 | |||
| ac6a81cbd8 | |||
| 9503cb89b6 | |||
| b130dbdcdc | |||
| b2b1865837 | |||
| ec5c4d51b3 | 
@@ -66,8 +66,11 @@ class EntityToJsonTransformer implements DataTransformerInterface
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function denormalizeOne(array $item)
 | 
			
		||||
    private function denormalizeOne(array|string $item)
 | 
			
		||||
    {
 | 
			
		||||
        if ('me' === $item) {
 | 
			
		||||
            return $item;
 | 
			
		||||
        }
 | 
			
		||||
        if (!\array_key_exists('type', $item)) {
 | 
			
		||||
            throw new TransformationFailedException('the key "type" is missing on element');
 | 
			
		||||
        }
 | 
			
		||||
@@ -98,5 +101,6 @@ class EntityToJsonTransformer implements DataTransformerInterface
 | 
			
		||||
                'json',
 | 
			
		||||
                $context,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Chill is a software for social workers
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view
 | 
			
		||||
 * the LICENSE file that was distributed with this source code.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Form\Type;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Entity\User;
 | 
			
		||||
use Chill\MainBundle\Form\Type\DataTransformer\EntityToJsonTransformer;
 | 
			
		||||
use Symfony\Component\Form\AbstractType;
 | 
			
		||||
use Symfony\Component\Form\FormBuilderInterface;
 | 
			
		||||
use Symfony\Component\Form\FormInterface;
 | 
			
		||||
use Symfony\Component\Form\FormView;
 | 
			
		||||
use Symfony\Component\OptionsResolver\OptionsResolver;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
 | 
			
		||||
use Symfony\Component\Serializer\SerializerInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Pick user dymically, using vuejs module "AddPerson".
 | 
			
		||||
 *
 | 
			
		||||
 * Possible options:
 | 
			
		||||
 *
 | 
			
		||||
 * - `multiple`: pick one or more users
 | 
			
		||||
 * - `suggested`: a list of suggested users
 | 
			
		||||
 * - `suggest_myself`: append the current user to the list of suggested
 | 
			
		||||
 * - `as_id`: only the id will be set in the returned data
 | 
			
		||||
 * - `submit_on_adding_new_entity`: the browser will immediately submit the form when new users are checked
 | 
			
		||||
 */
 | 
			
		||||
class PickUserOrMeDynamicType extends AbstractType
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private readonly DenormalizerInterface $denormalizer,
 | 
			
		||||
        private readonly SerializerInterface $serializer,
 | 
			
		||||
        private readonly NormalizerInterface $normalizer,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function buildForm(FormBuilderInterface $builder, array $options)
 | 
			
		||||
    {
 | 
			
		||||
        $builder->addViewTransformer(new EntityToJsonTransformer($this->denormalizer, $this->serializer, $options['multiple'], 'user'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildView(FormView $view, FormInterface $form, array $options)
 | 
			
		||||
    {
 | 
			
		||||
        $view->vars['multiple'] = $options['multiple'];
 | 
			
		||||
        $view->vars['types'] = ['user'];
 | 
			
		||||
        $view->vars['uniqid'] = uniqid('pick_user_or_me_dyn');
 | 
			
		||||
        $view->vars['suggested'] = [];
 | 
			
		||||
        $view->vars['as_id'] = true === $options['as_id'] ? '1' : '0';
 | 
			
		||||
        $view->vars['submit_on_adding_new_entity'] = true === $options['submit_on_adding_new_entity'] ? '1' : '0';
 | 
			
		||||
 | 
			
		||||
        foreach ($options['suggested'] as $user) {
 | 
			
		||||
            $view->vars['suggested'][] = $this->normalizer->normalize($user, 'json', ['groups' => 'read']);
 | 
			
		||||
        }
 | 
			
		||||
        //        $user = /* should come from context */ $options['context'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function configureOptions(OptionsResolver $resolver)
 | 
			
		||||
    {
 | 
			
		||||
        $resolver
 | 
			
		||||
            ->setDefault('multiple', false)
 | 
			
		||||
            ->setAllowedTypes('multiple', ['bool'])
 | 
			
		||||
            ->setDefault('compound', false)
 | 
			
		||||
            ->setDefault('suggested', [])
 | 
			
		||||
            // if set to true, only the id will be set inside the content. The denormalization will not work.
 | 
			
		||||
            ->setDefault('as_id', false)
 | 
			
		||||
            ->setAllowedTypes('as_id', ['bool'])
 | 
			
		||||
            ->setDefault('submit_on_adding_new_entity', false)
 | 
			
		||||
            ->setAllowedTypes('submit_on_adding_new_entity', ['bool']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getBlockPrefix()
 | 
			
		||||
    {
 | 
			
		||||
        return 'pick_entity_dynamic';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -12,6 +12,11 @@ function loadDynamicPicker(element) {
 | 
			
		||||
  let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
 | 
			
		||||
 | 
			
		||||
  apps.forEach(function (el) {
 | 
			
		||||
    let suggested;
 | 
			
		||||
    let as_id;
 | 
			
		||||
    let submit_on_adding_new_entity;
 | 
			
		||||
    let label;
 | 
			
		||||
    let isCurrentUserPicker;
 | 
			
		||||
    const isMultiple = parseInt(el.dataset.multiple) === 1,
 | 
			
		||||
      uniqId = el.dataset.uniqid,
 | 
			
		||||
      input = element.querySelector(
 | 
			
		||||
@@ -22,12 +27,13 @@ function loadDynamicPicker(element) {
 | 
			
		||||
        ? JSON.parse(input.value)
 | 
			
		||||
        : input.value === "[]" || input.value === ""
 | 
			
		||||
          ? null
 | 
			
		||||
          : [JSON.parse(input.value)],
 | 
			
		||||
      suggested = JSON.parse(el.dataset.suggested),
 | 
			
		||||
      as_id = parseInt(el.dataset.asId) === 1,
 | 
			
		||||
      submit_on_adding_new_entity =
 | 
			
		||||
        parseInt(el.dataset.submitOnAddingNewEntity) === 1,
 | 
			
		||||
      label = el.dataset.label;
 | 
			
		||||
          : [JSON.parse(input.value)];
 | 
			
		||||
    suggested = JSON.parse(el.dataset.suggested);
 | 
			
		||||
    as_id = parseInt(el.dataset.asId) === 1;
 | 
			
		||||
    submit_on_adding_new_entity =
 | 
			
		||||
      parseInt(el.dataset.submitOnAddingNewEntity) === 1;
 | 
			
		||||
    label = el.dataset.label;
 | 
			
		||||
    isCurrentUserPicker = uniqId.startsWith("pick_user_or_me_dyn");
 | 
			
		||||
 | 
			
		||||
    if (!isMultiple) {
 | 
			
		||||
      if (input.value === "[]") {
 | 
			
		||||
@@ -44,6 +50,7 @@ function loadDynamicPicker(element) {
 | 
			
		||||
        ':uniqid="uniqid" ' +
 | 
			
		||||
        ':suggested="notPickedSuggested" ' +
 | 
			
		||||
        ':label="label" ' +
 | 
			
		||||
        ':isCurrentUserPicker="isCurrentUserPicker" ' +
 | 
			
		||||
        '@addNewEntity="addNewEntity" ' +
 | 
			
		||||
        '@removeEntity="removeEntity" ' +
 | 
			
		||||
        '@addNewEntityProcessEnded="addNewEntityProcessEnded"' +
 | 
			
		||||
@@ -61,6 +68,7 @@ function loadDynamicPicker(element) {
 | 
			
		||||
          as_id,
 | 
			
		||||
          submit_on_adding_new_entity,
 | 
			
		||||
          label,
 | 
			
		||||
          isCurrentUserPicker,
 | 
			
		||||
        };
 | 
			
		||||
      },
 | 
			
		||||
      computed: {
 | 
			
		||||
@@ -89,7 +97,8 @@ function loadDynamicPicker(element) {
 | 
			
		||||
                const ids = this.picked.map((el) => el.id);
 | 
			
		||||
                input.value = ids.join(",");
 | 
			
		||||
              }
 | 
			
		||||
              console.log(entity);
 | 
			
		||||
              console.log(this.picked);
 | 
			
		||||
              // console.log(entity);
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            if (
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,25 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <ul :class="listClasses" v-if="picked.length && displayPicked">
 | 
			
		||||
        <li v-for="p in picked" @click="removeEntity(p)" :key="p.type + p.id">
 | 
			
		||||
            <span class="chill_denomination">{{ p.text }}</span>
 | 
			
		||||
            <span
 | 
			
		||||
                v-if="'me' === p"
 | 
			
		||||
                class="chill_denomination current-user updatedBy"
 | 
			
		||||
                >{{ trans(USER_CURRENT_USER) }}</span
 | 
			
		||||
            >
 | 
			
		||||
            <span v-else class="chill_denomination">{{ p.text }}</span>
 | 
			
		||||
        </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
    <ul class="record_actions">
 | 
			
		||||
        <li v-if="isCurrentUserPicker" class="btn btn-sm btn-misc">
 | 
			
		||||
            <label class="flex items-center gap-2">
 | 
			
		||||
                <input
 | 
			
		||||
                    ref="itsMeCheckbox"
 | 
			
		||||
                    :type="multiple ? 'checkbox' : 'radio'"
 | 
			
		||||
                    @change="selectItsMe"
 | 
			
		||||
                />
 | 
			
		||||
                {{ trans(USER_CURRENT_USER) }}
 | 
			
		||||
            </label>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li class="add-persons">
 | 
			
		||||
            <add-persons
 | 
			
		||||
                :options="addPersonsOptions"
 | 
			
		||||
@@ -24,119 +39,83 @@
 | 
			
		||||
    </ul>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref, computed } from "vue";
 | 
			
		||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue"; // eslint-disable-line
 | 
			
		||||
import { appMessages } from "./i18n";
 | 
			
		||||
import { trans, USER_CURRENT_USER } from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "PickEntity",
 | 
			
		||||
    props: {
 | 
			
		||||
        multiple: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        types: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        picked: {
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        uniqid: {
 | 
			
		||||
            type: String,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        removableIfSet: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            default: true,
 | 
			
		||||
        },
 | 
			
		||||
        displayPicked: {
 | 
			
		||||
            // display picked entities.
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            default: true,
 | 
			
		||||
        },
 | 
			
		||||
        suggested: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            default: [],
 | 
			
		||||
        },
 | 
			
		||||
        label: {
 | 
			
		||||
            type: String,
 | 
			
		||||
            required: false,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    emits: ["addNewEntity", "removeEntity", "addNewEntityProcessEnded"],
 | 
			
		||||
    components: {
 | 
			
		||||
        AddPersons,
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            key: "",
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        addPersonsOptions() {
 | 
			
		||||
            return {
 | 
			
		||||
                uniq: !this.multiple,
 | 
			
		||||
                type: this.types,
 | 
			
		||||
                priority: null,
 | 
			
		||||
                button: {
 | 
			
		||||
                    size: "btn-sm",
 | 
			
		||||
                    class: "btn-submit",
 | 
			
		||||
                },
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        translatedListOfTypes() {
 | 
			
		||||
            if (this.label !== "") {
 | 
			
		||||
                return this.label;
 | 
			
		||||
            }
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    multiple: Boolean,
 | 
			
		||||
    types: Array,
 | 
			
		||||
    picked: Array,
 | 
			
		||||
    uniqid: String,
 | 
			
		||||
    removableIfSet: { type: Boolean, default: true },
 | 
			
		||||
    displayPicked: { type: Boolean, default: true },
 | 
			
		||||
    suggested: { type: Array, default: () => [] },
 | 
			
		||||
    label: String,
 | 
			
		||||
    isCurrentUserPicker: { type: Boolean, default: false },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
            let trans = [];
 | 
			
		||||
            this.types.forEach((t) => {
 | 
			
		||||
                if (this.$props.multiple) {
 | 
			
		||||
                    trans.push(appMessages.fr.pick_entity[t].toLowerCase());
 | 
			
		||||
                } else {
 | 
			
		||||
                    trans.push(
 | 
			
		||||
                        appMessages.fr.pick_entity[t + "_one"].toLowerCase(),
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
const emit = defineEmits([
 | 
			
		||||
    "addNewEntity",
 | 
			
		||||
    "removeEntity",
 | 
			
		||||
    "addNewEntityProcessEnded",
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
            if (this.$props.multiple) {
 | 
			
		||||
                return (
 | 
			
		||||
                    appMessages.fr.pick_entity.modal_title + trans.join(", ")
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                return (
 | 
			
		||||
                    appMessages.fr.pick_entity.modal_title_one +
 | 
			
		||||
                    trans.join(", ")
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        listClasses() {
 | 
			
		||||
            return {
 | 
			
		||||
                "list-suggest": true,
 | 
			
		||||
                "remove-items": this.$props.removableIfSet,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        addNewSuggested(entity) {
 | 
			
		||||
            this.$emit("addNewEntity", { entity: entity });
 | 
			
		||||
        },
 | 
			
		||||
        addNewEntity({ selected, modal }) {
 | 
			
		||||
            selected.forEach((item) => {
 | 
			
		||||
                this.$emit("addNewEntity", { entity: item.result });
 | 
			
		||||
            }, this);
 | 
			
		||||
            this.$refs.addPersons.resetSearch(); // to cast child method
 | 
			
		||||
            modal.showModal = false;
 | 
			
		||||
            this.$emit("addNewEntityProcessEnded");
 | 
			
		||||
        },
 | 
			
		||||
        removeEntity(entity) {
 | 
			
		||||
            if (!this.$props.removableIfSet) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            this.$emit("removeEntity", { entity: entity });
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
const itsMeCheckbox = ref(null);
 | 
			
		||||
const addPersons = ref(null);
 | 
			
		||||
 | 
			
		||||
const addPersonsOptions = computed(() => ({
 | 
			
		||||
    uniq: !props.multiple,
 | 
			
		||||
    type: props.types,
 | 
			
		||||
    priority: null,
 | 
			
		||||
    button: { size: "btn-sm", class: "btn-submit" },
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
const translatedListOfTypes = computed(() => {
 | 
			
		||||
    if (props.label) return props.label;
 | 
			
		||||
    let trans = props.types.map((t) =>
 | 
			
		||||
        props.multiple
 | 
			
		||||
            ? appMessages.fr.pick_entity[t].toLowerCase()
 | 
			
		||||
            : appMessages.fr.pick_entity[t + "_one"].toLowerCase(),
 | 
			
		||||
    );
 | 
			
		||||
    return props.multiple
 | 
			
		||||
        ? appMessages.fr.pick_entity.modal_title + trans.join(", ")
 | 
			
		||||
        : appMessages.fr.pick_entity.modal_title_one + trans.join(", ");
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const listClasses = computed(() => ({
 | 
			
		||||
    "list-suggest": true,
 | 
			
		||||
    "remove-items": props.removableIfSet,
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
const selectItsMe = (event) =>
 | 
			
		||||
    event.target.checked ? addNewSuggested("me") : removeEntity("me");
 | 
			
		||||
 | 
			
		||||
const addNewSuggested = (entity) => {
 | 
			
		||||
    emit("addNewEntity", { entity });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addNewEntity = ({ selected, modal }) => {
 | 
			
		||||
    selected.forEach((item) => emit("addNewEntity", { entity: item.result }));
 | 
			
		||||
    addPersons.value?.resetSearch();
 | 
			
		||||
    modal.showModal = false;
 | 
			
		||||
    emit("addNewEntityProcessEnded");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const removeEntity = (entity) => {
 | 
			
		||||
    if (!props.removableIfSet) return;
 | 
			
		||||
    if (entity === "me" && itsMeCheckbox.value) {
 | 
			
		||||
        itsMeCheckbox.value.checked = false;
 | 
			
		||||
    }
 | 
			
		||||
    emit("removeEntity", { entity });
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.current-user {
 | 
			
		||||
    color: var(--bs-body-color);
 | 
			
		||||
    background-color: var(--bs-chill-l-gray) !important;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ Name: Nom
 | 
			
		||||
Label: Nom
 | 
			
		||||
 | 
			
		||||
user:
 | 
			
		||||
    current_user: Utilisateur courant
 | 
			
		||||
    profile:
 | 
			
		||||
        title: Mon profil
 | 
			
		||||
        Phonenumber successfully updated!: Numéro de téléphone mis à jour!
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Export\FilterInterface;
 | 
			
		||||
use Chill\MainBundle\Form\Type\PickRollingDateType;
 | 
			
		||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
 | 
			
		||||
use Chill\MainBundle\Form\Type\PickUserOrMeDynamicType;
 | 
			
		||||
use Chill\MainBundle\Service\RollingDate\RollingDate;
 | 
			
		||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
 | 
			
		||||
use Chill\PersonBundle\Export\Declarations;
 | 
			
		||||
@@ -66,7 +66,7 @@ class ReferrerFilter implements FilterInterface
 | 
			
		||||
    public function buildForm(FormBuilderInterface $builder)
 | 
			
		||||
    {
 | 
			
		||||
        $builder
 | 
			
		||||
            ->add('accepted_referrers', PickUserDynamicType::class, [
 | 
			
		||||
            ->add('accepted_referrers', PickUserOrMeDynamicType::class, [
 | 
			
		||||
                'multiple' => true,
 | 
			
		||||
            ])
 | 
			
		||||
            ->add('date_calc', PickRollingDateType::class, [
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user