[webpack.ue.view] no more need for $router (it is in Gstore) for navigation funcs [webpack.ue.manage] eased 'rem_form' (by index no more ID) + fetch professors / created layout for changing professor for a cours|TD|TP

This commit is contained in:
xdrm-brackets 2018-03-16 15:18:57 +01:00
parent 8218571498
commit cd9f342eda
4 changed files with 220 additions and 124 deletions

View File

@ -9,8 +9,8 @@
<!-- FILTERS --> <!-- FILTERS -->
<section class='filter'> <section class='filter'>
<div>Type</div>
<div>enseignant</div> <div>enseignant</div>
<div class='null'></div>
<div>volume horaire</div> <div>volume horaire</div>
<div>formations</div> <div>formations</div>
@ -21,13 +21,16 @@
v-for='(c,i) in gstore.manage.cours' v-for='(c,i) in gstore.manage.cours'
:data-id='c.idCours'> :data-id='c.idCours'>
<select v-model='c.idProf' @change='upd_prof(i)'>
<option value='-1' v-show='c.idProf!=-1'>Aucun enseignant affecté</option>
<option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=c.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option>
</select>
<div>Cours</div> <div>Cours</div>
<div :data-prof='c.idProf'>{{ c.idProf ? `${c.firstName} ${c.lastName}` : 'Aucun enseignant affecté' }}</div>
<div>{{ c.volume }}</div> <div>{{ c.volume }}</div>
<div class='taglist'> <div class='taglist'>
<div v-for='f in c.formations' data-action> <div v-for='f in c.formations' data-action>
<span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span> <span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span>
<span data-remove @click='gstore.rem_form(0, c.idCours, f)'></span> <span data-remove @click='gstore.rem_form(0, i, f)'></span>
</div> </div>
<div data-action> <div data-action>
@ -52,13 +55,16 @@
data-anim-incoming='1' data-anim-incoming='1'
:data-anim-bounce='gstore.nav_anim.out?1:0'> :data-anim-bounce='gstore.nav_anim.out?1:0'>
<select v-model='td.idProf' @change='upd_prof(i)'>
<option value='-1' v-show='td.idProf!=-1'>Aucun enseignant affecté</option>
<option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=td.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option>
</select>
<div>TD</div> <div>TD</div>
<div :data-prof='td.idProf'>{{ td.idProf ? `${td.firstName} ${td.lastName}` : 'Aucun enseignant affecté' }}</div>
<div>{{ td.volume }}</div> <div>{{ td.volume }}</div>
<div class='taglist'> <div class='taglist'>
<div v-for='f in td.formations' data-action> <div v-for='f in td.formations' data-action>
<span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span> <span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span>
<span data-remove @click='gstore.rem_form(1, td.idTD, f)'></span> <span data-remove @click='gstore.rem_form(1, i, f)'></span>
</div> </div>
<div data-action> <div data-action>
@ -83,13 +89,16 @@
data-anim-incoming='1' data-anim-incoming='1'
:data-anim-bounce='gstore.nav_anim.out?1:0'> :data-anim-bounce='gstore.nav_anim.out?1:0'>
<select v-model='tp.idProf' @change='upd_prof(i)'>
<option value='-1' v-show='tp.idProf!=-1'>Aucun enseignant affecté</option>
<option v-for='p in gstore.manage.prof' :value='p.idProfesseur' v-show='p.idProfesseur!=tp.idProf'>{{ `${p.firstName} ${p.lastName}` }}</option>
</select>
<div>TP</div> <div>TP</div>
<div :data-prof='tp.idProf'>{{ tp.idProf ? `${tp.firstName} ${tp.lastName}` : 'Aucun enseignant affecté' }}</div>
<div>{{ tp.volume }}</div> <div>{{ tp.volume }}</div>
<div class='taglist'> <div class='taglist'>
<div v-for='f in tp.formations' data-action> <div v-for='f in tp.formations' data-action>
<span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span> <span class='tag'>{{ gstore.form_by_id(f).labelForm || '???' }}</span>
<span data-remove @click='gstore.rem_form(2, tp.idTP, f)'></span> <span data-remove @click='gstore.rem_form(2, i, f)'></span>
</div> </div>
<div data-action> <div data-action>
@ -123,7 +132,14 @@
return { gstore: gstore.get } return { gstore: gstore.get }
}, },
beforeMount(){ beforeMount(){
gstore.get.manage_load(this.$route.params.code, this.$router);
/* (1) Try to load data */
gstore.get.load_ue_groups(this.$route.params.code, 3).catch( (err) => { // try at max 3 times (200ms each) for UE to be loaded
/* (2) On error -> go to 'view' page */
gstore.get.router.push('/ue/view/');
});
} }
} }

