WIP continue editor

This commit is contained in:
Julien Fastré 2021-06-03 18:11:05 +02:00
parent c6949490a4
commit d9a3e117b2
7 changed files with 274 additions and 32 deletions

View File

@ -5,6 +5,7 @@ namespace Chill\PersonBundle\Controller;
use Chill\PersonBundle\Entity\Household\Position;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Household\Household;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@ -57,6 +58,8 @@ class HouseholdMemberController extends ApiController
*/
public function editor(Request $request)
{
$em = $this->getDoctrine()->getManager();
if ($request->query->has('persons')) {
$ids = $request->query->get('persons', []);
@ -65,8 +68,7 @@ class HouseholdMemberController extends ApiController
"is not an array or empty");
}
$persons = $this->getDoctrine()->getManager()
->getRepository(Person::class)
$persons = $em->getRepository(Person::class)
->findById($ids)
;
@ -77,6 +79,20 @@ class HouseholdMemberController extends ApiController
}
}
if ($householdId = $request->query->get('household', false)) {
$household = $em->getRepository(Household::class)
->find($householdId)
;
$allowHouseholdCreate = false;
$allowHouseholdSearch = false;
$allowLeaveWithoutHousehold = false;
if (NULL === $household) {
throw $this->createNotFoundException('household not found');
}
// TODO ACL on household
}
$positions = $this->getDoctrine()->getManager()
->getRepository(Position::class)
->findAll()
@ -84,10 +100,14 @@ class HouseholdMemberController extends ApiController
$data = [
'persons' => $persons ?? false ?
$this->getSerializer()->normalize($persons, 'json', [ 'groups' => [ 'read' ]]): [],
'household' => null,
$this->getSerializer()->normalize($persons, 'json', [ 'groups' => [ 'read' ]]) : [],
'household' => $household ?? false ?
$this->getSerializer()->normalize($household, 'json', [ 'groups' => [ 'read' ]]) : null,
'positions' =>
$this->getSerializer()->normalize($positions, 'json', [ 'groups' => [ 'read' ]])
$this->getSerializer()->normalize($positions, 'json', [ 'groups' => [ 'read' ]]),
'allowHouseholdCreate' => $allowHouseholdCreate ?? true,
'allowHouseholdSearch' => $allowHouseholdSearch ?? true,
'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'),
];
return $this->render('@ChillPerson/Household/members_editor.html.twig', [

View File

@ -1,15 +1,19 @@
<template>
<household></household>
<concerned></concerned>
</template>
<script>
import Concerned from './components/Concerned.vue';
import { mapState } from 'vuex';
import Concerned from './components/Concerned.vue';
import Household from './components/Household.vue';
export default {
name: 'App',
components: {
Concerned,
Household,
},
computed: {
// for debugging purpose

View File

@ -1,12 +1,25 @@
<template>
<h1>{{ $t('household_members_editor.concerned.title') }}</h1>
<h2>{{ $t('household_members_editor.concerned.title') }}</h2>
<div>
<div v-for="person in personsUnpositionned"
<div v-for="conc in concUnpositionned"
v-bind:key="conc.person.id"
draggable="true"
@dragstart="onStartDragConcern($event, person.id)"
@dragstart="onStartDragConcern($event, conc.person.id)"
>
<span>{{ person.text }}</span>
<span>{{ conc.person.text }}</span>
<span>
{{ $t('household_members_editor.concerned.move_to') }}:
</span>
<span
v-for="position in positions"
@click="moveToPosition(conc.person.id, position.id)"
>
{{ position.label.fr }}
</span>
<button v-if="conc.allowRemove" @click="removeConcerned(conc)">
{{ $t('household_members_editor.remove_concerned') }}
</button>
</div>
</div>
@ -23,16 +36,19 @@
<div class="positions">
<div v-for="position in positions">
<div
v-for="position in positions"
>
<h2>{{ position.label.fr }}</h2>
<ul>
<li
v-for="person in personByPosition(position.id)"
<member-details
v-for="conc in concByPosition(position.id)"
v-bind:key="conc.person.id"
v-bind:conc="conc"
draggable="true"
@dragstart="onStartDragConcern($event, person.id)"
@dragstart="onStartDragConcern($event, conc.person.id)"
>
{{ person.text }}, {{ person.id }}
</li>
</member-details>
<li
class="droppable"
@drop="onDropConcern($event, position.id)"
@ -65,18 +81,20 @@
<script>
import { mapGetters } from 'vuex';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import MemberDetails from './MemberDetails.vue';
export default {
name: 'Concerned',
components: {
AddPersons,
MemberDetails,
},
computed: {
...mapGetters([
'personsUnpositionned',
'concUnpositionned',
'positions',
'personByPosition',
'concByPosition',
])
},
data() {
@ -111,8 +129,15 @@ export default {
console.log(evt);
console.log('position_id', position_id);
const person_id = Number(evt.dataTransfer.getData('application/x.person'));
this.moveToPosition(person_id, position_id);
},
moveToPosition(person_id, position_id) {
this.$store.dispatch('markPosition', { person_id, position_id });
}
},
removeConcerned(conc) {
this.$store.dispatch('removeConcerned', conc);
},
}
}
</script>

View File

@ -0,0 +1,70 @@
<template>
<h2>{{ $t('household_member_editor.household_part') }}</h2>
<div v-if="hasHousehold">
<span v-if="isHouseholdNew">
{{ $t('household_member_editor.new_household') }}
</span>
<div v-else>
Ménage existant
</div>
</div>
<div v-else-if="isForceLeaveWithoutHousehold">
{{ $t('household_member_editor.will_leave_any_household') }}
</div>
<div v-else>
Aucun ménage
</div>
<button v-if="allowHouseholdCreate" class="sc-button bt-create" @click="createHousehold">
{{ $t('household_member_editor.create_household') }}
</button>
<button v-if="allowHouseholdSearch">
{{ $t('household_member_editor.search_household') }}
</button>
<button v-if="allowLeaveWithoutHousehold" @click="forceLeaveWithoutHousehold">
{{ $t('household_member_editor.leave_without_household') }}
</button>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'Household',
computed: {
...mapGetters([
'hasHousehold',
'isHouseholdNew',
]),
household() {
return this.$store.household;
},
allowHouseholdCreate() {
console.log('allowHouseholdcreate', this.$store.state.allowHouseholdCreate);
return this.$store.state.allowHouseholdCreate;
},
allowHouseholdSearch() {
console.log('allowHouseholdcreate', this.$store.state.allowHouseholdSearch);
return this.$store.state.allowHouseholdSearch;
},
allowLeaveWithoutHousehold() {
return this.$store.state.allowLeaveWithoutHousehold;
},
isForceLeaveWithoutHousehold() {
return this.$store.state.forceLeaveWithoutHousehold;
}
},
methods: {
createHousehold() {
this.$store.dispatch('createHousehold');
},
forceLeaveWithoutHousehold() {
this.$store.dispatch('forceLeaveWithoutHousehold');
}
},
};
</script>

View File

@ -0,0 +1,51 @@
<template>
<li>
<div>
<span>{{ conc.person.text }}</span>
<span v-if="conc.position.allowHolder">
<button class="badge badge-pill" :class="{ 'badge-primary': isHolder, 'badge-secondary': !isHolder}" @click="toggleHolder">
{{ $t('household_members_editor.holder') }}
</button>
</span>
<button @click="removePosition">
{{ $t('household_members_editor.remove_position', {position: conc.position.label.fr}) }}
</button>
<button @click="removeConcerned">
{{ $t('household_members_editor.remove_concerned') }}
</button>
</div>
</li>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'MemberDetails',
props: [
'conc'
],
computed: {
...mapGetters( [
'concByPersonId'
]),
isHolder() {
return this.conc.holder;
}
},
methods: {
toggleHolder() {
this.$store.dispatch('toggleHolder', this.conc);
},
removePosition() {
this.$store.dispatch('removePosition', this.conc);
},
removeConcerned() {
this.$store.dispatch('removeConcerned', this.conc);
},
}
};
</script>

View File

@ -5,10 +5,18 @@ const appMessages = {
fr: {
household_members_editor: {
concerned: {
title: "Personnes concernées",
title: "Usagers concernés",
add_persons: "Ajouter d'autres usagers",
search: "Rechercher des usagers",
}
move_to: "Déplacer vers",
},
holder: "Titulaire du ménage",
remove_position: "Retirer des {position}",
remove_concerned: "Enlever du ménage",
household_part: "Ménage de destination",
new_household: "Nouveau ménage",
create_household: "Créer un ménage",
search_household: "Chercher un ménage",
}
}
};

