mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
show users as suggestions, not in constrained list
This commit is contained in:
parent
0a058bad82
commit
3f138dc152
@ -8,6 +8,7 @@ use Chill\MainBundle\Security\Authorization\ChillVoterInterface;
|
||||
use Chill\MainBundle\Security\ProvideRoleInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
|
||||
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
|
||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Chill\MainBundle\DependencyInjection\CompilerPass\SearchableServicesCompilerPass;
|
||||
@ -38,6 +39,8 @@ class ChillMainBundle extends Bundle
|
||||
->addTag('chill_main.center_resolver');
|
||||
$container->registerForAutoconfiguration(ScopeResolverInterface::class)
|
||||
->addTag('chill_main.scope_resolver');
|
||||
$container->registerForAutoconfiguration(ChillEntityRenderInterface::class)
|
||||
->addTag('chill.render_entity');
|
||||
|
||||
$container->addCompilerPass(new SearchableServicesCompilerPass());
|
||||
$container->addCompilerPass(new ConfigConsistencyCompilerPass());
|
||||
|
@ -3,10 +3,14 @@
|
||||
namespace Chill\MainBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table("chill_main_user_job")
|
||||
* @Serializer\DiscriminatorMap(typeProperty="type", mapping={
|
||||
* "user_job"=UserJob::class
|
||||
* })
|
||||
*/
|
||||
class UserJob
|
||||
{
|
||||
@ -15,12 +19,14 @@ class UserJob
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
protected ?int $id = null;
|
||||
|
||||
/**
|
||||
* @var array|string[]A
|
||||
* @ORM\Column(name="label", type="json")
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
protected array $label = [];
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<span class="chill-entity entity-user">
|
||||
{{ user.label }}
|
||||
<span class="user-job" v-if="user.user_job !== null">({{ user.user_job.label.fr }})</span>
|
||||
<span class="main-scope" v-if="user.main_scope !== null">({{ user.main_scope.name.fr }})</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "UserRenderBoxBadge",
|
||||
props: ['user'],
|
||||
}
|
||||
</script>
|
@ -0,0 +1,9 @@
|
||||
<span class="chill-entity entity-user">
|
||||
{{- user.label }}
|
||||
{%- if opts['user_job'] and user.userJob is not null %}
|
||||
<span class="user-job">({{ user.userJob.label|localize_translatable_string }})</span>
|
||||
{%- endif -%}
|
||||
{%- if opts['main_scope'] and user.mainScope is not null %}
|
||||
<span class="main-scope">({{ user.mainScope.name|localize_translatable_string }})</span>
|
||||
{%- endif -%}
|
||||
</span>
|
@ -20,14 +20,21 @@
|
||||
namespace Chill\MainBundle\Serializer\Normalizer;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* @internal we keep this normalizer, because the property 'text' may be replace by a rendering in the future
|
||||
*/
|
||||
class UserNormalizer implements NormalizerInterface
|
||||
class UserNormalizer implements NormalizerInterface, NormalizerAwareInterface
|
||||
{
|
||||
use NormalizerAwareTrait;
|
||||
private UserRender $userRender;
|
||||
|
||||
public function __construct(UserRender $userRender)
|
||||
{
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function normalize($user, string $format = null, array $context = array())
|
||||
{
|
||||
/** @var User $user */
|
||||
@ -35,7 +42,11 @@ class UserNormalizer implements NormalizerInterface
|
||||
'type' => 'user',
|
||||
'id' => $user->getId(),
|
||||
'username' => $user->getUsername(),
|
||||
'text' => $user->getUsername()
|
||||
'text' => $this->userRender->renderString($user, []),
|
||||
'label' => $user->getLabel(),
|
||||
'user_job' => $this->normalizer->normalize($user->getUserJob(), $format, $context),
|
||||
'main_center' => $this->normalizer->normalize($user->getMainCenter(), $format, $context),
|
||||
'main_scope' => $this->normalizer->normalize($user->getMainScope(), $format, $context),
|
||||
];
|
||||
}
|
||||
|
||||
|
66
src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php
Normal file
66
src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Templating\Entity;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
|
||||
class UserRender implements ChillEntityRenderInterface
|
||||
{
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
private EngineInterface $engine;
|
||||
|
||||
const DEFAULT_OPTIONS = [
|
||||
'main_scope' => true,
|
||||
'user_job' => true
|
||||
];
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
$this->engine = $engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function supports($entity, array $options): bool
|
||||
{
|
||||
return $entity instanceof User;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param User $entity
|
||||
*/
|
||||
public function renderString($entity, array $options): string
|
||||
{
|
||||
$opts = \array_merge(self::DEFAULT_OPTIONS, $options);
|
||||
|
||||
$str = $entity->getLabel();
|
||||
if (NULL !== $entity->getUserJob() && $opts['user_job']) {
|
||||
$str .= ' ('.$this->translatableStringHelper
|
||||
->localize($entity->getUserJob()->getLabel()).')';
|
||||
}
|
||||
if (NULL !== $entity->getMainScope() && $opts['main_scope']) {
|
||||
$str .= ' ('.$this->translatableStringHelper
|
||||
->localize($entity->getMainScope()->getName()).')';
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function renderBox($entity, array $options): string
|
||||
{
|
||||
$opts = \array_merge(self::DEFAULT_OPTIONS, $options);
|
||||
|
||||
return $this->engine->render('@ChillMain/Entity/user.html.twig', [
|
||||
'user' => $entity,
|
||||
'opts' => $opts
|
||||
]);
|
||||
}
|
||||
}
|
@ -42,10 +42,12 @@ services:
|
||||
- { name: twig.extension }
|
||||
|
||||
Chill\MainBundle\Templating\Entity\AddressRender:
|
||||
arguments:
|
||||
- '@Symfony\Component\Templating\EngineInterface'
|
||||
tags:
|
||||
- { name: 'chill.render_entity' }
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
|
||||
Chill\MainBundle\Templating\Entity\UserRender:
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
|
||||
Chill\MainBundle\Templating\Listing\:
|
||||
resource: './../../Templating/Listing'
|
||||
|
@ -199,9 +199,9 @@ $workflow = $this->registry->get($accompanyingPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/api/1.0/person/accompanying-course/{id}/referral-availables.{_format}",
|
||||
* @Route("/api/1.0/person/accompanying-course/{id}/referrers-suggested.{_format}",
|
||||
* requirements={ "_format"="json"},
|
||||
* name="chill_api_person_accompanying_period_referral_available")
|
||||
* name="chill_api_person_accompanying_period_referrers_suggested")
|
||||
* @param AccompanyingPeriod $period
|
||||
* @return JsonResponse
|
||||
*/
|
||||
|
@ -170,11 +170,8 @@ const postSocialIssue = (id, body, method) => {
|
||||
|
||||
const getUsers = () => {
|
||||
const url = `/api/1.0/main/user.json`;
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw { msg: 'Error while retriving users.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
||||
});
|
||||
|
||||
return fetchResults(url);
|
||||
};
|
||||
|
||||
const whoami = () => {
|
||||
@ -235,8 +232,8 @@ const removeScope = (id, scope) => {
|
||||
});
|
||||
};
|
||||
|
||||
const getAvailableReferrals = (course) => {
|
||||
const url = `/api/1.0/person/accompanying-course/${course.id}/referral-availables.json`;
|
||||
const getReferrersSuggested = (course) => {
|
||||
const url = `/api/1.0/person/accompanying-course/${course.id}/referrers-suggested.json`;
|
||||
|
||||
return fetchResults(url);
|
||||
}
|
||||
@ -255,5 +252,5 @@ export {
|
||||
postSocialIssue,
|
||||
addScope,
|
||||
removeScope,
|
||||
getAvailableReferrals
|
||||
getReferrersSuggested,
|
||||
};
|
||||
|
@ -15,9 +15,20 @@
|
||||
v-bind:searchable="true"
|
||||
v-bind:placeholder="$t('referrer.placeholder')"
|
||||
v-model="value"
|
||||
v-bind:options="referrersAvailable"
|
||||
v-bind:options="users"
|
||||
@select="updateReferrer">
|
||||
</VueMultiselect>
|
||||
|
||||
|
||||
<template v-if="referrersSuggested.length > 0">
|
||||
<ul>
|
||||
<li v-for="u in referrersSuggested" @click="updateReferrer(u)">
|
||||
<user-render-box-badge :user="u"></user-render-box-badge>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@ -41,14 +52,26 @@
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
import { getUsers, whoami } from '../api';
|
||||
import { mapState } from 'vuex';
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge";
|
||||
|
||||
export default {
|
||||
name: "Referrer",
|
||||
components: { VueMultiselect },
|
||||
components: {
|
||||
UserRenderBoxBadge,
|
||||
VueMultiselect,
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
value: state => state.accompanyingCourse.user,
|
||||
referrersAvailable: state => state.referrersAvailable,
|
||||
users: state => state.users,
|
||||
referrersSuggested: state => {
|
||||
return state.referrersSuggested.filter(u => {
|
||||
if (null === state.accompanyingCourse.user) {
|
||||
return true;
|
||||
}
|
||||
return state.accompanyingCourse.user.id !== u.id;
|
||||
})
|
||||
},
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
|
@ -10,7 +10,8 @@ import { getAccompanyingCourse,
|
||||
postSocialIssue,
|
||||
addScope,
|
||||
removeScope,
|
||||
getAvailableReferrals,
|
||||
getReferrersSuggested,
|
||||
getUsers,
|
||||
} from '../api';
|
||||
import { patchPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
||||
import { patchThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
||||
@ -40,7 +41,9 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
// the scope states at server side
|
||||
scopesAtBackend: accompanyingCourse.scopes.map(scope => scope),
|
||||
// the users which are available for referrer
|
||||
referrersAvailable: [],
|
||||
referrersSuggested: [],
|
||||
// all the users available
|
||||
users: [],
|
||||
},
|
||||
getters: {
|
||||
isParticipationValid(state) {
|
||||
@ -173,8 +176,15 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
//console.log('value', value);
|
||||
state.accompanyingCourse.user = value;
|
||||
},
|
||||
setReferrersAvailables(state, users) {
|
||||
state.referrersAvailable = users;
|
||||
setReferrersSuggested(state, users) {
|
||||
state.referrersSuggested = users.map(u => {
|
||||
if (state.accompanyingCourse.user !== null) {
|
||||
if (state.accompanyingCourse.user.id === u.id) {
|
||||
return state.accompanyingCourse.user;
|
||||
}
|
||||
}
|
||||
return u;
|
||||
});
|
||||
},
|
||||
confirmAccompanyingCourse(state, response) {
|
||||
//console.log('### mutation: confirmAccompanyingCourse: response', response);
|
||||
@ -184,6 +194,16 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
//console.log('define location context');
|
||||
state.addressContext = context;
|
||||
},
|
||||
setUsers(state, users) {
|
||||
state.users = users.map(u => {
|
||||
if (state.accompanyingCourse.user !== null) {
|
||||
if (state.accompanyingCourse.user.id === u.id) {
|
||||
return state.accompanyingCourse.user;
|
||||
}
|
||||
}
|
||||
return u;
|
||||
});
|
||||
},
|
||||
updateLocation(state, r) {
|
||||
//console.log('### mutation: set location attributes', r);
|
||||
state.accompanyingCourse.locationStatus = r.locationStatus;
|
||||
@ -397,14 +417,14 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
commit('setScopes', scopes);
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
return dispatch('fetchReferrersAvailable');
|
||||
return dispatch('fetchReferrersSuggested');
|
||||
});
|
||||
} else {
|
||||
return dispatch('setScopes', state.scopesAtStart).then(() => {
|
||||
commit('setScopes', scopes);
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
return dispatch('fetchReferrersAvailable');
|
||||
return dispatch('fetchReferrersSuggested');
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -458,7 +478,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
return getAccompanyingCourse(state.accompanyingCourse.id);
|
||||
}).then(accompanying_course => {
|
||||
commit('refreshSocialIssues', accompanying_course.socialIssues);
|
||||
dispatch('fetchReferrersAvailable');
|
||||
dispatch('fetchReferrersSuggested');
|
||||
})
|
||||
.catch((error) => { commit('catchError', error) });
|
||||
},
|
||||
@ -476,20 +496,23 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
resolve();
|
||||
})).catch((error) => { commit('catchError', error) });
|
||||
},
|
||||
async fetchReferrersAvailable({ state, commit}) {
|
||||
let users = await getAvailableReferrals(state.accompanyingCourse);
|
||||
commit('setReferrersAvailables', users);
|
||||
let userIds = users.map(u => u.id);
|
||||
async fetchReferrersSuggested({ state, commit}) {
|
||||
let users = await getReferrersSuggested(state.accompanyingCourse);
|
||||
commit('setReferrersSuggested', users);
|
||||
if (
|
||||
null !== state.accompanyingCourse.user
|
||||
null === state.accompanyingCourse.user
|
||||
&& !state.accompanyingCourse.confidential
|
||||
&& !state.accompanyingCourse.step === 'DRAFT'
|
||||
&& users.length === 1
|
||||
) {
|
||||
if (!userIds.include(state.accompanyingCourse.user.id)) {
|
||||
commit('updateReferrer', null);
|
||||
}
|
||||
// set the user if unique
|
||||
commit('updateReferrer', users[0]);
|
||||
}
|
||||
},
|
||||
async fetchUsers({commit}) {
|
||||
let users = await getUsers();
|
||||
commit('setUsers', users);
|
||||
},
|
||||
updateLocation({ commit, dispatch }, payload) {
|
||||
//console.log('## action: updateLocation', payload.locationStatusTo);
|
||||
let body = { 'type': payload.target, 'id': payload.targetId };
|
||||
@ -512,7 +535,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
personLocation: accompanyingCourse.personLocation
|
||||
});
|
||||
resolve();
|
||||
dispatch('fetchReferrersAvailable');
|
||||
dispatch('fetchReferrersSuggested');
|
||||
})).catch((error) => { commit('catchError', error) });
|
||||
},
|
||||
confirmAccompanyingCourse({ commit }) {
|
||||
@ -528,7 +551,8 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
}
|
||||
});
|
||||
|
||||
store.dispatch('fetchReferrersAvailable');
|
||||
store.dispatch('fetchReferrersSuggested');
|
||||
store.dispatch('fetchUsers');
|
||||
resolve(store);
|
||||
}));
|
||||
|
||||
|
@ -332,7 +332,7 @@ class AccompanyingCourseApiControllerTest extends WebTestCase
|
||||
{
|
||||
$this->client->request(
|
||||
Request::METHOD_POST,
|
||||
sprintf('/api/1.0/person/accompanying-course/%d/referral-availables.json', $periodId)
|
||||
sprintf('/api/1.0/person/accompanying-course/%d/referrers-suggested.json', $periodId)
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
@ -929,7 +929,7 @@ paths:
|
||||
description: "OK"
|
||||
422:
|
||||
description: "object with validation errors"
|
||||
/1.0/person/accompanying-course/{id}/referral-availables.json:
|
||||
/1.0/person/accompanying-course/{id}/referrers-suggested.json:
|
||||
get:
|
||||
tags:
|
||||
- accompanying-course
|
||||
|
Loading…
x
Reference in New Issue
Block a user