first layout for form edit

This commit is contained in:
Julien Fastré 2021-06-09 16:13:39 +02:00
parent 18217f53e8
commit e14205ae1d
16 changed files with 386 additions and 83 deletions

View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg34"
version="1.1"
viewBox="0 0 32 32">
<metadata
id="metadata40">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs38" />
<rect
id="rect2"
x="0"
y="4"
width="4"
height="4" />
<rect
id="rect4"
x="0"
y="12"
width="4"
height="4" />
<rect
id="rect6"
x="0"
y="20"
width="4"
height="4" />
<rect
id="rect8"
x="0"
y="28"
width="4"
height="4" />
<rect
id="rect10"
x="8"
y="4"
width="4"
height="4" />
<rect
id="rect12"
x="8"
y="12"
width="4"
height="4" />
<rect
id="rect14"
x="8"
y="20"
width="4"
height="4" />
<rect
id="rect16"
x="8"
y="28"
width="4"
height="4" />
<rect
id="rect18"
x="16"
y="4"
width="4"
height="4" />
<rect
id="rect20"
x="16"
y="12"
width="4"
height="4" />
<rect
id="rect22"
x="16"
y="20"
width="4"
height="4" />
<rect
id="rect24"
x="16"
y="28"
width="4"
height="4" />
<rect
id="rect26"
x="24"
y="4"
width="4"
height="4" />
<rect
id="rect28"
x="24"
y="12"
width="4"
height="4" />
<rect
id="rect30"
x="24"
y="20"
width="4"
height="4" />
<rect
id="rect32"
x="24"
y="28"
width="4"
height="4" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,5 +1,7 @@
/** /**
* Some utils for manipulating dates * Some utils for manipulating dates
*
* **WARNING** experimental
*/ */
/** /**
@ -8,6 +10,8 @@
* The date is valid for the same timezone as the date's locale * The date is valid for the same timezone as the date's locale
* *
* Do not take time into account * Do not take time into account
*
* **Experimental**
*/ */
const dateToISO = (date) => { const dateToISO = (date) => {
return [ return [
@ -19,16 +23,36 @@ const dateToISO = (date) => {
/** /**
* Return a date object from iso string formatted as YYYY-mm-dd * Return a date object from iso string formatted as YYYY-mm-dd
*
* **Experimental**
*/ */
const ISOToDate = (str) => { const ISOToDate = (str) => {
let let
[year, month, day] = str.split('-'); [year, month, day] = str.split('-');
return new Date(year, month-1, day); return new Date(year, month-1, day);
} }
/**
* Return a date object from iso string formatted as YYYY-mm-dd:HH:MM:ss+01:00
*
* **Experimental**
*/
const ISOToDatetime = (str) => {
console.log(str);
let
[cal, times] = str.split('T'),
[year, month, date] = cal.split('-'),
[time, timezone] = cal.split(times.charAt(9)),
[hours, minutes, seconds] = cal.split(':')
;
return new Date(year, month-1, date, hours, minutes, seconds);
}
/** /**
* Convert a date to ISO8601, valid for usage in api * Convert a date to ISO8601, valid for usage in api
*
*/ */
const datetimeToISO = (date) => { const datetimeToISO = (date) => {
let cal, time, offset; let cal, time, offset;
@ -52,7 +76,6 @@ const datetimeToISO = (date) => {
].join(''); ].join('');
let x = cal + 'T' + time + offset; let x = cal + 'T' + time + offset;
console.log('return date', x);
return x; return x;
}; };
@ -60,5 +83,6 @@ const datetimeToISO = (date) => {
export { export {
dateToISO, dateToISO,
ISOToDate, ISOToDate,
ISOToDatetime,
datetimeToISO datetimeToISO
}; };

View File

@ -17,7 +17,7 @@
// @import "bootstrap/scss/grid"; // @import "bootstrap/scss/grid";
// @import "bootstrap/scss/tables"; // @import "bootstrap/scss/tables";
// @import "bootstrap/scss/forms"; // @import "bootstrap/scss/forms";
// @import "bootstrap/scss/buttons"; @import "bootstrap/scss/buttons";
@import "bootstrap/scss/transitions"; @import "bootstrap/scss/transitions";
// @import "bootstrap/scss/dropdown"; // @import "bootstrap/scss/dropdown";
// @import "bootstrap/scss/button-group"; // @import "bootstrap/scss/button-group";
@ -30,7 +30,7 @@
// @import "bootstrap/scss/pagination"; // @import "bootstrap/scss/pagination";
@import "bootstrap/scss/badge"; @import "bootstrap/scss/badge";
// @import "bootstrap/scss/jumbotron"; // @import "bootstrap/scss/jumbotron";
// @import "bootstrap/scss/alert"; @import "bootstrap/scss/alert";
// @import "bootstrap/scss/progress"; // @import "bootstrap/scss/progress";
// @import "bootstrap/scss/media"; // @import "bootstrap/scss/media";
// @import "bootstrap/scss/list-group"; // @import "bootstrap/scss/list-group";

View File

@ -112,7 +112,7 @@ div.flex-bloc {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
div.item-row { & > div.item-row {
flex-grow: 1; flex-shrink: 1; flex-basis: auto; flex-grow: 1; flex-shrink: 1; flex-basis: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -62,7 +62,7 @@ const messages = {
person: "un nouvel usager", person: "un nouvel usager",
thirdparty: "un nouveau tiers" thirdparty: "un nouveau tiers"
}, },
} },
} }
}; };

View File

@ -47,7 +47,9 @@ div.list-household-members--summary {
.chill-entity__person { .chill-entity__person {
.chill-entity__person__first-name, .chill-entity__person__first-name,
.chill-entity__person__last-name { .chill-entity__person__last-name,
// text is used in vue component 'Person'
.chill-entity__person__text {
font-size: 1.3em; font-size: 1.3em;
font-weight: 700; font-weight: 700;
} }

View File

@ -1,25 +1,56 @@
<template> <template>
<h2>{{ $t('household_members_editor.concerned.title') }}</h2> <h2>{{ $t('household_members_editor.concerned.title') }}</h2>
<div> <h3>{{ $t('household_members_editor.concerned.persons_to_positionnate') }}</h3>
<div v-for="conc in concUnpositionned"
<div class="flex-table list-household-members">
<div v-for="conc in concUnpositionned"
class="item-bloc"
v-bind:key="conc.person.id" v-bind:key="conc.person.id"
draggable="true" draggable="true"
@dragstart="onStartDragConcern($event, conc.person.id)" @dragstart="onStartDragConcern($event, conc.person.id)"
> >
<span>{{ conc.person.text }}</span> <div class="item-row person">
<span> <div class="item-col box-person">
{{ $t('household_members_editor.concerned.move_to') }}: <div>
</span> <img src="~ChillMainAssets/img/draggable.svg" class="drag-icon" />
<span <person :person="conc.person"></person>
v-for="position in positions" </div>
@click="moveToPosition(conc.person.id, position.id)" <div>
> {{ $t('person.born', {'gender': conc.person.gender} ) }}
{{ position.label.fr }} {{ $d(conc.person.birthdate.datetime, 'short') }}
</span> </div>
<button v-if="conc.allowRemove" @click="removeConcerned(conc)">
{{ $t('household_members_editor.remove_concerned') }} </div>
</button> <div class="item-col box-where">
<ul class="list-content fa-ul">
<li>
<i class="fa fa-li fa-map-marker"></i>
<span class="chill-no-data-statement">Sans adresse</span>
</li>
</ul>
</div>
</div>
<div class="item-row move_to">
<div class="item-col">
<template
v-for="position in positions"
>
<button
class="btn btn-outline-primary"
@click="moveToPosition(conc.person.id, position.id)"
>
{{ position.label.fr }}
</button>&nbsp;
</template>
<button v-if="conc.allowRemove" @click="removeConcerned(conc)" class="btn bt-primary">
{{ $t('household_members_editor.remove_concerned') }}
</button>
</div>
</div>
</div> </div>
</div> </div>
@ -39,8 +70,8 @@
<div <div
v-for="position in positions" v-for="position in positions"
> >
<h2>{{ position.label.fr }}</h2> <h3>{{ position.label.fr }}</h3>
<ul> <div class="flex-table list-household-members">
<member-details <member-details
v-for="conc in concByPosition(position.id)" v-for="conc in concByPosition(position.id)"
v-bind:key="conc.person.id" v-bind:key="conc.person.id"
@ -49,14 +80,15 @@
@dragstart="onStartDragConcern($event, conc.person.id)" @dragstart="onStartDragConcern($event, conc.person.id)"
> >
</member-details> </member-details>
<li <div
class="droppable" class="droppable_zone"
@drop="onDropConcern($event, position.id)" @drop="onDropConcern($event, position.id)"
@dragover.prevent @dragover.prevent
@dragenter.prevent @dragenter.prevent
> >
</li> {{ $t('household_members_editor.drop_persons_here', {'position': position.label.fr }) }}
</ul> </div>
</div>
</div> </div>
</div> </div>
@ -64,33 +96,53 @@
</template> </template>
<style scoped> <style scoped>
.concerned_box { div.person {
cursor: move; cursor: move;
padding: 1.5em;
border: 1px solid black; * {
cursor: move
}
} }
.concerned_box * {
cursor: move; .drag-icon {
height: 1.1em;
margin-right: 0.5em;
} }
.droppable_zone { .droppable_zone {
min-height: 50px; background-color: var(--chill-llight-gray);
width: 100%; color: white;
border: 1px solid black; font-size: large;
text-align: center;
display: table-cell;
vertical-align: middle;
padding: 1em;
background: linear-gradient(to top, var(--chill-light-gray), 30%, var(--chill-llight-gray));
} }
</style> </style>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'; import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import Person from 'ChillPersonAssets/vuejs/_components/Person/Person.vue';
import MemberDetails from './MemberDetails.vue'; import MemberDetails from './MemberDetails.vue';
import { ISOToDatetime } from 'ChillMainAssets/js/date.js';
export default { export default {
name: 'Concerned', name: 'Concerned',
components: { components: {
AddPersons, AddPersons,
MemberDetails, MemberDetails,
Person,
}, },
computed: { computed: {
as_date: (state) => (d) => {
console.log(d);
let k = ISOToDatetime(d);
console.log(k);
return k;
},
...mapGetters([ ...mapGetters([
'concUnpositionned', 'concUnpositionned',
'positions', 'positions',

View File

@ -1,16 +1,31 @@
<template> <template>
<div v-if="hasWarnings" class="alert alert-warning">
{{ $t('household_members_editor.confirmation.there_are_warnings') }}
</div>
<p v-if="hasWarnings">
{{ $t('household_members_editor.confirmation.check_those_items') }}
</p>
<ul> <ul>
<li v-for="(msg, index) in warnings"> <li v-for="(msg, index) in warnings">
{{ $t(msg.m, msg.a) }} {{ $t(msg.m, msg.a) }}
</li> </li>
</ul> </ul>
<div v-if="hasNoWarnings"> <ul class="record_actions sticky-form-buttons">
<button class="sc-button bt-green" @click="confirm">{{ $t('household_member_editor.confirmation') }}</button> <li>
</div> <button class="sc-button bt-save" :disabled="hasWarnings" @click="confirm">
{{ $t('household_members_editor.confirmation.save') }}
</button>
</li>
</ul>
</template> </template>
<style scoped lang="scss">
</style>
<script> <script>
import { mapState } from 'vuex'; import { mapState } from 'vuex';
@ -20,6 +35,7 @@ export default {
...mapState({ ...mapState({
warnings: (state) => state.warnings, warnings: (state) => state.warnings,
hasNoWarnings: (state) => state.warnings.length === 0, hasNoWarnings: (state) => state.warnings.length === 0,
hasWarnings: (state) => state.warnings.length > 0,
}), }),
}, },
methods: { methods: {

View File

@ -1,9 +1,9 @@
<template> <template>
<h2>{{ $t('household_member_editor.dates_title') }}</h2> <h2>{{ $t('household_members_editor.dates_title') }}</h2>
<p> <p>
<label for="start_date"> <label for="start_date">
{{ $t('household_member_editor.dates.start_date') }} {{ $t('household_members_editor.dates.start_date') }}
</label> </label>
<input type="date" v-model="startDate" /> <input type="date" v-model="startDate" />
</p> </p>

View File

@ -1,29 +1,29 @@
<template> <template>
<h2>{{ $t('household_member_editor.household_part') }}</h2> <h2>{{ $t('household_members_editor.household_part') }}</h2>
<div v-if="hasHousehold"> <div v-if="hasHousehold">
<span v-if="isHouseholdNew"> <span v-if="isHouseholdNew">
{{ $t('household_member_editor.new_household') }} {{ $t('household_members_editor.new_household') }}
</span> </span>
<div v-else> <div v-else>
Ménage existant Ménage existant
</div> </div>
</div> </div>
<div v-else-if="isForceLeaveWithoutHousehold"> <div v-else-if="isForceLeaveWithoutHousehold">
{{ $t('household_member_editor.will_leave_any_household') }} {{ $t('household_members_editor.will_leave_any_household') }}
</div> </div>
<div v-else> <div v-else>
Aucun ménage Aucun ménage
</div> </div>
<button v-if="allowHouseholdCreate" class="sc-button bt-create" @click="createHousehold"> <button v-if="allowHouseholdCreate" class="sc-button bt-create" @click="createHousehold">
{{ $t('household_member_editor.create_household') }} {{ $t('household_members_editor.create_household') }}
</button> </button>
<button v-if="allowHouseholdSearch"> <button v-if="allowHouseholdSearch">
{{ $t('household_member_editor.search_household') }} {{ $t('household_members_editor.search_household') }}
</button> </button>
<button v-if="allowLeaveWithoutHousehold" @click="forceLeaveWithoutHousehold"> <button v-if="allowLeaveWithoutHousehold" @click="forceLeaveWithoutHousehold">
{{ $t('household_member_editor.leave_without_household') }} {{ $t('household_members_editor.leave_without_household') }}
</button> </button>
</template> </template>

View File

@ -1,29 +1,82 @@
<template> <template>
<li> <div class="item-bloc">
<div> <div class="item-row person">
<span>{{ conc.person.text }}</span> <div class="item-col box-person">
<span v-if="conc.position.allowHolder"> <div>
<button class="badge badge-pill" :class="{ 'badge-primary': isHolder, 'badge-secondary': !isHolder}" @click="toggleHolder"> <img src="~ChillMainAssets/img/draggable.svg" class="drag-icon" />
{{ $t('household_members_editor.holder') }} <person :person="conc.person"></person>
</button> <span v-if="isHolder" class="badge badge-primary holder">
{{ $t('household_members_editor.holder') }}
</span>
</div>
<div>{{ $t('person.born', {'gender': conc.person.gender} ) }}</div>
</div>
<div class="item-col box-where">
<ul class="list-content fa-ul">
<li>
<i class="fa fa-li fa-map-marker"></i>
<span class="chill-no-data-statement">Sans adresse</span>
</li>
</ul>
</div>
</div>
</span> <div class="item-row participation-details">
<button @click="removePosition"> <div v-if="conc.position.allowHolder" class="action">
{{ $t('household_members_editor.remove_position', {position: conc.position.label.fr}) }} <button class="btn" :class="{ 'btn-primary': isHolder, 'btn-secondary': !isHolder}" @click="toggleHolder">
</button> {{ $t(isHolder ? 'household_members_editor.is_holder' : 'household_members_editor.is_not_holder') }}
<button @click="removeConcerned"> </button>
{{ $t('household_members_editor.remove_concerned') }} </div>
</button>
<div>
<button @click="removePosition" class="btn btn-outline-primary">
{{ $t('household_members_editor.remove_position', {position: conc.position.label.fr}) }}
</button>
</div>
<div>
<button v-if="conc.allowRemove" @click="removeConcerned" class="btn btn-primary">
{{ $t('household_members_editor.remove_concerned') }}
</button>
</div>
</div>
</div> </div>
</li>
</template> </template>
<style scoped lang="scss">
.drag-icon {
height: 1.1em;
margin-right: 0.5em;
}
div.participation-details {
display: flex;
flex-direction: row !important;
justify-content: flex-end;
.action {
align-self: flex-start;
margin-right: auto;
}
}
.holder {
display: inline;
vertical-align: super;
font-size: 0.6em;
}
</style>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Person from 'ChillPersonAssets/vuejs/_components/Person/Person.vue';
export default { export default {
name: 'MemberDetails', name: 'MemberDetails',
components: {
Person,
},
props: [ props: [
'conc' 'conc'
], ],

View File

@ -9,15 +9,31 @@ const appMessages = {
add_persons: "Ajouter d'autres usagers", add_persons: "Ajouter d'autres usagers",
search: "Rechercher des usagers", search: "Rechercher des usagers",
move_to: "Déplacer vers", move_to: "Déplacer vers",
persons_to_positionnate: 'Usagers à positionner',
}, },
holder: "Titulaire du ménage", drop_persons_here: "Glissez-déposez ici les usagers pour la position \"{position}\"",
holder: "Titulaire",
is_holder: "Sera titulaire",
is_not_holder: "Ne sera pas titulaire",
remove_position: "Retirer des {position}", remove_position: "Retirer des {position}",
remove_concerned: "Enlever du ménage", remove_concerned: "Ne plus transférer",
household_part: "Ménage de destination", household_part: "Ménage de destination",
new_household: "Nouveau ménage", new_household: "Nouveau ménage",
create_household: "Créer un ménage", create_household: "Créer un ménage",
search_household: "Chercher un ménage", search_household: "Chercher un ménage",
} dates_title: "Période de validité",
dates: {
start_date: "Début de validité",
end_date: "Fin de validité",
},
confirmation: {
save: "Enregistrer",
there_are_warnings: "Impossible de valider actuellement",
check_those_items: "Veuillez corriger les éléments suivants",
},
give_a_position_to_every_person: "Indiquer une position pour chaque usager concerné",
}
} }
}; };

View File

@ -194,30 +194,19 @@ const store = createStore({
payload; payload;
if (!getters.hasHousehold && !state.forceLeaveWithoutHousehold) { if (!getters.hasHousehold && !state.forceLeaveWithoutHousehold) {
warnings.push({ m: 'household_member_editor.add_destination', a: {} }); warnings.push({ m: 'household_members_editor.add_destination', a: {} });
} }
if (state.concerned.length === 0) { if (state.concerned.length === 0) {
warnings.push({ m: 'household_member_editor.add_at_least_onePerson', a: {} }); warnings.push({ m: 'household_members_editor.add_at_least_onePerson', a: {} });
} }
if (getters.concUnpositionned.length > 0 if (getters.concUnpositionned.length > 0
&& !state.forceLeaveWithoutHousehold) { && !state.forceLeaveWithoutHousehold) {
warnings.push({ m: 'household_member_editor.give_a_position_to_every_person', a: {} }) warnings.push({ m: 'household_members_editor.give_a_position_to_every_person', a: {} })
} }
if (warnings.length === 0) { commit('setWarnings', warnings);
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 }) { confirm({ getters }) {
let payload = getters.buildPayload; let payload = getters.buildPayload;

View File

@ -0,0 +1,16 @@
<template>
<span class="chill-entity chill-entity__person">
<span class="chill-entity__person__text">
{{ person.text }}
</span>
</span>
</template>
<script>
export default {
name: 'Person',
props: ['person']
}
</script>

View File

@ -15,7 +15,15 @@ const personMessages = {
person: { person: {
firstname: "Prénom", firstname: "Prénom",
lastname: "Nom", lastname: "Nom",
born: "né{e} le ", born: (ctx) => {
if (ctx.gender === 'man') {
return 'Né le';
} else if (ctx.gender === 'woman') {
return 'Née le';
} else {
return 'Né·e le';
}
},
center_id: "Identifiant du centre", center_id: "Identifiant du centre",
center_type: "Type de centre", center_type: "Type de centre",
center_name: "Territoire", // vendée center_name: "Territoire", // vendée

View File

@ -1,8 +1,14 @@
{% extends '@ChillMain/layout.html.twig' %} {% extends '@ChillMain/layout.html.twig' %}
{% block title 'household.Edit household members'|trans %}
{% block content %} {% block content %}
<h1>Editor</h1> <div class="grid-12 parent">
<div id="household_members_editor"></div> <div class="grid-10 push-1 parent">
<h1>{{ block('title') }}</h1>
<div id="household_members_editor"></div>
</div>
</div>
{% endblock %} {% endblock %}
{% block js %} {% block js %}