mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
fix form create + WIP form edit for Accompanying Period Work
This commit is contained in:
parent
1cd376bf86
commit
0754d20622
@ -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);
|
||||
|
@ -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
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
<div v-if="hasSocialIssuePicked">
|
||||
<h2>{{ $t('pick_an_action') }}</h2>
|
||||
|
||||
<vue-multiselect
|
||||
v-model="socialActionPicked"
|
||||
label="text"
|
||||
|
@ -38,7 +38,7 @@ const store = createStore({
|
||||
buildPayloadCreate(state) {
|
||||
let payload = {
|
||||
type: 'accompanying_period_work',
|
||||
social_action: {
|
||||
socialAction: {
|
||||
type: 'social_work_social_action',
|
||||
id: state.socialActionPicked.id
|
||||
},
|
||||
@ -144,9 +144,6 @@ const store = createStore({
|
||||
commit('addErrors', { errors, cancel_posting: true });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<h1>Hello</h1>
|
||||
|
||||
<div id="workEditor">
|
||||
<div>
|
||||
<label>{{ $t('action_title') }}</label>
|
||||
<p>{{ work.socialAction.text }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<label>{{ $t('startDate') }}</label>
|
||||
<input type="date" v-model="startDate" />
|
||||
</div>
|
||||
<div>
|
||||
<label>{{ $t('endDate') }}</label>
|
||||
<input type="date" v-model="endDate" />
|
||||
</div>
|
||||
<div>
|
||||
<ckeditor
|
||||
:editor="editor"
|
||||
v-model="note"
|
||||
tag-name="textarea"
|
||||
></ckeditor>
|
||||
</div>
|
||||
<div class="objectives_list">
|
||||
<div class="title" aria="hidden">
|
||||
<div><h3>Objectifs</h3></div>
|
||||
<div><h3>Résultats</h3></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapState } from 'vuex';
|
||||
import { dateToISO, ISOToDatetime } from 'ChillMainAssets/js/date.js';
|
||||
import CKEditor from '@ckeditor/ckeditor5-vue';
|
||||
import ClassicEditor from 'ChillMainAssets/modules/ckeditor5/index.js';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
ckeditor: CKEditor.component,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: ClassicEditor,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState([
|
||||
'work'
|
||||
]),
|
||||
startDate: {
|
||||
get() {
|
||||
console.log('get start date', this.$store.state.startDate);
|
||||
return dateToISO(this.$store.state.startDate);
|
||||
},
|
||||
set(v) {
|
||||
this.$store.mutate('setStartDate', ISOToDate(v));
|
||||
}
|
||||
},
|
||||
endDate: {
|
||||
get() {
|
||||
console.log('get end date', this.$store.state.endDate);
|
||||
return dateToISO(this.$store.state.endDate);
|
||||
},
|
||||
set(v) {
|
||||
this.$store.mutate('setEndDate', ISOToDate(v));
|
||||
}
|
||||
},
|
||||
note: {
|
||||
get() {
|
||||
return this.$store.state.note;
|
||||
},
|
||||
set(v) {
|
||||
this.$store.mutate('setNote', note);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
@ -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: `<app></app>`,
|
||||
})
|
||||
.use(store)
|
||||
.use(i18n)
|
||||
.component('app', App)
|
||||
.mount('#accompanying_course_work_edit');
|
@ -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 };
|
@ -0,0 +1,24 @@
|
||||
{% extends '@ChillPerson/AccompanyingCourse/layout.html.twig' %}
|
||||
|
||||
{% block title 'accompanying_course_work.Edit accompanying course work'|trans %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ block('title') }}</h1>
|
||||
|
||||
<div id="accompanying_course_work_edit"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript">
|
||||
window.accompanyingCourseWork = {{ json|json_encode|raw }};
|
||||
</script>
|
||||
|
||||
{{ encore_entry_script_tags('accompanying_course_work_edit') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
{{ parent() }}
|
||||
{{ encore_entry_link_tags('accompanying_course_work_edit') }}
|
||||
{% endblock %}
|
@ -0,0 +1,28 @@
|
||||
{% extends '@ChillPerson/AccompanyingCourse/layout.html.twig' %}
|
||||
|
||||
{% block title 'accompanying_course_work.List accompanying course work'|trans %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ block('title') }}</h1>
|
||||
|
||||
<ul>
|
||||
{% for w in works %}
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_edit', { 'id': w.id }) }}">
|
||||
Work with id {{ w.id }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_new', { 'id': accompanyingCourse.id }) }}"
|
||||
class="sc-button bt-new">
|
||||
{{ 'accompanying_course_work.create'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
@ -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');
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user