View File

@ -6,7 +6,8 @@ const concerned = window.household_members_editor_data.persons.map(p => {
return {
person: p,
position: null,
start_date: null
start_date: null,
allowRemove: false,
};
});
@ -16,17 +17,31 @@ const store = createStore({
concerned,
household: window.household_members_editor_data.household,
positions: window.household_members_editor_data.positions,
allowHouseholdCreate: window.household_members_editor_data.allowHouseholdCreate,
allowHouseholdSearch: window.household_members_editor_data.allowHouseholdSearch,
allowLeaveWithoutHousehold: window.household_members_editor_data.allowLeaveWithoutHousehold,
forceLeaveWithoutHousehold: false
},
getters: {
isHouseholdNew(state) {
console.log('isHouseholdNew', !Number.isInteger(state.household.id));
console.log('household', state.household);
return !Number.isInteger(state.household.id);
},
hasHousehold(state) {
return state.household !== null;
},
persons(state) {
return state.concerned.map(conc => conc.person);
},
personsUnpositionned(state) {
concUnpositionned(state) {
return state.concerned
.filter(conc => conc.position === null)
.map(conc => conc.person)
;
},
positions(state) {
return state.positions;
},
personByPosition: (state) => (position_id) => {
return state.concerned
.filter(conc =>
@ -35,14 +50,28 @@ const store = createStore({
.map(conc => conc.person)
;
},
positions(state) {
return state.positions;
}
concByPosition: (state) => (position_id) => {
return state.concerned
.filter(conc =>
conc.position !== null ? conc.position.id === position_id : false
)
;
},
concByPersonId: (state) => (person_id) => {
return state.concerned
.find(conc => conc.person.id === person_id)
;
},
},
mutations: {
addConcerned(state, person) {
console.log('from mutation addConcerned');
state.concerned.push({ person, position: null, start_date: null });
let persons = state.concerned.map(conc => conc.person.id);
if (!persons.includes(person.id)) {
state.concerned.push({ person, position: null,
start_date: null, allowRemove: true });
} else {
console.err("person already included");
}
},
markPosition(state, { person_id, position_id}) {
console.log('from mutation markPosition');
@ -55,7 +84,27 @@ const store = createStore({
console.log(position);
console.log(conc);
conc.position = position;
}
},
toggleHolder(state, conc) {
console.log('toggleHolder', conc);
conc.holder = !conc.holder;
},
removePosition(state, conc) {
conc.holder = false;
conc.position = null;
},
removeConcerned(state, conc) {
state.concerned = state.concerned.filter(c =>
c.person.id !== conc.person.id
)
},
createHousehold(state) {
state.household = { type: 'household', members: [], address: null }
},
forceLeaveWithoutHousehold(state) {
state.household = null;
state.forceLeaveWithoutHousehold = true;
},
},
actions: {
addConcerned({ commit }, person) {
@ -67,7 +116,22 @@ const store = createStore({
console.log('person_id', person_id);
console.log('position_id', position_id);
commit('markPosition', { person_id, position_id });
}
},
toggleHolder({ commit }, conc) {
commit('toggleHolder', conc);
},
removePosition({ commit }, conc) {
commit('removePosition', conc);
},
removeConcerned({ commit }, conc) {
commit('removeConcerned', conc);
},
createHousehold({ commit }) {
commit('createHousehold');
},
forceLeaveWithoutHousehold({ commit }) {
commit('forceLeaveWithoutHousehold');
},
}
});