diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php index 8af7a204c..22bd45658 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -35,6 +35,7 @@ use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\CallbackTransformer; use Chill\PersonBundle\Form\DataTransformer\PersonToIdTransformer; use Chill\PersonBundle\Templating\Entity\SocialIssueRender; +use Chill\PersonBundle\Templating\Entity\SocialActionRender; class ActivityType extends AbstractType { @@ -46,6 +47,10 @@ class ActivityType extends AbstractType protected TranslatableStringHelper $translatableStringHelper; + protected SocialIssueRender $socialIssueRender; + + protected SocialActionRender $socialActionRender; + protected array $timeChoices; public function __construct ( @@ -54,7 +59,8 @@ class ActivityType extends AbstractType ObjectManager $om, TranslatableStringHelper $translatableStringHelper, array $timeChoices, - SocialIssueRender $socialIssueRender + SocialIssueRender $socialIssueRender, + SocialActionRender $socialActionRender ) { if (!$tokenStorage->getToken()->getUser() instanceof User) { throw new \RuntimeException("you should have a valid user"); @@ -66,6 +72,7 @@ class ActivityType extends AbstractType $this->translatableStringHelper = $translatableStringHelper; $this->timeChoices = $timeChoices; $this->socialIssueRender = $socialIssueRender; + $this->socialActionRender = $socialActionRender; } public function buildForm(FormBuilderInterface $builder, array $options): void @@ -124,7 +131,7 @@ class ActivityType extends AbstractType 'required' => $activityType->isRequired('socialActions'), 'class' => SocialAction::class, 'choice_label' => function (SocialAction $socialAction) { - return $this->translatableStringHelper->localize($socialAction->getTitle()); + return $this->socialActionRender->renderString($socialAction, []); }, 'multiple' => true, 'choices' => $accompanyingPeriod->getRecursiveSocialActions(), diff --git a/src/Bundle/ChillActivityBundle/config/services/form.yaml b/src/Bundle/ChillActivityBundle/config/services/form.yaml index 3da20cce5..fd034b2da 100644 --- a/src/Bundle/ChillActivityBundle/config/services/form.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/form.yaml @@ -32,6 +32,7 @@ services: - "@chill.main.helper.translatable_string" - "%chill_activity.form.time_duration%" - '@Chill\PersonBundle\Templating\Entity\SocialIssueRender' + - '@Chill\PersonBundle\Templating\Entity\SocialActionRender' tags: - { name: form.type, alias: chill_activitybundle_activity } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php index 71476fb78..a1d28483d 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php @@ -8,6 +8,11 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\Validator\ValidatorInterface; use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\CRUD\Resolver\Resolver; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Translation\TranslatorInterface; class AbstractCRUDController extends AbstractController { @@ -248,4 +253,24 @@ class AbstractCRUDController extends AbstractController { return $this->get('validator'); } + + /** + * @return array + */ + public static function getSubscribedServices(): array + { + return \array_merge( + parent::getSubscribedServices(), + [ + 'chill_main.paginator_factory' => PaginatorFactory::class, + + 'translator' => TranslatorInterface::class, + AuthorizationHelper::class => AuthorizationHelper::class, + EventDispatcherInterface::class => EventDispatcherInterface::class, + Resolver::class => Resolver::class, + SerializerInterface::class => SerializerInterface::class, + 'validator' => ValidatorInterface::class, + ] + ); + } } diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php new file mode 100644 index 000000000..40d7068ce --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php @@ -0,0 +1,21 @@ +where( + $query->expr()->orX( + $query->expr()->gt('e.desactivationDate', ':now'), + $query->expr()->isNull('e.desactivationDate') + ) + ); + $query->setParameter('now', new \DateTimeImmutable()); + } +} diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index b4116f47b..733579acb 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -488,6 +488,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac [ 'class' => \Chill\PersonBundle\Entity\SocialWork\SocialIssue::class, 'name' => 'social_work_social_issue', + 'controller' => \Chill\PersonBundle\Controller\SocialIssueApiController::class, 'base_path' => '/api/1.0/person/social-work/social-issue', 'base_role' => 'ROLE_USER', 'actions' => [ diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue index d0b09694b..15c500af2 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue @@ -41,11 +41,11 @@
- {{ g.title.fr }} + {{ g.goal.title.fr }}
- +
@@ -145,21 +145,47 @@ - + + + +
+

Veuillez corriger les erreurs suivantes:

+
+ + @@ -314,9 +344,9 @@ const i18n = { action_title: "Action d'accompagnement", startDate: "Date de début", endDate: "Date de fin", - results_without_objective: "Résultats sans objectifs", + results_without_objective: "Résultats - orientations sans objectifs", add_objectif: "Ajouter un motif - objectif - dispositif", - persons_involved: "Usagers concernés", + persons_involved: "Usagers concernés", } } }; @@ -360,7 +390,9 @@ export default { 'goalsPicked', 'personsReachables', 'handlingThirdParty', - 'thirdParties' + 'thirdParties', + 'isPosting', + 'errors', ]), ...mapGetters([ 'hasResultsForAction', @@ -390,11 +422,11 @@ export default { return this.$store.state.note; }, set(v) { - this.$store.commit('setNote', note); + this.$store.commit('setNote', v); } }, availableForCheckGoal() { - let pickedIds = this.$store.state.goalsPicked.map(g => g.id); + let pickedIds = this.$store.state.goalsPicked.map(g => g.goal.id); console.log('pickeds goals id', pickedIds); console.log(this.$store.state.goalsForAction); @@ -445,6 +477,9 @@ export default { console.log('remove third party', t); this.$store.commit('removeThirdParty', t); }, + submit() { + this.$store.dispatch('submit'); + }, } }; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/_components/AddResult.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/_components/AddResult.vue index 651d35243..2eb1e5b33 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/_components/AddResult.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/_components/AddResult.vue @@ -31,7 +31,7 @@
- {{ $t('goal_has_ho_result') }} + {{ $t('goal_has_no_result') }}
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js index 318853293..70e516153 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js @@ -25,6 +25,7 @@ const store = createStore({ .map(p => p.person), handlingThirdParty: window.accompanyingCourseWork.handlingThierParty, thirdParties: window.accompanyingCourseWork.thirdParties, + isPosting: false, errors: [], }, getters: { @@ -40,7 +41,7 @@ const store = createStore({ return founds === undefined ? [] : founds; }, resultsPickedForGoal: (state) => (goal) => { - let found = state.goalsPicked.find(g => g.id === goal.id); + let found = state.goalsPicked.find(g => g.goal.id === goal.id); return found === undefined ? [] : found.results; }, @@ -50,6 +51,43 @@ const store = createStore({ hasThirdParties(state) { return state.thirdParties.length > 0; }, + buildPayload(state) { + return { + type: 'accompanying_period_work', + id: state.work.id, + startDate: { + datetime: datetimeToISO(state.startDate) + }, + endDate: state.endDate === null ? null : { + datetime: datetimeToISO(state.endDate) + }, + note: state.note, + persons: state.personsPicked.map(p => ({id: p.id, type: p.type})), + handlingThierParty: state.handlingThirdParty === null ? null : { + id: state.handlingThirdParty.id, + type: state.handlingThirdParty.type + }, + results: state.resultsPicked.map(r => ({id: r.id, type: r.type})), + thirdParties: state.thirdParties.map(t => ({id: t.id, type: t.type})), + goals: state.goalsPicked.map(g => { + let o = { + type: g.type, + note: g.note, + goal: { + type: g.goal.type, + id: g.goal.id, + }, + results: g.results.map(r => ({id: r.id, type: r.type})), + }; + + if (g.id !== undefined) { + o.id = g.id; + } + + return o; + }) + }; + } }, mutations: { setStartDate(state, date) { @@ -79,16 +117,23 @@ const store = createStore({ state.resultsPicked = state.resultsPicked.filter(r => r.id !== result.id); }, addGoal(state, goal) { - let g = goal; - // initialize results to empty array - g.results = [] + let g = { + type: "accompanying_period_work_goal", + goal: goal, + note: '', + results: [] + } state.goalsPicked.push(g); }, removeGoal(state, goal) { state.goalsPicked = state.goalsPicked.filter(g => g.id !== goal.id); }, addResultForGoalPicked(state, { goal, result}) { - let found = state.goalsPicked.find(g => g.id === goal.id); + let found = state.goalsPicked.find(g => g.goal.id === goal.id); + console.log('adResultForGoalPicked'); + console.log('found', found); + console.log('goal', goal); + console.log('result', result); if (found === undefined) { return; @@ -97,7 +142,7 @@ const store = createStore({ found.results.push(result); }, removeResultForGoalPicked(state, { goal, result}) { - let found = state.goalsPicked.find(g => g.id === goal.id); + let found = state.goalsPicked.find(g => g.goal.id === goal.id); if (found === undefined) { return; @@ -130,11 +175,12 @@ const store = createStore({ state.thirdParties = state.thirdParties .filter(t => t.id !== thirdParty.id); }, - addErrors(state, errors) { + setErrors(state, errors) { console.log('handling errors', errors); - for (let i in errors) { - state.push(errors[i]); - } + state.errors = errors; + }, + setIsPosting(state, st) { + state.isPosting = st; }, }, actions: { @@ -206,6 +252,46 @@ const store = createStore({ commit('setResultsForAction', data.results); }); }, + submit({ getters, state, commit }) { + let + payload = getters.buildPayload, + url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json`, + errors = [] + ; + + console.log('action subitting', payload, url); + commit('setIsPosting', true); + + window.fetch(url, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }).then(response => { + if (response.ok || response.status === 422) { + return response.json().then(data => ({data, status: response.status})); + } + + throw new Error(response.status); + }).then(({data, status}) => { + if (status === 422) { + for (let i in data.violations) { + errors.push(data.violations[i].title); + } + commit('setErrors', errors); + commit('setIsPosting', false); + } else { + console.info('nothing to do here, bye bye'); + window.location.assign(`/fr/person/accompanying-period/${state.work.accompanyingPeriod.id}/work`); + } + }).catch(e => { + commit('setErrors', [ + 'Erreur serveur ou réseau: veuillez ré-essayer. Code erreur: ' + e + ]); + commit('setIsPosting', false); + }); + }, initAsync({ dispatch }) { dispatch('getReachablesResultsForAction'); dispatch('getReachablesGoalsForAction'); diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php index 1bd74fd87..85a4d2759 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php @@ -33,17 +33,18 @@ class SocialActionRender implements ChillEntityRenderInterface { /** @var $socialAction SocialAction */ $options = \array_merge(self::DEFAULT_ARGS, $options); - - $str = $this->translatableStringHelper->localize($socialAction->getTitle()); + $titles[] = $this->translatableStringHelper->localize($socialAction->getTitle()); while ($socialAction->hasParent()) { $socialAction = $socialAction->getParent(); - $str .= $options[self::SEPARATOR_KEY].$this->translatableStringHelper->localize( + $titles[] = $this->translatableStringHelper->localize( $socialAction->getTitle() ); } - return $str; + $titles = \array_reverse($titles); + + return \implode($options[self::SEPARATOR_KEY], $titles); } protected function buildParents($socialAction): array diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php index 84da45db4..5ed80182c 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php @@ -38,16 +38,20 @@ final class SocialIssueRender implements ChillEntityRenderInterface /** @var $socialIssue SocialIssue */ $options = array_merge(self::DEFAULT_ARGS, $options); - $str = $this->translatableStringHelper->localize($socialIssue->getTitle()); + $titles[] = $this->translatableStringHelper + ->localize($socialIssue->getTitle()); + // loop to parent, until root while ($socialIssue->hasParent()) { $socialIssue = $socialIssue->getParent(); - $str .= $options[self::SEPARATOR_KEY].$this->translatableStringHelper->localize( + $titles[] = $this->translatableStringHelper->localize( $socialIssue->getTitle() ); } - return $str; + $titles = \array_reverse($titles); + + return \implode($options[self::SEPARATOR_KEY], $titles); } protected function buildParents(SocialIssue $socialIssue): array