diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/date.js b/src/Bundle/ChillMainBundle/Resources/public/js/date.js index e49a05972..ec66da770 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/js/date.js +++ b/src/Bundle/ChillMainBundle/Resources/public/js/date.js @@ -48,8 +48,8 @@ const ISOToDatetime = (str) => { let [cal, times] = str.split('T'), [year, month, date] = cal.split('-'), - [time, timezone] = cal.split(times.charAt(9)), - [hours, minutes, seconds] = cal.split(':') + [time, timezone] = times.split(times.charAt(8)), + [hours, minutes, seconds] = time.split(':') ; return new Date(year, month-1, date, hours, minutes, seconds); diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php index 8cff8614c..077fa15d7 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php @@ -2,6 +2,7 @@ namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -10,22 +11,32 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Translation\TranslatorInterface; +use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; class AccompanyingCourseWorkController extends AbstractController { private TranslatorInterface $trans; private SerializerInterface $serializer; + private AccompanyingPeriodWorkRepository $workRepository; + private PaginatorFactory $paginator; - public function __construct(TranslatorInterface $trans, SerializerInterface $serializer) - { + public function __construct( + TranslatorInterface $trans, + SerializerInterface $serializer, + AccompanyingPeriodWorkRepository $workRepository, + PaginatorFactory $paginator + ) { $this->trans = $trans; $this->serializer = $serializer; + $this->workRepository = $workRepository; + $this->paginator = $paginator; } /** * @Route( * "{_locale}/person/accompanying-period/{id}/work/new", - * methods={"GET", "POST"} + * name="chill_person_accompanying_period_work_new", + * methods={"GET"} * ) */ public function createWork(AccompanyingPeriod $period): Response @@ -51,9 +62,48 @@ class AccompanyingCourseWorkController extends AbstractController ]); } + /** + * @Route( + * "{_locale}/person/accompanying-period/work/{id}/edit", + * name="chill_person_accompanying_period_work_edit", + * methods={"GET"} + * ) + */ public function editWork(AccompanyingPeriodWork $work): Response { // TODO ACL + $json = $this->serializer->normalize($work, 'json', [ "groups" => [ "read" ] ]); + return $this->render('@ChillPerson/AccompanyingCourseWork/edit.html.twig', [ + 'accompanyingCourse' => $work->getAccompanyingPeriod(), + 'work' => $work, + 'json' => $json + ]); + } + /** + * @Route( + * "{_locale}/person/accompanying-period/{id}/work", + * name="chill_person_accompanying_period_work_list", + * methods={"GET"} + * ) + */ + public function listWorkByAccompanyingPeriod(AccompanyingPeriod $period): Response + { + // TODO ACL + $totalItems = $this->workRepository->countByAccompanyingPeriod($period); + $paginator = $this->paginator->create($totalItems); + + $works = $this->workRepository->findByAccompanyingPeriod( + $period, + ['startDate' => 'DESC', 'endDate' => 'DESC'], + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); + + return $this->render('@ChillPerson/AccompanyingCourseWork/list_by_accompanying_period.html.twig', [ + 'accompanyingCourse' => $period, + 'works' => $works, + 'paginator' => $paginator + ]); } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php index d1d5ff002..b42242a5b 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php @@ -49,7 +49,8 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\ManyToOne(targetEntity=SocialAction::class) - * @Serializer\Groups({"accompanying_period_work:create", "read"}) + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:create"}) */ private ?SocialAction $socialAction = null; @@ -101,7 +102,6 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\ManyToOne(targetEntity=ThirdParty::class) * @Serializer\Groups({"read"}) - * @Serializer\Groups({"accompanying_period_work:create"}) * @Serializer\Groups({"accompanying_period_work:edit"}) * * In schema : traitant diff --git a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php index 49543c42d..b946f3f89 100644 --- a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -60,6 +60,13 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface 'accompanying_period_id' => $period->getId() ]]) ->setExtras(['order' => 30]); + + $menu->addChild($this->translator->trans('Accompanying Course Actions'), [ + 'route' => 'chill_person_accompanying_period_work_list', + 'routeParameters' => [ + 'id' => $period->getId() + ]]) + ->setExtras(['order' => 40]); } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php index 5d455b617..872feebbe 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php @@ -3,16 +3,12 @@ namespace Chill\PersonBundle\Repository\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\Persistence\ObjectRepository; -/** - * @method AccompanyingPeriodWork|null find($id, $lockMode = null, $lockVersion = null) - * @method AccompanyingPeriodWork|null findOneBy(array $criteria, array $orderBy = null) - * @method AccompanyingPeriodWork[] findAll() - * @method AccompanyingPeriodWork[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -final class AccompanyingPeriodWorkRepository +final class AccompanyingPeriodWorkRepository implements ObjectRepository { private EntityRepository $repository; @@ -20,4 +16,88 @@ final class AccompanyingPeriodWorkRepository { $this->repository = $entityManager->getRepository(AccompanyingPeriodWork::class); } + + public function find($id): ?AccompanyingPeriodWork + { + return $this->repository->find($id); + } + + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?AccompanyingPeriodWork + { + return $this->findOneBy($criteria); + } + + public function getClassName() + { + return AccompanyingPeriodWork::class; + } + + /** + * + * @return AccompanyingPeriodWork[] + */ + public function findByAccompanyingPeriod(AccompanyingPeriod $period, $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset); + } + + public function countByAccompanyingPeriod(AccompanyingPeriod $period): int + { + return $this->repository->countByAccompanyingPeriod($period); + } + + public function toDelete() + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('g'); + + foreach ($orderBy as $sort => $order) { + $qb->addOrderBy('g.'.$sort, $order); + } + + return $qb + ->setMaxResults($limit) + ->setFirstResult($offset) + ->getQuery() + ->getResult() + ; + } + + public function countBySocialActionWithDescendants(SocialAction $action): int + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('COUNT(g)'); + + return $qb + ->getQuery() + ->getSingleScalarResult() + ; + } + + protected function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder + { + $actions = $action->getDescendantsWithThis(); + + $qb = $this->repository->createQueryBuilder('g'); + + $orx = $qb->expr()->orX(); + $i = 0; + foreach ($actions as $action) { + $orx->add(":action_{$i} MEMBER OF g.socialActions"); + $qb->setParameter("action_{$i}", $action); + } + $qb->where($orx); + + return $qb; + } } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue index 3c1f4b07a..7e8f2d5f0 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue @@ -13,8 +13,7 @@
-

{{ $t('pick_an_action') }}

- +

{{ $t('pick_an_action') }}

+

Hello

+ +
+
+ +

{{ work.socialAction.text }}

+
+
+ + +
+
+ + +
+
+ +
+
+
+

Objectifs

+

Résultats

+
+
+
+ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js new file mode 100644 index 000000000..0ef2d0de4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js @@ -0,0 +1,15 @@ +import { createApp } from 'vue'; +import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'; +import { store } from './store'; +import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n' +import App from './App.vue'; + +const i18n = _createI18n(personMessages); + +const app = createApp({ + template: ``, +}) +.use(store) +.use(i18n) +.component('app', App) +.mount('#accompanying_course_work_edit'); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js new file mode 100644 index 000000000..f72badc91 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js @@ -0,0 +1,139 @@ +import { createStore } from 'vuex'; +import { datetimeToISO, ISOToDatetime } from 'ChillMainAssets/js/date.js'; +import { findSocialActionsBySocialIssue } from 'ChillPersonAssets/vuejs/_api/SocialWorkSocialAction.js'; +import { create } from 'ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js'; + +const debug = process.env.NODE_ENV !== 'production'; + +console.log(window.accompanyingCourseWork); + +const store = createStore({ + strict: debug, + state: { + work: window.accompanyingCourseWork, + startDate: ISOToDatetime(window.accompanyingCourseWork.startDate.datetime), + endDate: (window.accompanyingCourseWork.endDate !== null ? + ISOToDatetime(window.accompanyingCourseWork.endDate.datetime) : null), + note: window.accompanyingCourseWork.note, + goalsPicked: window.accompanyingCourseWork.goals, + resultsPicked: window.accompanyingCourseWork.results, + resultsForAction: [], + goalsForAction: [], + resultsForGoal: [], + errors: [], + }, + getters: { + socialAction(state) { + return state.work.socialAction; + }, + }, + mutations: { + setStartDate(state, date) { + state.startDate = date; + }, + setEndDate(state, date) { + state.endDate = date; + }, + setResultsForAction(state, results) { + console.log('set results for action', results); + state.resultsForAction = results; + }, + setResultsForGoal(state, { goal, results }) { + console.log('set results for goal', results); + state.goalsForAction = goal; + for (let i in results) { + let r = results[i]; + r.goalId = goal.id; + console.log('adding result', r); + state.resultsForGoal.push(r); + } + }, + addErrors(state, errors) { + console.log('handling errors', errors); + for (let i in errors) { + state.push(errors[i]); + } + }, + setNote(state, note) { + state.note = note; + }, + }, + actions: { + getReachablesGoalsForAction({ getters, commit, dispatch }) { + console.log('getReachablesGoalsForAction'); + let + socialActionId = getters.socialAction.id, + url = `/api/1.0/person/social-work/goal/by-social-action/${socialActionId}.json` + ; + + console.log(url); + + window + .fetch( + url + ).then( response => { + if (response.ok) { + return response.json(); + } + throw { m: 'Error while retriving goal for social action', s: response.status, b: response.body }; + }).then( data => { + for (let i in data.results) { + dispatch('getReachablesResultsForGoal', data.results[i]); + } + }).catch( errors => { + commit('addErrors', errors); + }); + }, + getReachablesResultsForGoal({ commit }, goal) { + console.log('getReachablesResultsForGoal'); + let + url = `/api/1.0/person/social-work/result/by-goal/${goal.id}.json` + ; + + console.log(url); + + window.fetch(url) + .then(response => { + if (response.ok) { + return response.json(); + } + + throw { m: 'Error while retriving results for goal', s: response.status, b: response.body }; + }) + .then(data => { + console.log('data'); + commit('setResultsForGoal', { goal, results: data.results }); + }); + }, + getReachablesResultsForAction({ getters, commit }) { + console.log('getReachablesResultsForAction'); + let + socialActionId = getters.socialAction.id, + url = `/api/1.0/person/social-work/result/by-social-action/${socialActionId}.json` + ; + + console.log(url); + + window.fetch(url) + .then(response => { + if (response.ok) { + return response.json(); + } + + throw { m: 'Error while retriving results for social action', s: response.status, b: response.body }; + }) + .then(data => { + console.log('data retrived', data); + commit('setResultsForAction', data.results); + }); + }, + initAsync({ dispatch }) { + dispatch('getReachablesResultsForAction'); + dispatch('getReachablesGoalsForAction'); + }, + } +}); + +store.dispatch('initAsync'); + +export { store }; diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/edit.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/edit.html.twig new file mode 100644 index 000000000..e9fdbd3ce --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/edit.html.twig @@ -0,0 +1,24 @@ +{% extends '@ChillPerson/AccompanyingCourse/layout.html.twig' %} + +{% block title 'accompanying_course_work.Edit accompanying course work'|trans %} + + +{% block content %} +

{{ block('title') }}

+ +
+ +{% endblock %} + +{% block js %} + + + {{ encore_entry_script_tags('accompanying_course_work_edit') }} +{% endblock %} + +{% block css %} + {{ parent() }} + {{ encore_entry_link_tags('accompanying_course_work_edit') }} +{% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/list_by_accompanying_period.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/list_by_accompanying_period.html.twig new file mode 100644 index 000000000..86a7c5401 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/list_by_accompanying_period.html.twig @@ -0,0 +1,28 @@ +{% extends '@ChillPerson/AccompanyingCourse/layout.html.twig' %} + +{% block title 'accompanying_course_work.List accompanying course work'|trans %} + + +{% block content %} +

{{ block('title') }}

+ + + + + +{% endblock %} diff --git a/src/Bundle/ChillPersonBundle/chill.webpack.config.js b/src/Bundle/ChillPersonBundle/chill.webpack.config.js index b20aa004e..bc1bf0679 100644 --- a/src/Bundle/ChillPersonBundle/chill.webpack.config.js +++ b/src/Bundle/ChillPersonBundle/chill.webpack.config.js @@ -14,4 +14,5 @@ module.exports = function(encore, entries) encore.addEntry('vue_accourse', __dirname + '/Resources/public/vuejs/AccompanyingCourse/index.js'); encore.addEntry('household_edit_metadata', __dirname + '/Resources/public/modules/household_edit_metadata/index.js'); encore.addEntry('accompanying_course_work_create', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkCreate/index.js'); + encore.addEntry('accompanying_course_work_edit', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js'); };