add confirm button for move

This commit is contained in:
Julien Fastré 2021-06-04 21:24:11 +02:00
parent 48e5809008
commit e5905902cc
6 changed files with 268 additions and 10 deletions

View File

@ -50,6 +50,49 @@ class HouseholdMemberController extends ApiController
return $this->json($editor->getHousehold(), Response::HTTP_OK, ["groups" => ["read"]]);
}
/**
* @Route(
* "/api/1.0/person/household/members/move/test.{_format}",
* name="chill_api_person_household_members_move_test"
* )
*/
public function test(Request $request, $_format): Response
{
try {
$editor = $this->getSerializer()
->deserialize($request->getContent(), MembersEditor::class,
$_format, ['groups' => [ "read" ]]);
} catch (Exception\InvalidArgumentException | Exception\UnexpectedValueException $e) {
throw new BadRequestException("Deserialization error: {$e->getMessage()}", 45896, $e);
}
// TODO ACL
//
// TODO validation
// temporary, to have at least one problem for testing purpose
/*$violations = [
new \Symfony\Component\Validator\ConstraintViolation(
"This is a fake message",
null,
[],
$editor->getHousehold(),
'household.members.startDate',
new \DateTime('10 years ago')
),
new \Symfony\Component\Validator\ConstraintViolation(
"This is another fake message",
null,
[],
$editor->getHousehold(),
'household.members.endDate',
new \DateTime('10 years ago')
)
];
$violationsList = new \Symfony\Component\Validator\ConstraintViolationList($violations);
*/
return $this->json($editor->getHousehold(), Response::HTTP_OK, ["groups" => ["read"]]);
}
/**
* @Route(
* "/{_locale}/person/household/members/editor",

View File

@ -2,6 +2,7 @@
<household></household>
<concerned></concerned>
<dates></dates>
<confirmation></confirmation>
</template>
<script>
@ -10,6 +11,7 @@ import { mapState } from 'vuex';
import Concerned from './components/Concerned.vue';
import Household from './components/Household.vue';
import Dates from './components/Dates.vue';
import Confirmation from './components/Confirmation.vue';
export default {
name: 'App',
@ -17,6 +19,7 @@ export default {
Concerned,
Household,
Dates,
Confirmation,
},
computed: {
// for debugging purpose

View File

@ -0,0 +1,47 @@
/*
*/
const householdMove = (payload) => {
const url = `/api/1.0/person/household/members/move.json`;
console.log(payload);
console.log(JSON.stringify(payload));
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.then(response => {
if (response.ok) {
return response.json();
}
throw Error('Error with testing move');
});
};
const householdMoveTest = (payload) => {
const url = `/api/1.0/person/household/members/move/test.json`;
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.then(response => {
if (response.status === 422) {
return response.json();
}
if (response.ok) {
// return an empty array if ok
return new Promise((resolve, reject) => resolve({ violations: [] }) );
}
throw Error('Error with testing move');
});
};
export {
householdMove,
householdMoveTest
};

View File

@ -0,0 +1,32 @@
<template>
<ul>
<li v-for="(msg, index) in warnings">
{{ $t(msg.m, msg.a) }}
</li>
</ul>
<div v-if="hasNoWarnings">
<button class="sc-button bt-green" @click="confirm">{{ $t('household_member_editor.confirmation') }}</button>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'Confirmation',
computed: {
...mapState({
warnings: (state) => state.warnings,
hasNoWarnings: (state) => state.warnings.length === 0,
}),
},
methods: {
confirm() {
this.$store.dispatch('confirm');
}
}
}
</script>

View File