View File

@ -105,7 +105,7 @@
<!-- if VIEW MODE --> <!-- if VIEW MODE -->
<div class='footer' v-show='gstore.edit_i!=pi'> <div class='footer' v-show='gstore.edit_i!=pi'>
<button class='neutral' @click='gstore.nav_in($router, pi)'>Configurer</button> <button class='neutral' @click='gstore.nav_in(pi)'>Configurer</button>
</div> </div>
<!-- if EDIT MODE --> <!-- if EDIT MODE -->
<div class='footer' v-show='gstore.edit_i==pi'> <div class='footer' v-show='gstore.edit_i==pi'>

View File

@ -543,6 +543,7 @@ gstore.add('manage', {
cours: [], cours: [],
td: [], td: [],
tp: [], tp: [],
prof: []
}); });
@ -578,16 +579,18 @@ gstore.add('load_ue_groups', function(code, recur=0){
api.call(`GET ue/cours/${code}`, {}, function(rs){ api.call(`GET ue/cours/${code}`, {}, function(rs){
// erase data
gstore.get.manage.cours.splice(0);
// reject on error // reject on error
if( rs.error !== 0 || !(rs['groups'] instanceof Array) ){ if( rs.error !== 0 || !(rs['groups'] instanceof Array) )
gstore.get.manage.cours.splice(); return reject({ label: 'Cours', code: rs.error});
reject({ label: 'Cours', code: rs.error});
}
// store data // store data
// for each field add a 'add_form' for instant-adding formations afterwards // for each field add a 'add_form' for instant-adding formations afterwards
for( var group of rs.groups ){ for( var group of rs.groups ){
group.add_form = '-'; group.add_form = '-';
( group.idProf == null ) && ( group.idProf = -1 );
gstore.get.manage.cours.push( group ); gstore.get.manage.cours.push( group );
} }
@ -603,16 +606,18 @@ gstore.add('load_ue_groups', function(code, recur=0){
api.call(`GET ue/td/${code}`, {}, function(rs){ api.call(`GET ue/td/${code}`, {}, function(rs){
// erase data
gstore.get.manage.td.splice(0);
// reject on error // reject on error
if( rs.error !== 0 || !(rs['groups'] instanceof Array) ){ if( rs.error !== 0 || !(rs['groups'] instanceof Array) )
gstore.get.manage.td.splice(); return reject({ label: 'TD', code: rs.error});
reject({ label: 'TD', code: rs.error});
}
// store data // store data
// for each field add a 'add_form' for instant-adding formations afterwards // for each field add a 'add_form' for instant-adding formations afterwards
for( var group of rs.groups ){ for( var group of rs.groups ){
group.add_form = '-'; group.add_form = '-';
( group.idProf == null ) && ( group.idProf = -1 );
gstore.get.manage.td.push( group ); gstore.get.manage.td.push( group );
} }
@ -630,16 +635,18 @@ gstore.add('load_ue_groups', function(code, recur=0){
api.call(`GET ue/tp/${code}`, {}, function(rs){ api.call(`GET ue/tp/${code}`, {}, function(rs){
// erase data
gstore.get.manage.tp.splice(0);
// reject on error // reject on error
if( rs.error !== 0 || !(rs['groups'] instanceof Array) ){ if( rs.error !== 0 || !(rs['groups'] instanceof Array) )
gstore.get.manage.tp.splice(); return reject({ label: 'TP', code: rs.error});
reject({ label: 'TP', code: rs.error});
}
// store data // store data
// for each field add a 'add_form' for instant-adding formations afterwards // for each field add a 'add_form' for instant-adding formations afterwards
for( var group of rs.groups ){ for( var group of rs.groups ){
group.add_form = '-'; group.add_form = '-';
( group.idProf == null ) && ( group.idProf = -1 );
gstore.get.manage.tp.push( group ); gstore.get.manage.tp.push( group );
} }
@ -650,6 +657,35 @@ gstore.add('load_ue_groups', function(code, recur=0){
}); });
/* (6) Ask for professors data */
}).then( () => {
return new Promise( (resolve, reject) => {
// 1. if already downloaded
if( gstore.get.manage.prof.length > 0 )
return resolve();
// 2. Else fetch from database
api.call(`GET professor/0`, {}, function(rs){
// erase data
gstore.get.manage.prof.splice(0);
// reject on error
if( rs.error !== 0 || !(rs['professors'] instanceof Array) )
return reject({ label: 'Professeurs', code: rs.error});
// store data
gstore.get.manage.prof = rs.professors;
// resolve data on success
resolve();
});
});
}); });
}) })
@ -668,35 +704,29 @@ gstore.add('nav_anim', {
}); });
/* (2) Manage nav in */ /* (2) Manage nav in */
gstore.add('nav_in', function($router, ue_i){ gstore.add('nav_in', function(ue_i){
/* (1) Abort if wrong ue_i */ /* (1) Abort if wrong ue_i */
if( ue_i == null || isNaN(ue_i) || gstore.get.ues[ue_i] == null) if( ue_i == null || isNaN(ue_i) || gstore.get.ues[ue_i] == null)
return; return;
/* (2) Try to get data (Promise) */ /* 1. Start animation */
gstore.get.load_ue_groups(gstore.get.ues[ue_i].code).then( () => { gstore.get.nav_anim.in = true;
/* 1. Start animation */ setTimeout( () => {
gstore.get.nav_anim.in = true;
setTimeout( () => { /* 2. Load page */
gstore.get.router.push(`/ue/manage/${gstore.get.ues[ue_i].code}`);
/* 2. Load page */ /* 3. Stop animation */
$router.push(`/ue/manage/${gstore.get.ues[ue_i].code}`); gstore.get.nav_anim.in = false;
/* 3. Stop animation */
gstore.get.nav_anim.in = false;
}, 500 );
}).catch( (err) => console.log(`[label] ${err.label} [error] ${err.code}`) );
}, 500 );
}); });
/* (3) Manage nav out */ /* (3) Manage nav out */
gstore.add('nav_out', function($router){ gstore.add('nav_out', function(){
/* 1. Start animation */ /* 1. Start animation */
gstore.get.nav_anim.out = true; gstore.get.nav_anim.out = true;
@ -704,15 +734,15 @@ gstore.add('nav_out', function($router){
setTimeout( () => { setTimeout( () => {
/* 2. Load page */ /* 2. Load page */
$router.push(`/ue/view/`); gstore.get.router.push(`/ue/view/`);
/* 3. Stop animation */ /* 3. Stop animation */
gstore.get.nav_anim.out = false; gstore.get.nav_anim.out = false;
/* 4. Remove 'manage' data */ /* 4. Remove 'manage' data */
gstore.get.manage.cours = []; gstore.get.manage.cours.splice();
gstore.get.manage.td = []; gstore.get.manage.td.splice();
gstore.get.manage.tp = []; gstore.get.manage.tp.splice();
}, 500 ); }, 500 );
@ -723,30 +753,113 @@ gstore.add('nav_out', function($router){
/* (11) Manage 'manage' formations add|rem
/* (11) Load 'manage' page data if loaded from URL
---------------------------------------------------------*/ ---------------------------------------------------------*/
gstore.add('manage_load', function(code, $router){ /* (1) Remove a formation */
gstore.add('rem_form', function(type, res_i, id_form){
/* (1) Try to load data */ // 1. Check params types
gstore.get.load_ue_groups(code, 3).catch( (err) => { // try at max 3 times (200ms each) for UE to be loaded if( isNaN(type) || isNaN(res_i) || isNaN(id_form) )
return;
// 2. Check @type param
if( [0,1,2].indexOf(type) == -1 )
return;
// 3. extract API resource from @type
var res = [ 'cours', 'td', 'tp' ][type];
var resM = [ 'Cours', 'TD', 'TP' ][type];
// 4. Extract @resource from @res_i
var resource = gstore.get.manage[res][res_i];
// 4- Manage unreachable resource
if( resource == null )
return;
// 5. Extract resource ID
var res_id = resource[`id${resM}`];
// 6. Request to remove formation
api.call(`PUT ue/${res}/${res_id}`, { rem_form: [id_form] }, (rs) => {
// 6.1. Manage error
if( rs.error !== 0 || rs.updated !== true )
return;
// 6.2. Get reference of data in gstore (if Cours, TD, TP)
var local = gstore.get.manage[res];
// 6.3. Unset formation to remove from view
for( var f_index in resource.formations ){ // search its index
// if found -> remove by index
if( resource.formations[f_index] === id_form ){
resource.formations.splice(f_index, 1);
break;
}
}
/* (2) On error -> go to 'view' page */
$router.push('/ue/view/');
}); });
})
});
/* (2) Add a formation */
gstore.add('add_form', function(type, id_res, i){
// 1. Check params types
if( isNaN(type) || isNaN(id_res) || isNaN(i) )
return;
// 2. Check @type param
if( [0,1,2].indexOf(type) == -1 )
return;
// 3. extract API resource from @type
var res = [ 'cours', 'td', 'tp' ][type];
var resM = [ 'Cours', 'TD', 'TP' ][type];
// 4. Exit if @i is invalid
if( gstore.get.manage[res][i] == null )
return;
// 5. Extract <select> formation id
var id_form = gstore.get.manage[res][i].add_form;
// 6. Exit if not a number
if( isNaN(id_form) )
return;
// 7. Request to add formation
api.call(`PUT ue/${res}/${id_res}`, { add_form: [id_form] }, (rs) => {
// 7.1. Manage error
if( rs.error !== 0 || rs.updated !== true )
return;
// 7.2. Unselect the <select>
gstore.get.manage[res][i].add_form = '-';
// 7.3. Add formation to update VueJS
gstore.get.manage[res][i].formations.push(id_form);
});
});
/* (12) Manage 'manage' formations add|rem /* (12) Manage 'prof' for Cours|TD|T{}
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Remove a formation */ /* (1) Update a prof (or unset) */
gstore.add('rem_form', function(type, id_res, id_form){ gstore.add('upd_prof', function(type, id_res, id_form){
// 1. Check params types // 1. Check params types
if( isNaN(type) || isNaN(id_res) || isNaN(id_form) ) if( isNaN(type) || isNaN(id_res) || isNaN(id_form) )
@ -796,48 +909,4 @@ gstore.add('rem_form', function(type, id_res, id_form){
}); });
});
/* (2) Add a formation */
gstore.add('add_form', function(type, id_res, i){
// 1. Check params types
if( isNaN(type) || isNaN(id_res) || isNaN(i) )
return;
// 2. Check @type param
if( [0,1,2].indexOf(type) == -1 )
return;
// 3. extract API resource from @type
var res = [ 'cours', 'td', 'tp' ][type];
var resM = [ 'Cours', 'TD', 'TP' ][type];
// 4. Exit if @i is invalid
if( gstore.get.manage[res][i] == null )
return;
// 5. Extract <select> formation id
var id_form = gstore.get.manage[res][i].add_form;
// 6. Exit if not a number
if( isNaN(id_form) )
return;
// 7. Request to add formation
api.call(`PUT ue/${res}/${id_res}`, { add_form: [id_form] }, (rs) => {
// 7.1. Manage error
if( rs.error !== 0 || rs.updated !== true )
return;
// 7.2. Unselect the <select>
gstore.get.manage[res][i].add_form = '-';
// 7.3. Add formation to update VueJS
gstore.get.manage[res][i].formations.push(id_form);
});
}); });

View File

@ -22,7 +22,7 @@
/* (1) List element */ /* (1) List element */
& > section{ & > section{
flex: 1 1 95%; flex: 1 1 90%;
display: flex; display: flex;
@ -37,7 +37,7 @@
// flex properties // flex properties
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: space-between;
align-items: center; align-items: center;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -62,6 +62,39 @@
&.tp:hover{ border-left-color: $form-invalid-color; } &.tp:hover{ border-left-color: $form-invalid-color; }
} }
/* (1.3) Select elements*/
& > select{
display: inline-block;
position: relative;
height: 1.8em;
width: auto;
margin: 0;
margin-right: 1em;
padding: .2em .5em;
padding-right: 1em;
border: 1px solid lighten($form-neutral-color, 5%);
border-radius: 3px;
background: transparent url('/asset/svg/down_arrow.svg@bbbbbb') right .5em bottom .1em no-repeat;
background-size: auto 80%;
color: #999;
font-size: .8em;
cursor: default;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
justify-self: space-around;
flex: 0 1 20em;
}
} }
@ -94,36 +127,14 @@
&[data-filter='up']{ background-image: url('/asset/svg/up_arrow.svg@aaaaaa'); } &[data-filter='up']{ background-image: url('/asset/svg/up_arrow.svg@aaaaaa'); }
} }
}
& > div.null:after{ content: none; }
/* (3) List title */
& > h1{
flex: 1 0 95%;
display: inline-block;
margin: .8em 1.2em;
font-size: inherit;
color: #888;
}
/* (4) List separator */
& > hr{
display: block;
position: relative;
margin: 1em 1.5em;
border: 0;
border-bottom: 2px solid darken($bg-color, 5%);
} }
/* Tags color -> darker */ /* Tags color -> darker */
.tag{ .tag,
& > section > select{
color: $primary-color; color: $primary-color;
} }