@ -1,4 +1,6 @@
import { createStore } from 'vuex';
import { householdMove, householdMoveTest } from './../api.js';
import { datetimeToISO } from 'ChillMainAssets/js/date.js';
const debug = process.env.NODE_ENV !== 'production';
@ -7,6 +9,7 @@ const concerned = window.household_members_editor_data.persons.map(p => {
person: p,
position: null,
allowRemove: false,
holder: false
};
});
@ -21,7 +24,7 @@ const store = createStore({
allowHouseholdSearch: window.household_members_editor_data.allowHouseholdSearch,
allowLeaveWithoutHousehold: window.household_members_editor_data.allowLeaveWithoutHousehold,
forceLeaveWithoutHousehold: false,
warnings: [],
},
getters: {
isHouseholdNew(state) {
@ -63,13 +66,51 @@ const store = createStore({
.find(conc => conc.person.id === person_id)
;
},
buildPayload: (state) => {
let
conc,
payload = {
concerned: [],
destination: {
id: state.household.id,
type: state.household.type
}
}
;
for (let i in state.concerned) {
conc = state.concerned[i];
console.log('loop', conc);
payload.concerned.push({
person: {
id: conc.person.id,
type: conc.person.type
},
position: {
id: conc.position.id,
type: conc.position.type
},
holder: conc.holder,
comment: "",
start_date: {
datetime: datetimeToISO(state.startDate)
}
});
}
return payload;
},
},
mutations: {
addConcerned(state, person) {
let persons = state.concerned.map(conc => conc.person.id);
if (!persons.includes(person.id)) {
state.concerned.push({ person, position: null,
allowRemove: true });
state.concerned.push({
person,
position: null,
allowRemove: true,
holder: false
});
} else {
console.err("person already included");
}
@ -107,39 +148,89 @@ const store = createStore({
state.forceLeaveWithoutHousehold = true;
},
setStartDate(state, dateI) {
state.startDate = dateI
state.startDate = dateI;
},
setWarnings(state, warnings) {
state.warnings = warnings;
},
},
actions: {
addConcerned({ commit }, person) {
addConcerned({ commit, dispatch }, person) {
console.log('from actions addConcerned');
commit('addConcerned', person);
dispatch('computeWarnings');
},
markPosition({ commit, state }, { person_id, position_id }) {
markPosition({ commit, state, dispatch }, { person_id, position_id }) {
console.log('from action markPosition');
console.log('person_id', person_id);
console.log('position_id', position_id);
commit('markPosition', { person_id, position_id });
dispatch('computeWarnings');
},
toggleHolder({ commit }, conc) {
commit('toggleHolder', conc);
},
removePosition({ commit }, conc) {
removePosition({ commit, dispatch }, conc) {
commit('removePosition', conc);
dispatch('computeWarnings');
},
removeConcerned({ commit }, conc) {
removeConcerned({ commit, dispatch }, conc) {
commit('removeConcerned', conc);
dispatch('computeWarnings');
},
createHousehold({ commit }) {
createHousehold({ commit, dispatch }) {
commit('createHousehold');
dispatch('computeWarnings');
},
forceLeaveWithoutHousehold({ commit }) {
forceLeaveWithoutHousehold({ commit, dispatch }) {
commit('forceLeaveWithoutHousehold');
dispatch('computeWarnings');
},
setStartDate({ commit }, date) {
commit('setStartDate', date);
},
computeWarnings({ commit, state, getters }) {
let warnings = [],
payload;
if (!getters.hasHousehold && !state.forceLeaveWithoutHousehold) {
warnings.push({ m: 'household_member_editor.add_destination', a: {} });
}
if (state.concerned.length === 0) {
warnings.push({ m: 'household_member_editor.add_at_least_onePerson', a: {} });
}
if (getters.concUnpositionned.length > 0
&& !state.forceLeaveWithoutHousehold) {
warnings.push({ m: 'household_member_editor.give_a_position_to_every_person', a: {} })
}
if (warnings.length === 0) {
payload = getters.buildPayload;
householdMoveTest(payload).then(errors => {
for (let i in errors.violations) {
console.log('error from server', errors.violations[i]);
warnings.push({ m: errors.violations[i].title, a: {} });
}
commit('setWarnings', warnings);
});
} else {
commit('setWarnings', warnings);
}
},
confirm({ getters }) {
let payload = getters.buildPayload;
householdMove(payload).then(household => {
console.log('move success', household);
let id = household.id;
// nothing to do anymore here, bye-bye !
window.location.replace(`/fr/person/household/{id}/members`);
});
},
}
});
store.dispatch('computeWarnings');
export { store };

View File

@ -826,3 +826,45 @@ paths:
400:
description: "transition cannot be applyed"
/1.0/person/household/members/move/test.json:
post:
tags:
- household
summary: test the move of one or more person, without persisting changes in database
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
concerned:
type: array
items:
type: object
properties:
person:
$ref: '#/components/schemas/PersonById'
start_date:
$ref: '#/components/schemas/Date'
position:
$ref: '#/components/schemas/HouseholdPosition'
holder:
type: boolean
comment:
type: string
destination:
oneOf:
- $ref: '#/components/schemas/Household'
responses:
401:
description: "Unauthorized"
404:
description: "Not found"
200:
description: "OK"
422:
description: "Unprocessable entity (validation errors)"
400:
description: "transition cannot be applyed"